Skip to content

Commit bb6ce94

Browse files
committed
Utilise custom event handlers
1 parent 8d531be commit bb6ce94

File tree

2 files changed

+29
-13
lines changed

2 files changed

+29
-13
lines changed

ModFramework/Emitters/EventEmitter.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,21 @@ public static class EventEmitter
3737
/// <returns>A tuple of the field and event definitions</returns>
3838
public static (FieldDefinition fieldDefinition, EventDefinition eventDefinition) CreateEvent(this MethodDefinition sourceDefinition, TypeDefinition containingType, TypeDefinition eventArgsType, MonoModder modder, string? name = null)
3939
{
40-
var eventHandlerType = modder.ResolveTypeReference(typeof(EventHandler<>));
40+
//var eventHandlerType = modder.ResolveTypeReference(typeof(EventHandler<>));
41+
var eventHandlerType = !sourceDefinition.IsStatic ? HookEmitter.GetOrCreateHookDelegate(modder) : modder.ResolveTypeReference(typeof(EventHandler<>));
42+
var eventHandlerTypeGeneric = new GenericInstanceType(eventHandlerType)
43+
{
44+
GenericArguments = { eventArgsType }
45+
};
46+
if (!sourceDefinition.IsStatic)
47+
eventHandlerTypeGeneric.GenericArguments.Insert(0, sourceDefinition.DeclaringType);
4148

4249
// Define the event backing field
4350
var fieldName = name ?? $"{sourceDefinition.Name}Event";
4451
FieldDefinition eventField = new(
4552
fieldName,
4653
FieldAttributes.Private | FieldAttributes.Static,
47-
new GenericInstanceType(eventHandlerType)
48-
{
49-
GenericArguments = { eventArgsType }
50-
}
54+
eventHandlerTypeGeneric
5155
);
5256
containingType.Fields.Add(eventField);
5357

ModFramework/Emitters/HookEmitter.cs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,8 @@ public static Instruction CreateStoreIndirectFunction(TypeReference type)
173173
};
174174
}
175175

176-
public static TypeDefinition CreateHookDelegate(MonoModder modder)
176+
public static TypeDefinition GetOrCreateHookDelegate(MonoModder modder)
177177
{
178-
var test = modder.Module.ImportReference(typeof(HookDelegate<,>));
179178
var hookDelegate = modder.Module.Types.SingleOrDefault(x => x.Name == "HookDelegate");
180179
if (hookDelegate is not null)
181180
return hookDelegate;
@@ -235,7 +234,13 @@ public static TypeDefinition CreateHookDelegate(MonoModder modder)
235234
return hookDelegate;
236235
}
237236

238-
static MethodDefinition CreateInvokeMethod(TypeDefinition hookType, FieldDefinition eventField, TypeDefinition hookEventArgsType, MonoModder modder, string? name = null)
237+
static MethodDefinition CreateInvokeMethod(
238+
TypeDefinition hookType,
239+
FieldDefinition eventField,
240+
TypeDefinition hookEventArgsType,
241+
MonoModder modder,
242+
TypeReference? instanceType,
243+
string? name = null)
239244
{
240245
var methodName = name ?? $"Invoke{eventField.Name.TrimStart('_')}";
241246

@@ -250,7 +255,7 @@ static MethodDefinition CreateInvokeMethod(TypeDefinition hookType, FieldDefinit
250255
var senderFieldName = "instanceAsSender";
251256
while (hookType.Fields.Any(x => x.Name == senderFieldName))
252257
senderFieldName = "_" + senderFieldName;
253-
ParameterDefinition senderParam = new(senderFieldName, ParameterAttributes.None, hookType.Module.TypeSystem.Object);
258+
ParameterDefinition senderParam = new(senderFieldName, ParameterAttributes.None, instanceType ?? hookType.Module.TypeSystem.Object);
254259
invokeMethod.Parameters.Add(senderParam);
255260

256261
//var returnValueField = hookEventArgsType.Fields.SingleOrDefault(x => x.Name == HookReturnValueName);
@@ -271,12 +276,16 @@ static MethodDefinition CreateInvokeMethod(TypeDefinition hookType, FieldDefinit
271276

272277
// Create a GenericInstanceType for EventHandler<HookEventArgsType>
273278
//var eventHandlerGenericType = EventEmitter.GetEventHandlerReference(modder);
274-
var eventHandlerType = modder.ResolveTypeReference(typeof(EventHandler<>));
279+
//var eventHandlerType = modder.ResolveTypeReference(typeof(EventHandler<>));
280+
var eventHandlerType = instanceType is not null ? GetOrCreateHookDelegate(modder) : modder.ResolveTypeReference(typeof(EventHandler<>));
275281
GenericInstanceType genericEventHandlerType = new(eventHandlerType)
276282
{
277283
GenericArguments = { hookEventArgsType }
278284
};
279285

286+
if (instanceType is not null)
287+
genericEventHandlerType.GenericArguments.Insert(0, instanceType);
288+
280289
// Import the "Invoke" method of EventHandler<HookEventArgsType>
281290
var eventHandlerInvokeMethod = eventHandlerType.Resolve().Methods.First(m => m.Name == "Invoke");
282291
MethodReference invokeMethodReference = new(
@@ -289,7 +298,10 @@ static MethodDefinition CreateInvokeMethod(TypeDefinition hookType, FieldDefinit
289298
};
290299

291300
// Add parameters to the invokeMethodReference
292-
invokeMethodReference.Parameters.Add(new(hookType.Module.TypeSystem.Object)); // sender
301+
//invokeMethodReference.Parameters.Add(new(instanceType ?? hookType.Module.TypeSystem.Object)); // sender
302+
invokeMethodReference.Parameters.Add(new(instanceType is not null ?
303+
eventHandlerInvokeMethod.Parameters[0].ParameterType :
304+
hookType.Module.TypeSystem.Object)); // sender
293305
invokeMethodReference.Parameters.Add(new(eventHandlerInvokeMethod.Parameters[1].ParameterType)); // args - see EventHandler<>.Invoke, il is !0
294306

295307
// Generate IL for the Invoke method
@@ -451,14 +463,14 @@ public static void CreateHook(this MethodDefinition definition, ModFwModder modd
451463
// call an event
452464
// check whether to continue or not, using a simple bool flag
453465

454-
CreateHookDelegate(modder);
466+
GetOrCreateHookDelegate(modder);
455467

456468
var uniqueName = GetUniqueName(definition);
457469
var hookType = GetOrCreateHookType(definition.DeclaringType);
458470

459471
var hookEventArgs = CreateHookEventArgs(hookType, definition, name: $"{uniqueName}EventArgs", modder: modder);
460472
var (hookField, _) = definition.CreateEvent(hookType, hookEventArgs, modder, name: uniqueName);
461-
var newMethod = CreateInvokeMethod(hookType, hookField, hookEventArgs, modder, name: $"Invoke{uniqueName}");
473+
var newMethod = CreateInvokeMethod(hookType, hookField, hookEventArgs, modder, definition.IsStatic ? null : definition.DeclaringType, name: $"Invoke{uniqueName}");
462474

463475
var replacement = CreateReplacement(definition, newMethod, name: $"{HookMethodNamePrefix}{definition.Name}");
464476

0 commit comments

Comments
 (0)