diff --git a/Il2CppInterop.Generator/Contexts/FieldRewriteContext.cs b/Il2CppInterop.Generator/Contexts/FieldRewriteContext.cs index a2420e68..692d7390 100644 --- a/Il2CppInterop.Generator/Contexts/FieldRewriteContext.cs +++ b/Il2CppInterop.Generator/Contexts/FieldRewriteContext.cs @@ -62,7 +62,13 @@ private string UnmangleFieldName(FieldDefinition field, GeneratorOptions options if (!field.Name.IsObfuscated(options)) { - return field.Name.MakeValidInSource(); + var name = field.Name.MakeValidInSource(); + while (field.DeclaringType!.Events.Any(e => e.Name == name) + || field.DeclaringType!.Fields.Any(f => f.Name == name && f != field)) + { + name += "_"; // Backing fields for events have the same name as the event. + } + return name; } if (renamedFieldCounts == null) throw new ArgumentNullException(nameof(renamedFieldCounts)); diff --git a/Il2CppInterop.Generator/Passes/Pass71GenerateEvents.cs b/Il2CppInterop.Generator/Passes/Pass71GenerateEvents.cs new file mode 100644 index 00000000..315bdcaa --- /dev/null +++ b/Il2CppInterop.Generator/Passes/Pass71GenerateEvents.cs @@ -0,0 +1,60 @@ +using AsmResolver.DotNet; +using Il2CppInterop.Generator.Contexts; +using Il2CppInterop.Generator.Extensions; + +namespace Il2CppInterop.Generator.Passes; + +public static class Pass71GenerateEvents +{ + public static void DoPass(RewriteGlobalContext context) + { + foreach (var assemblyContext in context.Assemblies) + foreach (var typeContext in assemblyContext.Types) + { + var type = typeContext.OriginalType; + var eventCountsByName = new Dictionary(); + + foreach (var oldEvent in type.Events) + { + var unmangledEventName = UnmangleEventName(assemblyContext, oldEvent, typeContext.NewType, eventCountsByName); + + var eventType = assemblyContext.RewriteTypeRef(oldEvent.EventType?.ToTypeSignature()); + var @event = new EventDefinition(unmangledEventName, oldEvent.Attributes, eventType.ToTypeDefOrRef()); + + typeContext.NewType.Events.Add(@event); + + @event.SetSemanticMethods( + oldEvent.AddMethod is null ? null : typeContext.GetMethodByOldMethod(oldEvent.AddMethod).NewMethod, + oldEvent.RemoveMethod is null ? null : typeContext.GetMethodByOldMethod(oldEvent.RemoveMethod).NewMethod, + oldEvent.FireMethod is null ? null : typeContext.GetMethodByOldMethod(oldEvent.FireMethod).NewMethod); + } + } + } + + private static string UnmangleEventName(AssemblyRewriteContext assemblyContext, EventDefinition @event, + ITypeDefOrRef declaringType, Dictionary countsByBaseName) + { + if (assemblyContext.GlobalContext.Options.PassthroughNames || + !@event.Name.IsObfuscated(assemblyContext.GlobalContext.Options)) return @event.Name!; + + var baseName = "event_" + assemblyContext.RewriteTypeRef(@event.EventType?.ToTypeSignature()).GetUnmangledName(@event.DeclaringType); + + countsByBaseName.TryGetValue(baseName, out var index); + countsByBaseName[baseName] = index + 1; + + var unmangleEventName = baseName + "_" + index; + + if (assemblyContext.GlobalContext.Options.RenameMap.TryGetValue( + declaringType.GetNamespacePrefix() + "." + declaringType.Name + "::" + unmangleEventName, out var newNameByType)) + { + unmangleEventName = newNameByType; + } + else if (assemblyContext.GlobalContext.Options.RenameMap.TryGetValue( + declaringType.GetNamespacePrefix() + "::" + unmangleEventName, out var newName)) + { + unmangleEventName = newName; + } + + return unmangleEventName; + } +} diff --git a/Il2CppInterop.Generator/Passes/Pass80UnstripMethods.cs b/Il2CppInterop.Generator/Passes/Pass80UnstripMethods.cs index 11165cc2..d6f1b7db 100644 --- a/Il2CppInterop.Generator/Passes/Pass80UnstripMethods.cs +++ b/Il2CppInterop.Generator/Passes/Pass80UnstripMethods.cs @@ -124,6 +124,16 @@ public static void DoPass(RewriteGlobalContext context) var property = GetOrCreateProperty(unityMethod, newMethod); property.SetMethod = newMethod; } + else if (unityMethod.IsAddMethod) + { + var @event = GetOrCreateEvent(unityMethod, newMethod); + @event.AddMethod = newMethod; + } + else if (unityMethod.IsRemoveMethod) + { + var @event = GetOrCreateEvent(unityMethod, newMethod); + @event.RemoveMethod = newMethod; + } var paramsMethod = context.CreateParamsMethod(unityMethod, newMethod, imports, type => ResolveTypeInNewAssemblies(context, type, imports)); @@ -171,6 +181,21 @@ private static PropertyDefinition GetOrCreateProperty(MethodDefinition unityMeth return newProperty; } + private static EventDefinition GetOrCreateEvent(MethodDefinition unityMethod, MethodDefinition newMethod) + { + var unityEvent = + unityMethod.DeclaringType!.Events.Single( + it => it.AddMethod == unityMethod || it.RemoveMethod == unityMethod); + var newEvent = newMethod.DeclaringType!.Events.SingleOrDefault(it => it.Name == unityEvent.Name); + if (newEvent == null) + { + newEvent = new EventDefinition(unityEvent.Name, unityEvent.Attributes, newMethod.Signature!.ParameterTypes.Single().ToTypeDefOrRef()); + newMethod.DeclaringType.Events.Add(newEvent); + } + + return newEvent; + } + internal static TypeSignature? ResolveTypeInNewAssemblies(RewriteGlobalContext context, TypeSignature? unityType, RuntimeAssemblyReferences imports, bool useSystemCorlibPrimitives = true) { diff --git a/Il2CppInterop.Generator/Runners/InteropAssemblyGenerator.cs b/Il2CppInterop.Generator/Runners/InteropAssemblyGenerator.cs index b1c66b7c..3744bfb3 100644 --- a/Il2CppInterop.Generator/Runners/InteropAssemblyGenerator.cs +++ b/Il2CppInterop.Generator/Runners/InteropAssemblyGenerator.cs @@ -153,6 +153,11 @@ public void Run(GeneratorOptions options) Pass70GenerateProperties.DoPass(rewriteContext); } + using (new TimingCookie("Creating events")) + { + Pass71GenerateEvents.DoPass(rewriteContext); + } + if (options.UnityBaseLibsDir != null) { using (new TimingCookie("Unstripping types"))