@@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License
1818*/
1919using Mono . Cecil ;
2020using Mono . Cecil . Cil ;
21+ using MonoMod ;
2122using System ;
2223using System . Linq ;
2324
@@ -55,22 +56,28 @@ static string GetUniqueName(MethodDefinition method)
5556 if ( method . DeclaringType . Methods . Count ( x => x . Name == name ) > 1 && method . Parameters . Count > 0 )
5657 {
5758 // overloads are detected, append parameter types to the name
58- name += "_" + string . Join ( "_" , method . Parameters . Select ( y => y . ParameterType . Name ) ) ;
59+ name += "_" + string . Join ( "_" , method . Parameters . Select ( y =>
60+ {
61+ var name = y . ParameterType . Name ;
62+ if ( y . ParameterType . IsByReference )
63+ name = $ "{ y . ParameterType . GetElementType ( ) . Name } ByRef";
64+ return name ;
65+ } ) ) ;
5966 }
6067 return name ;
6168 }
6269
6370 const String HookReturnValueName = "HookReturnValue" ;
6471 const String ContinueExecutionName = "ContinueExecution" ;
6572
66- static TypeDefinition CreateHookEventArgs ( TypeDefinition hookType , MethodDefinition hookDefinition , string ? name = null )
73+ static TypeDefinition CreateHookEventArgs ( TypeDefinition hookType , MethodDefinition hookDefinition , string ? name = null , MonoModder ? modder = null )
6774 {
6875 var hookEventName = name ?? ( hookDefinition . Name + "EventArgs" ) ;
6976 TypeDefinition hookEvent = new (
7077 "" , //hookType.Namespace,
7178 hookEventName ,
7279 TypeAttributes . Class | TypeAttributes . BeforeFieldInit | TypeAttributes . NestedPublic | TypeAttributes . Sealed ,
73- hookType . Module . ImportReference ( typeof ( Object ) )
80+ hookType . Module . TypeSystem . Object
7481 ) ;
7582 hookType . NestedTypes . Add ( hookEvent ) ;
7683
@@ -95,14 +102,12 @@ static TypeDefinition CreateHookEventArgs(TypeDefinition hookType, MethodDefinit
95102
96103 // create ctor, calling base ctor
97104 MethodDefinition ctor = new ( ".ctor" , MethodAttributes . Public | MethodAttributes . HideBySig | MethodAttributes . SpecialName | MethodAttributes . RTSpecialName , hookDefinition . Module . TypeSystem . Void ) ;
98- //ctor.Body = new(ctor)
99- //{
100- // InitLocals = true
101- //};
102105 var il = ctor . Body . GetILProcessor ( ) ;
103106
104107 il . Emit ( OpCodes . Ldarg_0 ) ;
105- il . Emit ( OpCodes . Call , hookDefinition . Module . ImportReference ( typeof ( object ) . GetConstructors ( ) . Single ( ) ) ) ;
108+
109+ var objCtor = hookDefinition . Module . TypeSystem . Object . Resolve ( ) . Methods . Single ( x => x . Name == ".ctor" ) ;
110+ il . Emit ( OpCodes . Call , hookDefinition . Module . ImportReference ( objCtor ) ) ;
106111
107112 // Set ContinueExecution to true
108113 il . Emit ( OpCodes . Ldarg_0 ) ;
@@ -165,7 +170,7 @@ public static Instruction CreateStoreIndirectFunction(TypeReference type)
165170 } ;
166171 }
167172
168- static MethodDefinition CreateInvokeMethod ( TypeDefinition hookType , FieldDefinition eventField , TypeDefinition hookEventArgsType , string ? name = null )
173+ static MethodDefinition CreateInvokeMethod ( TypeDefinition hookType , FieldDefinition eventField , TypeDefinition hookEventArgsType , MonoModder modder , string ? name = null )
169174 {
170175 var methodName = name ?? $ "Invoke{ eventField . Name . TrimStart ( '_' ) } ";
171176
@@ -200,7 +205,8 @@ static MethodDefinition CreateInvokeMethod(TypeDefinition hookType, FieldDefinit
200205 }
201206
202207 // Create a GenericInstanceType for EventHandler<HookEventArgsType>
203- var eventHandlerGenericType = hookType . Module . ImportReference ( typeof ( EventHandler < > ) ) ;
208+ var eventHandlerGenericType = EventEmitter . GetEventHandlerReference ( modder ) ;
209+
204210 GenericInstanceType genericEventHandlerType = new ( eventHandlerGenericType )
205211 {
206212 GenericArguments = { hookEventArgsType }
@@ -241,7 +247,7 @@ static MethodDefinition CreateInvokeMethod(TypeDefinition hookType, FieldDefinit
241247
242248 // Check if the event is not null
243249 il . Emit ( OpCodes . Ldsfld , eventField ) ; // Load the static event field
244- il . Emit ( OpCodes . Brfalse_S , returnLabel ) ; // If null, skip invocation
250+ il . Emit ( OpCodes . Brfalse , returnLabel ) ; // If null, skip invocation
245251
246252 // Invoke the event delegate
247253 il . Emit ( OpCodes . Ldsfld , eventField ) ; // Load the static event field
@@ -292,10 +298,8 @@ static MethodDefinition CreateReplacement(MethodDefinition original, MethodDefin
292298 il . Emit ( OpCodes . Ldarg_S , param ) ;
293299 var defaultValue = CreateDefaultValueInstruction ( type ) ;
294300 il . Append ( defaultValue ) ;
295- //il.Emit(OpCodes.Stind_Ref);
296301 if ( defaultValue . OpCode != OpCodes . Initobj )
297302 il . Append ( CreateStoreIndirectFunction ( type ) ) ;
298- //il.Emit(OpCodes.Stind_I1);
299303 }
300304
301305 il . Emit ( original . IsStatic ? OpCodes . Ldnull : OpCodes . Ldarg_0 ) ;
@@ -319,7 +323,6 @@ static MethodDefinition CreateReplacement(MethodDefinition original, MethodDefin
319323 il . Emit ( OpCodes . Ldarg_S , param ) ;
320324 il . Emit ( OpCodes . Ldloc , eventArgsVariable ) ;
321325 il . Emit ( OpCodes . Ldfld , field ) ;
322- //il.Emit(OpCodes.Stind_Ref);
323326 il . Append ( CreateStoreIndirectFunction ( field . FieldType . GetElementType ( ) ) ) ;
324327 }
325328
@@ -329,7 +332,7 @@ static MethodDefinition CreateReplacement(MethodDefinition original, MethodDefin
329332
330333 // the event invoke is a boolen, if false, return else invoke the original method
331334 var returnLabel = hookReturnValueField is not null ? il . Create ( OpCodes . Ldloc , eventArgsVariable ) : il . Create ( OpCodes . Ret ) ;
332- il . Emit ( OpCodes . Brfalse_S , returnLabel ) ;
335+ il . Emit ( OpCodes . Brfalse , returnLabel ) ;
333336
334337 if ( ! original . IsStatic )
335338 il . Emit ( OpCodes . Ldarg_0 ) ;
@@ -349,7 +352,8 @@ static MethodDefinition CreateReplacement(MethodDefinition original, MethodDefin
349352 }
350353 }
351354 il . Emit ( OpCodes . Call , original . Module . ImportReference ( original ) ) ;
352- il . Emit ( OpCodes . Ret ) ;
355+ if ( hookReturnValueField is not null )
356+ il . Emit ( OpCodes . Ret ) ;
353357
354358 il . Append ( returnLabel ) ;
355359
@@ -362,6 +366,12 @@ static MethodDefinition CreateReplacement(MethodDefinition original, MethodDefin
362366 return methodDefinition ;
363367 }
364368
369+ /// <summary>
370+ /// The name to place in front of the preserved hook method
371+ /// </summary>
372+ /// <remarks>ModFramework Hook</remarks>
373+ public const String HookMethodNamePrefix = "mfwh_" ;
374+
365375 /// <summary>
366376 /// Creates a hook for a single method.
367377 /// </summary>
@@ -379,26 +389,20 @@ public static void CreateHook(this MethodDefinition definition, ModFwModder modd
379389 var uniqueName = GetUniqueName ( definition ) ;
380390 var hookType = GetOrCreateHookType ( definition . DeclaringType ) ;
381391
382- var hookEventArgs = CreateHookEventArgs ( hookType , definition , name : $ "{ uniqueName } EventArgs") ;
383- var ( hookField , _) = definition . CreateEvent ( hookType , hookEventArgs , name : uniqueName ) ;
384- var newMethod = CreateInvokeMethod ( hookType , hookField , hookEventArgs , name : $ "Invoke{ uniqueName } ") ;
392+ var hookEventArgs = CreateHookEventArgs ( hookType , definition , name : $ "{ uniqueName } EventArgs", modder : modder ) ;
393+ var ( hookField , _) = definition . CreateEvent ( hookType , hookEventArgs , modder , name : uniqueName ) ;
394+ var newMethod = CreateInvokeMethod ( hookType , hookField , hookEventArgs , modder , name : $ "Invoke{ uniqueName } ") ;
385395
386- //var originalName = definition.Name;
387- //definition.Name = $"hooked_{definition.Name}";
388-
389- var replacement = CreateReplacement ( definition , newMethod , name : $ "hooked_{ definition . Name } ") ;
396+ var replacement = CreateReplacement ( definition , newMethod , name : $ "{ HookMethodNamePrefix } { definition . Name } ") ;
390397
391398 definition . DeclaringType . Methods . Add ( replacement ) ;
392399
393- //// rename the original method
394- //definition.Name = $"hooked_{definition.Name}";
395-
396400 // remove any overrides etc
397401 replacement . Attributes &= ~ MethodAttributes . Virtual ;
398402 replacement . Attributes &= ~ MethodAttributes . NewSlot ;
399403 replacement . Attributes &= ~ MethodAttributes . SpecialName ;
400404
401- // swap bodies instead
405+ // swap bodies, much easier this way...
402406
403407 // swap the method references
404408 foreach ( var instr in replacement . Body . Instructions )
@@ -411,8 +415,6 @@ public static void CreateHook(this MethodDefinition definition, ModFwModder modd
411415 var temp = definition . Body ;
412416 definition . Body = replacement . Body ;
413417 replacement . Body = temp ;
414-
415- //
416418 }
417419
418420 /// <summary>
@@ -428,7 +430,9 @@ public static void CreateHooks(this TypeDefinition definition, ModFwModder modde
428430 // not a constructor
429431 ! x . IsConstructor &&
430432 // not an event
431- ! ( definition . Events . Any ( evt => evt . AddMethod == x || evt . RemoveMethod == x || evt . InvokeMethod == x ) )
433+ ! ( definition . Events . Any ( evt => evt . AddMethod == x || evt . RemoveMethod == x || evt . InvokeMethod == x ) ) &&
434+ // not generic instance (TODO)
435+ ! x . HasGenericParameters
432436 ) . ToList ( ) )
433437 method . CreateHook ( modder ) ;
434438 }
0 commit comments