14
14
*************************************************************************/
15
15
16
16
using System ;
17
+ using System . Collections . Concurrent ;
17
18
using System . Collections . Generic ;
18
19
using System . IO ;
19
20
using System . Linq ;
20
21
using System . Reflection ;
21
22
using System . Runtime . CompilerServices ;
22
23
using System . Runtime . Loader ;
24
+ using Server . Logging ;
23
25
24
26
namespace Server ;
25
27
26
28
public static class AssemblyHandler
27
29
{
28
30
private static readonly Dictionary < Assembly , TypeCache > m_TypeCaches = new ( ) ;
29
31
private static TypeCache m_NullCache ;
32
+
30
33
public static Assembly [ ] Assemblies { get ; set ; }
31
34
32
35
internal static Assembly AssemblyResolver ( object sender , ResolveEventArgs args )
@@ -66,6 +69,8 @@ public static Assembly LoadAssemblyByAssemblyName(AssemblyName assemblyName)
66
69
EnsureAssemblyDirectories ( ) ;
67
70
var assemblyDirectories = ServerConfiguration . AssemblyDirectories ;
68
71
72
+ Assembly assembly = null ;
73
+
69
74
foreach ( var assemblyDir in assemblyDirectories )
70
75
{
71
76
var assemblyPath = PathUtility . GetFullPath ( Path . Combine ( assemblyDir , fileName ) , Core . BaseDirectory ) ;
@@ -74,12 +79,17 @@ public static Assembly LoadAssemblyByAssemblyName(AssemblyName assemblyName)
74
79
var assemblyNameCheck = AssemblyName . GetAssemblyName ( assemblyPath ) ;
75
80
if ( assemblyNameCheck . FullName == fullName )
76
81
{
77
- return AssemblyLoadContext . Default . LoadFromAssemblyPath ( assemblyPath ) ;
82
+ assembly = AssemblyLoadContext . Default . LoadFromAssemblyPath ( assemblyPath ) ;
83
+ break ;
78
84
}
79
85
}
80
86
}
81
87
82
- return null ;
88
+ // This forces the type caching to be generated.
89
+ // We need this for world loading to find types by hash.
90
+ GetTypeCache ( assembly ) ;
91
+
92
+ return assembly ;
83
93
}
84
94
85
95
public static Assembly LoadAssemblyByFileName ( string assemblyFile )
@@ -154,6 +164,11 @@ private static void AddMethods(this Assembly assembly, string method, List<Metho
154
164
}
155
165
}
156
166
167
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
168
+ public static ulong GetTypeHash ( Type type ) => GetTypeHash ( type . FullName ) ;
169
+
170
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
171
+ public static ulong GetTypeHash ( string key ) => key == null ? 0 : HashUtility . ComputeHash64 ( key ) ;
157
172
158
173
public static TypeCache GetTypeCache ( Assembly asm )
159
174
{
@@ -195,149 +210,171 @@ public static Type FindTypeByName(string name, bool fullName = false, bool ignor
195
210
196
211
return null ;
197
212
}
213
+
214
+ public static Type FindTypeByHash ( ulong hash )
215
+ {
216
+ for ( var i = 0 ; i < Assemblies . Length ; i ++ )
217
+ {
218
+ foreach ( var type in GetTypeCache ( Assemblies [ i ] ) . GetTypesByHash ( hash , true , false ) )
219
+ {
220
+ return type ;
221
+ }
222
+ }
223
+
224
+ foreach ( var type in GetTypeCache ( Core . Assembly ) . GetTypesByHash ( hash , true , false ) )
225
+ {
226
+ return type ;
227
+ }
228
+
229
+ return null ;
230
+ }
198
231
}
199
232
200
233
public class TypeCache
201
234
{
202
- private readonly Dictionary < string , int [ ] > _nameMap = new ( ) ;
203
- private readonly Dictionary < string , int [ ] > _nameMapInsensitive = new ( ) ;
204
- private readonly Dictionary < string , int [ ] > _fullNameMap = new ( ) ;
205
- private readonly Dictionary < string , int [ ] > _fullNameMapInsensitive = new ( ) ;
235
+ private static ILogger logger = LogFactory . GetLogger ( typeof ( TypeCache ) ) ;
236
+
237
+ private Dictionary < ulong , Type [ ] > _nameMap = new ( ) ;
238
+ private Dictionary < ulong , Type [ ] > _nameMapInsensitive = new ( ) ;
239
+ private Dictionary < ulong , Type [ ] > _fullNameMap = new ( ) ;
240
+ private Dictionary < ulong , Type [ ] > _fullNameMapInsensitive = new ( ) ;
206
241
207
242
public TypeCache ( Assembly asm )
208
243
{
209
244
Types = asm ? . GetTypes ( ) ?? Type . EmptyTypes ;
210
245
211
- var nameMap = new Dictionary < string , HashSet < int > > ( ) ;
212
- var nameMapInsensitive = new Dictionary < string , HashSet < int > > ( ) ;
213
- var fullNameMap = new Dictionary < string , HashSet < int > > ( ) ;
214
- var fullNameMapInsensitive = new Dictionary < string , HashSet < int > > ( ) ;
246
+ var nameMap = new Dictionary < string , HashSet < Type > > ( ) ;
247
+ var nameMapInsensitive = new Dictionary < string , HashSet < Type > > ( ) ;
248
+ var fullNameMap = new Dictionary < string , HashSet < Type > > ( ) ;
249
+ var fullNameMapInsensitive = new Dictionary < string , HashSet < Type > > ( ) ;
215
250
216
251
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
217
- void addTypeToRefs ( int index , string fullTypeName )
252
+ void addTypeToRefs ( Type type , string typeName , string fullTypeName )
218
253
{
219
- var typeName = fullTypeName [ ( fullTypeName . LastIndexOf ( '.' ) + 1 ) ..] ;
220
- AddToRefs ( index , typeName , nameMap ) ;
221
- AddToRefs ( index , typeName . ToLower ( ) , nameMapInsensitive ) ;
222
- AddToRefs ( index , fullTypeName , fullNameMap ) ;
223
- AddToRefs ( index , fullTypeName . ToLower ( ) , fullNameMapInsensitive ) ;
254
+ AddToRefs ( type , typeName , nameMap ) ;
255
+ AddToRefs ( type , typeName . ToLower ( ) , nameMapInsensitive ) ;
256
+ AddToRefs ( type , fullTypeName , fullNameMap ) ;
257
+ AddToRefs ( type , fullTypeName . ToLower ( ) , fullNameMapInsensitive ) ;
224
258
}
225
259
226
260
var aliasType = typeof ( TypeAliasAttribute ) ;
227
261
for ( var i = 0 ; i < Types . Length ; i ++ )
228
262
{
229
263
var current = Types [ i ] ;
230
- addTypeToRefs ( i , current . FullName ) ;
264
+ addTypeToRefs ( current , current . Name , current . FullName ?? "" ) ;
231
265
if ( current . GetCustomAttribute ( aliasType , false ) is TypeAliasAttribute alias )
232
266
{
233
267
for ( var j = 0 ; j < alias . Aliases . Length ; j ++ )
234
268
{
235
- addTypeToRefs ( i , alias . Aliases [ j ] ) ;
269
+ var fullTypeName = alias . Aliases [ j ] ;
270
+ var typeName = fullTypeName [ ( fullTypeName . LastIndexOf ( '.' ) + 1 ) ..] ;
271
+ addTypeToRefs ( current , typeName , fullTypeName ) ;
236
272
}
237
273
}
238
274
}
239
275
240
276
foreach ( var ( key , value ) in nameMap )
241
277
{
242
- _nameMap [ key ] = value . ToArray ( ) ;
278
+ _nameMap [ HashUtility . ComputeHash64 ( key ) ] = value . ToArray ( ) ;
243
279
}
244
280
245
281
foreach ( var ( key , value ) in nameMapInsensitive )
246
282
{
247
- _nameMapInsensitive [ key ] = value . ToArray ( ) ;
283
+ _nameMapInsensitive [ HashUtility . ComputeHash64 ( key ) ] = value . ToArray ( ) ;
248
284
}
249
285
250
286
foreach ( var ( key , value ) in fullNameMap )
251
287
{
252
- _fullNameMap [ key ] = value . ToArray ( ) ;
288
+ var values = value . ToArray ( ) ;
289
+ _fullNameMap [ HashUtility . ComputeHash64 ( key ) ] = value . ToArray ( ) ;
290
+ #if DEBUG
291
+ if ( values . Length > 1 )
292
+ {
293
+ for ( var i = 0 ; i < values . Length ; i ++ )
294
+ {
295
+ var type = values [ i ] ;
296
+ logger . Warning (
297
+ "Duplicate type {Type1} for {Name}." ,
298
+ type ,
299
+ key
300
+ ) ;
301
+ }
302
+ }
303
+ #endif
253
304
}
254
305
255
306
foreach ( var ( key , value ) in fullNameMapInsensitive )
256
307
{
257
- _fullNameMapInsensitive [ key ] = value . ToArray ( ) ;
308
+ _fullNameMapInsensitive [ HashUtility . ComputeHash64 ( key ) ] = value . ToArray ( ) ;
258
309
}
259
310
}
260
311
261
312
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
262
- private static void AddToRefs ( int index , string key , Dictionary < string , HashSet < int > > map )
313
+ private static void AddToRefs ( Type type , string key , Dictionary < string , HashSet < Type > > map )
263
314
{
264
- if ( key == null )
315
+ if ( string . IsNullOrEmpty ( key ) )
265
316
{
266
317
return ;
267
318
}
268
319
269
320
if ( map . TryGetValue ( key , out var refs ) )
270
321
{
271
- refs . Add ( index ) ;
322
+ refs . Add ( type ) ;
272
323
}
273
324
else
274
325
{
275
- refs = new HashSet < int > { index } ;
326
+ refs = new HashSet < Type > { type } ;
276
327
map . Add ( key , refs ) ;
277
328
}
278
329
}
279
330
280
331
public Type [ ] Types { get ; }
281
332
282
333
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
283
- public TypeEnumerable GetTypesByName ( string name , bool full , bool ignoreCase ) => new ( name , this , full , ignoreCase ) ;
284
-
285
- public ref struct TypeEnumerable
286
- {
287
- private readonly TypeCache _cache ;
288
- private readonly string _name ;
289
- private readonly bool _ignoreCase ;
290
- private readonly bool _full ;
291
-
292
- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
293
- public TypeEnumerable ( string name , TypeCache cache , bool full , bool ignoreCase )
294
- {
295
- _name = name ;
296
- _cache = cache ;
297
- _ignoreCase = ignoreCase ;
298
- _full = full ;
299
- }
334
+ public TypeEnumerator GetTypesByName ( string name , bool full , bool ignoreCase ) => new ( name , this , full , ignoreCase ) ;
300
335
301
- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
302
- public TypeEnumerator GetEnumerator ( ) => new ( _name , _cache , _full , _ignoreCase ) ;
303
- }
336
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
337
+ public TypeEnumerator GetTypesByHash ( ulong hash , bool full , bool ignoreCase ) => new ( hash , this , full , ignoreCase ) ;
304
338
305
339
public ref struct TypeEnumerator
306
340
{
307
- private readonly TypeCache _cache ;
308
- private readonly int [ ] _values ;
341
+ private Type [ ] _values ;
309
342
private int _index ;
310
343
private Type _current ;
311
344
312
345
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
313
346
internal TypeEnumerator ( string name , TypeCache cache , bool full , bool ignoreCase )
347
+ : this ( HashUtility . ComputeHash64 ( ignoreCase ? name . ToLower ( ) : name ) , cache , full , ignoreCase )
314
348
{
315
- _cache = cache ;
349
+ }
316
350
351
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
352
+ internal TypeEnumerator ( ulong hash , TypeCache cache , bool full , bool ignoreCase )
353
+ {
317
354
if ( ignoreCase )
318
355
{
319
- var map = full ? _cache . _fullNameMapInsensitive : _cache . _nameMapInsensitive ;
320
- _values = map . TryGetValue ( name . ToLower ( ) , out var values ) ? values : Array . Empty < int > ( ) ;
356
+ var map = full ? cache . _fullNameMapInsensitive : cache . _nameMapInsensitive ;
357
+ _values = map . TryGetValue ( hash , out var values ) ? values : Array . Empty < Type > ( ) ;
321
358
}
322
359
else
323
360
{
324
- var map = full ? _cache . _fullNameMap : _cache . _nameMap ;
325
- _values = map . TryGetValue ( name , out var values ) ? values : Array . Empty < int > ( ) ;
361
+ var map = full ? cache . _fullNameMap : cache . _nameMap ;
362
+ _values = map . TryGetValue ( hash , out var values ) ? values : Array . Empty < Type > ( ) ;
326
363
}
327
364
328
365
_index = 0 ;
329
366
_current = default ;
330
367
}
331
368
369
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
370
+ public TypeEnumerator GetEnumerator ( ) => this ;
371
+
332
372
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
333
373
public bool MoveNext ( )
334
374
{
335
- int [ ] localList = _values ;
336
-
337
- if ( ( uint ) _index < ( uint ) localList . Length )
375
+ if ( ( uint ) _index < ( uint ) _values . Length )
338
376
{
339
- _current = _cache . Types [ _values [ _index ++ ] ] ;
340
-
377
+ _current = _values [ _index ++ ] ;
341
378
return true ;
342
379
}
343
380
0 commit comments