From 621d5fa1fd7a02681bad3ad83a22b59d2caf093c Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Mon, 25 Aug 2025 22:03:00 -0700 Subject: [PATCH 001/486] WIP --- .editorconfig | 30 +- Documentation/Design/Arrays.md | 15 + Documentation/Design/Attributes.md | 3 + Documentation/Design/CorLibTypes.md | 187 +++++ Documentation/Design/Delegates.md | 0 Documentation/Design/Enums.md | 118 +++ Documentation/Design/Exceptions.md | 10 + Documentation/Design/Fields.md | 15 + Documentation/Design/ForbiddenTypes.md | 28 + Documentation/Design/GenericMethods.md | 22 + Documentation/Design/GenericTypes.md | 10 + Documentation/Design/Injection.md | 79 ++ Documentation/Design/Interfaces.md | 2 + .../Design/NativeStaticConstructors.md | 7 + Documentation/Design/NestedTypes.md | 6 + Documentation/Design/ReturnObjects.md | 34 + Documentation/Design/SimpleClasses.md | 82 ++ Documentation/Design/Unstripping.md | 42 + Documentation/Design/ValueTypes.md | 235 ++++++ Il2CppInterop.CLI/Il2CppInterop.CLI.csproj | 12 +- Il2CppInterop.CLI/Program.cs | 364 ++------- Il2CppInterop.CLI/Utils.cs | 14 - .../Il2CppInterop.Common.csproj | 8 +- Il2CppInterop.Common/ObjectPointer.cs | 7 + .../ApplicationAnalysisContextExtensions.cs | 49 ++ .../AsmResolverDllOutputFormatBinding.cs | 45 ++ .../AsmResolverDllOutputFormatUnstripped.cs | 24 + .../AssemblyAnalysisContextExtensions.cs | 47 ++ .../AttributeRemovalProcessingLayer.cs | 94 +++ .../AttributesOverrideProcessingLayer.cs | 104 +++ .../BooleanAndTypeVisitor.cs | 30 + .../BooleanOrTypeVisitor.cs | 30 + .../CleanRenamingProcessingLayer.cs | 252 ++++++ .../ConstantInitializationProcessingLayer.cs | 72 ++ Il2CppInterop.Generator/ContextResolver.cs | 366 +++++++++ .../ContextWithDataStorageExtensions.cs | 70 ++ Il2CppInterop.Generator/DefaultTypeVisitor.cs | 68 ++ .../DelegateConversionProcessingLayer.cs | 320 ++++++++ .../DictionaryExtensions.cs | 18 + .../EnumProcessingLayer.cs | 220 +++++ .../ExceptionHierarchyProcessingLayer.cs | 202 +++++ .../FieldAccessorProcessingLayer.cs | 146 ++++ .../FieldAnalysisContextExtensions.cs | 69 ++ .../HasGenericParametersExtensions.cs | 14 + .../ICallProcessingLayer.cs | 46 ++ Il2CppInterop.Generator/Il2CppGame.cs | 68 ++ .../Il2CppInterop.Generator.csproj | 22 +- .../Il2CppRenamingProcessingLayer.cs | 76 ++ Il2CppInterop.Generator/Il2CppTypeInfo.cs | 10 + .../InitializationClassProcessingLayer.cs | 512 ++++++++++++ ...InjectedMethodAnalysisContextExtensions.cs | 15 + ...ectedParameterAnalysisContextExtensions.cs | 15 + .../InjectedTypeAnalysisContextExtensions.cs | 112 +++ .../InstructionListExtensions.cs | 16 + .../LocalVariableListExtensions.cs | 14 + .../MethodAnalysisContextExtensions.cs | 68 ++ Il2CppInterop.Generator/MethodBodyBase.cs | 84 ++ .../MethodBodyTranslationProcessingLayer.cs | 33 + .../MonoIl2CppConversion.cs | 137 ++++ ...scorlibAssemblyInjectionProcessingLayer.cs | 54 ++ Il2CppInterop.Generator/NativeMethodBody.cs | 6 + .../NativeMethodBodyProcessingLayer.cs | 491 ++++++++++++ .../ObjectInterfaceProcessingLayer.cs | 63 ++ Il2CppInterop.Generator/Operands/EndLabel.cs | 9 + .../Operands/ExceptionHandler.cs | 15 + Il2CppInterop.Generator/Operands/ILabel.cs | 5 + .../Operands/Instruction.cs | 22 + .../Operands/LocalVariable.cs | 19 + .../Operands/MultiDimensionalArrayMethod.cs | 33 + .../MultiDimensionalArrayMethodType.cs | 21 + Il2CppInterop.Generator/Operands/This.cs | 9 + Il2CppInterop.Generator/OriginalMethodBody.cs | 158 ++++ .../PointerConstructorProcessingLayer.cs | 100 +++ ...mitiveImplicitConversionProcessingLayer.cs | 193 +++++ .../PropertyAnalysisContextExtensions.cs | 17 + .../PublicizerProcessingLayer.cs | 57 ++ ...ferenceAssemblyInjectionProcessingLayer.cs | 69 ++ .../ReferenceReplacementProcessingLayer.cs | 124 +++ .../StaticConstructorProcessingLayer.cs | 50 ++ .../TranslatedMethodBody.cs | 751 ++++++++++++++++++ .../TypeAnalysisContextEqualityComparer.cs | 364 +++++++++ .../TypeAnalysisContextExtensions.cs | 182 +++++ Il2CppInterop.Generator/TypeBlittability.cs | 9 + .../TypeConversionVisitor.cs | 81 ++ .../TypeInfoProcessingLayer.cs | 121 +++ .../TypeReplacementVisitor.cs | 82 ++ Il2CppInterop.Generator/TypeVisitor.cs | 42 + .../UnstripBaseProcessingLayer.cs | 495 ++++++++++++ .../UnstripProcessingLayer.cs | 40 + .../Il2CppInterop.HarmonySupport.csproj | 2 +- Il2CppInterop.Runtime/DelegateSupport.cs | 9 +- Il2CppInterop.Runtime/IL2CPP.cs | 88 +- Il2CppInterop.Runtime/Il2CppException.cs | 47 +- .../Il2CppInterop.Runtime.csproj | 19 +- Il2CppInterop.Runtime/Il2CppType.cs | 10 +- ...GetTypeInfoFromTypeDefinitionIndex_Hook.cs | 2 +- .../InteropTypes/Arrays/Il2CppArrayBase.cs | 78 +- .../Arrays/Il2CppMultiArrayBase.cs | 23 + .../Arrays/Il2CppNonBlittableArray.cs | 75 ++ .../InteropTypes/Arrays/Il2CppObjectArray.cs | 61 ++ .../Arrays/Il2CppReferenceArray.cs | 2 +- .../InteropTypes/Arrays/Il2CppStringArray.cs | 2 +- .../InteropTypes/Arrays/Il2CppStructArray.cs | 8 +- .../Arrays/Il2CppUnmanagedArray.cs | 77 ++ .../InteropTypes/ByReference.cs | 85 ++ .../InteropTypes/FieldAccessHelper.cs | 82 ++ .../InteropTypes/IIl2CppObjectBase.cs | 14 + .../InteropTypes/IIl2CppType.cs | 130 +++ .../IIl2CppValueTypeExtensions.cs | 39 + .../InteropTypes/Il2CppObjectBase.cs | 175 +--- .../InteropTypes/Il2CppTypeHelper.cs | 77 ++ Il2CppInterop.Runtime/InteropTypes/Pointer.cs | 26 + .../InteropTypes/RuntimeInvokeHelper.cs | 208 +++++ Il2CppInterop.Runtime/Libs/Il2Cppmscorlib.dll | Bin 2960896 -> 0 bytes .../Runtime/Il2CppObjectPool.cs | 41 + .../Runtime/UnmanagedInitializers.cs | 52 ++ .../Il2CppInterop.StructGenerator.csproj | 6 +- Il2CppInterop.sln | 196 +++-- Il2Cppmscorlib/Array.cs | 8 + Il2Cppmscorlib/Delegate.cs | 34 + Il2Cppmscorlib/Enum.cs | 5 + Il2Cppmscorlib/Exception.cs | 19 + Il2Cppmscorlib/GC.cs | 9 + Il2Cppmscorlib/Il2Cppmscorlib.csproj | 13 + Il2Cppmscorlib/Object.cs | 45 ++ Il2Cppmscorlib/Reflection/Assembly.cs | 13 + Il2Cppmscorlib/Reflection/AssemblyName.cs | 6 + Il2Cppmscorlib/Reflection/BindingFlags.cs | 26 + Il2Cppmscorlib/Reflection/ConstructorInfo.cs | 5 + Il2Cppmscorlib/Reflection/FieldInfo.cs | 5 + Il2Cppmscorlib/Reflection/MemberInfo.cs | 8 + Il2Cppmscorlib/Reflection/MethodBase.cs | 6 + Il2Cppmscorlib/Reflection/MethodInfo.cs | 23 + Il2Cppmscorlib/Reflection/MonoField.cs | 6 + Il2Cppmscorlib/Reflection/ParameterInfo.cs | 6 + Il2Cppmscorlib/Reflection/RtFieldInfo.cs | 5 + Il2Cppmscorlib/Reflection/RuntimeFieldInfo.cs | 5 + Il2Cppmscorlib/Reflection/TypeInfo.cs | 5 + .../CompilerServices/RuntimeHelpers.cs | 9 + Il2Cppmscorlib/RuntimeType.cs | 8 + Il2Cppmscorlib/RuntimeTypeHandle.cs | 6 + Il2Cppmscorlib/String.cs | 13 + Il2Cppmscorlib/Type.cs | 48 ++ Il2Cppmscorlib/ValueType.cs | 5 + Il2Cppmscorlib/Void.cs | 5 + global.json | 6 - nuget.config | 5 + 147 files changed, 9729 insertions(+), 742 deletions(-) create mode 100644 Documentation/Design/Arrays.md create mode 100644 Documentation/Design/Attributes.md create mode 100644 Documentation/Design/CorLibTypes.md create mode 100644 Documentation/Design/Delegates.md create mode 100644 Documentation/Design/Enums.md create mode 100644 Documentation/Design/Exceptions.md create mode 100644 Documentation/Design/Fields.md create mode 100644 Documentation/Design/ForbiddenTypes.md create mode 100644 Documentation/Design/GenericMethods.md create mode 100644 Documentation/Design/GenericTypes.md create mode 100644 Documentation/Design/Injection.md create mode 100644 Documentation/Design/Interfaces.md create mode 100644 Documentation/Design/NativeStaticConstructors.md create mode 100644 Documentation/Design/NestedTypes.md create mode 100644 Documentation/Design/ReturnObjects.md create mode 100644 Documentation/Design/SimpleClasses.md create mode 100644 Documentation/Design/Unstripping.md create mode 100644 Documentation/Design/ValueTypes.md delete mode 100644 Il2CppInterop.CLI/Utils.cs create mode 100644 Il2CppInterop.Common/ObjectPointer.cs create mode 100644 Il2CppInterop.Generator/ApplicationAnalysisContextExtensions.cs create mode 100644 Il2CppInterop.Generator/AsmResolverDllOutputFormatBinding.cs create mode 100644 Il2CppInterop.Generator/AsmResolverDllOutputFormatUnstripped.cs create mode 100644 Il2CppInterop.Generator/AssemblyAnalysisContextExtensions.cs create mode 100644 Il2CppInterop.Generator/AttributeRemovalProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/AttributesOverrideProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/BooleanAndTypeVisitor.cs create mode 100644 Il2CppInterop.Generator/BooleanOrTypeVisitor.cs create mode 100644 Il2CppInterop.Generator/CleanRenamingProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/ConstantInitializationProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/ContextResolver.cs create mode 100644 Il2CppInterop.Generator/ContextWithDataStorageExtensions.cs create mode 100644 Il2CppInterop.Generator/DefaultTypeVisitor.cs create mode 100644 Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/DictionaryExtensions.cs create mode 100644 Il2CppInterop.Generator/EnumProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/ExceptionHierarchyProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/FieldAccessorProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/FieldAnalysisContextExtensions.cs create mode 100644 Il2CppInterop.Generator/HasGenericParametersExtensions.cs create mode 100644 Il2CppInterop.Generator/ICallProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/Il2CppGame.cs create mode 100644 Il2CppInterop.Generator/Il2CppRenamingProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/Il2CppTypeInfo.cs create mode 100644 Il2CppInterop.Generator/InitializationClassProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/InjectedMethodAnalysisContextExtensions.cs create mode 100644 Il2CppInterop.Generator/InjectedParameterAnalysisContextExtensions.cs create mode 100644 Il2CppInterop.Generator/InjectedTypeAnalysisContextExtensions.cs create mode 100644 Il2CppInterop.Generator/InstructionListExtensions.cs create mode 100644 Il2CppInterop.Generator/LocalVariableListExtensions.cs create mode 100644 Il2CppInterop.Generator/MethodAnalysisContextExtensions.cs create mode 100644 Il2CppInterop.Generator/MethodBodyBase.cs create mode 100644 Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/MonoIl2CppConversion.cs create mode 100644 Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/NativeMethodBody.cs create mode 100644 Il2CppInterop.Generator/NativeMethodBodyProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/ObjectInterfaceProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/Operands/EndLabel.cs create mode 100644 Il2CppInterop.Generator/Operands/ExceptionHandler.cs create mode 100644 Il2CppInterop.Generator/Operands/ILabel.cs create mode 100644 Il2CppInterop.Generator/Operands/Instruction.cs create mode 100644 Il2CppInterop.Generator/Operands/LocalVariable.cs create mode 100644 Il2CppInterop.Generator/Operands/MultiDimensionalArrayMethod.cs create mode 100644 Il2CppInterop.Generator/Operands/MultiDimensionalArrayMethodType.cs create mode 100644 Il2CppInterop.Generator/Operands/This.cs create mode 100644 Il2CppInterop.Generator/OriginalMethodBody.cs create mode 100644 Il2CppInterop.Generator/PointerConstructorProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/PrimitiveImplicitConversionProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/PropertyAnalysisContextExtensions.cs create mode 100644 Il2CppInterop.Generator/PublicizerProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/ReferenceReplacementProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/StaticConstructorProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/TranslatedMethodBody.cs create mode 100644 Il2CppInterop.Generator/TypeAnalysisContextEqualityComparer.cs create mode 100644 Il2CppInterop.Generator/TypeAnalysisContextExtensions.cs create mode 100644 Il2CppInterop.Generator/TypeBlittability.cs create mode 100644 Il2CppInterop.Generator/TypeConversionVisitor.cs create mode 100644 Il2CppInterop.Generator/TypeInfoProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/TypeReplacementVisitor.cs create mode 100644 Il2CppInterop.Generator/TypeVisitor.cs create mode 100644 Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs create mode 100644 Il2CppInterop.Generator/UnstripProcessingLayer.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppMultiArrayBase.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppNonBlittableArray.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppObjectArray.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppUnmanagedArray.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/ByReference.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/FieldAccessHelper.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/IIl2CppObjectBase.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/IIl2CppType.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/IIl2CppValueTypeExtensions.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/Il2CppTypeHelper.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/Pointer.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/RuntimeInvokeHelper.cs delete mode 100644 Il2CppInterop.Runtime/Libs/Il2Cppmscorlib.dll create mode 100644 Il2CppInterop.Runtime/Runtime/UnmanagedInitializers.cs create mode 100644 Il2Cppmscorlib/Array.cs create mode 100644 Il2Cppmscorlib/Delegate.cs create mode 100644 Il2Cppmscorlib/Enum.cs create mode 100644 Il2Cppmscorlib/Exception.cs create mode 100644 Il2Cppmscorlib/GC.cs create mode 100644 Il2Cppmscorlib/Il2Cppmscorlib.csproj create mode 100644 Il2Cppmscorlib/Object.cs create mode 100644 Il2Cppmscorlib/Reflection/Assembly.cs create mode 100644 Il2Cppmscorlib/Reflection/AssemblyName.cs create mode 100644 Il2Cppmscorlib/Reflection/BindingFlags.cs create mode 100644 Il2Cppmscorlib/Reflection/ConstructorInfo.cs create mode 100644 Il2Cppmscorlib/Reflection/FieldInfo.cs create mode 100644 Il2Cppmscorlib/Reflection/MemberInfo.cs create mode 100644 Il2Cppmscorlib/Reflection/MethodBase.cs create mode 100644 Il2Cppmscorlib/Reflection/MethodInfo.cs create mode 100644 Il2Cppmscorlib/Reflection/MonoField.cs create mode 100644 Il2Cppmscorlib/Reflection/ParameterInfo.cs create mode 100644 Il2Cppmscorlib/Reflection/RtFieldInfo.cs create mode 100644 Il2Cppmscorlib/Reflection/RuntimeFieldInfo.cs create mode 100644 Il2Cppmscorlib/Reflection/TypeInfo.cs create mode 100644 Il2Cppmscorlib/Runtime/CompilerServices/RuntimeHelpers.cs create mode 100644 Il2Cppmscorlib/RuntimeType.cs create mode 100644 Il2Cppmscorlib/RuntimeTypeHandle.cs create mode 100644 Il2Cppmscorlib/String.cs create mode 100644 Il2Cppmscorlib/Type.cs create mode 100644 Il2Cppmscorlib/ValueType.cs create mode 100644 Il2Cppmscorlib/Void.cs delete mode 100644 global.json create mode 100644 nuget.config diff --git a/.editorconfig b/.editorconfig index 3478ef3a..b6c6c3fb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,10 +11,29 @@ insert_final_newline = true indent_style = space indent_size = 4 trim_trailing_whitespace = true +end_of_line = lf # Generated code [*{_AssemblyInfo.cs,.notsupported.cs,AsmOffsets.cs}] generated_code = true +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +end_of_line = lf +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion # C# files [*.cs] @@ -54,7 +73,7 @@ dotnet_style_predefined_type_for_member_access = true:suggestion # name all constant fields using PascalCase dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields -dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style dotnet_naming_symbols.constant_fields.applicable_kinds = field dotnet_naming_symbols.constant_fields.required_modifiers = const dotnet_naming_style.pascal_case_style.capitalization = pascal_case @@ -62,7 +81,7 @@ dotnet_naming_style.pascal_case_style.capitalization = pascal_case # static fields should have s_ prefix dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields -dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style +dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style dotnet_naming_symbols.static_fields.applicable_kinds = field dotnet_naming_symbols.static_fields.required_modifiers = static dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected @@ -72,7 +91,7 @@ dotnet_naming_style.static_prefix_style.capitalization = camel_case # internal and private fields should be _camelCase dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields -dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style +dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style dotnet_naming_symbols.private_internal_fields.applicable_kinds = field dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal dotnet_naming_style.camel_case_underscore_style.required_prefix = _ @@ -150,6 +169,11 @@ csharp_space_between_method_declaration_name_and_open_parenthesis = false csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_parentheses = false csharp_space_between_square_brackets = false +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_prefer_system_threading_lock = true:suggestion # C++ Files [*.{cpp,h,in}] diff --git a/Documentation/Design/Arrays.md b/Documentation/Design/Arrays.md new file mode 100644 index 00000000..8625b8b3 --- /dev/null +++ b/Documentation/Design/Arrays.md @@ -0,0 +1,15 @@ +# Arrays + +## Array Types + +Il2Cpp arrays are represented with a closed type hierarchy. + +* `Il2CppArrayBase` +* `Il2CppArrayBase` +* `Il2CppReferenceArray` +* `Il2CppObjectArray` +* `Il2CppInterfaceArray` +* `Il2CppBlittableArray` +* `Il2CppNonBlittableArray` + +`Il2CppArrayBase` is the type used everywhere. The others are just for construction. diff --git a/Documentation/Design/Attributes.md b/Documentation/Design/Attributes.md new file mode 100644 index 00000000..5bf251c0 --- /dev/null +++ b/Documentation/Design/Attributes.md @@ -0,0 +1,3 @@ +# Attributes + +Attributes are not applied to types. diff --git a/Documentation/Design/CorLibTypes.md b/Documentation/Design/CorLibTypes.md new file mode 100644 index 00000000..b99950c4 --- /dev/null +++ b/Documentation/Design/CorLibTypes.md @@ -0,0 +1,187 @@ +# Core Library Types + +## Numeric Primitives, `char`, and `bool` + +These are blittable and should be directly reused, kind of. Signatures will use the Il2Cpp types, but implicit conversions will be used inside unstripped method bodies. + +```cs +public static Il2CppSystem.Int32 Add(Il2CppSystem.Int32 x, Il2CppSystem.Int32 y) +{ + // Conversions to Managed are applied on function entry + ref + int x2 = (int)x; + int y2 = (int)y; + + // All operations are done with managed types + int z = x2 + y2; + + // If an Il2Cpp primitive must be returned, conversion back is applied right before the return instruction. + return (Il2CppSystem.Int32)z; +} +``` + +This ensures that CIL opcodes function as expected. However, it can cause some complexities with instance methods on the corlib types. For that, unsafe helpers are used. + +```cs +public static Il2CppSystem.String Sum(Il2CppSystem.Int32 x, Il2CppSystem.Int32 y) +{ + int z = (int)x + (int)y; + return Unsafe.As(ref z).ToString(); +} +``` + +## `string` + +Strings should not be implicitly marshalled. In other words, `Il2CppSystem.String` should be used. + +## `object` + +For compatibility with interfaces and value types, this should be emitted as-is, despite the more complicated marshalling involved. + +## `Attribute` + +## `ValueType` and `Enum` + +Boxing to these types is invalid. + +## `Exception` + +## Counterargument to all of the above + +```cs +// Original code +public static void DoSomething(T value) where T : System.IConvertible +{ +} +public static void DoSomethingElse() +{ + DoSomething(System.StringComparison.Ordinal); + DoSomething(default); + DoSomething(default); +} + +// Unstripped code +public static void DoSomething() where T : Il2CppSystem.IConvertible +{ +} +public static void DoSomethingElse() +{ + // Which is correct? + // System.Enum fails the constraint check. + // Il2CppSystem.Enum makes the method unusable because boxed enums inherit from `System.Enum` not `Il2CppSystem.Enum`. + DoSomething(Il2CppSystem.StringComparison.Ordinal); + DoSomething(Il2CppSystem.StringComparison.Ordinal); + DoSomething(Cast(Il2CppSystem.StringComparison.Ordinal)); // Maybe this is the way it should be emitted? + + // If the type is a real enum, it fails the constraint check. + DoSomething(default); + + // Which is correct? + // int fails the constraint check, but is what we currently do. + DoSomething(default); + DoSomething(default); +} +private static Il2CppSystem.Enum Cast(object value) +{ + if (value is Il2CppSystem.Enum il2cppEnum) + { + return il2cppEnum; + } + if (value is System.Enum sysEnum) + { + throw new NotImplementedException("Cannot cast System.Enum to Il2CppSystem.Enum"); + } + throw new InvalidCastException("Cannot cast to Il2CppSystem.Enum"); +} + +// Proposal +public static void DoSomething() where T : Il2CppSystem.IConvertible +{ +} +public static void DoSomethingElse() +{ + DoSomething(Il2CppSystem.StringComparison.Ordinal); + DoSomething(default); + DoSomething(default); +} +namespace Il2CppSystem +{ + public interface IObject + { + // Instance members of Il2CppSystem.Object + } + public interface IValueType : IObject + { + // No members + } + public interface IEnum : IValueType, Il2CppSystem.IComparable, Il2CppSystem.IFormattable, Il2CppSystem.IConvertible + { + // Instance members of Il2CppSystem.Enum, except for interface implementations + } + public class Object : IObject + { + // A static method should be generated for each instance method + } + public abstract class ValueType : Object, IValueType + { + // A static method should be generated for each instance method + } + public abstract class Enum : ValueType, IEnum + { + // A static method should be generated for each instance method + } + public readonly struct StringComparison : IEnum // Maybe inject other interfaces like System.IEquatable<> for user convenience + { + // [System.Flags] // Only if the Il2Cpp enum has the Flags attribute + private enum __Internal + { + CurrentCulture = 0, + CurrentCultureIgnoreCase = 1, + InvariantCulture = 2, + InvariantCultureIgnoreCase = 3, + Ordinal = 4, + OrdinalIgnoreCase = 5 + } + + // Might make this `int` instead. The only reason to use `__Internal` is to have a more efficient ToString implementation. + private readonly __Internal value__; + + // Sacrifice the ability to use Il2Cpp enums in constants. + public static readonly StringComparison CurrentCulture = new StringComparison(__Internal.CurrentCulture); + public static readonly StringComparison CurrentCultureIgnoreCase = new StringComparison(__Internal.CurrentCultureIgnoreCase); + public static readonly StringComparison InvariantCulture = new StringComparison(__Internal.InvariantCulture); + public static readonly StringComparison InvariantCultureIgnoreCase = new StringComparison(__Internal.InvariantCultureIgnoreCase); + public static readonly StringComparison Ordinal = new StringComparison(__Internal.Ordinal); + public static readonly StringComparison OrdinalIgnoreCase = new StringComparison(__Internal.OrdinalIgnoreCase); + + private StringComparison(__Internal value) => value__ = value; + public StringComparison(int value) => value__ = unchecked((__Internal)value); + public static explicit operator int(StringComparison value) => unchecked((int)value.value__); + public static explicit operator StringComparison(int value) => new StringComparison(value); + + // Numerical operators like shift + + // Override ToString, GetHashCode, Equals, etc. + public override int GetHashCode() + { + // Use the static method from Il2CppSystem.Enum + // We need to ensure that behavior is consistent with the native method. + return Il2CppSystem.Enum.GetHashCode(this); + } + + static StringComparison() + { + // OriginalNameAttribute no longer needed. + } + } + public interface ICloneable : IObject, System.ICloneable + { + IObject Clone(); + + object System.ICloneable.Clone() + { + return Clone(); + } + } +} +``` diff --git a/Documentation/Design/Delegates.md b/Documentation/Design/Delegates.md new file mode 100644 index 00000000..e69de29b diff --git a/Documentation/Design/Enums.md b/Documentation/Design/Enums.md new file mode 100644 index 00000000..409e44fb --- /dev/null +++ b/Documentation/Design/Enums.md @@ -0,0 +1,118 @@ +# Enums + +Despite the complexity involved, enums should be reproduced as-is. + +```cs +public enum ElectricityType +{ + Off = 0, + On = 1 +} +``` + +## Il2Cpp Initialization + +Il2Cpp initialization may be complicated. + +### Option 1: `[OriginalName]` Attribute + +This was the Il2CppInterop approach. + +```cs +[OriginalName("Assembly-CSharp.dll", "", "ElectricityType")] +public enum ElectricityType +{ + Off = 0, + On = 1 +} +``` + +### Option 2: `[InitializerType]` Attribute + +This allows storing field pointers. + +```cs +[InitializerType(typeof(ElectricityType_UniqueHash))] +public enum ElectricityType +{ + Off = 0, + On = 1 +} +internal static class ElectricityType_UniqueHash +{ + static ElectricityType_UniqueHash() + { + Il2CppClassPointerStore.NativeClassPtr = IL2CPP.GetIl2CppClass("Assembly-CSharp.dll", "", "ElectricityType"); + IL2CPP.il2cpp_runtime_class_init(Il2CppClassPointerStore.NativeClassPtr); + // Field pointers are also stored in this class. + } +} +``` + +### Option 3: Module Initialization + +```cs +public enum ElectricityType +{ + Off = 0, + On = 1 +} +internal static class ElectricityType_UniqueHash +{ + internal static void Initialize() + { + Il2CppClassPointerStore.NativeClassPtr = IL2CPP.GetIl2CppClass("Assembly-CSharp.dll", "", "ElectricityType"); + IL2CPP.il2cpp_runtime_class_init(Il2CppClassPointerStore.NativeClassPtr); + // Field pointers are also stored in this class. + } +} +internal static class ModuleInitialization +{ + internal static void Initialize() + { + ElectricityType_UniqueHash.Initialize(); + // And all the other types too. + } +} +``` + +### Option 4: Global Initialization + +```cs +public enum ElectricityType +{ + Off = 0, + On = 1 +} +internal static class ElectricityType_UniqueHash +{ + internal static void Initialize() + { + Il2CppClassPointerStore.NativeClassPtr = IL2CPP.GetIl2CppClass("Assembly-CSharp.dll", "", "ElectricityType"); + IL2CPP.il2cpp_runtime_class_init(Il2CppClassPointerStore.NativeClassPtr); + // Field pointers are also stored in this class. + } +} +public static class ModuleInitialization_AssemblyNameHash +{ + public static void Initialize() + { + ElectricityType_UniqueHash.Initialize(); + // And all the other types too. + } +} + +// Il2CppInitialization.dll +public static class Il2CppInitialization +{ + public static void Initialize() + { + ModuleInitialization_AssemblyNameHash.Initialize(); + // And all the other assemblies too. + } +} +``` + +## Generic constraint + +`Il2CppSystem.Enum` should be replaced with `System.Enum` in generic constraints. diff --git a/Documentation/Design/Exceptions.md b/Documentation/Design/Exceptions.md new file mode 100644 index 00000000..19ad0897 --- /dev/null +++ b/Documentation/Design/Exceptions.md @@ -0,0 +1,10 @@ +# Exceptions + +```cs +public abstract class Il2CppException : Exception +{ +} +public sealed class Il2CppException : Il2CppException where T : Il2CppSystem.Exception +{ +} +``` diff --git a/Documentation/Design/Fields.md b/Documentation/Design/Fields.md new file mode 100644 index 00000000..19f92271 --- /dev/null +++ b/Documentation/Design/Fields.md @@ -0,0 +1,15 @@ +# Fields + +## Generated code + +```cs +private static readonly IntPtr NativeFieldInfoPtr_fieldName; +public FieldType fieldName +{ + get => throw null; + set => throw null; +} + +// If value type +public static ref FieldType GetFieldAddress_fieldName(ref Class obj) => throw null; +``` diff --git a/Documentation/Design/ForbiddenTypes.md b/Documentation/Design/ForbiddenTypes.md new file mode 100644 index 00000000..c9e6494c --- /dev/null +++ b/Documentation/Design/ForbiddenTypes.md @@ -0,0 +1,28 @@ +# Forbidden Types + +Some types are poison and cannot be used anywhere. + +* Arrays of pointers + * Pointer types can't be used as generic arguments +* Static classes + * Exception for stuff like `typeof()` and member references +* Pointer and byref types for nonblittable base types + * The C# representation of these is very different from Il2Cpp. +* Any type specification that uses the above + +## Pointers + +These could also be made generic. + +```cs +public readonly unsafe struct Pointer +{ + private readonly T* value; + + public Pointer(T* value) => this.value = value; + public static implicit operator Pointer(T* value) => new(value); + public static implicit operator T*(Pointer pointer) => pointer.value; +} +``` + +`void*` would become `Pointer`. diff --git a/Documentation/Design/GenericMethods.md b/Documentation/Design/GenericMethods.md new file mode 100644 index 00000000..cf25b2b8 --- /dev/null +++ b/Documentation/Design/GenericMethods.md @@ -0,0 +1,22 @@ +# Generic Methods + +## Pointers + +Pointers are resolved as needed using Il2Cpp reflection. It's fine to do this initialization lazily because all generic type instances are known in advance. + +```cs +private static class MethodInfoStoreGeneric_Aggregate +{ + internal static System.IntPtr Pointer = IL2CPP.il2cpp_method_get_from_reflection(IL2CPP.Il2CppObjectBaseToPtrNotNull(new MethodInfo(IL2CPP.il2cpp_method_get_object(NativeMethodInfoPtr_Aggregate, Il2CppClassPointerStore.NativeClassPtr)) + .MakeGenericMethod(new Il2CppReferenceArray(new Type[2] + { + Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(Il2CppClassPointerStore.NativeClassPtr)), + Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(Il2CppClassPointerStore.NativeClassPtr)) + })))); +} +``` + +If a modder tries to use a generic method instantiation that doesn't exist, an exception is thrown. + +* +* diff --git a/Documentation/Design/GenericTypes.md b/Documentation/Design/GenericTypes.md new file mode 100644 index 00000000..a068a2f4 --- /dev/null +++ b/Documentation/Design/GenericTypes.md @@ -0,0 +1,10 @@ +# Generic Types + +```cs +Il2CppClassPointerStore>.NativeClassPtr = IL2CPP.il2cpp_class_from_type(Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(IL2CPP.GetIl2CppClass("mscorlib.dll", "System.Collections.Generic", "Dictionary`2"))).MakeGenericType(new Il2CppReferenceArray(new Type[2] +{ + Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(Il2CppClassPointerStore.NativeClassPtr)), + Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(Il2CppClassPointerStore.NativeClassPtr)) +})).TypeHandle.value); +IL2CPP.il2cpp_runtime_class_init(Il2CppClassPointerStore>.NativeClassPtr); +``` diff --git a/Documentation/Design/Injection.md b/Documentation/Design/Injection.md new file mode 100644 index 00000000..cf2fa1fd --- /dev/null +++ b/Documentation/Design/Injection.md @@ -0,0 +1,79 @@ +# Injection + +## Class + +```cs +// User code + +[InjectInIl2Cpp(Assembly = "OptionalAssemblyName")] // By default, types are injected into Assembly-CSharp +public partial class MyMonoBehaviour : MonoBehaviour +{ + [Il2CppField] + public static partial int staticField { get; set; } + [Il2CppField] + public partial bool instanceField { get; set; } + + [HideFromIl2Cpp] // This attribute is valid on types, methods, properties. Injected classes cannot have uninjected instance fields and static fields are ignored by default. + public static void DoAnything(string s) // If this wasn't hidden, it would be invalid because string is not a valid Il2Cpp parameter type. + { + } +} + +// Source generated + +partial class MyMonoBehaviour +{ + static MyMonoBehaviour() + { + ClassInjector.Inject(typeof(MyMonoBehaviour)); + } + + // Required + public MyMonoBehaviour(ObjectPointer ptr) : base(ptr) + { + } + + public static partial int staticField { get => Il2CppInternals.staticField.Get(); set => Il2CppInternals.staticField.Set(value); } + public partial bool instanceField { get => Il2CppInternals.instanceField.Get(this); set => Il2CppInternals.instanceField.Set(this, value); } +} +file static class Il2CppInternals // If the injected class is generic, this will also be generic. +{ + internal static readonly Il2CppStaticField staticField = new("staticField", GetClassPointer); + internal static readonly Il2CppField instanceField = new("instanceField", GetClassPointer); + private static IntPtr GetClassPointer() => Il2CppClassPointerStore.NativeClassPtr; +} +``` + +## Struct + +```cs +// User code + +[InjectInIl2Cpp] +public partial struct MyStruct +{ + [Il2CppField] + public static partial T staticField { get; set; } // Fine because the injected field is static + // [Il2CppField] is optional for struct instance fields. + public bool instanceField; + // public T unconstrainedGenericField; // Error: Injected generic fields in structs must be constrained value types. + // public Il2CppSystem.Collection.Generic.List listField; // Fine +} + +// Source generated + +partial struct MyStruct +{ + static MyStruct() + { + ClassInjector.Inject(typeof(MyStruct)); + } + + public static partial T staticField { get => Il2CppInternals.staticField.Get(); set => Il2CppInternals.staticField.Set(value); } +} +file static class Il2CppInternals +{ + internal static readonly Il2CppStaticField staticField = new("staticField", GetClassPointer); + private static IntPtr GetClassPointer() => Il2CppClassPointerStore.NativeClassPtr; +} +``` diff --git a/Documentation/Design/Interfaces.md b/Documentation/Design/Interfaces.md new file mode 100644 index 00000000..5a101c0f --- /dev/null +++ b/Documentation/Design/Interfaces.md @@ -0,0 +1,2 @@ +# Interfaces + diff --git a/Documentation/Design/NativeStaticConstructors.md b/Documentation/Design/NativeStaticConstructors.md new file mode 100644 index 00000000..a01358c2 --- /dev/null +++ b/Documentation/Design/NativeStaticConstructors.md @@ -0,0 +1,7 @@ +# Native Static Constructors + +It would be desirable to offer users a way to interact with static constructors. + +* They should be renamed from `.cctor` to `_cctor`. If this is unavailable, additional underscores should be added to the beginning. +* Like other methods, they should be publicized. +* The `specialname` and `rtspecialname` attributes should be removed. diff --git a/Documentation/Design/NestedTypes.md b/Documentation/Design/NestedTypes.md new file mode 100644 index 00000000..40e43ccb --- /dev/null +++ b/Documentation/Design/NestedTypes.md @@ -0,0 +1,6 @@ +# Nested Types + +```cs +Il2CppClassPointerStore.NativeClassPtr = IL2CPP.GetIl2CppNestedType(Il2CppClassPointerStore.NativeClassPtr, "NestedClass"); +IL2CPP.il2cpp_runtime_class_init(Il2CppClassPointerStore.NativeClassPtr); +``` diff --git a/Documentation/Design/ReturnObjects.md b/Documentation/Design/ReturnObjects.md new file mode 100644 index 00000000..ca5d78df --- /dev/null +++ b/Documentation/Design/ReturnObjects.md @@ -0,0 +1,34 @@ +# Return Objects + +## Value Types + +These should be returned "as-is". + +```cs +return *(bool*)IL2CPP.il2cpp_object_unbox(intPtr); +``` + +## Sealed Classes + +Since these can't be inherited from, we can call the pointer constructor directly. However, we may want to treat all classes the same, for simplicity. + +## Normal Classes + +During initialization, we cache delegates (or function pointers) for creating an object. + +```cs +private static object Create(ObjectPointer ptr) => new Class(ptr); +internal static void Initialize() +{ + Il2CppObjectPool.RegisterFactoryMethod(Il2CppClassPointerStore.NativeClassPtr, (Func)Create); +} +``` + +When returning from a method, we check the pool to see if the object already exists. If the object doesn't yet exist in managed code, we use the cached factory method to create a new one. + +```cs +// Maybe instead Il2CppObjectPool.Get should perform this null check? +return (intPtr != (System.IntPtr)0) ? (ReturnType)Il2CppObjectPool.Get(intPtr) : null; +``` + +In the event that a factory method has not been registered, we throw an exception. If we pre-register factory methods for all generic type instances this should never happen. diff --git a/Documentation/Design/SimpleClasses.md b/Documentation/Design/SimpleClasses.md new file mode 100644 index 00000000..81c9a0bb --- /dev/null +++ b/Documentation/Design/SimpleClasses.md @@ -0,0 +1,82 @@ +# Simple Classes + +This document outlines the high level emission of simple classes. + +## Universal Base Type + +All reference classes inherit from `Il2CppObjectBase`. + +## Constructors + +All reference classes have an injected primary constructor. This carries the object pointer from derived classes to their base + +```cs +public class Derived(ObjectPointer ptr) : MonoBehaviour(ptr) +{ + static Derived() + { + Il2CppClassPointerStore.NativeClassPtr = IL2CPP.GetIl2CppClass("Assembly-CSharp.dll", "", "Derived"); + IL2CPP.il2cpp_runtime_class_init(Il2CppClassPointerStore.NativeClassPtr); + NativeMethodInfoPtr__ctor_Public_Void_0 = IL2CPP.GetIl2CppMethodByToken(Il2CppClassPointerStore.NativeClassPtr, 100666213); + } + + public unsafe Derived() : this(IL2CPP.il2cpp_object_new(Il2CppClassPointerStore.NativeClassPtr)) + { + Unsafe.SkipInit(out IntPtr intPtr2); + IntPtr intPtr = IL2CPP.il2cpp_runtime_invoke(NativeMethodInfoPtr__ctor_Public_Void_0, IL2CPP.Il2CppObjectBaseToPtrNotNull(this), (void**)null, ref intPtr2); + Il2CppException.RaiseExceptionIfNecessary(intPtr2); + } +} +``` + +A wrapper struct in the common library prevents conflicts. + +```cs +public readonly record struct ObjectPointer(IntPtr Value) +{ + public static implicit operator ObjectPointer(IntPtr value) => new(value); + public static implicit operator IntPtr(ObjectPointer value) => value.Value; +} +``` + +## Static classes + +### Option 1: Make class abstract but not sealed and inject a private constructor + +```cs +public abstract class StaticClass +{ + static StaticClass() + { + Il2CppClassPointerStore.NativeClassPtr = IL2CPP.GetIl2CppClass("Assembly-CSharp.dll", "", "StaticClass"); + IL2CPP.il2cpp_runtime_class_init(Il2CppClassPointerStore.NativeClassPtr); + } + + private StaticClass() + { + } +} +``` + +### Option 2: Inject a nested class to use as a type parameter + +```cs +public static class StaticClass +{ + static StaticClass() + { + Il2CppClassPointerStore.NativeClassPtr = IL2CPP.GetIl2CppClass("Assembly-CSharp.dll", "", "StaticClass"); + IL2CPP.il2cpp_runtime_class_init(Il2CppClassPointerStore.NativeClassPtr); + } + + private sealed class InjectedNestedClass() + { + } +} +``` + +### Comparison + +Option 1 is more friendly to the rest of the generation process, but option 2 is more representative of the actual situation and allows extension methods to function as intended. + +Recommendation: option 1. diff --git a/Documentation/Design/Unstripping.md b/Documentation/Design/Unstripping.md new file mode 100644 index 00000000..5b919291 --- /dev/null +++ b/Documentation/Design/Unstripping.md @@ -0,0 +1,42 @@ +# Unstripping + +Certain assemblies can be unstripped because we have source code available, eg mscorlib and UnityEngine. + +## Injection + +Unstripped types and members get injected, similar to custom user classes. + +## Replace Native Implementation + +If the success rate for unstripping is high, and if a certain method can be unstripped, its implementation should be moved to managed land. This enables several things: + +* Transpilers (assuming that native is patched to use this implementation) +* Generic instances not present in the game + +## ICalls + +Unity internal calls can be recovered. + +```cs +// Ignore the use of string, rather than Il2CppSystem.String +public static class SceneUtility +{ + private delegate IntPtr GetScenePathByBuildIndexDelegate(int buildIndex); + + private delegate int GetBuildIndexByScenePathDelegate(IntPtr scenePath); + + private static readonly GetScenePathByBuildIndexDelegate GetScenePathByBuildIndexDelegateField = IL2CPP.ResolveICall("UnityEngine.SceneManagement.SceneUtility::GetScenePathByBuildIndex"); + + private static readonly GetBuildIndexByScenePathDelegate GetBuildIndexByScenePathDelegateField = IL2CPP.ResolveICall("UnityEngine.SceneManagement.SceneUtility::GetBuildIndexByScenePath"); + + public static string GetScenePathByBuildIndex(int buildIndex) + { + return IL2CPP.Il2CppStringToManaged(GetScenePathByBuildIndexDelegateField(buildIndex)); + } + + public static int GetBuildIndexByScenePath(string scenePath) + { + return GetBuildIndexByScenePathDelegateField(IL2CPP.ManagedStringToIl2Cpp(scenePath)); + } +} +``` diff --git a/Documentation/Design/ValueTypes.md b/Documentation/Design/ValueTypes.md new file mode 100644 index 00000000..fc7ae56d --- /dev/null +++ b/Documentation/Design/ValueTypes.md @@ -0,0 +1,235 @@ +# Value Types + +## `readonly` + +Structs that were originally readonly no longer are. + +## Non-generic with only value type fields + +These can be passed to Il2Cpp directly. + +## Non-generic with at least one reference type field + +The reason these aren't blittable is because they contain reference types. Those field can be typed as `IntPtr` instead. + +```cs +public struct StructWithReferenceField +{ + public bool boolField; + private IntPtr monoBehaviourField_BackingField; + public int intField; + + public MonoBehaviour monoBehaviourField + { + get => (MonoBehaviour)Il2CppObjectPool.Get(monoBehaviourField_BackingField); + set => monoBehaviourField_BackingField = Il2CppObjectBase.GetPointer(value); + } +} +``` + +## Constrained Generic + +If a generic parameter is constrained to be a value type, no special handling is required. + +If a generic parameter is constrained to be a reference type, fields with it as the type can be treated the same as non-generic reference type fields. + +## Unconstrained Generic + +These are the most tricky. Let's have a simple example: + +```cs +public struct Pair +{ + public T Item1; + public T Item2; +} +``` + +### Idea 1: Add a second type parameter for the backing field + +```cs +public struct Pair where T_Backing : struct +{ + private T_Backing Item1_BackingField; + private T_Backing Item2_BackingField; + + public T Item1 { get => throw null; set => throw null; } + public T Item2 { get => throw null; set => throw null; } +} +``` + +However, that transformation has quite a few issues. + +* How should the injected type parameter be propagated up? + * `static void M(Pair pair) {}` -> `static void M(Pair pair) {}` + * Finding everywhere that it gets used and changing them could be difficult. +* Should the IL name of `Pair'1` be changed to `Pair'2`? + * What about potential conflicts? +* Will this cause multiple Il2Cpp initializations? + * This can be solved easily, but it's something to be aware of. + +### Idea 2: Generate constrained helper classes + +```cs +public struct Pair +{ + public T Item1; + public T Item2; + + // No change needed when T is a value type + + public struct T_ReferenceType + { + private IntPtr Item1_BackingField; + private IntPtr Item2_BackingField; + + public T Item1 { get => throw null; set => throw null; } + public T Item2 { get => throw null; set => throw null; } + } +} +``` + +This idea doesn't seem very promising. + +### Idea 3: Custom Marshalling + +```cs +public struct Pair +{ + public T Item1; + public T Item2; + + public static int GetIl2CppSize() => throw null; + public static void WriteToSpan(Pair value, Span span) + { + span.Clear(); + + // Item 1 + if (/* T is reference type */) + { + Span span2 = span.Slice(Item1_fieldOffset); + IntPtr ptr = Il2CppObjectBase.GetPointer((IIl2CppObjectBase)Item1); + MemoryMarshal.Write(span2, in ptr); + } + else + { + Span span2 = span.Slice(Item1_fieldOffset); + MemoryMarshal.Write(span2, in value.Item1); + } + + // Item 2 + if (/* T is reference type */) + { + Span span2 = span.Slice(Item2_fieldOffset); + IntPtr ptr = Il2CppObjectBase.GetPointer((IIl2CppObjectBase)Item2); + MemoryMarshal.Write(span2, in ptr); + } + else + { + Span span2 = span.Slice(Item2_fieldOffset); + MemoryMarshal.Write(span2, in value.Item2); + } + } + + public static Pair ReadFromSpan(ReadOnlySpan span) + { + // Essentially the same as WriteToSpan + } + + public static unsafe Pair ReadFromPointer(IntPtr ptr) + { + return ReadFromSpan(new ReadOnlySpan((void*)ptr, GetIl2CppSize())); + } +} +``` + +Also required for any value type that uses it, recursively. + +```cs +public struct HasPair +{ + public Pair pairField; // It doesn't matter that this is instantiated. The extra methods are still required. + public int otherField; + + public static int GetIl2CppSize() => throw null; + public static void WriteToSpan(HasPair value, Span span) + { + span.Clear(); + + // pairField + { + Span span2 = span.Slice(pairField_fieldOffset, Pair.GetIl2CppSize()); + MemoryMarshal.Write(span2, in value.pairField); + } + + // otherField + { + Span span2 = span.Slice(otherField_fieldOffset); + MemoryMarshal.Write(span2, in value.otherField); + } + } + + public static HasPair ReadFromSpan(ReadOnlySpan span) + { + // Essentially the same as WriteToSpan + } + + public static unsafe HasPair ReadFromPointer(IntPtr ptr) + { + return ReadFromSpan(new ReadOnlySpan((void*)ptr, GetIl2CppSize())); + } +} +``` + +In the case of a method returning one, it works like this: + +```cs +return HasPair.ReadFromPointer(IL2CPP.il2cpp_object_unbox(intPtr)); +``` + +Array access can potentially be handled with a subclass of a base array type. + +Any method that uses one of these in their signature as a pointer (eg `HasPair*`) will throw a not supported exception. This includes generated properties for fields. Byref returns will throw, but parameters can be handled. + +### Idea 4: Just throw + +In theory, this could be treated as not supported, and we throw an exception anywhere they get used. It's not desirable, but it's a simple solution to the problem. + +```cs +public struct Pair +{ + public T Item1 { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public T Item2 { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } +} +public struct HasPair +{ + public Pair pairField { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + public int otherField { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } // One bad field poisons the rest in a struct +} +public class Class +{ + // Can't be accessed + public Pair pairField { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } + + // This is fine + public List> pairListField { get => throw null; set => throw null; } // In a class, bad fields do not impact the others. + + public static void M1(Pair pair) => throw new NotSupportedException(); + public static Pair M2() => throw new NotSupportedException(); + public static void M3(HasPair pair) => throw new NotSupportedException(); + public static HasPair M4() => throw new NotSupportedException(); + public static void M5(List> list) + { + // This is fine + } +} +``` + +`ValueTuple` will probably be the biggest painpoint with this approach. + +### Assessment + +* Idea 1 seems prone to causing bugs. +* Idea 2 doesn't do anything for arrays. +* Idea 3 is complicated, but seems to be the best option. +* Idea 4 is simple and leaves the door open to future implementation. diff --git a/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj b/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj index 1e5a507e..ecf3cb5a 100644 --- a/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj +++ b/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj @@ -1,7 +1,7 @@ - net6.0 + net9.0 Exe true il2cppinterop @@ -15,14 +15,14 @@ - - + + - - - + + + diff --git a/Il2CppInterop.CLI/Program.cs b/Il2CppInterop.CLI/Program.cs index 5796435c..2e8916e1 100644 --- a/Il2CppInterop.CLI/Program.cs +++ b/Il2CppInterop.CLI/Program.cs @@ -1,316 +1,52 @@ -using System.CommandLine; -using System.CommandLine.NamingConventionBinder; -using System.Text.RegularExpressions; -using Il2CppInterop; -using Il2CppInterop.Common; +using Cpp2IL.Core.ProcessingLayers; using Il2CppInterop.Generator; -using Il2CppInterop.Generator.Runners; -using Il2CppInterop.StructGenerator; -using Microsoft.Extensions.Logging; -var command = new RootCommand { new Option("--verbose", "Produce more verbose output") }; -command.Description = "Generate Managed<->IL2CPP interop assemblies from Cpp2IL's output."; - -var generateCommand = new Command("generate") -{ - new Option("--input", "Directory with Il2CppDumper's dummy assemblies") {IsRequired = true} - .ExistingOnly(), - new Option("--output", "Directory to write generated assemblies to") {IsRequired = true}, - new Option("--unity", "Directory with original Unity assemblies for unstripping").ExistingOnly(), - new Option("--game-assembly", "Path to GameAssembly.dll. Used for certain analyses").ExistingOnly(), - new Option("--no-xref-cache", "Don't generate xref scanning cache. All scanning will be done at runtime."), - new Option("--add-prefix-to", - "Assemblies and namespaces starting with these will get an Il2Cpp prefix in generated assemblies. Allows multiple values. Obsolete."), - new Option("--dont-add-prefix-to", - "Assemblies and namespaces starting with these will not get an Il2Cpp prefix in generated assemblies. Allows multiple values."), - new Option("--use-opt-out-prefixing", - "Assemblies and namespaces will get an Il2Cpp prefix in generated assemblies unless otherwise specified. Obsolete."), - new Option("--deobf-map", - "Specifies a file specifying deobfuscation map for obfuscated types and members.").ExistingOnly(), - new Option("--deobf-uniq-chars", "How many characters per unique token to use during deobfuscation"), - new Option("--deobf-uniq-max", "How many maximum unique tokens per type are allowed during deobfuscation"), - new Option("--blacklist-assembly", "Don't write specified assembly to output. Allows multiple values."), - new Option("--obf-regex", - "Specifies a regex for obfuscated names. All types and members matching will be renamed."), - new Option("--passthrough-names", - "If specified, names will be copied from input assemblies as-is without renaming or deobfuscation."), - new Option("--no-parallel", "Disable parallel processing when writing assemblies. Use if you encounter stability issues when generating assemblies."), -}; -generateCommand.Description = "Generate wrapper assemblies that can be used to interop with Il2Cpp"; -generateCommand.Handler = CommandHandler.Create((GenerateCommandOptions opts) => -{ - var buildResult = opts.Build(); - Il2CppInteropGenerator.Create(buildResult.Options) - .AddLogger(buildResult.Logger) - .AddInteropAssemblyGenerator() - .Run(); -}); - -var deobfCommand = new Command("deobf"); -deobfCommand.Description = "Tools for deobfuscating assemblies"; -var deobfAnalyzeCommand = new Command("analyze") -{ - new Option("--input", "Directory of assemblies to deobfuscate") {IsRequired = true}.ExistingOnly(), - new Option("--add-prefix-to", - "Assemblies and namespaces starting with these will get an Il2Cpp prefix in generated assemblies. Allows multiple values. Obsolete."), - new Option("--dont-add-prefix-to", - "Assemblies and namespaces starting with these will not get an Il2Cpp prefix in generated assemblies. Allows multiple values."), - new Option("--use-opt-out-prefixing", - "Assemblies and namespaces will get an Il2Cpp prefix in generated assemblies unless otherwise specified. Obsolete.") -}; -deobfAnalyzeCommand.Description = - "Analyze deobfuscation performance with different parameter values. Will not generate assemblies."; - -deobfAnalyzeCommand.Handler = CommandHandler.Create((DeobfAnalyzeCommandOptions opts) => -{ - var buildResult = opts.Build(); - Il2CppInteropGenerator.Create(buildResult.Options) - .AddLogger(buildResult.Logger) - .AddDeobfuscationAnalyzer() - .Run(); -}); - -var deobfGenerateCommand = new Command("generate") -{ - new Option("--old-assemblies", "Directory with old unobfuscated assemblies") {IsRequired = true} - .ExistingOnly(), - new Option("--new-assemblies", "Directory to write obfuscation maps to") {IsRequired = true} - .ExistingOnly(), - new Option("--output", "Directory to write obfuscation maps to") {IsRequired = true}, - new Option("--include", - "Include these assemblies for deobfuscation map generation. If none are specified, all assemblies will be included."), - new Option("--deobf-uniq-chars", "How many characters per unique token to use during deobfuscation"), - new Option("--deobf-uniq-max", "How many maximum unique tokens per type are allowed during deobfuscation"), - new Option("--obf-regex", - "Specifies a regex for obfuscated names. All types and members matching will be renamed.") -}; -deobfGenerateCommand.Description = - "Generate a deobfuscation map from original unobfuscated assemblies. Will not generate assemblies."; -deobfGenerateCommand.Handler = CommandHandler.Create((DeobfGenerateCommandOptions opts) => -{ - var buildResult = opts.Build(); - Il2CppInteropGenerator.Create(buildResult.Options) - .AddLogger(buildResult.Logger) - .AddDeobfuscationMapGenerator() - .Run(); -}); - -var wrapperCommand = new Command("wrapper-gen") -{ - new Option("--headers", - "Directory that contains libil2cpp headers. Directory must contains subdirectories named after libil2cpp version.") - { - IsRequired = true - }.ExistingOnly(), - new Option("--output", "Directory to write managed struct wrapper sources to") {IsRequired = true} -}; -wrapperCommand.Description = "Tools for generating Il2Cpp struct wrappers from libi2lcpp source"; -wrapperCommand.Handler = CommandHandler.Create((WrapperCommandOptions opts) => -{ - Il2CppStructWrapperGenerator.Generate(opts.Build()); -}); - -deobfCommand.Add(deobfAnalyzeCommand); -deobfCommand.Add(deobfGenerateCommand); -command.Add(deobfCommand); -command.Add(generateCommand); -command.Add(wrapperCommand); - -return command.Invoke(args); - - -internal record CmdOptionsResult(GeneratorOptions Options, ILogger Logger); - -internal record BaseCmdOptions(bool Verbose) -{ - public virtual CmdOptionsResult Build() - { - var loggerFactory = LoggerFactory.Create(builder => - { - builder - .AddFilter("Il2CppInterop", Verbose ? LogLevel.Trace : LogLevel.Information) - .AddSimpleConsole(opt => { opt.SingleLine = true; }); - }); - - var logger = loggerFactory.CreateLogger("Il2CppInterop"); - - return new CmdOptionsResult(new GeneratorOptions { Verbose = Verbose }, logger); - } -} - -internal record WrapperCommandOptions(DirectoryInfo Headers, DirectoryInfo Output, bool Verbose) -{ - public virtual Il2CppStructWrapperGeneratorOptions Build() - { - var loggerFactory = LoggerFactory.Create(builder => - { - builder - .AddFilter("Il2CppInterop", Verbose ? LogLevel.Trace : LogLevel.Information) - .AddSimpleConsole(opt => { opt.SingleLine = true; }); - }); - var logger = loggerFactory.CreateLogger("Il2CppInterop"); - return new Il2CppStructWrapperGeneratorOptions(Headers.FullName, Output.FullName, logger); - } -} - -internal record GenerateCommandOptions( - bool Verbose, - DirectoryInfo Input, - DirectoryInfo Output, - DirectoryInfo? Unity, - FileInfo? GameAssembly, - bool NoXrefCache, - string[]? AddPrefixTo, - string[]? DontAddPrefixTo, - bool UseOptOutPrefixing, - FileInfo? DeobfMap, - int DeobfUniqChars, - int DeobfUniqMax, - string[]? BlacklistAssembly, - Regex? ObfRegex, - bool PassthroughNames, - bool NoParallel -) : BaseCmdOptions(Verbose) -{ - public override CmdOptionsResult Build() - { - var res = base.Build(); - var opts = res.Options; - - opts.Source = Utils.LoadAssembliesFrom(Input); - opts.OutputDir = Output.FullName; - opts.UnityBaseLibsDir = Unity?.FullName; - opts.GameAssemblyPath = GameAssembly?.FullName ?? ""; - opts.NoXrefCache = NoXrefCache; - opts.TypeDeobfuscationCharsPerUniquifier = DeobfUniqChars; - opts.TypeDeobfuscationMaxUniquifiers = DeobfUniqMax; - opts.AdditionalAssembliesBlacklist.AddRange(BlacklistAssembly ?? Array.Empty()); - opts.ObfuscatedNamesRegex = ObfRegex; - opts.PassthroughNames = PassthroughNames; - opts.Parallel = !NoParallel; - - if (AddPrefixTo is not null && AddPrefixTo.Length > 0) - { - if (DontAddPrefixTo is not null && DontAddPrefixTo.Length > 0) - { - throw new Exception("--add-prefix-to cannot be used with --dont-add-prefix-to"); - } - else if (UseOptOutPrefixing) - { - throw new Exception("--add-prefix-to cannot be used with --use-opt-out-prefixing"); - } - - opts.Il2CppPrefixMode = GeneratorOptions.PrefixMode.OptIn; - foreach (var s in AddPrefixTo) - { - opts.NamespacesAndAssembliesToPrefix.Add(s); - } - } - else if (DontAddPrefixTo is not null && DontAddPrefixTo.Length > 0) - { - opts.Il2CppPrefixMode = GeneratorOptions.PrefixMode.OptOut; - foreach (var s in DontAddPrefixTo) - { - opts.NamespacesAndAssembliesToNotPrefix.Add(s); - } - } - else if (UseOptOutPrefixing) - { - opts.Il2CppPrefixMode = GeneratorOptions.PrefixMode.OptOut; - } - - if (opts.Il2CppPrefixMode == GeneratorOptions.PrefixMode.OptIn) - { - res.Logger.LogWarning("Opt-In prefixing is obsolete and will be removed in a future version."); - } - - if (DeobfMap is not null) - { - opts.ReadRenameMap(DeobfMap.FullName); - } - - return res; - } -} - -internal record DeobfAnalyzeCommandOptions( - bool Verbose, - string[]? AddPrefixTo, - string[]? DontAddPrefixTo, - bool UseOptOutPrefixing, - DirectoryInfo Input -) : BaseCmdOptions(Verbose) -{ - public override CmdOptionsResult Build() - { - var res = base.Build(); - var opts = res.Options; - - opts.Source = Utils.LoadAssembliesFrom(Input); - - if (AddPrefixTo is not null && AddPrefixTo.Length > 0) - { - if (DontAddPrefixTo is not null && DontAddPrefixTo.Length > 0) - { - throw new Exception("--add-prefix-to cannot be used with --dont-add-prefix-to"); - } - else if (UseOptOutPrefixing) - { - throw new Exception("--add-prefix-to cannot be used with --use-opt-out-prefixing"); - } - - opts.Il2CppPrefixMode = GeneratorOptions.PrefixMode.OptIn; - foreach (var s in AddPrefixTo) - { - opts.NamespacesAndAssembliesToPrefix.Add(s); - } - } - else if (DontAddPrefixTo is not null && DontAddPrefixTo.Length > 0) - { - opts.Il2CppPrefixMode = GeneratorOptions.PrefixMode.OptOut; - foreach (var s in DontAddPrefixTo) - { - opts.NamespacesAndAssembliesToNotPrefix.Add(s); - } - } - else if (UseOptOutPrefixing) - { - opts.Il2CppPrefixMode = GeneratorOptions.PrefixMode.OptOut; - } - - if (opts.Il2CppPrefixMode == GeneratorOptions.PrefixMode.OptIn) - { - res.Logger.LogWarning("Opt-In prefixing is obsolete and will be removed in a future version."); - } - - return res; - } -} - -internal record DeobfGenerateCommandOptions( - bool Verbose, - DirectoryInfo OldAssemblies, - DirectoryInfo NewAssemblies, - DirectoryInfo Output, - string[]? Include, - int DeobfUniqChars, - int DeobfUniqMax, - Regex? ObfRegex -) : BaseCmdOptions(Verbose) -{ - public override CmdOptionsResult Build() - { - var res = base.Build(); - var opts = res.Options; - - opts.Source = Utils.LoadAssembliesFrom(OldAssemblies); - opts.OutputDir = Output.FullName; - opts.DeobfuscationNewAssembliesPath = NewAssemblies.FullName; - opts.DeobfuscationGenerationAssemblies.AddRange(Include ?? Array.Empty()); - opts.TypeDeobfuscationCharsPerUniquifier = DeobfUniqChars; - opts.TypeDeobfuscationMaxUniquifiers = DeobfUniqMax; - opts.ObfuscatedNamesRegex = ObfRegex; - - return res; - } -} +string gameExePath = args[0]; +string outputFolder = args[1]; +Il2CppGame.Process( + gameExePath, + outputFolder, + new AsmResolverDllOutputFormatBinding(), + [ + new AttributeAnalysisProcessingLayer(), // Needed for recovery of params and unmanaged constraints + new StableRenamingProcessingLayer(), + new UnstripProcessingLayer(), // Can be disabled for performance during development + new TypeInfoProcessingLayer(), + new Il2CppRenamingProcessingLayer(), + new CleanRenamingProcessingLayer(), + new AttributesOverrideProcessingLayer(), + new PublicizerProcessingLayer(), + new MscorlibAssemblyInjectionProcessingLayer(), + new ReferenceAssemblyInjectionProcessingLayer(), + new ObjectInterfaceProcessingLayer(), + new ReferenceReplacementProcessingLayer(), + new AttributeRemovalProcessingLayer(), + // Call analysis goes here or anywhere after this + new InitializationClassProcessingLayer(), + new PointerConstructorProcessingLayer(), + new PrimitiveImplicitConversionProcessingLayer(), + new EnumProcessingLayer(), + new FieldAccessorProcessingLayer(), + new ExceptionHierarchyProcessingLayer(), + new MethodBodyTranslationProcessingLayer(), + new NativeMethodBodyProcessingLayer(), + new DelegateConversionProcessingLayer(), + // new SystemInterfaceRecoveryProcessingLayer(), // Should handle INotifyCompletion, IEnumerable, IEquatable, etc + new ConstantInitializationProcessingLayer(), + new StaticConstructorProcessingLayer(), + ]); +Console.WriteLine("Done!"); + +/* +Todo: +- Interface implementation for marshalling +- Il2Cppmscorlib cyclical dependency resolution - solved? +- Object/ValueType/Enum special handling +- Creation method registration +- ICall +- System interfaces +- Params (or collections expression support for arrays) +- Multidimensional arrays https://github.com/js6pak/libil2cpp-archive/blob/90c6b7ed1c291d54b257d751a4d743d07dea8d62/vm/Array.cpp#L273-L286 +- Unstripped class injection +- Finalizers might need renamed/removed +*/ diff --git a/Il2CppInterop.CLI/Utils.cs b/Il2CppInterop.CLI/Utils.cs deleted file mode 100644 index 6fa7fa1e..00000000 --- a/Il2CppInterop.CLI/Utils.cs +++ /dev/null @@ -1,14 +0,0 @@ -using AsmResolver.DotNet; - -namespace Il2CppInterop; - -internal static class Utils -{ - public static List LoadAssembliesFrom(DirectoryInfo directoryInfo) - { - var inputAssemblies = directoryInfo.EnumerateFiles("*.dll").Select(f => AssemblyDefinition.FromFile( - f.FullName)).ToList(); - - return inputAssemblies; - } -} diff --git a/Il2CppInterop.Common/Il2CppInterop.Common.csproj b/Il2CppInterop.Common/Il2CppInterop.Common.csproj index d9320b4d..dc725d92 100644 --- a/Il2CppInterop.Common/Il2CppInterop.Common.csproj +++ b/Il2CppInterop.Common/Il2CppInterop.Common.csproj @@ -1,16 +1,16 @@ - netstandard2.0 + net9.0 BepInEx, knah et al. Common API for Il2CppInterop packages Il2CppInterop.Common - - - + + + diff --git a/Il2CppInterop.Common/ObjectPointer.cs b/Il2CppInterop.Common/ObjectPointer.cs new file mode 100644 index 00000000..73884ba8 --- /dev/null +++ b/Il2CppInterop.Common/ObjectPointer.cs @@ -0,0 +1,7 @@ +namespace Il2CppInterop.Runtime.InteropTypes; + +public readonly record struct ObjectPointer(IntPtr Value) +{ + public static explicit operator ObjectPointer(IntPtr value) => new(value); + public static explicit operator IntPtr(ObjectPointer value) => value.Value; +} diff --git a/Il2CppInterop.Generator/ApplicationAnalysisContextExtensions.cs b/Il2CppInterop.Generator/ApplicationAnalysisContextExtensions.cs new file mode 100644 index 00000000..4f35b5fe --- /dev/null +++ b/Il2CppInterop.Generator/ApplicationAnalysisContextExtensions.cs @@ -0,0 +1,49 @@ +using System.Reflection; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +internal static class ApplicationAnalysisContextExtensions +{ + extension (ApplicationAnalysisContext appContext) + { + public InjectedAssemblyAnalysisContext InjectAssembly(Assembly assembly) + { + return appContext.InjectAssembly(assembly.GetName()); + } + + public InjectedAssemblyAnalysisContext InjectAssembly(AssemblyName assemblyName) + { +#pragma warning disable SYSLIB0037 // Type or member is obsolete + return appContext.InjectAssembly( + assemblyName.Name!, + assemblyName.Version, + (uint)assemblyName.HashAlgorithm, + (uint)assemblyName.Flags, + assemblyName.CultureName, + assemblyName.GetPublicKeyToken(), + assemblyName.GetPublicKey()); +#pragma warning restore SYSLIB0037 // Type or member is obsolete + } + + public TypeAnalysisContext ResolveTypeOrThrow(Type? type) + { + return appContext.ResolveType(type) ?? throw new($"Unable to resolve type {type?.FullName}"); + } + + public TypeAnalysisContext? ResolveType(Type? type) + { + if (type is null) + return null; + + var assemblyName = type.Assembly.GetName().Name!; + if (assemblyName == "System.Private.CoreLib") + assemblyName = "mscorlib"; + var assembly = appContext.GetAssemblyByName(assemblyName); + return assembly?.GetTypeByFullName(type.FullName!); + } + + public AssemblyAnalysisContext Mscorlib => appContext.AssembliesByName["mscorlib"]; + public AssemblyAnalysisContext Il2CppMscorlib => appContext.AssembliesByName["Il2Cppmscorlib"]; + } +} diff --git a/Il2CppInterop.Generator/AsmResolverDllOutputFormatBinding.cs b/Il2CppInterop.Generator/AsmResolverDllOutputFormatBinding.cs new file mode 100644 index 00000000..b7778cf6 --- /dev/null +++ b/Il2CppInterop.Generator/AsmResolverDllOutputFormatBinding.cs @@ -0,0 +1,45 @@ +using AsmResolver.DotNet; +using Cpp2IL.Core.Model.Contexts; +using Cpp2IL.Core.OutputFormats; + +namespace Il2CppInterop.Generator; + +public class AsmResolverDllOutputFormatBinding : AsmResolverDllOutputFormatThrowNull +{ + public override string OutputFormatId => "dll_binding"; + + public override string OutputFormatName => "DLL files with method bodies containing a binding for modding."; + + protected override void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext) + { + if (methodContext.RuntimeImplemented) + { + // This is a runtime-implemented method, so we don't need to do anything. + } + else if (methodContext.TryGetExtraData(out TranslatedMethodBody? translatedBody)) + { + translatedBody.FillMethodBody(methodDefinition); + } + else if (methodContext.TryGetExtraData(out NativeMethodBody? nativeBody)) + { + nativeBody.FillMethodBody(methodDefinition); + } + else + { + // This gets called when the body of an unstripped method could not be translated. + // We could have it throw a custom exception with a message, but throwing null is sufficient for now. + base.FillMethodBody(methodDefinition, methodContext); + } + } + + public override List BuildAssemblies(ApplicationAnalysisContext context) + { + var list = base.BuildAssemblies(context); + + // Todo: Remove injected reference assemblies from the output + + // Todo: Replace mscorlib references with .NET Core references + + return list; + } +} diff --git a/Il2CppInterop.Generator/AsmResolverDllOutputFormatUnstripped.cs b/Il2CppInterop.Generator/AsmResolverDllOutputFormatUnstripped.cs new file mode 100644 index 00000000..e0ba35fd --- /dev/null +++ b/Il2CppInterop.Generator/AsmResolverDllOutputFormatUnstripped.cs @@ -0,0 +1,24 @@ +using AsmResolver.DotNet; +using Cpp2IL.Core.Model.Contexts; +using Cpp2IL.Core.OutputFormats; + +namespace Il2CppInterop.Generator; + +public class AsmResolverDllOutputFormatUnstripped : AsmResolverDllOutputFormatThrowNull +{ + public override string OutputFormatId => "dll_unstripped"; + + public override string OutputFormatName => "DLL files with method bodies containing an unstripped implementation if available."; + + protected override void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext) + { + if (methodContext.TryGetExtraData(out OriginalMethodBody? originalBody)) + { + originalBody.FillMethodBody(methodDefinition); + } + else + { + base.FillMethodBody(methodDefinition, methodContext); + } + } +} diff --git a/Il2CppInterop.Generator/AssemblyAnalysisContextExtensions.cs b/Il2CppInterop.Generator/AssemblyAnalysisContextExtensions.cs new file mode 100644 index 00000000..7959c3c7 --- /dev/null +++ b/Il2CppInterop.Generator/AssemblyAnalysisContextExtensions.cs @@ -0,0 +1,47 @@ +using Cpp2IL.Core.Model.Contexts; +using LibCpp2IL.BinaryStructures; + +namespace Il2CppInterop.Generator; + +internal static class AssemblyAnalysisContextExtensions +{ + extension (AssemblyAnalysisContext assembly) + { + public bool IsReferenceAssembly + { + get => assembly.GetExtraData("ReferenceAssembly") is true; + set => assembly.PutExtraData("ReferenceAssembly", value); + } + + public InjectedTypeAnalysisContext InjectType(Type type) + { + var result = assembly.InjectType(type.Namespace ?? "", type.Name, null, type.Attributes); + if (type.ContainsGenericParameters) + { + foreach (var genericParameter in type.GetGenericArguments()) + { + var genericParameterContext = new GenericParameterTypeAnalysisContext(genericParameter.Name, genericParameter.GenericParameterPosition, Il2CppTypeEnum.IL2CPP_TYPE_VAR, genericParameter.GenericParameterAttributes, result); + result.GenericParameters.Add(genericParameterContext); + } + } + result.SourceType = type; + return result; + } + + public TypeAnalysisContext GetTypeByFullNameOrThrow(string fullName) + { + return assembly.GetTypeByFullName(fullName) ?? throw new($"Unable to find type by full name {fullName}"); + } + + public TypeAnalysisContext? GetTypeByFullName(Type type) + { + var fullName = type.FullName; + return string.IsNullOrEmpty(fullName) ? null : assembly.GetTypeByFullName(fullName); + } + + public TypeAnalysisContext GetTypeByFullNameOrThrow(Type type) + { + return assembly.GetTypeByFullName(type) ?? throw new($"Unable to find type by full name {type.FullName}"); + } + } +} diff --git a/Il2CppInterop.Generator/AttributeRemovalProcessingLayer.cs b/Il2CppInterop.Generator/AttributeRemovalProcessingLayer.cs new file mode 100644 index 00000000..e9de3683 --- /dev/null +++ b/Il2CppInterop.Generator/AttributeRemovalProcessingLayer.cs @@ -0,0 +1,94 @@ +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Logging; +using Cpp2IL.Core.Model.Contexts; +using Cpp2IL.Core.Model.CustomAttributes; + +namespace Il2CppInterop.Generator; + +public class AttributeRemovalProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Id => "attribute_removal"; + public override string Name => "Attribute Removal"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var isUnmanagedAttributeType = appContext.GetAssemblyByName("mscorlib")?.GetTypeByFullName("System.Runtime.CompilerServices.IsUnmanagedAttribute"); + + if (isUnmanagedAttributeType is null) + { + Logger.WarnNewline("IsUnmanagedAttribute not found. They cannot be recovered.", nameof(AttributeRemovalProcessingLayer)); + } + + var isUnmanagedAttributeConstructor = isUnmanagedAttributeType?.Methods.First(m => m.Name == ".ctor" && m.Parameters.Count == 0); + + foreach (var assembly in appContext.Assemblies) + { + ClearAttributes(assembly); + } + + foreach (var type in appContext.AllTypes) + { + ClearAttributes(type); + + foreach (var genericParameter in type.GenericParameters) + { + ClearGenericParameterAttributes(genericParameter, isUnmanagedAttributeConstructor); + } + + foreach (var field in type.Fields) + { + ClearAttributes(field); + } + + foreach (var method in type.Methods) + { + ClearAttributes(method); + + foreach (var parameter in method.Parameters) + { + ClearAttributes(parameter); + } + + foreach (var genericParameter in method.GenericParameters) + { + ClearGenericParameterAttributes(genericParameter, isUnmanagedAttributeConstructor); + } + } + + foreach (var property in type.Properties) + { + ClearAttributes(property); + } + + foreach (var @event in type.Events) + { + ClearAttributes(@event); + } + } + } + + private static void ClearGenericParameterAttributes(GenericParameterTypeAnalysisContext genericParameter, MethodAnalysisContext? isUnmanagedAttributeConstructor) + { + if (isUnmanagedAttributeConstructor is not null && HasIsUnmanagedAttribute(genericParameter)) + { + ClearAttributes(genericParameter); + genericParameter.CustomAttributes ??= new(1); + genericParameter.CustomAttributes.Add(new AnalyzedCustomAttribute(isUnmanagedAttributeConstructor)); + } + else + { + ClearAttributes(genericParameter); + } + + static bool HasIsUnmanagedAttribute(GenericParameterTypeAnalysisContext genericParameter) + { + return genericParameter.HasCustomAttributeWithFullName("System.Runtime.CompilerServices.IsUnmanagedAttribute") + || genericParameter.HasCustomAttributeWithFullName("Il2CppSystem.Runtime.CompilerServices.IsUnmanagedAttribute"); + } + } + + private static void ClearAttributes(HasCustomAttributes context) + { + context.AttributeTypes?.Clear(); + context.CustomAttributes?.Clear(); + } +} diff --git a/Il2CppInterop.Generator/AttributesOverrideProcessingLayer.cs b/Il2CppInterop.Generator/AttributesOverrideProcessingLayer.cs new file mode 100644 index 00000000..dd7105d9 --- /dev/null +++ b/Il2CppInterop.Generator/AttributesOverrideProcessingLayer.cs @@ -0,0 +1,104 @@ +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public class AttributesOverrideProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Id => "attributes_override"; + public override string Name => "Attributes Override"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + // Il2CppSystem.Object + { + var il2CppType = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Object"); + + // Need to fix a couple method attributes, so that they are not marked as newslot + + // bool Equals(object) + { + var equalsMethod = il2CppType.Methods.First(m => m.Name == nameof(object.Equals) && m.Parameters.Count == 1); + equalsMethod.OverrideAttributes = equalsMethod.Attributes & ~MethodAttributes.NewSlot; + } + + // int GetHashCode() + { + var getHashCodeMethod = il2CppType.Methods.First(m => m.Name == nameof(object.GetHashCode) && m.Parameters.Count == 0); + getHashCodeMethod.OverrideAttributes = getHashCodeMethod.Attributes & ~MethodAttributes.NewSlot; + } + } + + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly || assembly.IsInjected) + { + continue; + } + + foreach (var type in assembly.Types) + { + if (type.IsInjected) + { + continue; + } + + if (type.IsStatic) + { + type.OverrideAttributes = type.Attributes & ~TypeAttributes.Sealed; + + // We add a private constructor to prevent instantiation. + var constructor = new InjectedMethodAnalysisContext( + type, + ".ctor", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, + []) + { + IsInjected = true + }; + type.Methods.Add(constructor); + } + + foreach (var method in type.Methods) + { + if (method.IsInjected) + { + continue; + } + + const MethodAttributes FlagsToRemove = + MethodAttributes.HasSecurity | + MethodAttributes.RequireSecObject | + MethodAttributes.UnmanagedExport | + MethodAttributes.PinvokeImpl; + + method.OverrideAttributes = method.Attributes & ~FlagsToRemove; + + method.OverrideImplAttributes = MethodImplAttributes.Managed; + } + + foreach (var field in type.Fields) + { + if (field.IsInjected) + { + continue; + } + + // Change constant fields to static readonly + if (field.Attributes.HasFlag(FieldAttributes.Literal)) + { + field.OverrideAttributes = (field.Attributes & ~FieldAttributes.Literal) | FieldAttributes.InitOnly; + } + + const FieldAttributes FlagsToRemove = + FieldAttributes.HasFieldRVA | + FieldAttributes.HasDefault | + FieldAttributes.HasFieldMarshal; + + field.OverrideAttributes = field.Attributes & ~FlagsToRemove; + } + } + } + } +} diff --git a/Il2CppInterop.Generator/BooleanAndTypeVisitor.cs b/Il2CppInterop.Generator/BooleanAndTypeVisitor.cs new file mode 100644 index 00000000..983c4530 --- /dev/null +++ b/Il2CppInterop.Generator/BooleanAndTypeVisitor.cs @@ -0,0 +1,30 @@ +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public abstract class BooleanAndTypeVisitor : TypeVisitor +{ + public override bool Visit(ArrayTypeAnalysisContext type) => Visit(type.ElementType); + public override bool Visit(BoxedTypeAnalysisContext type) => Visit(type.ElementType); + public override bool Visit(ByRefTypeAnalysisContext type) => Visit(type.ElementType); + public override bool Visit(CustomModifierTypeAnalysisContext type) => Visit(type.ElementType) && Visit(type.ModifierType); + public override bool Visit(GenericInstanceTypeAnalysisContext type) + { + if (!Visit(type.GenericType)) + return false; + + foreach (var genericArgument in type.GenericArguments) + { + if (!Visit(genericArgument)) + return false; + } + + return true; + } + public override bool Visit(GenericParameterTypeAnalysisContext type) => true; + public override bool Visit(PinnedTypeAnalysisContext type) => Visit(type.ElementType); + public override bool Visit(PointerTypeAnalysisContext type) => Visit(type.ElementType); + public override bool Visit(SentinelTypeAnalysisContext type) => true; + public override bool Visit(SzArrayTypeAnalysisContext type) => Visit(type.ElementType); + protected override bool VisitSimpleType(TypeAnalysisContext type) => true; +} diff --git a/Il2CppInterop.Generator/BooleanOrTypeVisitor.cs b/Il2CppInterop.Generator/BooleanOrTypeVisitor.cs new file mode 100644 index 00000000..1d4f6b3b --- /dev/null +++ b/Il2CppInterop.Generator/BooleanOrTypeVisitor.cs @@ -0,0 +1,30 @@ +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public abstract class BooleanOrTypeVisitor : TypeVisitor +{ + public override bool Visit(ArrayTypeAnalysisContext type) => Visit(type.ElementType); + public override bool Visit(BoxedTypeAnalysisContext type) => Visit(type.ElementType); + public override bool Visit(ByRefTypeAnalysisContext type) => Visit(type.ElementType); + public override bool Visit(CustomModifierTypeAnalysisContext type) => Visit(type.ElementType) || Visit(type.ModifierType); + public override bool Visit(GenericInstanceTypeAnalysisContext type) + { + if (Visit(type.GenericType)) + return true; + + foreach (var genericArgument in type.GenericArguments) + { + if (Visit(genericArgument)) + return true; + } + + return false; + } + public override bool Visit(GenericParameterTypeAnalysisContext type) => false; + public override bool Visit(PinnedTypeAnalysisContext type) => Visit(type.ElementType); + public override bool Visit(PointerTypeAnalysisContext type) => Visit(type.ElementType); + public override bool Visit(SentinelTypeAnalysisContext type) => false; + public override bool Visit(SzArrayTypeAnalysisContext type) => Visit(type.ElementType); + protected override bool VisitSimpleType(TypeAnalysisContext type) => false; +} diff --git a/Il2CppInterop.Generator/CleanRenamingProcessingLayer.cs b/Il2CppInterop.Generator/CleanRenamingProcessingLayer.cs new file mode 100644 index 00000000..88521e19 --- /dev/null +++ b/Il2CppInterop.Generator/CleanRenamingProcessingLayer.cs @@ -0,0 +1,252 @@ +using System.Buffers; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Text.RegularExpressions; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public partial class CleanRenamingProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Clean Name Changes"; + + public override string Id => "cleanrenamer"; + + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + for (var i = 0; i < appContext.Assemblies.Count; i++) + { + var assembly = appContext.Assemblies[i]; + + if (assembly.IsReferenceAssembly || assembly.IsInjected) + continue; + + RenameTypes(assembly.TopLevelTypes); + + foreach (var type in assembly.Types) + { + if (type.IsInjected) + continue; + + RenameMembers(type); + } + + progressCallback?.Invoke(i, appContext.Assemblies.Count); + } + } + + private static void RenameTypes(IEnumerable types, string? declaringTypeName = null) + { + HashSet<(string, string)> reservedFullNames = []; + foreach (var type in types) + { + if (type.IsInjected) + { + reservedFullNames.Add((type.Namespace, type.Name)); + continue; + } + + if (TryMatchGenericType(type.Name, out var typeName, out var genericCount)) + { + type.OverrideName = $"{ReplaceInvalidWithUnderscore(typeName)}`{genericCount}"; + } + else if (type.IsModuleType) + { + type.OverrideName = $"Module_{ReplaceInvalidWithUnderscore(type.DeclaringAssembly.DefaultName)}"; + } + else if (type.IsPrivateImplementationDetailsType) + { + type.OverrideName = $"PrivateImplementationDetails_{ReplaceInvalidWithUnderscore(type.DeclaringAssembly.DefaultName)}"; + } + else + { + type.OverrideName = ReplaceInvalidWithUnderscore(type.Name); + } + } + + // Resolve any name conflicts + foreach (var type in types) + { + if (type.IsInjected) + continue; + + var @namespace = type.Namespace; + var name = type.Name; + while (name == declaringTypeName || !reservedFullNames.Add((@namespace, name))) + { + name = $"_{name}"; + } + + type.OverrideName = name; + } + + foreach (var type in types) + { + RenameTypes(type.NestedTypes, type.Name); + } + } + + private static void RenameMembers(TypeAnalysisContext type) + { + const MethodAttributes FlagsWhichRequireNameConsistency = + MethodAttributes.SpecialName | + MethodAttributes.Abstract | + MethodAttributes.Virtual | + MethodAttributes.RTSpecialName; + + // Fields + foreach (var field in type.Fields) + { + if (field.IsInjected) + continue; + + if (TryMatchPropertyBackingField(field.Name, out var propertyName)) + { + field.OverrideName = $"{propertyName}_BackingField"; + } + else if (type.Events.Any(e => e.Name == field.Name)) + { + field.OverrideName = $"{field.Name}_BackingField"; + } + else + { + field.OverrideName = ReplaceInvalidWithUnderscore(field.Name); + } + } + + // Methods + foreach (var method in type.Methods) + { + if (method.IsInjected) + continue; + + if ((method.Attributes & FlagsWhichRequireNameConsistency) != 0) + continue; + + method.OverrideName = ReplaceInvalidWithUnderscore(method.Name); + } + + // Collect all reserved names + HashSet reservedNames = + [ + "", + "_", + type.Name, + .. GetConflictingNames(type.Properties), + .. GetConflictingNames(type.Events), + .. GetConflictingNames(type.Methods), + ]; + if (StartsWithGetSet(type.Name)) + { + reservedNames.Add(type.Name.Substring(4)); + } + + // Resolve any name conflicts for fields + foreach (var field in type.Fields) + { + if (field.IsInjected) + continue; + + field.OverrideName = PrependUnderscoreIfConflicting(field.Name, reservedNames); + reservedNames.Add(field.Name); + } + + // Rename static constructors + foreach (var method in type.Methods) + { + if (method.IsInjected) + continue; + + if (!method.IsStaticConstructor) + continue; + + method.OverrideName = PrependUnderscoreIfConflicting("StaticConstructor", reservedNames); + method.OverrideAttributes = method.Attributes & ~(MethodAttributes.SpecialName | MethodAttributes.RTSpecialName); + reservedNames.Add(method.Name); + } + } + + private static IEnumerable GetConflictingNames(IEnumerable members) + { + foreach (var member in members) + { + yield return member.Name; + if (StartsWithGetSet(member.Name)) + { + yield return member.Name.Substring(4); + } + } + } + + private static string PrependUnderscoreIfConflicting(string name, HashSet reservedNames) + { + while (reservedNames.Contains(name)) + { + name = $"_{name}"; + } + return name; + } + + private static bool StartsWithGetSet(string name) + { + return name.StartsWith("get_", StringComparison.Ordinal) + || name.StartsWith("set_", StringComparison.Ordinal); + } + + private static string ReplaceInvalidWithUnderscore(string name) + { + ArgumentException.ThrowIfNullOrEmpty(name); + var array = ArrayPool.Shared.Rent(name.Length + 1); + array[0] = '_'; + name.AsSpan().CopyTo(array.AsSpan(1)); + for (var i = name.Length; i > 0; i--) + { + if (!char.IsLetterOrDigit(array[i])) + { + array[i] = '_'; + } + } + var result = char.IsDigit(array[1]) ? new string(array.AsSpan(0, name.Length + 1)) : new string(array.AsSpan(1, name.Length)); + ArrayPool.Shared.Return(array); + return result; + } + + private static bool TryMatchPropertyBackingField(string fieldName, [NotNullWhen(true)] out string? propertyName) + { + var match = PropertyBackingFieldRegex.Match(fieldName); + if (match.Success) + { + propertyName = match.Groups[1].Value; + return true; + } + else + { + propertyName = null; + return false; + } + } + + [GeneratedRegex(@"^<(\w+)>k__BackingField$")] + private static partial Regex PropertyBackingFieldRegex { get; } + + private static bool TryMatchGenericType(string genericName, [NotNullWhen(true)] out string? typeName, [NotNullWhen(true)] out string? genericCount) + { + var match = GenericTypeRegex.Match(genericName); + if (match.Success) + { + typeName = match.Groups[1].Value; + genericCount = match.Groups[2].Value; + return true; + } + else + { + typeName = null; + genericCount = null; + return false; + } + } + + [GeneratedRegex(@"^(.+)`(\d+)$")] + private static partial Regex GenericTypeRegex { get; } +} diff --git a/Il2CppInterop.Generator/ConstantInitializationProcessingLayer.cs b/Il2CppInterop.Generator/ConstantInitializationProcessingLayer.cs new file mode 100644 index 00000000..2b22f123 --- /dev/null +++ b/Il2CppInterop.Generator/ConstantInitializationProcessingLayer.cs @@ -0,0 +1,72 @@ +using System.Diagnostics; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator; + +public class ConstantInitializationProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Constant Initialization Processor"; + public override string Id => "constant_initialization_processor"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly || assembly.IsInjected) + continue; + foreach (var type in assembly.Types) + { + if (type.IsInjected) + continue; + + foreach (var field in type.Fields) + { + if (field.ConstantValue is null || field.IsInjected) + continue; + + Debug.Assert(field.IsStatic); + + var instructions = type.GetOrCreateStaticConstructorInstructions(); + + object operandCast; + unchecked + { + operandCast = field.ConstantValue switch + { + bool value => value ? 1 : 0, + char value => (int)value, + byte value => (int)value, + sbyte value => (int)value, + ushort value => (int)value, + short value => (int)value, + uint value => (int)value, + ulong value => (long)value, + _ => field.ConstantValue, + }; + } + + var opCode = operandCast switch + { + long => OpCodes.Ldc_I8, + float => OpCodes.Ldc_R4, + double => OpCodes.Ldc_R8, + string => OpCodes.Ldstr, + _ => OpCodes.Ldc_I4 + }; + + instructions.Add(new Instruction(opCode, operandCast)); + if (opCode == OpCodes.Ldstr) + { + MonoIl2CppConversion.AddMonoToIl2CppStringConversion(instructions, appContext); + } + else + { + MonoIl2CppConversion.AddMonoToIl2CppConversion(instructions, field.FieldType); + } + instructions.Add(new Instruction(OpCodes.Stsfld, field)); + } + } + } + } +} diff --git a/Il2CppInterop.Generator/ContextResolver.cs b/Il2CppInterop.Generator/ContextResolver.cs new file mode 100644 index 00000000..4ac1679b --- /dev/null +++ b/Il2CppInterop.Generator/ContextResolver.cs @@ -0,0 +1,366 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using AsmResolver.DotNet; +using AsmResolver.DotNet.Signatures; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; +using LibCpp2IL.BinaryStructures; + +namespace Il2CppInterop.Generator; + +public readonly struct ContextResolver +{ + private readonly AssemblyAnalysisContext referencedFrom; + private readonly TypeAnalysisContext? referencingType; + private readonly MethodAnalysisContext? referencingMethod; + + public ContextResolver(AssemblyAnalysisContext referencedFrom) + { + this.referencedFrom = referencedFrom; + } + + public ContextResolver(TypeAnalysisContext referencingType) + { + if (referencingType is ReferencedTypeAnalysisContext) + throw new ArgumentException("Must be a simple type", nameof(referencingType)); + referencedFrom = referencingType.DeclaringAssembly; + this.referencingType = referencingType; + } + + public ContextResolver(MethodAnalysisContext referencingMethod) + { + if (referencingMethod is ConcreteGenericMethodAnalysisContext) + throw new ArgumentException("Must be a simple method", nameof(referencingMethod)); + referencedFrom = referencingMethod.CustomAttributeAssembly; + referencingType = referencingMethod.DeclaringType; + this.referencingMethod = referencingMethod; + } + + public TypeAnalysisContext? Resolve(TypeSignature? type) => type switch + { + // Ordered roughly by frequency + TypeDefOrRefSignature typeDefOrRef => Resolve(typeDefOrRef), + CorLibTypeSignature primitive => Resolve(primitive), + GenericInstanceTypeSignature genericInstance => Resolve(genericInstance), + SzArrayTypeSignature szArray => Resolve(szArray.BaseType)?.MakeSzArrayType(), + GenericParameterSignature genericParameter => genericParameter.ParameterType switch + { + GenericParameterType.Type => TryGetGenericParameter(referencingType?.GenericParameters, genericParameter.Index), + _ => TryGetGenericParameter(referencingMethod?.GenericParameters, genericParameter.Index), + }, + ByReferenceTypeSignature byRef => Resolve(byRef.BaseType)?.MakeByReferenceType(), + PointerTypeSignature pointer => Resolve(pointer.BaseType)?.MakePointerType(), + ArrayTypeSignature array => Resolve(array.BaseType)?.MakeArrayType(array.Rank), + PinnedTypeSignature pinned => Resolve(pinned.BaseType)?.MakePinnedType(), + CustomModifierTypeSignature customModifier => Resolve(customModifier), + BoxedTypeSignature boxed => Resolve(boxed.BaseType)?.MakeBoxedType(), + SentinelTypeSignature => new SentinelTypeAnalysisContext(referencedFrom), + _ => null + }; + + private static GenericParameterTypeAnalysisContext? TryGetGenericParameter(List? genericParameters, int index) + { + if (genericParameters is null || index < 0 || index >= genericParameters.Count) + return null; + return genericParameters[index]; + } + + public bool TryResolve(TypeSignature? type, [NotNullWhen(true)] out TypeAnalysisContext? result) + { + result = Resolve(type); + return result is not null; + } + + private GenericInstanceTypeAnalysisContext? Resolve(GenericInstanceTypeSignature genericInstance) + { + return TryResolve(genericInstance.GenericType, out var genericType) && TryResolve(genericInstance.TypeArguments, out var genericArguments) + ? new GenericInstanceTypeAnalysisContext(genericType, genericArguments, referencedFrom) + : null; + } + + private CustomModifierTypeAnalysisContext? Resolve(CustomModifierTypeSignature customModifier) + { + return TryResolve(customModifier.BaseType, out var baseType) && TryResolve(customModifier.ModifierType, out var modifier) + ? new CustomModifierTypeAnalysisContext(baseType, modifier, customModifier.IsRequired, referencedFrom) + : null; + } + + private TypeAnalysisContext? Resolve(TypeDefOrRefSignature typeDefOrRef) + { + if (typeDefOrRef.DeclaringType is not null) + { + if (!TryResolve(typeDefOrRef.DeclaringType, out var declaringType)) + return null; + + foreach (var nestedType in declaringType.NestedTypes) + { + if (nestedType.Name == typeDefOrRef.Name) + { + return nestedType; + } + } + + return null; + } + + if (typeDefOrRef.Type is not TypeDefinition) + { + typeDefOrRef = (TypeDefOrRefSignature?)typeDefOrRef.Resolve()?.ToTypeSignature() ?? typeDefOrRef; + } + + var assemblyName = GetName(typeDefOrRef.Scope); + if (assemblyName == null) + return null; + + var targetAssembly = referencedFrom.AppContext.Assemblies.FirstOrDefault(a => a.Name == assemblyName); + if (targetAssembly == null) + return null; + + return targetAssembly.GetTypeByFullName(typeDefOrRef.FullName); + + static string? GetName(IResolutionScope? scope) => scope switch + { + ModuleDefinition module => module.Assembly!.Name, + AssemblyReference assembly => assembly.Name, + _ => throw new NotImplementedException(), + }; + } + + private TypeAnalysisContext? Resolve(CorLibTypeSignature corLibType) + { + return referencedFrom.AppContext.Mscorlib.GetTypeByFullName(corLibType.FullName); + } + + public TypeAnalysisContext? Resolve(ITypeDescriptor? type) + { + return Resolve(type?.ToTypeSignature()); + } + + public bool TryResolve(ITypeDescriptor? type, [NotNullWhen(true)] out TypeAnalysisContext? result) + { + result = Resolve(type); + return result is not null; + } + + public IEnumerable Resolve(IEnumerable types) + { + foreach (var type in types) + { + yield return Resolve(type); + } + } + + public bool TryResolve(IEnumerable types, [NotNullWhen(true)] out List? result) + { + result = []; + foreach (var type in types) + { + if (TryResolve(type, out var resolvedType)) + { + result.Add(resolvedType); + } + else + { + result = null; + return false; + } + } + return true; + } + + public FieldAnalysisContext? Resolve(IFieldDescriptor fieldDescriptor) + { + var declaringType = Resolve(fieldDescriptor.DeclaringType?.ToTypeSignature()); + if (declaringType is null) + return null; + + if (declaringType is GenericInstanceTypeAnalysisContext genericInstanceType) + { + var baseField = genericInstanceType.GenericType.TryGetFieldByName(fieldDescriptor.Name); + if (baseField is null) + return null; + + return new ConcreteGenericFieldAnalysisContext(baseField, genericInstanceType); + } + else + { + return declaringType.TryGetFieldByName(fieldDescriptor.Name); + } + } + + public bool TryResolve(IFieldDescriptor fieldDescriptor, [NotNullWhen(true)] out FieldAnalysisContext? result) + { + result = Resolve(fieldDescriptor); + return result is not null; + } + + public object? Resolve(IMethodDescriptor methodDescriptor) + { + if (methodDescriptor is MethodSpecification specification) + { + return Resolve(specification); + } + + var methodDefOrRef = (IMethodDefOrRef)methodDescriptor; + + if (!TryResolve(methodDefOrRef.DeclaringType, out var declaringType)) + return null; + + var nonGenericDeclaringType = (declaringType as GenericInstanceTypeAnalysisContext)?.GenericType ?? declaringType; + + if (nonGenericDeclaringType is ArrayTypeAnalysisContext arrayDeclaringType) + { + Debug.Assert(nonGenericDeclaringType == declaringType, "Array types should not be generic instances"); + return methodDefOrRef.Name?.Value switch + { + "Get" => new MultiDimensionalArrayMethod(arrayDeclaringType, MultiDimensionalArrayMethodType.Get), + "Set" => new MultiDimensionalArrayMethod(arrayDeclaringType, MultiDimensionalArrayMethodType.Set), + "Address" => new MultiDimensionalArrayMethod(arrayDeclaringType, MultiDimensionalArrayMethodType.Address), + ".ctor" => new MultiDimensionalArrayMethod(arrayDeclaringType, MultiDimensionalArrayMethodType.Constructor), + _ => null, + }; + } + + Debug.Assert(nonGenericDeclaringType is not ReferencedTypeAnalysisContext); + + var targetMethod = new ContextResolver(nonGenericDeclaringType).ResolveInType(methodDefOrRef); + if (targetMethod is null) + return null; + + if (declaringType is GenericInstanceTypeAnalysisContext genericInstanceType) + { + return new ConcreteGenericMethodAnalysisContext(targetMethod, genericInstanceType.GenericArguments, []); + } + else + { + return targetMethod; + } + } + + public bool TryResolve(IMethodDescriptor methodDescriptor, [NotNullWhen(true)] out object? result) + { + result = Resolve(methodDescriptor); + return result is not null; + } + + public MethodAnalysisContext? Resolve(MethodDefinition methodDefinition) + { + // The declaring type can be resolved with nothing, but resolution for the method itself requires a context. + return TryResolve(methodDefinition.DeclaringType, out var declaringType) ? new ContextResolver(declaringType).ResolveInType(methodDefinition) : null; + } + + public MethodAnalysisContext? ResolveInType(IMethodDefOrRef methodDefOrRef) + { + if (referencingType is null) + throw new InvalidOperationException("Cannot resolve method in type without a referencing type"); + + if (methodDefOrRef.Signature is null || methodDefOrRef.Signature.SentinelParameterTypes.Count > 0) + return null; + + foreach (var methodContext in referencingType.Methods) + { + if (methodContext.Name != methodDefOrRef.Name) + continue; + + if (methodContext.Parameters.Count != methodDefOrRef.Signature.ParameterTypes.Count) + continue; + + if (methodContext.GenericParameters.Count != methodDefOrRef.Signature.GenericParameterCount) + continue; + + if (methodContext.IsStatic == methodDefOrRef.Signature.HasThis) + continue; + + if (methodContext.IsVoid == methodDefOrRef.Signature.ReturnsValue) + continue; + + // We need to use a resolver for the method context to resolve potential method generic parameters correctly. + var methodResolver = new ContextResolver(methodContext); + + if (!methodResolver.TryResolve(methodDefOrRef.Signature.ReturnType, out var returnType) || + !TypeAnalysisContextEqualityComparer.Instance.Equals(methodContext.ReturnType, returnType)) + continue; + + if (!methodResolver.TryResolve(methodDefOrRef.Signature.ParameterTypes, out var parameterTypes) || + !methodContext.Parameters.Select(p => p.ParameterType).SequenceEqual(parameterTypes, TypeAnalysisContextEqualityComparer.Instance)) + continue; + + return methodContext; + } + + return null; + } + + public ConcreteGenericMethodAnalysisContext? Resolve(MethodSpecification specification) + { + if (specification.Method is null || specification.Signature is null) + return null; + + var baseMethod = (MethodAnalysisContext?)Resolve(specification.Method); + if (baseMethod is null or { DeclaringType: null }) + return null; + + if (!TryResolve(specification.Signature.TypeArguments, out var methodTypeArguments)) + return null; + + return baseMethod.MakeGenericInstanceMethod(methodTypeArguments); + } + + public TypeAnalysisContext ResolveOrThrow(Type? type, bool allowGenericInstance = true) + { + return Resolve(type, allowGenericInstance) ?? throw new($"Unable to resolve type {type?.FullName}"); + } + + public TypeAnalysisContext? Resolve(Type? type) => Resolve(type, true); + public TypeAnalysisContext? Resolve(Type? type, bool allowGenericInstance) + { + if (type is null) + return null; + + if (type.IsSZArray) + return Resolve(type.GetElementType())?.MakeSzArrayType(); + + if (type.IsByRef) + return Resolve(type.GetElementType())?.MakeByReferenceType(); + + if (type.IsPointer) + return Resolve(type.GetElementType())?.MakePointerType(); + + if (type.IsArray) + return Resolve(type.GetElementType())?.MakeArrayType(type.GetArrayRank()); + + if (type.IsGenericParameter) + { + if (type.IsGenericTypeParameter) + { + return TryGetGenericParameter(referencingType?.GenericParameters, type.GenericParameterPosition); + } + else + { + Debug.Assert(type.IsGenericMethodParameter); + return TryGetGenericParameter(referencingMethod?.GenericParameters, type.GenericParameterPosition); + } + } + + if (type.IsGenericType && allowGenericInstance) + { + var genericArguments = type.GetGenericArguments().Select(Resolve).ToArray(); + if (genericArguments.Any(x => x is null)) + return null; + + var genericType = type.GetGenericTypeDefinition(); + return Resolve(genericType, false)?.MakeGenericInstanceType(genericArguments!); + } + + if (type.IsFunctionPointer) + throw new NotSupportedException($"Function pointers are not supported: {type.Name}"); + + // Custom modifiers might be possible to support, but probably not necessary + + var assemblyName = type.Assembly.GetName().Name!; + if (assemblyName == "System.Private.CoreLib") + assemblyName = "mscorlib"; + var assembly = referencedFrom.AppContext.GetAssemblyByName(assemblyName); + return assembly?.GetTypeByFullName(type.FullName!); + } +} diff --git a/Il2CppInterop.Generator/ContextWithDataStorageExtensions.cs b/Il2CppInterop.Generator/ContextWithDataStorageExtensions.cs new file mode 100644 index 00000000..0da85e8d --- /dev/null +++ b/Il2CppInterop.Generator/ContextWithDataStorageExtensions.cs @@ -0,0 +1,70 @@ +using System.Diagnostics.CodeAnalysis; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +internal static class ContextWithDataStorageExtensions +{ + // Prevent boxing a large number of booleans. + private static readonly object True = true; + private static readonly object False = false; + + extension(ContextWithDataStorage context) + { + public void PutExtraData(T data) where T : class + { + context.PutExtraData(typeof(T).Name, data); + } + + public T? GetExtraData() where T : class + { + return context.GetExtraData(typeof(T).Name); + } + + public bool TryGetExtraData([NotNullWhen(true)] out T? data) where T : class + { + data = context.GetExtraData(); + return data is not null; + } + + public bool HasExtraData() where T : class + { + return context.TryGetExtraData(out _); + } + + /// + /// This type or member was stripped by the compiler, but we restored it using external assemblies. + /// + public bool IsUnstripped + { + get => context.GetExtraBoolean("IsUnstripped"); + set => context.PutExtraBoolean("IsUnstripped", value); + } + + /// + /// This type or member is injected by the generator as a helper method. For example, static constructors to trigger Il2Cpp initialization. + /// + /// + /// For memory efficiency, this is only set at the top-level. If a type is injected, its members are not marked as injected, even though they obviously are. + /// For the purpose of this property, nested types are not considered "members" and must be marked as injected separately. + /// + public bool IsInjected + { + get => context.GetExtraBoolean("IsInjected") || (context.Parent?.IsInjected ?? false); + set => context.PutExtraBoolean("IsInjected", value); + } + + public ContextWithDataStorage? Parent => context switch + { + MethodAnalysisContext method => method.DeclaringType, + FieldAnalysisContext @field => @field.DeclaringType, + PropertyAnalysisContext property => property.DeclaringType, + EventAnalysisContext @event => @event.DeclaringType, + TypeAnalysisContext type => (ContextWithDataStorage?)type.DeclaringType ?? type.DeclaringAssembly, + _ => null, + }; + + public bool GetExtraBoolean(string key) => context.GetExtraData(key) is true; + public void PutExtraBoolean(string key, bool value) => context.PutExtraData(key, value ? True : False); + } +} diff --git a/Il2CppInterop.Generator/DefaultTypeVisitor.cs b/Il2CppInterop.Generator/DefaultTypeVisitor.cs new file mode 100644 index 00000000..aeb3eac2 --- /dev/null +++ b/Il2CppInterop.Generator/DefaultTypeVisitor.cs @@ -0,0 +1,68 @@ +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public abstract class DefaultTypeVisitor : TypeVisitor +{ + public override T Visit(ArrayTypeAnalysisContext type) => CombineResults(type, Visit(type.ElementType)); + public override T Visit(BoxedTypeAnalysisContext type) => CombineResults(type, Visit(type.ElementType)); + public override T Visit(ByRefTypeAnalysisContext type) => CombineResults(type, Visit(type.ElementType)); + public override T Visit(CustomModifierTypeAnalysisContext type) => CombineResults(type, Visit(type.ElementType), Visit(type.ModifierType)); + public override T Visit(GenericInstanceTypeAnalysisContext type) + { + var genericTypeResult = Visit(type.GenericType); + var genericArgumentsResults = new T[type.GenericArguments.Count]; + for (var i = 0; i < type.GenericArguments.Count; i++) + { + genericArgumentsResults[i] = Visit(type.GenericArguments[i]); + } + return CombineResults(type, genericTypeResult, genericArgumentsResults); + } + /// + /// If not overridden, this will return . + /// + public override T Visit(GenericParameterTypeAnalysisContext type) => default!; + public override T Visit(PinnedTypeAnalysisContext type) => CombineResults(type, Visit(type.ElementType)); + public override T Visit(PointerTypeAnalysisContext type) => CombineResults(type, Visit(type.ElementType)); + /// + /// If not overridden, this will return . + /// + public override T Visit(SentinelTypeAnalysisContext type) => default!; + public override T Visit(SzArrayTypeAnalysisContext type) => CombineResults(type, Visit(type.ElementType)); + /// + /// If not overridden, this will return . + /// + protected override T VisitSimpleType(TypeAnalysisContext type) => default!; + /// + /// If not overridden, this will return the . + /// + protected virtual T CombineResults(ArrayTypeAnalysisContext type, T elementResult) => elementResult; + /// + /// If not overridden, this will return the . + /// + protected virtual T CombineResults(BoxedTypeAnalysisContext type, T elementResult) => elementResult; + /// + /// If not overridden, this will return the . + /// + protected virtual T CombineResults(ByRefTypeAnalysisContext type, T elementResult) => elementResult; + /// + /// If not overridden, this will return the . + /// + protected virtual T CombineResults(CustomModifierTypeAnalysisContext type, T elementResult, T modifierResult) => elementResult; + /// + /// If not overridden, this will return the . + /// + protected virtual T CombineResults(GenericInstanceTypeAnalysisContext type, T genericTypeResult, T[] genericArgumentsResults) => genericTypeResult; + /// + /// If not overridden, this will return the . + /// + protected virtual T CombineResults(PinnedTypeAnalysisContext type, T elementResult) => elementResult; + /// + /// If not overridden, this will return the . + /// + protected virtual T CombineResults(PointerTypeAnalysisContext type, T elementResult) => elementResult; + /// + /// If not overridden, this will return the . + /// + protected virtual T CombineResults(SzArrayTypeAnalysisContext type, T elementResult) => elementResult; +} diff --git a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs new file mode 100644 index 00000000..1031a7bf --- /dev/null +++ b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs @@ -0,0 +1,320 @@ +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; +using Il2CppInterop.Runtime; + +namespace Il2CppInterop.Generator; + +public class DelegateConversionProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Delegate Conversion"; + + public override string Id => "delegate_conversion"; + + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + PolyfillActionFuncDelegates(appContext); + + var multicastDelegateType = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.MulticastDelegate"); + var asyncCallbackType = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.AsyncCallback"); + var iasyncResultType = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.IAsyncResult"); + + var delegateSupportType = appContext.ResolveTypeOrThrow(typeof(DelegateSupport)); + var delegateSupportMethod = delegateSupportType.GetMethodByName(nameof(DelegateSupport.ConvertDelegate)); + + var il2CppSystemDelegate = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Delegate"); + var il2CppSystemDelegateCombine = il2CppSystemDelegate.Methods.Single(m => m.Name == "Combine" && m.Parameters.Count == 2); + var il2CppSystemDelegateRemove = il2CppSystemDelegate.GetMethodByName("Remove"); + + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly) + continue; + + // for rather than foreach, as we will be adding items to the collection + for (var typeIndex = 0; typeIndex < assembly.Types.Count; typeIndex++) + { + var type = assembly.Types[typeIndex]; + if (type.BaseType is not { Namespace: "Il2CppSystem", Name: "MulticastDelegate" }) + continue; + + // Remove variance on generic parameters because only interfaces and (real) delegates can have variance. + // https://github.com/dotnet/csharplang/discussions/2498 + // https://learn.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance + { + // Before: Func + // After: Func + // + // This inherently makes some code invalid, both normal and unstripped. + // There's probably no (good) way to fix that because the runtime doesn't actually change the type. + // https://lab.razor.fyi/#hZDBSsRADIaRetCcxCfIcXrpA7giqIsFURFcEDw5zoYamM6UmbSwLD36BB68-wC-nyels3VVFM0hhPzk-38CzxnAZfBV0HVh4u5j1kZ2FV4tolA9AWjaO8sGjdUx4pGOhEvov2-nFLijOe596ith5MISEBGjaGGDnec5nmt2Kk_rlTjUsXfRWyquAwudsSNVkoxwlRclyWzRkMqLk9baC11TPkm3fepN4E4LfdgcGmHv9odEB1iSDMMPx0DSBodTP7tnV_1PG8Mk4DrY78y15R_U9IrRXKXfiQ4VyVdkDz2cZqF1N9tbLw9vT6-0s3m78Q4 + // One way the problem might be solved is to: + // * Generate a nested interface for every Il2Cpp delegate type, eg IFunc. + // * Replace all occurances of the class type with the interface type, everywhere. + // * During unstripping, redirect references to the class methods to the interface methods. + + foreach (var genericParameter in type.GenericParameters) + { + genericParameter.OverrideAttributes = genericParameter.Attributes & ~GenericParameterAttributes.VarianceMask; + } + } + + var invokeMethod = type.GetMethodByName("Invoke"); + + TypeAnalysisContext managedDelegateType; + + if (invokeMethod.Parameters.Count <= 16 + && invokeMethod.ReturnType is not PointerTypeAnalysisContext and not ByRefTypeAnalysisContext + && invokeMethod.Parameters.All(p => p.ParameterType is not PointerTypeAnalysisContext and not ByRefTypeAnalysisContext)) + { + // We can use a System delegate + + if (!invokeMethod.IsVoid) + { + var systemType = invokeMethod.Parameters.Count switch + { + 0 => typeof(Func<>), + 1 => typeof(Func<,>), + 2 => typeof(Func<,,>), + 3 => typeof(Func<,,,>), + 4 => typeof(Func<,,,,>), + 5 => typeof(Func<,,,,,>), + 6 => typeof(Func<,,,,,,>), + 7 => typeof(Func<,,,,,,,>), + 8 => typeof(Func<,,,,,,,,>), + 9 => typeof(Func<,,,,,,,,,>), + 10 => typeof(Func<,,,,,,,,,,>), + 11 => typeof(Func<,,,,,,,,,,,>), + 12 => typeof(Func<,,,,,,,,,,,,>), + 13 => typeof(Func<,,,,,,,,,,,,,>), + 14 => typeof(Func<,,,,,,,,,,,,,,>), + 15 => typeof(Func<,,,,,,,,,,,,,,,>), + 16 => typeof(Func<,,,,,,,,,,,,,,,,>), + _ => default!, // unreachable + }; + managedDelegateType = appContext.ResolveTypeOrThrow(systemType) + .MakeGenericInstanceType(invokeMethod.Parameters.Select(p => p.ParameterType).Append(invokeMethod.ReturnType)); + } + else if (invokeMethod.Parameters.Count > 0) + { + var systemType = invokeMethod.Parameters.Count switch + { + 1 => typeof(Action<>), + 2 => typeof(Action<,>), + 3 => typeof(Action<,,>), + 4 => typeof(Action<,,,>), + 5 => typeof(Action<,,,,>), + 6 => typeof(Action<,,,,,>), + 7 => typeof(Action<,,,,,,>), + 8 => typeof(Action<,,,,,,,>), + 9 => typeof(Action<,,,,,,,,>), + 10 => typeof(Action<,,,,,,,,,>), + 11 => typeof(Action<,,,,,,,,,,>), + 12 => typeof(Action<,,,,,,,,,,,>), + 13 => typeof(Action<,,,,,,,,,,,,>), + 14 => typeof(Action<,,,,,,,,,,,,,>), + 15 => typeof(Action<,,,,,,,,,,,,,,>), + 16 => typeof(Action<,,,,,,,,,,,,,,,>), + _ => default!, // unreachable + }; + managedDelegateType = appContext.ResolveTypeOrThrow(systemType).MakeGenericInstanceType(invokeMethod.Parameters.Select(p => p.ParameterType)); + } + else + { + managedDelegateType = appContext.ResolveTypeOrThrow(typeof(Action)); + } + } + else + { + // We need to create a new delegate type + + var name = type.Name is "Delegate" ? "Converted" : "Delegate"; // Name can't be the same as the declaring type + managedDelegateType = type.InjectNestedType( + name, + multicastDelegateType); + + managedDelegateType.CopyGenericParameters(type); + + List parameterTypes = invokeMethod.Parameters.Select(p => p.ParameterType).ToList(); + { + var genericParameterDictionary = Enumerable.Range(0, type.GenericParameters.Count) + .ToDictionary(i => type.GenericParameters[i], i => managedDelegateType.GenericParameters[i]); + var replacementVisitor = new TypeReplacementVisitor(genericParameterDictionary); + replacementVisitor.Replace(parameterTypes); + } + + // Constructor + { + managedDelegateType.Methods.Add(new InjectedMethodAnalysisContext( + managedDelegateType, + ".ctor", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, + [appContext.SystemTypes.SystemObjectType, appContext.SystemTypes.SystemIntPtrType], + defaultImplAttributes: MethodImplAttributes.Runtime) + { + RuntimeImplemented = true, + }); + } + + // Invoke + { + managedDelegateType.Methods.Add(new InjectedMethodAnalysisContext( + managedDelegateType, + "Invoke", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, + parameterTypes.ToArray(), + defaultImplAttributes: MethodImplAttributes.Runtime) + { + RuntimeImplemented = true, + }); + } + + // BeginInvoke + { + managedDelegateType.Methods.Add(new InjectedMethodAnalysisContext( + managedDelegateType, + "BeginInvoke", + iasyncResultType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, + parameterTypes.Append(asyncCallbackType).Append(appContext.SystemTypes.SystemObjectType).ToArray(), + defaultImplAttributes: MethodImplAttributes.Runtime) + { + RuntimeImplemented = true, + }); + } + + // EndInvoke + { + managedDelegateType.Methods.Add(new InjectedMethodAnalysisContext( + managedDelegateType, + "EndInvoke", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, + [iasyncResultType], + defaultImplAttributes: MethodImplAttributes.Runtime) + { + RuntimeImplemented = true, + }); + } + } + + var concreteType = type.HasGenericParameters ? type.MakeGenericInstanceType(type.GenericParameters) : type; + var implicitConversion = new InjectedMethodAnalysisContext( + type, + "op_Implicit", + concreteType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, + [managedDelegateType]); + type.Methods.Add(implicitConversion); + implicitConversion.PutExtraData(new() + { + Instructions = + [ + new Instruction(OpCodes.Ldarg_0), + new Instruction(OpCodes.Call, delegateSupportMethod.MakeGenericInstanceMethod(concreteType)), + new Instruction(OpCodes.Ret), + ] + }); + + var addition = new InjectedMethodAnalysisContext( + type, + "op_Addition", + concreteType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, + [concreteType, concreteType]); + type.Methods.Add(addition); + addition.PutExtraData(new() + { + Instructions = + [ + new Instruction(OpCodes.Ldarg_0), + new Instruction(OpCodes.Ldarg_1), + new Instruction(OpCodes.Call, il2CppSystemDelegateCombine), + new Instruction(OpCodes.Castclass, concreteType), + new Instruction(OpCodes.Ret), + ] + }); + + var subtraction = new InjectedMethodAnalysisContext( + type, + "op_Subtraction", + concreteType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, + [concreteType, concreteType]); + type.Methods.Add(subtraction); + subtraction.PutExtraData(new() + { + Instructions = + [ + new Instruction(OpCodes.Ldarg_0), + new Instruction(OpCodes.Ldarg_1), + new Instruction(OpCodes.Call, il2CppSystemDelegateRemove), + new Instruction(OpCodes.Castclass, concreteType), + new Instruction(OpCodes.Ret), + ] + }); + } + } + } + + /// + /// mscorlib only contains Action and Func delegates with up to 8 parameters. + /// However, System.Private.CoreLib contains Action and Func delegates with up to 16 parameters. + /// This method will create the Action and Func delegates with more than 8 parameters, + /// so that they can be used when the mscorlib assembly references are replaced with System.Private.CoreLib references. + /// + /// + private static void PolyfillActionFuncDelegates(ApplicationAnalysisContext appContext) + { + var mscorlib = appContext.AssembliesByName["mscorlib"]; + + ReadOnlySpan types = + [ + typeof(Action), + typeof(Action<>), + typeof(Action<,>), + typeof(Action<,,>), + typeof(Action<,,,>), + typeof(Action<,,,,>), + typeof(Action<,,,,,>), + typeof(Action<,,,,,,>), + typeof(Action<,,,,,,,>), + typeof(Action<,,,,,,,,>), + typeof(Action<,,,,,,,,,>), + typeof(Action<,,,,,,,,,,>), + typeof(Action<,,,,,,,,,,,>), + typeof(Action<,,,,,,,,,,,,>), + typeof(Action<,,,,,,,,,,,,,>), + typeof(Action<,,,,,,,,,,,,,,>), + typeof(Action<,,,,,,,,,,,,,,,>), + typeof(Func<>), + typeof(Func<,>), + typeof(Func<,,>), + typeof(Func<,,,>), + typeof(Func<,,,,>), + typeof(Func<,,,,,>), + typeof(Func<,,,,,,>), + typeof(Func<,,,,,,,>), + typeof(Func<,,,,,,,,>), + typeof(Func<,,,,,,,,,>), + typeof(Func<,,,,,,,,,,>), + typeof(Func<,,,,,,,,,,,>), + typeof(Func<,,,,,,,,,,,,>), + typeof(Func<,,,,,,,,,,,,,>), + typeof(Func<,,,,,,,,,,,,,,>), + typeof(Func<,,,,,,,,,,,,,,,>), + typeof(Func<,,,,,,,,,,,,,,,,>), + ]; + + foreach (var type in types) + { + if (mscorlib.GetTypeByFullName(type.FullName!) is not null) + continue; + + mscorlib.InjectType(type).InjectContentFromSourceType(); + } + } +} diff --git a/Il2CppInterop.Generator/DictionaryExtensions.cs b/Il2CppInterop.Generator/DictionaryExtensions.cs new file mode 100644 index 00000000..54ded043 --- /dev/null +++ b/Il2CppInterop.Generator/DictionaryExtensions.cs @@ -0,0 +1,18 @@ +namespace Il2CppInterop.Generator; + +internal static class DictionaryExtensions +{ + public static TValue? TryGetValue(this Dictionary dictionary, TKey? key) + where TKey : class + where TValue : class + { + return key is not null && dictionary.TryGetValue(key, out var value) ? value : null; + } + + public static TValue? GetValue(this Dictionary dictionary, TKey? key) + where TKey : class + where TValue : class + { + return key is not null ? dictionary[key] : null; + } +} diff --git a/Il2CppInterop.Generator/EnumProcessingLayer.cs b/Il2CppInterop.Generator/EnumProcessingLayer.cs new file mode 100644 index 00000000..edaf97df --- /dev/null +++ b/Il2CppInterop.Generator/EnumProcessingLayer.cs @@ -0,0 +1,220 @@ +using System.Diagnostics; +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator; + +public class EnumProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Enum Processor"; + public override string Id => "enum_processor"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var il2CppSystemObject = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Object"); + var il2CppSystemValueType = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.ValueType"); + var il2CppSystemEnum = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Enum"); + + var icomparable = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.IComparable"); + var iformattable = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.IFormattable"); + var iconvertible = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.IConvertible"); + + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly) + continue; + + foreach (var type in assembly.Types) + { + if (type.DefaultBaseType != il2CppSystemEnum) + continue; + + // Sequential layout is required to ensure that this struct has the same memory layout as a C# enum. + type.OverrideAttributes = (type.Attributes & ~TypeAttributes.LayoutMask) | TypeAttributes.SequentialLayout; + + var valueField = type.Fields.First(f => f.Name == "value__"); + + valueField.OverrideAttributes = FieldAttributes.Private | FieldAttributes.InitOnly; + + Debug.Assert(valueField.FieldType == valueField.DefaultFieldType, "Field type should not be overriden."); + + var il2CppType = valueField.FieldType; + var monoType = appContext.Mscorlib.GetTypeByFullNameOrThrow($"System.{il2CppType.Name}"); + + Debug.Assert(monoType != il2CppType); + + type.EnumIl2CppUnderlyingType = il2CppType; + type.EnumMonoUnderlyingType = monoType; + + // Constructor + var constructor = new InjectedMethodAnalysisContext( + type, + ".ctor", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, + [il2CppType], + ["value"]) + { + IsInjected = true, + }; + { + type.Methods.Add(constructor); + + var methodBody = new NativeMethodBody() + { + Instructions = [ + new Instruction(OpCodes.Ldarg_0), + new Instruction(OpCodes.Ldarg_1), + new Instruction(OpCodes.Stfld, valueField), + new Instruction(OpCodes.Ret) + ] + }; + + constructor.PutExtraData(methodBody); + } + + #region Conversions + // Conversion: enum -> il2cpp + var conversionEnumIl2Cpp = new InjectedMethodAnalysisContext( + type, + "op_Explicit", + il2CppType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, + [type], + ["value"]) + { + IsInjected = true, + }; + { + type.Methods.Add(conversionEnumIl2Cpp); + var methodBody = new NativeMethodBody() + { + Instructions = [ + new Instruction(OpCodes.Ldarga, conversionEnumIl2Cpp.Parameters[0]), + new Instruction(OpCodes.Ldfld, valueField), + new Instruction(OpCodes.Ret) + ] + }; + conversionEnumIl2Cpp.PutExtraData(methodBody); + } + + // Conversion: il2cpp -> enum + var conversionIl2CppEnum = new InjectedMethodAnalysisContext( + type, + "op_Explicit", + type, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, + [il2CppType], + ["value"]) + { + IsInjected = true, + }; + { + type.Methods.Add(conversionIl2CppEnum); + var methodBody = new NativeMethodBody() + { + Instructions = [ + new Instruction(OpCodes.Ldarg_0), + new Instruction(OpCodes.Newobj, constructor), + new Instruction(OpCodes.Ret) + ] + }; + conversionIl2CppEnum.PutExtraData(methodBody); + } + + // Conversion: enum -> mono + var conversionEnumMono = new InjectedMethodAnalysisContext( + type, + "op_Explicit", + monoType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, + [type], + ["value"]) + { + IsInjected = true, + }; + { + type.Methods.Add(conversionEnumMono); + var methodBody = new NativeMethodBody() + { + Instructions = [ + new Instruction(OpCodes.Ldarg_0), + new Instruction(OpCodes.Call, conversionEnumIl2Cpp), + new Instruction(OpCodes.Call, il2CppType.GetImplicitConversionTo(monoType)), + new Instruction(OpCodes.Ret) + ] + }; + conversionEnumMono.PutExtraData(methodBody); + } + + // Conversion: mono -> enum + var conversionMonoEnum = new InjectedMethodAnalysisContext( + type, + "op_Explicit", + type, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, + [monoType], + ["value"]) + { + IsInjected = true, + }; + { + type.Methods.Add(conversionMonoEnum); + var methodBody = new NativeMethodBody() + { + Instructions = [ + new Instruction(OpCodes.Ldarg_0), + new Instruction(OpCodes.Call, il2CppType.GetImplicitConversionFrom(monoType)), + new Instruction(OpCodes.Call, conversionIl2CppEnum), + new Instruction(OpCodes.Ret) + ] + }; + conversionMonoEnum.PutExtraData(methodBody); + } + #endregion + + #region Implicit Interfaces + foreach (var @interface in (ReadOnlySpan)[icomparable, iformattable, iconvertible]) + { + type.InterfaceContexts.Add(@interface); + + foreach (var interfaceMethod in @interface.Methods) + { + if (interfaceMethod.IsInjected || !interfaceMethod.IsVirtual || !interfaceMethod.Attributes.HasFlag(MethodAttributes.NewSlot)) + continue; + + var method = new InjectedMethodAnalysisContext( + type, + $"{@interface.FullName}.{interfaceMethod.Name}", + interfaceMethod.ReturnType, + interfaceMethod.Attributes & ~MethodAttributes.Abstract | MethodAttributes.Final, + interfaceMethod.Parameters.Select(p => p.ParameterType).ToArray(), + interfaceMethod.Parameters.Select(p => p.Name).ToArray(), + interfaceMethod.Parameters.Select(p => p.Attributes).ToArray()) + { + IsInjected = true, + Visibility = MethodAttributes.Private, + }; + method.OverridesList.Add(interfaceMethod); + type.Methods.Add(method); + + var methodBody = new NativeMethodBody() + { + Instructions = [ + new Instruction(OpCodes.Ldarg, This.Instance), + new Instruction(OpCodes.Ldfld, valueField), + new Instruction(OpCodes.Box, valueField.FieldType), + .. method.Parameters.Select(p => new Instruction(OpCodes.Ldarg, p)), + new Instruction(OpCodes.Callvirt, interfaceMethod), + new Instruction(OpCodes.Ret) + ] + }; + method.PutExtraData(methodBody); + } + } + #endregion + } + } + } +} diff --git a/Il2CppInterop.Generator/ExceptionHierarchyProcessingLayer.cs b/Il2CppInterop.Generator/ExceptionHierarchyProcessingLayer.cs new file mode 100644 index 00000000..58bfd545 --- /dev/null +++ b/Il2CppInterop.Generator/ExceptionHierarchyProcessingLayer.cs @@ -0,0 +1,202 @@ +using System.Diagnostics; +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Runtime; + +namespace Il2CppInterop.Generator; + +public class ExceptionHierarchyProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Exception Hierarchy"; + public override string Id => "exception_hierarchy"; + + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var systemExceptionType = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.Exception"); + + var il2CppSystemExceptionType = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Exception"); + + var il2CppExceptionInterface = appContext.ResolveTypeOrThrow(typeof(IIl2CppException)); + var il2CppExceptionInterfaceMethod = il2CppExceptionInterface.GetMethodByName(nameof(IIl2CppException.CreateSystemException)); + var il2CppExceptionInterfaceMethodName = $"{il2CppExceptionInterface.FullName}.{il2CppExceptionInterfaceMethod.Name}"; + + var exceptionTypes = GetExceptionTypes(appContext); + + foreach (var exceptionType in exceptionTypes) + { + var nestedExceptionType = exceptionType.InjectNestedType(GetUniqueNameForNestedClass(exceptionType), null, TypeAttributes.NestedPublic); + nestedExceptionType.IsInjected = true; + exceptionType.SystemExceptionType = nestedExceptionType; + + // Copy generic parameters + if (exceptionType.HasGenericParameters) + { + foreach (var genericParameter in exceptionType.GenericParameters) + { + nestedExceptionType.GenericParameters.Add(new GenericParameterTypeAnalysisContext( + genericParameter.Name, + genericParameter.Index, + genericParameter.Type, + genericParameter.Attributes & GenericParameterAttributes.AllowByRefLike, + nestedExceptionType)); + } + } + + // Inject constructor + nestedExceptionType.InjectMethodContext( + ".ctor", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, + il2CppSystemExceptionType); + } + + foreach (var exceptionType in exceptionTypes) + { + var nestedExceptionType = exceptionType.SystemExceptionType!; + + // Base type + Debug.Assert(exceptionType.BaseType is not null); + if (exceptionType == il2CppSystemExceptionType) + { + nestedExceptionType.SetDefaultBaseType(appContext.ResolveTypeOrThrow(typeof(Il2CppException))); + } + else if (exceptionType.BaseType is GenericInstanceTypeAnalysisContext exceptionBaseTypeGenericInstance) + { + // Build replacements dictionary + Dictionary replacements = new(); + for (var i = 0; i < exceptionType.GenericParameters.Count; i++) + { + replacements.Add(exceptionType.GenericParameters[i], nestedExceptionType.GenericParameters[i]); + } + replacements.Add(exceptionBaseTypeGenericInstance.GenericType, exceptionBaseTypeGenericInstance.GenericType.SystemExceptionType!); + + nestedExceptionType.SetDefaultBaseType(new TypeReplacementVisitor(replacements).Replace(exceptionBaseTypeGenericInstance)); + } + else + { + nestedExceptionType.SetDefaultBaseType(exceptionType.BaseType.SystemExceptionType); + } + + // Constructor + Debug.Assert(nestedExceptionType.Methods.Count is 1); + var constructor = nestedExceptionType.Methods[0]; + Debug.Assert(nestedExceptionType.BaseType is not null); + MethodAnalysisContext baseConstructor; + if (nestedExceptionType.BaseType is GenericInstanceTypeAnalysisContext nestedExceptionBaseTypeGenericInstance) + { + baseConstructor = new ConcreteGenericMethodAnalysisContext( + nestedExceptionBaseTypeGenericInstance.GenericType.GetMethodByName(".ctor"), + nestedExceptionBaseTypeGenericInstance.GenericArguments, + []); + } + else + { + baseConstructor = nestedExceptionType.BaseType.GetMethodByName(".ctor"); + } + constructor.PutExtraData(new NativeMethodBody() + { + Instructions = + [ + new(OpCodes.Ldarg_0), // this + new(OpCodes.Ldarg_1), // object + new(OpCodes.Call, baseConstructor), + new(OpCodes.Ret), + ], + }); + + // Interface implementation + exceptionType.InterfaceContexts.Add(il2CppExceptionInterface); + { + var interfaceMethod = new InjectedMethodAnalysisContext( + exceptionType, + il2CppExceptionInterfaceMethodName, + systemExceptionType, + MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot, + []) + { + IsInjected = true + }; + exceptionType.Methods.Add(interfaceMethod); + interfaceMethod.PutExtraData(new NativeMethodBody() + { + Instructions = + [ + new(OpCodes.Ldarg_0), // this + new(OpCodes.Newobj, exceptionType.HasGenericParameters ? new ConcreteGenericMethodAnalysisContext(constructor, exceptionType.GenericParameters, []) : constructor), + new(OpCodes.Ret), + ], + }); + interfaceMethod.OverridesList.Add(il2CppExceptionInterfaceMethod); + } + } + } + + private static HashSet GetExceptionTypes(ApplicationAnalysisContext appContext) + { + var exceptionTypes = new HashSet(); + var nonExceptionTypes = new HashSet(); + + // Add Il2CppSystem.Exception + { + exceptionTypes.Add(appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Exception")); + } + + // Add all derived types of Il2CppSystem.Exception + foreach (var type in appContext.AllTypes) + { + AddTypeToSet(type, exceptionTypes, nonExceptionTypes); + } + + return exceptionTypes; + + static bool AddTypeToSet(TypeAnalysisContext? type, HashSet exceptionTypes, HashSet nonExceptionTypes) + { + if (type is GenericInstanceTypeAnalysisContext genericInstance) + { + return AddTypeToSet(genericInstance.GenericType, exceptionTypes, nonExceptionTypes); + } + Debug.Assert(type is not ReferencedTypeAnalysisContext); + if (type == null) + { + return false; + } + if (exceptionTypes.Contains(type)) + { + return true; + } + if (nonExceptionTypes.Contains(type)) + { + return false; + } + var isException = AddTypeToSet(type.BaseType, exceptionTypes, nonExceptionTypes); + if (isException) + { + exceptionTypes.Add(type); + } + else + { + nonExceptionTypes.Add(type); + } + return isException; + } + } + + private static string GetUniqueNameForNestedClass(TypeAnalysisContext declaringType) + { + var genericParameterCount = declaringType.GenericParameters.Count; + var nonGenericName = "Exception"; + while (true) + { + var name = genericParameterCount > 0 ? $"{nonGenericName}`{genericParameterCount}" : nonGenericName; + if (declaringType.Name == name || declaringType.NestedTypes.Any(t => t.Name == name)) + { + nonGenericName += "_"; + } + else + { + return name; + } + } + } +} diff --git a/Il2CppInterop.Generator/FieldAccessorProcessingLayer.cs b/Il2CppInterop.Generator/FieldAccessorProcessingLayer.cs new file mode 100644 index 00000000..82a68ec4 --- /dev/null +++ b/Il2CppInterop.Generator/FieldAccessorProcessingLayer.cs @@ -0,0 +1,146 @@ +using System.Diagnostics; +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; +using Il2CppInterop.Runtime.InteropTypes; + +namespace Il2CppInterop.Generator; + +public class FieldAccessorProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Field Accessor Processor"; + public override string Id => "field_accessor_processor"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var fieldAccessHelper = appContext.ResolveTypeOrThrow(typeof(FieldAccessHelper)); + var getStaticFieldValue = fieldAccessHelper.GetMethodByName(nameof(FieldAccessHelper.GetStaticFieldValue)); + var setStaticFieldValue = fieldAccessHelper.GetMethodByName(nameof(FieldAccessHelper.SetStaticFieldValue)); + var getInstanceFieldValue = fieldAccessHelper.GetMethodByName(nameof(FieldAccessHelper.GetInstanceFieldValue)); + var setInstanceFieldValue_Wbarrior = fieldAccessHelper.GetMethodByName(nameof(FieldAccessHelper.SetInstanceFieldValue_Wbarrior)); + var setInstanceFieldValue_Pointer = fieldAccessHelper.GetMethodByName(nameof(FieldAccessHelper.SetInstanceFieldValue_Pointer)); + + var setInstanceFieldValue = appContext.Binary.GetExportedFunctions().Any(pair => pair.Key == "il2cpp_gc_wbarrier_set_field") + ? setInstanceFieldValue_Wbarrior + : setInstanceFieldValue_Pointer; + + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly || assembly.IsInjected) + continue; + + foreach (var type in assembly.Types) + { + if (type.IsInjected) + continue; + + var il2CppTypeInfo = type.GetExtraData(); + Debug.Assert(il2CppTypeInfo is not null); + + var fields = il2CppTypeInfo.Blittability == TypeBlittability.ReferenceType + ? il2CppTypeInfo.InstanceFields.Concat(il2CppTypeInfo.StaticFields) + : il2CppTypeInfo.StaticFields; + + foreach (var field in fields) + { + if (field.ConstantValue is not null) + { + Debug.Assert(field.IsStatic); + continue; // Skip fields with constant values, as they are not suitable for property conversion. + } + + var methodAttributes = field.IsStatic + ? MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Static + : MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName; + + var getMethod = new InjectedMethodAnalysisContext( + field.DeclaringType, + "get_" + field.Name, + field.FieldType, + methodAttributes, + []) + { + IsInjected = true, + }; + field.DeclaringType.Methods.Add(getMethod); + + // get accessor body + { + var instructions = new List(); + if (field.IsStatic) + { + instructions.Add(OpCodes.Ldsfld, field.GetInstantiatedFieldInfoAddressStorage()); + instructions.Add(OpCodes.Call, getStaticFieldValue.MakeGenericInstanceMethod([field.FieldType])); + instructions.Add(OpCodes.Ret); + } + else + { + instructions.Add(OpCodes.Ldarg, This.Instance); + instructions.Add(OpCodes.Ldsfld, field.GetInstantiatedOffsetStorage()); + instructions.Add(OpCodes.Call, getInstanceFieldValue.MakeGenericInstanceMethod([field.FieldType])); + instructions.Add(OpCodes.Ret); + } + + getMethod.PutExtraData(new NativeMethodBody() + { + Instructions = instructions, + }); + } + + var setMethod = new InjectedMethodAnalysisContext( + field.DeclaringType, + "set_" + field.Name, + field.AppContext.SystemTypes.SystemVoidType, + methodAttributes, + [field.FieldType]) + { + IsInjected = true, + }; + field.DeclaringType.Methods.Add(setMethod); + + // set accessor body + { + var instructions = new List(); + if (field.IsStatic) + { + instructions.Add(OpCodes.Ldsfld, field.GetInstantiatedFieldInfoAddressStorage()); + instructions.Add(OpCodes.Ldarg, setMethod.Parameters[0]); + instructions.Add(OpCodes.Call, setStaticFieldValue.MakeGenericInstanceMethod([field.FieldType])); + instructions.Add(OpCodes.Ret); + } + else + { + instructions.Add(OpCodes.Ldarg, This.Instance); + instructions.Add(OpCodes.Ldsfld, field.GetInstantiatedOffsetStorage()); + instructions.Add(OpCodes.Ldarg, setMethod.Parameters[0]); + instructions.Add(OpCodes.Call, setInstanceFieldValue.MakeGenericInstanceMethod([field.FieldType])); + instructions.Add(OpCodes.Ret); + } + + setMethod.PutExtraData(new NativeMethodBody() + { + Instructions = instructions, + }); + } + + var property = new InjectedPropertyAnalysisContext( + field.Name, + field.FieldType, + getMethod, + setMethod, + PropertyAttributes.None, + field.DeclaringType) + { + IsInjected = true, + }; + field.DeclaringType.Properties.Add(property); + + property.OriginalField = field; + field.PropertyAccessor = property; + + field.DeclaringType.Fields.Remove(field); + } + } + } + } +} diff --git a/Il2CppInterop.Generator/FieldAnalysisContextExtensions.cs b/Il2CppInterop.Generator/FieldAnalysisContextExtensions.cs new file mode 100644 index 00000000..30492f23 --- /dev/null +++ b/Il2CppInterop.Generator/FieldAnalysisContextExtensions.cs @@ -0,0 +1,69 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +internal static class FieldAnalysisContextExtensions +{ + extension(FieldAnalysisContext field) + { + [MaybeNull] + public PropertyAnalysisContext PropertyAccessor + { + get => @field.GetExtraData("PropertyAccessor"); + set => @field.PutExtraData("PropertyAccessor", value); + } + + [MaybeNull] + public FieldAnalysisContext FieldInfoAddressStorage + { + get => @field.GetExtraData("FieldInfoAddressStorage"); + set => @field.PutExtraData("FieldInfoAddressStorage", value); + } + + [MaybeNull] + public FieldAnalysisContext OffsetStorage + { + get => @field.GetExtraData("OffsetStorage"); + set => @field.PutExtraData("OffsetStorage", value); + } + + /// + /// Gets the field info address storage for this field, and instantiate for use in this field's declaring type. + /// + /// The instantiated storage field + public FieldAnalysisContext GetInstantiatedFieldInfoAddressStorage() + { + return field.GetInstantiatedStorageField(field.FieldInfoAddressStorage); + } + + public FieldAnalysisContext GetInstantiatedOffsetStorage() + { + return field.GetInstantiatedStorageField(field.OffsetStorage); + } + + private FieldAnalysisContext GetInstantiatedStorageField(FieldAnalysisContext? storageField) + { + Debug.Assert(storageField is not null); + Debug.Assert(storageField.DeclaringType.GenericParameters.Count == field.DeclaringType.GenericParameters.Count); + + if (storageField.DeclaringType.GenericParameters.Count == 0) + { + return storageField; + } + else + { + return storageField.MakeConcreteGeneric(field.DeclaringType.GenericParameters); + } + } + + public ConcreteGenericFieldAnalysisContext MakeConcreteGeneric(IEnumerable declaringTypeGenericArguments) + { + return new ConcreteGenericFieldAnalysisContext( + field, + field.DeclaringType.MakeGenericInstanceType(declaringTypeGenericArguments) + ); + } + } +} diff --git a/Il2CppInterop.Generator/HasGenericParametersExtensions.cs b/Il2CppInterop.Generator/HasGenericParametersExtensions.cs new file mode 100644 index 00000000..56c9220c --- /dev/null +++ b/Il2CppInterop.Generator/HasGenericParametersExtensions.cs @@ -0,0 +1,14 @@ +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +internal static class HasGenericParametersExtensions +{ + public static void CopyGenericParameters(this HasGenericParameters destination, HasGenericParameters source) + { + foreach (var genericParameter in source.GenericParameters) + { + destination.GenericParameters.Add(new GenericParameterTypeAnalysisContext(genericParameter.Name, genericParameter.Index, genericParameter.Type, genericParameter.Attributes, destination)); + } + } +} diff --git a/Il2CppInterop.Generator/ICallProcessingLayer.cs b/Il2CppInterop.Generator/ICallProcessingLayer.cs new file mode 100644 index 00000000..19a184af --- /dev/null +++ b/Il2CppInterop.Generator/ICallProcessingLayer.cs @@ -0,0 +1,46 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Text; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public class ICallProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "ICall Processor"; + public override string Id => "icall_processor"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly || assembly.IsInjected) + continue; + + foreach (var type in assembly.Types) + { + if (type.IsInjected) + continue; + + foreach (var method in type.Methods) + { + if (!method.IsUnstripped || !method.DefaultImplAttributes.HasFlag(MethodImplAttributes.InternalCall)) + continue; + + Debug.Assert(type.InitializationType is not null); + Debug.Assert(!method.HasExtraData()); + Debug.Assert(!method.HasExtraData()); + Debug.Assert(!method.HasExtraData()); + Debug.Assert(method.GenericParameters.Count == 0 && type.GenericParameters.Count == 0, "Internal calls cannot be generic."); + + } + } + } + } + + private static string GetICallSignature(MethodAnalysisContext method) + { + return $"{method.DeclaringType!.DefaultFullName}::{method.DefaultName}"; + } +} diff --git a/Il2CppInterop.Generator/Il2CppGame.cs b/Il2CppInterop.Generator/Il2CppGame.cs new file mode 100644 index 00000000..684b18e8 --- /dev/null +++ b/Il2CppInterop.Generator/Il2CppGame.cs @@ -0,0 +1,68 @@ +using Cpp2IL.Core; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.InstructionSets; +using Cpp2IL.Core.Logging; +using Cpp2IL.Core.Model.Contexts; +using LibCpp2IL; + +namespace Il2CppInterop.Generator; + +public static class Il2CppGame +{ + static Il2CppGame() + { + Logger.InfoLog += Console.WriteLine; + Logger.WarningLog += Console.WriteLine; + Logger.ErrorLog += Console.WriteLine; + Logger.VerboseLog += Console.WriteLine; + + InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.X86_32); + InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.X86_64); + InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.WASM); + InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.ARM_V7); + InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.ARM_V8); + + LibCpp2IlBinaryRegistry.RegisterBuiltInBinarySupport(); + } + + public static void Process(string gameExePath, string outputFolder, Cpp2IlOutputFormat outputFormat, List processingLayers) + { + Process(gameExePath, processingLayers); + + outputFormat.DoOutput(GetCurrentAppContext(), outputFolder); + } + + public static void Process(string gameExePath, List processingLayers) + { + var gameExeName = Path.GetFileNameWithoutExtension(gameExePath); + + var gameDirectory = Path.GetDirectoryName(gameExePath)!; + + var GameDataPath = Path.Combine(gameDirectory, $"{gameExeName}_Data"); + + var UnityPlayerPath = Path.Combine(gameDirectory, "UnityPlayer.dll"); + + var GameAssemblyPath = Path.Combine(gameDirectory, "GameAssembly.dll"); + + var MetaDataPath = Path.Combine(GameDataPath, "il2cpp_data", "Metadata", "global-metadata.dat"); + + var UnityVersion = Cpp2IlApi.DetermineUnityVersion(UnityPlayerPath, GameDataPath); + + Cpp2IlApi.InitializeLibCpp2Il(GameAssemblyPath, MetaDataPath, UnityVersion, false); + + foreach (var cpp2IlProcessingLayer in processingLayers) + { + cpp2IlProcessingLayer.PreProcess(GetCurrentAppContext(), processingLayers); + } + + foreach (var cpp2IlProcessingLayer in processingLayers) + { + cpp2IlProcessingLayer.Process(GetCurrentAppContext()); + } + } + + private static ApplicationAnalysisContext GetCurrentAppContext() + { + return Cpp2IlApi.CurrentAppContext ?? throw new NullReferenceException(); + } +} diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index bab17953..482eeb9c 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -4,20 +4,27 @@ Il2CppInterop.Generator knah, BepInEx et al. Library for generating assemblies and metadata for calling Il2Cpp functions from .NET - netstandard2.1;net472 + net9.0 Il2CppInterop.Generator Debug;Release AnyCPU - latest + preview enable + true + + + + + + + + - - - MonoModBackports - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -25,5 +32,6 @@ + diff --git a/Il2CppInterop.Generator/Il2CppRenamingProcessingLayer.cs b/Il2CppInterop.Generator/Il2CppRenamingProcessingLayer.cs new file mode 100644 index 00000000..a73cb14c --- /dev/null +++ b/Il2CppInterop.Generator/Il2CppRenamingProcessingLayer.cs @@ -0,0 +1,76 @@ +using System.Runtime.CompilerServices; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Logging; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public class Il2CppRenamingProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Il2Cpp Name Changes"; + + public override string Id => "il2cpprenamer"; + + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + Logger.InfoNewline("Renaming assemblies and types to Il2Cpp", nameof(Il2CppRenamingProcessingLayer)); + + var assemblyCount = appContext.Assemblies.Count; + for (var i = 0; i < assemblyCount; i++) + { + var assembly = appContext.Assemblies[i]; + + if (!IsUnity(assembly.Name) && !IsAssemblyCSharp(assembly.Name)) + { + assembly.OverrideName = "Il2Cpp" + assembly.Name; + } + + foreach (var type in assembly.Types) + { + if (!IsUnity(type.Namespace)) + { + type.OverrideNamespace = "Il2Cpp" + type.Namespace; + } + } + + ResetTypesByName(assembly); + + progressCallback?.Invoke(i, assemblyCount); + } + + ResetAssembliesByName(appContext); + } + + private static bool IsUnity(string name) + { + return name.StartsWith("Unity", StringComparison.Ordinal); + } + + private static bool IsAssemblyCSharp(string name) + { + return name.StartsWith("Assembly-CSharp", StringComparison.Ordinal); + } + + private static void ResetAssembliesByName(ApplicationAnalysisContext appContext) + { + var dictionary = appContext.AssembliesByName; + dictionary.Clear(); + foreach (var assembly in appContext.Assemblies) + { + dictionary[assembly.Name] = assembly; + } + } + + private static void ResetTypesByName(AssemblyAnalysisContext assembly) + { + var dictionary = GetTypesByName(assembly); + dictionary.Clear(); + foreach (var type in assembly.Types) + { + dictionary[type.FullName] = type; + } + } + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "TypesByName")] + private static extern ref Dictionary GetTypesByName(AssemblyAnalysisContext assembly); +} diff --git a/Il2CppInterop.Generator/Il2CppTypeInfo.cs b/Il2CppInterop.Generator/Il2CppTypeInfo.cs new file mode 100644 index 00000000..087c51a7 --- /dev/null +++ b/Il2CppInterop.Generator/Il2CppTypeInfo.cs @@ -0,0 +1,10 @@ +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public sealed class Il2CppTypeInfo +{ + public List StaticFields { get; } = new(); + public List InstanceFields { get; } = new(); + public TypeBlittability Blittability { get; set; } = TypeBlittability.Unknown; +} diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs new file mode 100644 index 00000000..6560e210 --- /dev/null +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -0,0 +1,512 @@ +using System.Buffers.Binary; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Logging; +using Cpp2IL.Core.Model.Contexts; +using Cpp2IL.Core.Utils; +using Il2CppInterop.Generator.Operands; +using Il2CppInterop.Runtime; +using LibCpp2IL.BinaryStructures; + +namespace Il2CppInterop.Generator; + +public class InitializationClassProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Id => "initialization_class_injector"; + public override string Name => "Inject initialization class into the Cpp2IL context system"; + + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var runClassConstructor = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.Runtime.CompilerServices.RuntimeHelpers") + .Methods.First(m => m.Name == nameof(RuntimeHelpers.RunClassConstructor) && m.Parameters[0].ParameterType != appContext.SystemTypes.SystemIntPtrType); + var il2CppClassPointerStore = appContext.ResolveTypeOrThrow(typeof(Il2CppClassPointerStore<>)); + var classPointerField = il2CppClassPointerStore.GetFieldByName("NativeClassPtr"); + + var il2CppStaticClass = appContext.ResolveTypeOrThrow(typeof(IL2CPP)); + var getIl2CppNestedType = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.GetIl2CppNestedType)); + var getIl2CppClass = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.GetIl2CppClass)); + var il2CppRuntimeClassInit = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.il2cpp_runtime_class_init)); + var getIl2CppField = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.GetIl2CppField)); + var il2CppFieldGetOffset = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.il2cpp_field_get_offset)); + var getIl2CppMethod = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.GetIl2CppMethod)); + var getIl2CppMethodByToken = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.GetIl2CppMethodByToken)); + var getIl2CppGenericInstanceMethod = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.GetIl2CppGenericInstanceMethod)); + var il2CppClassValueSize = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.il2cpp_class_value_size)); + var resolveICall = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.ResolveICall)); + + var multicastDelegateType = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.MulticastDelegate"); + var asyncCallbackType = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.AsyncCallback"); + var iasyncResultType = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.IAsyncResult"); + + var tokenLessMethodCount = 0; + + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly || assembly.IsInjected) + continue; + + for (var i = 0; i < assembly.Types.Count; i++) + { + var type = assembly.Types[i]; + + if (type.IsInjected) + continue; + + var typeInfo = type.GetExtraData(); + Debug.Assert(typeInfo is not null); + + var initializationType = assembly.InjectType( + "Il2CppInterop.Generated", + $"Il2CppInternals_{HashString(type.FullName):x16}", + appContext.SystemTypes.SystemObjectType, + TypeAttributes.NotPublic | TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.Class); + initializationType.IsInjected = true; + foreach (var genericParameter in type.GenericParameters) + { + initializationType.GenericParameters.Add(new GenericParameterTypeAnalysisContext( + genericParameter.Name, + genericParameter.Index, + genericParameter.Type, + genericParameter.Attributes & GenericParameterAttributes.AllowByRefLike, + initializationType)); + } + + AddInstructionsToStaticConstructor(type, initializationType, runClassConstructor); + + // Initialization static constructor + { + var staticConstructor = new InjectedMethodAnalysisContext( + initializationType, + ".cctor", + type.AppContext.SystemTypes.SystemVoidType, + MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, + []); + initializationType.Methods.Add(staticConstructor); + + var instructions = new List(); + var localVariables = new List(); + + var typeToInitialize = initializationType.GenericParameters.Count == 0 + ? type + : type.MakeGenericInstanceType(initializationType.GenericParameters); + + var concreteClassPointerField = new ConcreteGenericFieldAnalysisContext(classPointerField, il2CppClassPointerStore.MakeGenericInstanceType([typeToInitialize])); + if (typeToInitialize.DeclaringType is not null) + { + // Ensure declaring type is initialized first + instructions.Add(new Instruction(OpCodes.Ldtoken, typeToInitialize.DeclaringType)); + instructions.Add(new Instruction(OpCodes.Call, runClassConstructor)); + + // Il2CppClassPointerStore.NativeClassPtr = IL2CPP.GetIl2CppNestedType(Il2CppClassPointerStore.NativeClassPtr, "NestedClass"); + var declaringTypeClassPointerField = new ConcreteGenericFieldAnalysisContext(classPointerField, il2CppClassPointerStore.MakeGenericInstanceType([typeToInitialize.DeclaringType])); + instructions.Add(new Instruction(OpCodes.Ldsfld, declaringTypeClassPointerField)); + instructions.Add(new Instruction(OpCodes.Ldstr, type.DefaultName));// typeToInitialize can have the wrong DefaultName + instructions.Add(new Instruction(OpCodes.Call, getIl2CppNestedType)); + instructions.Add(new Instruction(OpCodes.Stsfld, concreteClassPointerField)); + } + else + { + // Il2CppClassPointerStore.NativeClassPtr = IL2CPP.GetIl2CppClass("Assembly-CSharp.dll", "", "Class"); + instructions.Add(new Instruction(OpCodes.Ldstr, $"{assembly.DefaultName}.dll")); + instructions.Add(new Instruction(OpCodes.Ldstr, type.DefaultNamespace)); + instructions.Add(new Instruction(OpCodes.Ldstr, type.DefaultName)); + instructions.Add(new Instruction(OpCodes.Call, getIl2CppClass)); + instructions.Add(new Instruction(OpCodes.Stsfld, concreteClassPointerField)); + } + + // IL2CPP.il2cpp_runtime_class_init(Il2CppClassPointerStore.NativeClassPtr); + instructions.Add(new Instruction(OpCodes.Ldsfld, concreteClassPointerField)); + instructions.Add(new Instruction(OpCodes.Call, il2CppRuntimeClassInit)); + + // Size = IL2CPP.il2cpp_class_value_size(Il2CppClassPointerStore.NativeClassPtr, ref align); + if (typeInfo.Blittability != TypeBlittability.ReferenceType) + { + var sizeStore = initializationType.InjectFieldContext( + "Size", + appContext.SystemTypes.SystemInt32Type, + FieldAttributes.Assembly | FieldAttributes.Static | FieldAttributes.InitOnly); + type.SizeStorage = sizeStore; + + FieldAnalysisContext instantiatedSizeStore = initializationType.GenericParameters.Count > 0 + ? new ConcreteGenericFieldAnalysisContext(sizeStore, initializationType.MakeGenericInstanceType(initializationType.GenericParameters)) + : sizeStore; + + LocalVariable tempLocal = new() { Type = appContext.SystemTypes.SystemUInt32Type }; + localVariables.Add(tempLocal); + + instructions.Add(new Instruction(OpCodes.Ldc_I4_0)); + instructions.Add(new Instruction(OpCodes.Stloc, tempLocal)); + + instructions.Add(new Instruction(OpCodes.Ldsfld, concreteClassPointerField)); + instructions.Add(new Instruction(OpCodes.Ldloca, tempLocal)); + instructions.Add(new Instruction(OpCodes.Call, il2CppClassValueSize)); + instructions.Add(new Instruction(OpCodes.Stsfld, instantiatedSizeStore)); + } + + // FieldOffset_Instance_0 = (int)IL2CPP.il2cpp_field_get_offset(IL2CPP.GetIl2CppField(Il2CppClassPointerStore.NativeClassPtr, "field_name")); + for (var index = 0; index < typeInfo.InstanceFields.Count; index++) + { + var instanceField = typeInfo.InstanceFields[index]; + + var infoStore = initializationType.InjectFieldContext( + $"FieldInfoPtr_Instance_{index}", + appContext.SystemTypes.SystemIntPtrType, + FieldAttributes.Assembly | FieldAttributes.Static | FieldAttributes.InitOnly); + instanceField.FieldInfoAddressStorage = infoStore; + + FieldAnalysisContext instantiatedInfoStore = initializationType.GenericParameters.Count > 0 + ? new ConcreteGenericFieldAnalysisContext(infoStore, initializationType.MakeGenericInstanceType(initializationType.GenericParameters)) + : infoStore; + + var offsetStore = initializationType.InjectFieldContext( + $"FieldOffset_Instance_{index}", + appContext.SystemTypes.SystemInt32Type, + FieldAttributes.Assembly | FieldAttributes.Static | FieldAttributes.InitOnly); + instanceField.OffsetStorage = offsetStore; + + FieldAnalysisContext instantiatedOffsetStore = initializationType.GenericParameters.Count > 0 + ? new ConcreteGenericFieldAnalysisContext(offsetStore, initializationType.MakeGenericInstanceType(initializationType.GenericParameters)) + : offsetStore; + + instructions.Add(new Instruction(OpCodes.Ldsfld, concreteClassPointerField)); + instructions.Add(new Instruction(OpCodes.Ldstr, instanceField.DefaultName)); + instructions.Add(new Instruction(OpCodes.Call, getIl2CppField)); + instructions.Add(new Instruction(OpCodes.Dup)); + instructions.Add(new Instruction(OpCodes.Stsfld, instantiatedInfoStore)); + instructions.Add(new Instruction(OpCodes.Call, il2CppFieldGetOffset)); + instructions.Add(new Instruction(OpCodes.Conv_I4)); + instructions.Add(new Instruction(OpCodes.Stsfld, instantiatedOffsetStore)); + } + + // FieldInfoPtr_Static_0 = IL2CPP.GetIl2CppField(Il2CppClassPointerStore.NativeClassPtr, "field_name"); + for (var index = 0; index < typeInfo.StaticFields.Count; index++) + { + var staticField = typeInfo.StaticFields[index]; + var infoStore = initializationType.InjectFieldContext( + $"FieldInfoPtr_Static_{index}", + appContext.SystemTypes.SystemIntPtrType, + FieldAttributes.Assembly | FieldAttributes.Static | FieldAttributes.InitOnly); + staticField.FieldInfoAddressStorage = infoStore; + + FieldAnalysisContext instantiatedInfoStore = initializationType.GenericParameters.Count > 0 + ? new ConcreteGenericFieldAnalysisContext(infoStore, initializationType.MakeGenericInstanceType(initializationType.GenericParameters)) + : infoStore; + + instructions.Add(new Instruction(OpCodes.Ldsfld, concreteClassPointerField)); + instructions.Add(new Instruction(OpCodes.Ldstr, staticField.DefaultName)); + instructions.Add(new Instruction(OpCodes.Call, getIl2CppField)); + instructions.Add(new Instruction(OpCodes.Stsfld, instantiatedInfoStore)); + } + + // MethodInfoPtr_0 + for (var index = 0; index < type.Methods.Count; index++) + { + var method = type.Methods[index]; + + if (method.IsUnstripped || method.IsInjected) + continue; + + var methodInfoStore = initializationType.InjectFieldContext( + $"MethodInfoPtr_{index}", + appContext.SystemTypes.SystemIntPtrType, + FieldAttributes.Assembly | FieldAttributes.Static | FieldAttributes.InitOnly); + method.MethodInfoField = methodInfoStore; + + FieldAnalysisContext concreteMethodInfoStore = initializationType.GenericParameters.Count > 0 + ? new ConcreteGenericFieldAnalysisContext(methodInfoStore, initializationType.MakeGenericInstanceType(initializationType.GenericParameters)) + : methodInfoStore; + + if (method.Token == 0) + { + tokenLessMethodCount++; + + instructions.Add(new Instruction(OpCodes.Ldsfld, concreteClassPointerField)); + instructions.Add(new Instruction(method.GenericParameters.Count == 0 ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1)); + instructions.Add(new Instruction(OpCodes.Ldstr, method.DefaultName)); + instructions.Add(new Instruction(OpCodes.Ldstr, method.DefaultReturnType.DefaultFullName)); + instructions.Add(new Instruction(OpCodes.Ldc_I4, method.Parameters.Count)); + instructions.Add(new Instruction(OpCodes.Newarr, method.AppContext.SystemTypes.SystemStringType)); + + for (var parameterIndex = 0; i < method.Parameters.Count; i++) + { + instructions.Add(new Instruction(OpCodes.Dup)); + instructions.Add(new Instruction(OpCodes.Ldc_I4, parameterIndex)); + instructions.Add(new Instruction(OpCodes.Ldstr, method.Parameters[i].DefaultParameterType.DefaultFullName)); + instructions.Add(new Instruction(OpCodes.Stelem_Ref)); + } + + instructions.Add(new Instruction(OpCodes.Call, getIl2CppMethod)); + } + else + { + instructions.Add(new Instruction(OpCodes.Ldsfld, concreteClassPointerField)); + instructions.Add(new Instruction(OpCodes.Ldc_I4, unchecked((int)method.Token))); + instructions.Add(new Instruction(OpCodes.Call, getIl2CppMethodByToken)); + } + instructions.Add(new Instruction(OpCodes.Stsfld, concreteMethodInfoStore)); + + if (method.GenericParameters.Count > 0) + { + var methodInfoPtrGenericClass = initializationType.InjectNestedType( + $"MethodInfoPtrGeneric_{index}", + appContext.SystemTypes.SystemObjectType, + TypeAttributes.NestedAssembly | TypeAttributes.Abstract | TypeAttributes.Sealed); + methodInfoPtrGenericClass.IsInjected = true; + methodInfoPtrGenericClass.CopyGenericParameters(initializationType); + foreach (var genericParameter in method.GenericParameters) + { + methodInfoPtrGenericClass.GenericParameters.Add(new GenericParameterTypeAnalysisContext( + genericParameter.Name, + methodInfoPtrGenericClass.GenericParameters.Count, + Il2CppTypeEnum.IL2CPP_TYPE_VAR, + genericParameter.Attributes & GenericParameterAttributes.AllowByRefLike, + methodInfoPtrGenericClass)); + } + + var methodInfoPtrGenericField = methodInfoPtrGenericClass.InjectFieldContext( + "Pointer", + appContext.SystemTypes.SystemIntPtrType, + FieldAttributes.Assembly | FieldAttributes.Static | FieldAttributes.InitOnly); + method.MethodInfoField = methodInfoPtrGenericField; // A generic method's real MethodInfoField is the generically instantiated one. + + var methodInfoPtrGenericStaticConstructor = new InjectedMethodAnalysisContext( + methodInfoPtrGenericClass, + ".cctor", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, + []); + methodInfoPtrGenericClass.Methods.Add(methodInfoPtrGenericStaticConstructor); + + FieldAnalysisContext concreteMethodInfoStore2 = initializationType.GenericParameters.Count > 0 + ? new ConcreteGenericFieldAnalysisContext(methodInfoStore, initializationType.MakeGenericInstanceType(methodInfoPtrGenericClass.GenericParameters.Take(initializationType.GenericParameters.Count))) + : methodInfoStore; + + var instructions2 = new List(); + instructions2.Add(new Instruction(OpCodes.Ldsfld, concreteMethodInfoStore2)); + instructions2.Add(new Instruction(OpCodes.Ldsfld, concreteClassPointerField)); + instructions2.Add(new Instruction(OpCodes.Ldc_I4, method.GenericParameters.Count)); + instructions2.Add(new Instruction(OpCodes.Newarr, appContext.SystemTypes.SystemIntPtrType)); + for (var j = 0; j < method.GenericParameters.Count; j++) + { + instructions2.Add(new Instruction(OpCodes.Dup)); + instructions2.Add(new Instruction(OpCodes.Ldc_I4, j)); + var genericParameter = methodInfoPtrGenericClass.GenericParameters[j + initializationType.GenericParameters.Count]; + var classPointerForGenericParameter = new ConcreteGenericFieldAnalysisContext(classPointerField, il2CppClassPointerStore.MakeGenericInstanceType([genericParameter])); + instructions2.Add(new Instruction(OpCodes.Ldsfld, classPointerForGenericParameter)); + instructions2.Add(new Instruction(OpCodes.Stelem_I)); + } + instructions2.Add(new Instruction(OpCodes.Call, getIl2CppGenericInstanceMethod)); + instructions2.Add(new Instruction(OpCodes.Stsfld, new ConcreteGenericFieldAnalysisContext(methodInfoPtrGenericField, methodInfoPtrGenericClass.MakeGenericInstanceType(methodInfoPtrGenericClass.GenericParameters)))); + instructions2.Add(new Instruction(OpCodes.Ret)); + + methodInfoPtrGenericStaticConstructor.PutExtraData(new NativeMethodBody() + { + Instructions = instructions2, + }); + } + } + + // Internal call methods + for (var index = 0; index < type.Methods.Count; index++) + { + var method = type.Methods[index]; + + if (!method.IsUnstripped || !method.DefaultImplAttributes.HasFlag(MethodImplAttributes.InternalCall)) + continue; + + Debug.Assert(!method.HasExtraData()); + Debug.Assert(!method.HasExtraData()); + Debug.Assert(!method.HasExtraData()); + Debug.Assert(method.GenericParameters.Count == 0 && type.GenericParameters.Count == 0, "Internal calls cannot be generic."); + + // ICall_Delegate_Type_0 + TypeAnalysisContext delegateType; + MethodAnalysisContext invokeMethod; + { + delegateType = initializationType.InjectNestedType( + $"ICall_Delegate_Type_{index}", + multicastDelegateType); + + List parameterTypes = method.Parameters.Select(p => p.ParameterType).ToList(); + List parameterNames = method.Parameters.Select(p => p.Name).ToList(); + + // Constructor + { + delegateType.Methods.Add(new InjectedMethodAnalysisContext( + delegateType, + ".ctor", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, + [appContext.SystemTypes.SystemObjectType, appContext.SystemTypes.SystemIntPtrType], + defaultImplAttributes: MethodImplAttributes.Runtime) + { + RuntimeImplemented = true, + }); + } + + // Invoke + { + invokeMethod = new InjectedMethodAnalysisContext( + delegateType, + "Invoke", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, + parameterTypes.ToArray(), + parameterNames.ToArray(), + defaultImplAttributes: MethodImplAttributes.Runtime) + { + RuntimeImplemented = true, + }; + delegateType.Methods.Add(invokeMethod); + } + + // BeginInvoke + { + delegateType.Methods.Add(new InjectedMethodAnalysisContext( + delegateType, + "BeginInvoke", + iasyncResultType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, + parameterTypes.Append(asyncCallbackType).Append(appContext.SystemTypes.SystemObjectType).ToArray(), + parameterNames.Append("callback").Append("object").ToArray(), + defaultImplAttributes: MethodImplAttributes.Runtime) + { + RuntimeImplemented = true, + }); + } + + // EndInvoke + { + delegateType.Methods.Add(new InjectedMethodAnalysisContext( + delegateType, + "EndInvoke", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, + [iasyncResultType], + ["result"], + defaultImplAttributes: MethodImplAttributes.Runtime) + { + RuntimeImplemented = true, + }); + } + } + + // ICall_Delegate_Field_0 + FieldAnalysisContext delegateField; + { + delegateField = initializationType.InjectFieldContext( + $"ICall_Delegate_Field_{index}", + delegateType, + FieldAttributes.Assembly | FieldAttributes.Static | FieldAttributes.InitOnly); + } + + // Static constructor instructions + { + instructions.Add(new Instruction(OpCodes.Ldstr, $"{type.DefaultFullName}::{method.DefaultName}")); + instructions.Add(new Instruction(OpCodes.Call, new ConcreteGenericMethodAnalysisContext(resolveICall, [], [delegateType]))); + instructions.Add(new Instruction(OpCodes.Stsfld, delegateField)); + } + } + + instructions.Add(new Instruction(OpCodes.Ret)); + + staticConstructor.PutExtraData(new NativeMethodBody() + { + Instructions = instructions, + LocalVariables = localVariables.Count > 0 ? localVariables : [], + }); + } + } + } + + Logger.Info($"Tokenless method count: {tokenLessMethodCount}", nameof(InitializationClassProcessingLayer)); + + // Il2CppInterop.Initialization.dll + { + var injectedAssembly = appContext.InjectAssembly("Il2CppInterop.Initialization"); + injectedAssembly.IsInjected = true; + + var initializationType = injectedAssembly.InjectType( + "Il2CppInterop.Initialization", + "Il2CppInitialization", + appContext.SystemTypes.SystemObjectType, + TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Sealed | TypeAttributes.Class); + + var initializeMethod = initializationType.InjectMethodContext( + "Initialize", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, + []); + + var instructions = new List(); + + var typeConverter = TypeConversionVisitor.Create(appContext); + + var processedTypes = new HashSet(TypeAnalysisContextEqualityComparer.Instance); + // Ensure all generic instantiations are initialized + foreach (var il2CppType in appContext.Binary.AllTypes) + { + var typeContext = injectedAssembly.ResolveIl2CppType(il2CppType); + if (InvalidTypeChecker.ContainsInvalidType(typeContext)) + continue; + + if (typeContext is not ReferencedTypeAnalysisContext && typeContext.GenericParameters.Count > 0) + continue; // Skip open generics + + typeContext = typeConverter.Replace(typeContext); + + if (!processedTypes.Add(typeContext)) + continue; + + // Ensure the type is initialized + instructions.Add(new Instruction(OpCodes.Ldtoken, typeContext)); + instructions.Add(new Instruction(OpCodes.Call, runClassConstructor)); + } + + instructions.Add(new Instruction(OpCodes.Ret)); + + initializeMethod.PutExtraData(new NativeMethodBody() + { + Instructions = instructions, + }); + } + } + + private static void AddInstructionsToStaticConstructor(TypeAnalysisContext type, InjectedTypeAnalysisContext initializationType, MethodAnalysisContext runClassConstructor) + { + var instructions = type.GetOrCreateStaticConstructorInstructions(); + + var typeToInitialize = type.GenericParameters.Count == 0 ? initializationType : (TypeAnalysisContext)initializationType.MakeGenericInstanceType(type.GenericParameters); + + instructions.Add(new Instruction(OpCodes.Ldtoken, typeToInitialize)); + instructions.Add(new Instruction(OpCodes.Call, runClassConstructor)); + } + + private static ulong HashString(ReadOnlySpan chars) + { + var bytes = MemoryMarshal.AsBytes(chars); + Span hash = stackalloc byte[MD5.HashSizeInBytes]; + MD5.HashData(bytes, hash); + return BinaryPrimitives.ReadUInt64LittleEndian(hash); + } + + private sealed class InvalidTypeChecker : BooleanOrTypeVisitor + { + public static InvalidTypeChecker Instance { get; } = new InvalidTypeChecker(); + + public static bool ContainsInvalidType(TypeAnalysisContext type) + { + return Instance.Visit(type); + } + + public override bool Visit(BoxedTypeAnalysisContext type) => true; + public override bool Visit(ByRefTypeAnalysisContext type) => true; + public override bool Visit(GenericParameterTypeAnalysisContext type) => true; + public override bool Visit(PinnedTypeAnalysisContext type) => true; + public override bool Visit(SentinelTypeAnalysisContext type) => true; + } +} diff --git a/Il2CppInterop.Generator/InjectedMethodAnalysisContextExtensions.cs b/Il2CppInterop.Generator/InjectedMethodAnalysisContextExtensions.cs new file mode 100644 index 00000000..78d94f67 --- /dev/null +++ b/Il2CppInterop.Generator/InjectedMethodAnalysisContextExtensions.cs @@ -0,0 +1,15 @@ +using System.Runtime.CompilerServices; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +internal static class InjectedMethodAnalysisContextExtensions +{ + public static void SetDefaultReturnType(this InjectedMethodAnalysisContext context, TypeAnalysisContext type) + { + GetDefaultReturnType(context) = type; + } + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = $"<{nameof(InjectedMethodAnalysisContext.DefaultReturnType)}>k__BackingField")] + private static extern ref TypeAnalysisContext GetDefaultReturnType(InjectedMethodAnalysisContext context); +} diff --git a/Il2CppInterop.Generator/InjectedParameterAnalysisContextExtensions.cs b/Il2CppInterop.Generator/InjectedParameterAnalysisContextExtensions.cs new file mode 100644 index 00000000..4e96a185 --- /dev/null +++ b/Il2CppInterop.Generator/InjectedParameterAnalysisContextExtensions.cs @@ -0,0 +1,15 @@ +using System.Runtime.CompilerServices; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +internal static class InjectedParameterAnalysisContextExtensions +{ + public static void SetDefaultParameterType(this InjectedParameterAnalysisContext context, TypeAnalysisContext type) + { + GetDefaultParameterType(context) = type; + } + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = $"<{nameof(InjectedParameterAnalysisContext.DefaultParameterType)}>k__BackingField")] + private static extern ref TypeAnalysisContext GetDefaultParameterType(InjectedParameterAnalysisContext context); +} diff --git a/Il2CppInterop.Generator/InjectedTypeAnalysisContextExtensions.cs b/Il2CppInterop.Generator/InjectedTypeAnalysisContextExtensions.cs new file mode 100644 index 00000000..613141c4 --- /dev/null +++ b/Il2CppInterop.Generator/InjectedTypeAnalysisContextExtensions.cs @@ -0,0 +1,112 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using Cpp2IL.Core.Model.Contexts; +using LibCpp2IL.BinaryStructures; + +namespace Il2CppInterop.Generator; + +internal static class InjectedTypeAnalysisContextExtensions +{ + extension(InjectedTypeAnalysisContext type) + { + public void InjectContentFromSourceType() + { + var sourceType = type.SourceType; + ArgumentNullException.ThrowIfNull(sourceType); + + var appContext = type.AppContext; + + type.SetDefaultBaseType(sourceType.BaseType != null + ? new ContextResolver(type).ResolveOrThrow(sourceType.BaseType) + : null); + + foreach (var fieldInfo in sourceType.GetFields()) + { + if (fieldInfo.DeclaringType != sourceType) + continue; + + var resolver = new ContextResolver(type); + + type.InjectFieldContext( + fieldInfo.Name, + resolver.ResolveOrThrow(fieldInfo.FieldType), + fieldInfo.Attributes); + } + + foreach (var method in GetPublicAndProtectedMethods(sourceType)) + { + if (method.DeclaringType != sourceType) + continue; + + var parameterInfoArray = method.GetParameters(); + var parameterNames = parameterInfoArray + .Select(x => x.Name!) + .ToArray(); + var parameterAttributes = parameterInfoArray + .Select(x => x.Attributes) + .ToArray(); + var methodContext = new InjectedMethodAnalysisContext( + type, + method.Name, + appContext.SystemTypes.SystemObjectType, + method.Attributes, + Enumerable.Repeat(appContext.SystemTypes.SystemObjectType, parameterInfoArray.Length).ToArray(), + parameterNames, + parameterAttributes); + if (method is not ConstructorInfo) + { + foreach (var genericParameter in method.GetGenericArguments()) + { + var genericParameterContext = new GenericParameterTypeAnalysisContext(genericParameter.Name, genericParameter.GenericParameterPosition, Il2CppTypeEnum.IL2CPP_TYPE_MVAR, genericParameter.GenericParameterAttributes, methodContext); + methodContext.GenericParameters.Add(genericParameterContext); + } + } + type.Methods.Add(methodContext); + + var resolver = new ContextResolver(methodContext); + + var returnType = method switch + { + MethodInfo methodInfo => resolver.ResolveOrThrow(methodInfo.ReturnType), + ConstructorInfo => appContext.SystemTypes.SystemVoidType, + _ => throw new NotSupportedException($"Unsupported method type: {method.GetType()}") + }; + methodContext.SetDefaultReturnType(returnType); + for (var i = 0; i < parameterInfoArray.Length; i++) + { + var parameterType = resolver.ResolveOrThrow(parameterInfoArray[i].ParameterType); + var parameterContext = (InjectedParameterAnalysisContext)methodContext.Parameters[i]; + parameterContext.SetDefaultParameterType(parameterType); + } + } + } + + public void SetDefaultBaseType(TypeAnalysisContext? baseType) + { + GetDefaultBaseType(type) = baseType; + } + } + + static IEnumerable GetPublicAndProtectedMethods(Type type) + { + var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + foreach (var constructor in constructors) + { + if (constructor.IsPublic || constructor.IsFamily || constructor.IsFamilyOrAssembly) + { + yield return constructor; + } + } + var methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); + foreach (var method in methods) + { + if (method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly) + { + yield return method; + } + } + } + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = $"<{nameof(InjectedTypeAnalysisContext.DefaultBaseType)}>k__BackingField")] + private static extern ref TypeAnalysisContext? GetDefaultBaseType(InjectedTypeAnalysisContext context); +} diff --git a/Il2CppInterop.Generator/InstructionListExtensions.cs b/Il2CppInterop.Generator/InstructionListExtensions.cs new file mode 100644 index 00000000..c6074654 --- /dev/null +++ b/Il2CppInterop.Generator/InstructionListExtensions.cs @@ -0,0 +1,16 @@ +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator; + +internal static class InstructionListExtensions +{ + public static void Add(this List instructions, OpCode opCode) + { + instructions.Add(new Instruction(opCode)); + } + + public static void Add(this List instructions, OpCode opCode, object? operand) + { + instructions.Add(new Instruction(opCode, operand)); + } +} diff --git a/Il2CppInterop.Generator/LocalVariableListExtensions.cs b/Il2CppInterop.Generator/LocalVariableListExtensions.cs new file mode 100644 index 00000000..a3c3a87e --- /dev/null +++ b/Il2CppInterop.Generator/LocalVariableListExtensions.cs @@ -0,0 +1,14 @@ +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator; + +internal static class LocalVariableListExtensions +{ + public static LocalVariable AddNew(this List localVariables, TypeAnalysisContext variableType) + { + var localVariable = new LocalVariable(variableType); + localVariables.Add(localVariable); + return localVariable; + } +} diff --git a/Il2CppInterop.Generator/MethodAnalysisContextExtensions.cs b/Il2CppInterop.Generator/MethodAnalysisContextExtensions.cs new file mode 100644 index 00000000..deb1c2b0 --- /dev/null +++ b/Il2CppInterop.Generator/MethodAnalysisContextExtensions.cs @@ -0,0 +1,68 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +internal static class MethodAnalysisContextExtensions +{ + extension(MethodAnalysisContext method) + { + /// + /// This is a runtime-implemented method. In other words, it should not have a method body because the runtime provides its own implementation. + /// + /// + /// One example of this is in delegate invocation methods. + /// + public bool RuntimeImplemented + { + get => method.GetExtraData("RuntimeImplemented") is true; + set => method.PutExtraData("RuntimeImplemented", value); + } + + [MaybeNull] + public FieldAnalysisContext MethodInfoField + { + get => method.GetExtraData("MethodInfoField"); + set => method.PutExtraData("MethodInfoField", value); + } + + public bool IsInstanceConstructor => method.Name == ".ctor"; + public bool IsStaticConstructor => method.Name == ".cctor"; + public bool IsConstructor => method.IsInstanceConstructor || method.IsStaticConstructor; + + public bool ImplementsAnInterfaceMethod + { + get + { + var count = 0; + foreach (var x in method.Overrides) + { + count++; + if (count > 1) + { + return true; + } + } + return count == 1 && method.BaseMethod is null; + } + } + + public FieldAnalysisContext GetInstantiatedMethodInfoField() + { + var methodInfoField = method.MethodInfoField; + Debug.Assert(methodInfoField is not null); + Debug.Assert(method.DeclaringType is not null); + + IReadOnlyList methodInfoGenericArguments = [.. method.DeclaringType.GenericParameters, .. method.GenericParameters]; + if (methodInfoGenericArguments.Count == 0) + { + return methodInfoField; + } + else + { + return methodInfoField.MakeConcreteGeneric(methodInfoGenericArguments); + } + } + } +} diff --git a/Il2CppInterop.Generator/MethodBodyBase.cs b/Il2CppInterop.Generator/MethodBodyBase.cs new file mode 100644 index 00000000..f7b8018f --- /dev/null +++ b/Il2CppInterop.Generator/MethodBodyBase.cs @@ -0,0 +1,84 @@ +using AsmResolver.DotNet; +using AsmResolver.DotNet.Code.Cil; +using AsmResolver.PE.DotNet.Cil; +using AssetRipper.CIL; +using Cpp2IL.Core.Model.Contexts; +using Cpp2IL.Core.Utils.AsmResolver; +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator; + +public abstract class MethodBodyBase +{ + public required IReadOnlyList Instructions { get; init; } + public IReadOnlyList LocalVariables { get; init; } = []; + public IReadOnlyList ExceptionHandlers { get; init; } = []; + + public void FillMethodBody(MethodDefinition method) + { + if (!method.IsManagedMethodWithBody()) + { + return; + } + + var body = new CilMethodBody(method); + method.CilMethodBody = body; + var module = method.Module!; + var instructions = body.Instructions; + + var labels = new Dictionary(Instructions.Count + 1); + for (var i = Instructions.Count - 1; i >= 0; i--) + { + labels.Add(Instructions[i], new CilInstructionLabel()); + } + labels.Add(EndLabel.Instance, instructions.EndLabel); + + foreach (var exceptionHandler in ExceptionHandlers) + { + var handler = new CilExceptionHandler + { + HandlerType = exceptionHandler.HandlerType, + TryStart = labels.GetValue(exceptionHandler.TryStart), + TryEnd = labels.GetValue(exceptionHandler.TryEnd), + HandlerStart = labels.GetValue(exceptionHandler.HandlerStart), + HandlerEnd = labels.GetValue(exceptionHandler.HandlerEnd) ?? instructions.EndLabel, + FilterStart = labels.GetValue(exceptionHandler.FilterStart), + ExceptionType = exceptionHandler.ExceptionType?.ToTypeSignature(module).ToTypeDefOrRef(), + }; + body.ExceptionHandlers.Add(handler); + } + + Dictionary localVariableMap = new(LocalVariables.Count); + for (var i = LocalVariables.Count - 1; i >= 0; i--) + { + var localVariable = LocalVariables[i]; + var localVariableType = localVariable.Type.ToTypeSignature(module); + var value = new CilLocalVariable(localVariableType); + body.LocalVariables.Add(value); + localVariableMap.Add(localVariable, value); + } + + for (var i = 0; i < Instructions.Count; i++) + { + var instruction = Instructions[i]; + var operand = instruction.Operand switch + { + This => method.Parameters.ThisParameter, + LocalVariable localVariable => localVariableMap[localVariable], + TypeAnalysisContext type => type.ToTypeSignature(module).ToTypeDefOrRef(), + MethodAnalysisContext methodOperand => methodOperand.ToMethodDescriptor(module), + FieldAnalysisContext field => field.ToFieldDescriptor(module), + ParameterAnalysisContext parameter => method.Parameters[parameter.ParameterIndex], + MultiDimensionalArrayMethod arrayMethod => arrayMethod.ToMethodDescriptor(module), + ILabel label => labels[label], + IReadOnlyList labelArray => labelArray.Select(labels.GetValue).ToArray(), + _ => instruction.Operand, + }; + var cilInstruction = new CilInstruction(instruction.Code, operand); + instructions.Add(cilInstruction); + ((CilInstructionLabel)labels[instruction]).Instruction = cilInstruction; + } + + instructions.OptimizeMacros(); + } +} diff --git a/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs b/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs new file mode 100644 index 00000000..2a65d05b --- /dev/null +++ b/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs @@ -0,0 +1,33 @@ +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Logging; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public class MethodBodyTranslationProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Id => "method_body_translation"; + public override string Name => "Method Body Translation"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var successfulCount = 0; + var totalCount = 0; + foreach (var method in appContext.AllTypes.SelectMany(t => t.Methods)) + { + var successful = TranslatedMethodBody.MaybeStoreTranslatedMethodBody(method); + if (successful) + { + successfulCount++; + } + if (method.HasExtraData()) + { + totalCount++; + } + } + + // Report how many method bodies were successfully translated. + // Note: this total count is less than the count of methods with original bodies that were unstripped earlier. + // This is because static constructors were removed. + Logger.InfoNewline($"Translated the original method body for {successfulCount}/{totalCount} attempts.", nameof(MethodBodyTranslationProcessingLayer)); + } +} diff --git a/Il2CppInterop.Generator/MonoIl2CppConversion.cs b/Il2CppInterop.Generator/MonoIl2CppConversion.cs new file mode 100644 index 00000000..a6c7dac7 --- /dev/null +++ b/Il2CppInterop.Generator/MonoIl2CppConversion.cs @@ -0,0 +1,137 @@ +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator; +using Il2CppInterop.Generator.Operands; +using Il2CppInterop.Runtime.InteropTypes; + +namespace Il2CppInterop.Generator; + +internal static class MonoIl2CppConversion +{ + /// + /// Does not convert strings, which are treated as normal Il2Cpp objects. + /// + public static bool AddIl2CppToMonoConversion(List instructions, TypeAnalysisContext il2CppType) + { + // Depending on the type of the local variable, we may need to convert it. + // If the local variable is Pointer, we need to convert it to T*. + // If the local variable is an Il2Cpp primitive (like Il2CppSystem.Int32), we need to convert it to the corresponding C# type. + // If the local variable is an Il2Cpp enum, we need to convert it to the underlying C# primitive type. + + if (IsIl2CppPrimitiveValueType(il2CppType)) + { + var monoType = il2CppType.AppContext.Mscorlib.GetTypeByFullNameOrThrow($"System.{il2CppType.Name}"); + var conversionMethod = il2CppType.GetImplicitConversionTo(monoType); + instructions.Add(new Instruction(OpCodes.Call, conversionMethod)); + return true; + } + else if (il2CppType is GenericInstanceTypeAnalysisContext { GenericArguments.Count: 1, GenericType.DeclaringType: null } genericInstanceType) + { + if (genericInstanceType.GenericType.Name == $"{nameof(Pointer<>)}`1" && genericInstanceType.GenericType.Namespace == typeof(Pointer<>).Namespace) + { + var elementType = genericInstanceType.GenericArguments[0]; + var conversionMethod = genericInstanceType.GenericType.Methods.First(m => m.Name == "op_Implicit" && m.ReturnType is PointerTypeAnalysisContext); + instructions.Add(new Instruction(OpCodes.Call, new ConcreteGenericMethodAnalysisContext(conversionMethod, [elementType], []))); + return true; + } + if (genericInstanceType.GenericType.Name == $"{nameof(ByReference<>)}`1" && genericInstanceType.GenericType.Namespace == typeof(ByReference<>).Namespace) + { + var elementType = genericInstanceType.GenericArguments[0]; + var conversionMethod = genericInstanceType.GenericType.Methods.First(m => m.Name == nameof(ByReference<>.ToRef)); + instructions.Add(new Instruction(OpCodes.Call, new ConcreteGenericMethodAnalysisContext(conversionMethod, [elementType], []))); + return true; + } + } + else if (il2CppType.EnumMonoUnderlyingType is { } underlyingType) + { + var conversionMethod = il2CppType.GetExplicitConversionTo(underlyingType); + instructions.Add(new Instruction(OpCodes.Call, conversionMethod)); + return true; + } + return false; + } + + /// + /// Does not convert strings, which are treated as normal Il2Cpp objects. + /// + public static bool AddMonoToIl2CppConversion(List instructions, TypeAnalysisContext il2CppType) + { + if (IsIl2CppPrimitiveValueType(il2CppType)) + { + var monoType = il2CppType.AppContext.Mscorlib.GetTypeByFullNameOrThrow($"System.{il2CppType.Name}"); + var conversionMethod = il2CppType.GetImplicitConversionFrom(monoType); + instructions.Add(new Instruction(OpCodes.Call, conversionMethod)); + return true; + } + else if (il2CppType is GenericInstanceTypeAnalysisContext { GenericArguments.Count: 1, GenericType.DeclaringType: null } genericInstanceType) + { + if (genericInstanceType.GenericType.Name == $"{nameof(Pointer<>)}`1" && genericInstanceType.GenericType.Namespace == typeof(Pointer<>).Namespace) + { + var elementType = genericInstanceType.GenericArguments[0]; + var conversionMethod = genericInstanceType.GenericType.Methods.First(m => m.Name == "op_Implicit" && m.Parameters.Count == 1 && m.Parameters[0].ParameterType is PointerTypeAnalysisContext); + instructions.Add(new Instruction(OpCodes.Call, new ConcreteGenericMethodAnalysisContext(conversionMethod, [elementType], []))); + return true; + } + if (genericInstanceType.GenericType.Name == $"{nameof(ByReference<>)}`1" && genericInstanceType.GenericType.Namespace == typeof(ByReference<>).Namespace) + { + var elementType = genericInstanceType.GenericArguments[0]; + var conversionMethod = genericInstanceType.GenericType.Methods.First(m => m.Name == nameof(ByReference<>.FromRef)); + instructions.Add(new Instruction(OpCodes.Call, new ConcreteGenericMethodAnalysisContext(conversionMethod, [elementType], []))); + return true; + } + } + else if (il2CppType.EnumMonoUnderlyingType is { } underlyingType) + { + var conversionMethod = il2CppType.GetExplicitConversionFrom(underlyingType); + instructions.Add(new Instruction(OpCodes.Call, conversionMethod)); + return true; + } + return false; + } + + public static void AddIl2CppToMonoStringConversion(List instructions, ApplicationAnalysisContext appContext) + { + var il2CppSystemString = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.String"); + var monoSystemString = appContext.SystemTypes.SystemStringType; + var conversionMethod = il2CppSystemString.GetImplicitConversionTo(monoSystemString); + instructions.Add(new Instruction(OpCodes.Call, conversionMethod)); + } + + public static void AddMonoToIl2CppStringConversion(List instructions, ApplicationAnalysisContext appContext) + { + var il2CppSystemString = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.String"); + var monoSystemString = appContext.SystemTypes.SystemStringType; + var conversionMethod = il2CppSystemString.GetImplicitConversionFrom(monoSystemString); + instructions.Add(new Instruction(OpCodes.Call, conversionMethod)); + } + + private static bool IsIl2CppPrimitiveValueType(TypeAnalysisContext type) + { + if (type is ReferencedTypeAnalysisContext) + return false; + + if (type.DeclaringType is not null) + return false; + + if (type.DeclaringAssembly != type.AppContext.Il2CppMscorlib) + return false; + + if (type.Namespace != "Il2CppSystem") + return false; + + return type.Name + is "Byte" + or "SByte" + or "Int16" + or "UInt16" + or "Int32" + or "UInt32" + or "IntPtr" + or "UIntPtr" + or "Int64" + or "UInt64" + or "Single" + or "Double" + or "Boolean" + or "Char"; + } +} diff --git a/Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs b/Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs new file mode 100644 index 00000000..a7a1be53 --- /dev/null +++ b/Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs @@ -0,0 +1,54 @@ +using AsmResolver.DotNet; +using Cpp2IL.Core.Logging; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public class MscorlibAssemblyInjectionProcessingLayer : UnstripBaseProcessingLayer +{ + public override string Name => "Inject a new mscorlib into the Cpp2IL context system"; + + public override string Id => "mscorlib_injector"; + + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var assemblyList = appContext.GetExtraData>(AssembliesKey); + if (assemblyList is null) + { + var directoryPath = appContext.GetExtraData(DirectoryKey); + if (directoryPath is null) + { + Logger.WarnNewline($"No assemblies specified - processor will not run. You need to provide the {DirectoryKey}, either by programmatically adding it as extra data in the app context, or by specifying it in the --processor-config command line option.", nameof(UnstripProcessingLayer)); + return; + } + + assemblyList = Directory.GetFiles(directoryPath, "*.dll", SearchOption.AllDirectories) + .Where(x => x.Contains("mscorlib", StringComparison.OrdinalIgnoreCase)) + .Select(AssemblyDefinition.FromFile) + .ToList(); + } + + var mscorlib = assemblyList.FirstOrDefault(x => x.Name == "mscorlib"); + + if (mscorlib is null) + { + Logger.WarnNewline("mscorlib not provided - processor will not run.", nameof(UnstripProcessingLayer)); + return; + } + + if (appContext.AssembliesByName.ContainsKey("mscorlib")) + { + Logger.WarnNewline("mscorlib already injected - processor will not run.", nameof(MscorlibAssemblyInjectionProcessingLayer)); + return; + } + + Logger.InfoNewline($"Injecting new mscorlib...", nameof(MscorlibAssemblyInjectionProcessingLayer)); + + InjectAssemblies(appContext, [mscorlib], false); + + // Need to reset the system types context to use the new corlib + appContext.SystemTypes = new SystemTypesContext(appContext); + + appContext.AssembliesByName["mscorlib"].IsReferenceAssembly = true; + } +} diff --git a/Il2CppInterop.Generator/NativeMethodBody.cs b/Il2CppInterop.Generator/NativeMethodBody.cs new file mode 100644 index 00000000..a76d6332 --- /dev/null +++ b/Il2CppInterop.Generator/NativeMethodBody.cs @@ -0,0 +1,6 @@ +namespace Il2CppInterop.Generator; + +public class NativeMethodBody : MethodBodyBase +{ + +} diff --git a/Il2CppInterop.Generator/NativeMethodBodyProcessingLayer.cs b/Il2CppInterop.Generator/NativeMethodBodyProcessingLayer.cs new file mode 100644 index 00000000..340ad725 --- /dev/null +++ b/Il2CppInterop.Generator/NativeMethodBodyProcessingLayer.cs @@ -0,0 +1,491 @@ +using System.Diagnostics; +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; +using Il2CppInterop.Runtime; +using Il2CppInterop.Runtime.InteropTypes; + +namespace Il2CppInterop.Generator; + +public class NativeMethodBodyProcessingLayer : Cpp2IlProcessingLayer +{ + private const int ParameterOffset = 2; + public override string Name => "Native Method Body Processor"; + public override string Id => "native_method_body_processor"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var iil2CppValueType = appContext.ResolveTypeOrThrow(typeof(IIl2CppValueType)); + var iil2CppValueType_get_Size = iil2CppValueType.GetMethodByName($"get_{nameof(IIl2CppValueType.Size)}"); + + var iil2CppValueTypeExtensions = appContext.ResolveTypeOrThrow(typeof(IIl2CppValueTypeExtensions)); + var iil2CppValueType_ReadFromPointer = iil2CppValueTypeExtensions.GetMethodByName(nameof(IIl2CppValueTypeExtensions.ReadFromPointer)); + var iil2CppValueType_WriteToPointer = iil2CppValueTypeExtensions.GetMethodByName(nameof(IIl2CppValueTypeExtensions.WriteToPointer)); + + var runtimeInvokeHelper = appContext.ResolveTypeOrThrow(typeof(RuntimeInvokeHelper)); + var invokeAction = runtimeInvokeHelper.GetMethodByName(nameof(RuntimeInvokeHelper.InvokeAction)); + var invokeFunction = runtimeInvokeHelper.GetMethodByName(nameof(RuntimeInvokeHelper.InvokeFunction)); + var requiredStackAllocationSize = runtimeInvokeHelper.GetMethodByName(nameof(RuntimeInvokeHelper.RequiredStackAllocationSize)); + var prepareParameter = runtimeInvokeHelper.GetMethodByName(nameof(RuntimeInvokeHelper.PrepareParameter)); + var cleanupParameter = runtimeInvokeHelper.GetMethodByName(nameof(RuntimeInvokeHelper.CleanupParameter)); + + var intptrPointerType = appContext.SystemTypes.SystemIntPtrType.MakePointerType(); + var bytePointerType = appContext.SystemTypes.SystemByteType.MakePointerType(); + + var byRefType = appContext.ResolveTypeOrThrow(typeof(ByReference<>)); + var fromRef = byRefType.GetMethodByName(nameof(ByReference<>.FromRef)); + + var iil2CppObjectBase = appContext.ResolveTypeOrThrow(typeof(IIl2CppObjectBase)); + var get_Pointer = iil2CppObjectBase.GetMethodByName($"get_{nameof(IIl2CppObjectBase.Pointer)}"); + + var objectPointerType = appContext.ResolveTypeOrThrow(typeof(ObjectPointer)); + + var objectPointerNew = appContext.ResolveTypeOrThrow(typeof(IL2CPP)).GetMethodByName(nameof(IL2CPP.NewObjectPointer)); + + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly || assembly.IsInjected) + continue; + + var assemblyInvokeHelper = assembly.InjectType( + "Il2CppInterop.Generated.Helpers", + "InvokeHelper", + appContext.SystemTypes.SystemObjectType, + TypeAttributes.NotPublic | TypeAttributes.Abstract | TypeAttributes.Sealed); + assemblyInvokeHelper.IsInjected = true; + + var actionDictionary = new Dictionary(); + var functionDictionary = new Dictionary(); + + foreach (var type in assembly.Types) + { + if (type.IsInjected || type.IsUnstripped) + continue; + foreach (var method in type.Methods) + { + if (method.IsInjected || method.IsUnstripped) + continue; + + if (method.HasExtraData()) + continue; // Already has a translated body, skip. + + Debug.Assert(!method.HasExtraData()); + + var parameterCount = method.Parameters.Count; + MethodAnalysisContext invokeHelper; + if (method.IsVoid) + { + if (!actionDictionary.TryGetValue(parameterCount, out var actionMethod)) + { + actionMethod = new InjectedMethodAnalysisContext( + assemblyInvokeHelper, + "InvokeAction", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, + []) + { + IsInjected = true, + }; + + AddParameterForMethodInfo(actionMethod); + AddParameterForObjectPointer(actionMethod); + AddNormalAndGenericParameters(actionMethod, parameterCount, iil2CppValueType); + + actionDictionary[parameterCount] = actionMethod; + + var instructions = new List(); + var localVariables = new List(); + + if (parameterCount == 0) + { + AndImplementationForParameterlessMethod(instructions, invokeAction); + } + else + { + var parametersPointerLocal = StackAllocateIntPtr(instructions, localVariables, parameterCount, intptrPointerType, appContext); + + var stackAllocDataLocals = new LocalVariable[parameterCount]; + for (var i = 0; i < parameterCount; i++) + { + var parameter = actionMethod.Parameters[i + ParameterOffset]; + var stackAllocSizeLocal = localVariables.AddNew(appContext.SystemTypes.SystemInt32Type); + var stackAllocDataLocal = localVariables.AddNew(bytePointerType); + + StackAllocateForParameter(instructions, parameter, stackAllocSizeLocal, stackAllocDataLocal, requiredStackAllocationSize); + + // @params[{i}] = + instructions.Add(OpCodes.Ldloc, parametersPointerLocal); + AddOffsetForPointerIndex(instructions, i, appContext); + + // PrepareParameter(parameter, stackAllocData) + PrepareParameter(instructions, parameter, stackAllocDataLocal, prepareParameter); + + // Write the parameter to the pointer + instructions.Add(OpCodes.Stind_I); + + stackAllocDataLocals[i] = stackAllocDataLocal; + } + + // InvokeAction(method, obj, (void**)parameters); + InvokeMethod(instructions, parametersPointerLocal, invokeAction); + + for (var i = 0; i < parameterCount; i++) + { + // CleanupParameter(parameter, stackAllocData) + CleanupParameter(instructions, actionMethod.Parameters[i + ParameterOffset], stackAllocDataLocals[i], cleanupParameter); + } + + instructions.Add(OpCodes.Ret); + } + + actionMethod.PutExtraData(new NativeMethodBody() + { + Instructions = instructions, + LocalVariables = localVariables.Count > 0 ? localVariables : [], + }); + } + invokeHelper = actionMethod; + } + else + { + if (!functionDictionary.TryGetValue(method.Parameters.Count, out var functionMethod)) + { + functionMethod = new InjectedMethodAnalysisContext( + assemblyInvokeHelper, + "InvokeFunction", + appContext.SystemTypes.SystemVoidType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, + []) + { + IsInjected = true, + }; + + AddParameterForMethodInfo(functionMethod); + AddParameterForObjectPointer(functionMethod); + AddNormalAndGenericParameters(functionMethod, parameterCount, iil2CppValueType); + AddReturnGenericParameterAndSetReturnType(functionMethod, iil2CppValueType); + + functionDictionary[method.Parameters.Count] = functionMethod; + + var instructions = new List(); + var localVariables = new List(); + + var invokeFunctionInstantiated = invokeFunction.MakeGenericInstanceMethod(functionMethod.GenericParameters[^1]); + + if (parameterCount == 0) + { + AndImplementationForParameterlessMethod(instructions, invokeFunctionInstantiated); + } + else + { + var parametersPointerLocal = StackAllocateIntPtr(instructions, localVariables, parameterCount, intptrPointerType, appContext); + + var stackAllocDataLocals = new LocalVariable[parameterCount]; + for (var i = 0; i < parameterCount; i++) + { + var parameter = functionMethod.Parameters[i + ParameterOffset]; + var stackAllocSizeLocal = localVariables.AddNew(appContext.SystemTypes.SystemInt32Type); + var stackAllocDataLocal = localVariables.AddNew(bytePointerType); + + StackAllocateForParameter(instructions, parameter, stackAllocSizeLocal, stackAllocDataLocal, requiredStackAllocationSize); + + // @params[{i}] = + instructions.Add(OpCodes.Ldloc, parametersPointerLocal); + AddOffsetForPointerIndex(instructions, i, appContext); + + // PrepareParameter(parameter, stackAllocData) + PrepareParameter(instructions, parameter, stackAllocDataLocal, prepareParameter); + + // Write the parameter to the pointer + instructions.Add(OpCodes.Stind_I); + + stackAllocDataLocals[i] = stackAllocDataLocal; + } + + // var result = InvokeFunction(method, obj, (void**)parameters); + var resultLocal = localVariables.AddNew(functionMethod.ReturnType); + InvokeMethod(instructions, parametersPointerLocal, invokeFunctionInstantiated); + instructions.Add(OpCodes.Stloc, resultLocal); + + for (var i = 0; i < parameterCount; i++) + { + // CleanupParameter(parameter, stackAllocData) + CleanupParameter(instructions, functionMethod.Parameters[i + ParameterOffset], stackAllocDataLocals[i], cleanupParameter); + } + + instructions.Add(OpCodes.Ldloc, resultLocal); + instructions.Add(OpCodes.Ret); + } + + functionMethod.PutExtraData(new NativeMethodBody() + { + Instructions = instructions, + LocalVariables = localVariables.Count > 0 ? localVariables : [], + }); + } + invokeHelper = functionMethod; + } + + // Implement the method body + { + var instructions = new List(); + + Debug.Assert(method.DeclaringType is not null); + + if (method.IsInstanceConstructor && !method.DeclaringType.IsValueType) + { + Debug.Assert(method.DeclaringType.PointerConstructor is not null); + + var pointerConstructorInstantiated = method.DeclaringType.GenericParameters.Count > 0 + ? new ConcreteGenericMethodAnalysisContext(method.DeclaringType.PointerConstructor!, method.DeclaringType.GenericParameters, []) + : method.DeclaringType.PointerConstructor!; + + instructions.Add(OpCodes.Ldarg_0); + instructions.Add(OpCodes.Call, objectPointerNew.MakeGenericInstanceMethod(method.DeclaringType.SelfInstantiateIfGeneric())); + instructions.Add(OpCodes.Call, pointerConstructorInstantiated); + } + + // MethodInfo and Object Pointer + LocalVariable? valueTypeDataPointer = null; + if (method.IsStatic) + { + instructions.Add(OpCodes.Ldsfld, method.GetInstantiatedMethodInfoField()); + instructions.Add(OpCodes.Ldc_I4_0); + instructions.Add(OpCodes.Conv_I); + } + else if (method.DeclaringType.IsValueType) + { + valueTypeDataPointer = new LocalVariable(bytePointerType); + var declaringTypeInstantiated = method.DeclaringType.SelfInstantiateIfGeneric(); + + instructions.Add(OpCodes.Ldarg, This.Instance); + instructions.Add(OpCodes.Ldobj, declaringTypeInstantiated); + instructions.Add(OpCodes.Box, declaringTypeInstantiated); + instructions.Add(OpCodes.Callvirt, iil2CppValueType_get_Size); + instructions.Add(OpCodes.Conv_U); + instructions.Add(OpCodes.Localloc); + instructions.Add(OpCodes.Stloc, valueTypeDataPointer); + + instructions.Add(OpCodes.Ldarg, This.Instance); + instructions.Add(OpCodes.Ldobj, declaringTypeInstantiated); + instructions.Add(OpCodes.Ldloc, valueTypeDataPointer); + instructions.Add(OpCodes.Call, iil2CppValueType_WriteToPointer.MakeGenericInstanceMethod(declaringTypeInstantiated)); + + instructions.Add(OpCodes.Ldsfld, method.GetInstantiatedMethodInfoField()); + instructions.Add(OpCodes.Ldloc, valueTypeDataPointer); + } + else + { + instructions.Add(OpCodes.Ldsfld, method.GetInstantiatedMethodInfoField()); + instructions.Add(OpCodes.Ldarg, This.Instance); + instructions.Add(OpCodes.Callvirt, get_Pointer); + } + + var genericArgumentsCount = method.IsVoid ? method.Parameters.Count : method.Parameters.Count + 1; + var genericArguments = new TypeAnalysisContext[genericArgumentsCount]; + for (var i = 0; i < method.Parameters.Count; i++) + { + var parameter = method.Parameters[i]; + var parameterType = parameter.ParameterType; + + instructions.Add(OpCodes.Ldarg, parameter); + if (parameterType is ByRefTypeAnalysisContext byRefTypeAnalysisContext) + { + instructions.Add(OpCodes.Call, new ConcreteGenericMethodAnalysisContext(fromRef, [byRefTypeAnalysisContext.ElementType], [])); + genericArguments[i] = byRefType.MakeGenericInstanceType([byRefTypeAnalysisContext.ElementType]); + } + else + { + genericArguments[i] = parameterType; + } + } + if (!method.IsVoid) + { + genericArguments[^1] = method.ReturnType; + } + var invokeHelperInstantiated = genericArguments.Length > 0 + ? invokeHelper.MakeGenericInstanceMethod(genericArguments) + : invokeHelper; + instructions.Add(OpCodes.Call, invokeHelperInstantiated); + + if (valueTypeDataPointer is not null) + { + instructions.Add(OpCodes.Ldarg, This.Instance); + instructions.Add(OpCodes.Ldloc, valueTypeDataPointer); + instructions.Add(OpCodes.Call, iil2CppValueType_ReadFromPointer.MakeGenericInstanceMethod(method.DeclaringType.SelfInstantiateIfGeneric())); + } + + instructions.Add(OpCodes.Ret); + + method.PutExtraData(new NativeMethodBody() + { + Instructions = instructions, + LocalVariables = valueTypeDataPointer is not null + ? [valueTypeDataPointer] + : [], + }); + } + } + } + + foreach (var method in actionDictionary.OrderBy(pair => pair.Key).Select(pair => pair.Value)) + { + assemblyInvokeHelper.Methods.Add(method); + } + foreach (var method in functionDictionary.OrderBy(pair => pair.Key).Select(pair => pair.Value)) + { + assemblyInvokeHelper.Methods.Add(method); + } + } + } + + private static void InvokeMethod(List instructions, LocalVariable parametersPointerLocal, MethodAnalysisContext invokeHelper) + { + instructions.Add(OpCodes.Ldarg_0); // method + instructions.Add(OpCodes.Ldarg_1); // obj + instructions.Add(OpCodes.Ldloc, parametersPointerLocal); // parameters + instructions.Add(OpCodes.Call, invokeHelper); + } + + private static void CleanupParameter(List instructions, ParameterAnalysisContext parameter, LocalVariable stackAllocDataLocal, MethodAnalysisContext cleanupParameter) + { + instructions.Add(OpCodes.Ldarg, parameter); + instructions.Add(OpCodes.Ldloc, stackAllocDataLocal); + instructions.Add(OpCodes.Call, cleanupParameter.MakeGenericInstanceMethod(parameter.ParameterType)); + } + + private static void PrepareParameter(List instructions, ParameterAnalysisContext parameter, LocalVariable stackAllocDataLocal, MethodAnalysisContext prepareParameter) + { + instructions.Add(OpCodes.Ldarg, parameter); + instructions.Add(OpCodes.Ldloc, stackAllocDataLocal); + instructions.Add(OpCodes.Call, prepareParameter.MakeGenericInstanceMethod(parameter.ParameterType)); + } + + private static void StackAllocateForParameter(List instructions, ParameterAnalysisContext parameter, LocalVariable stackAllocSizeLocal, LocalVariable stackAllocDataLocal, MethodAnalysisContext requiredStackAllocationSize) + { + instructions.Add(OpCodes.Call, requiredStackAllocationSize.MakeGenericInstanceMethod(parameter.ParameterType)); + instructions.Add(OpCodes.Stloc, stackAllocSizeLocal); + + var zeroSizeLabel = new Instruction(OpCodes.Nop); + var endLabel = new Instruction(OpCodes.Nop); + + instructions.Add(OpCodes.Ldloc, stackAllocSizeLocal); + instructions.Add(OpCodes.Brfalse, zeroSizeLabel); + + instructions.Add(OpCodes.Ldloc, stackAllocSizeLocal); + instructions.Add(OpCodes.Conv_U); + instructions.Add(OpCodes.Localloc); + instructions.Add(OpCodes.Stloc, stackAllocDataLocal); + instructions.Add(OpCodes.Br, endLabel); + + instructions.Add(zeroSizeLabel); + instructions.Add(OpCodes.Ldc_I4_0); + instructions.Add(OpCodes.Conv_U); + instructions.Add(OpCodes.Stloc, stackAllocDataLocal); + + instructions.Add(endLabel); + } + + private static void AddOffsetForPointerIndex(List instructions, int index, ApplicationAnalysisContext appContext) + { + if (index != 0) + { + if (index > 1) + { + instructions.Add(OpCodes.Ldc_I4, index); + instructions.Add(OpCodes.Conv_I); + } + + instructions.Add(OpCodes.Sizeof, appContext.SystemTypes.SystemIntPtrType); + + if (index > 1) + { + instructions.Add(OpCodes.Mul); + } + + instructions.Add(OpCodes.Add); + } + } + + private static LocalVariable StackAllocateIntPtr(List instructions, List localVariables, int count, PointerTypeAnalysisContext intptrPointerType, ApplicationAnalysisContext appContext) + { + var parametersPointerLocal = localVariables.AddNew(intptrPointerType); + + instructions.Add(OpCodes.Ldc_I4, count); + instructions.Add(OpCodes.Conv_U); + instructions.Add(OpCodes.Sizeof, appContext.SystemTypes.SystemIntPtrType); + instructions.Add(OpCodes.Mul_Ovf_Un); + instructions.Add(OpCodes.Localloc); + instructions.Add(OpCodes.Stloc, parametersPointerLocal); + return parametersPointerLocal; + } + + private static void AndImplementationForParameterlessMethod(List instructions, MethodAnalysisContext invokeHelper) + { + instructions.Add(OpCodes.Ldarg_0); + instructions.Add(OpCodes.Ldarg_1); + instructions.Add(OpCodes.Ldc_I4_0); + instructions.Add(OpCodes.Conv_U); + instructions.Add(OpCodes.Call, invokeHelper); + instructions.Add(OpCodes.Ret); + } + + private static void AddParameterForMethodInfo(InjectedMethodAnalysisContext method) + { + method.Parameters.Add(new InjectedParameterAnalysisContext( + "method", + method.AppContext.SystemTypes.SystemIntPtrType, + ParameterAttributes.None, + 0, + method)); + } + + private static void AddParameterForObjectPointer(InjectedMethodAnalysisContext method) + { + method.Parameters.Add(new InjectedParameterAnalysisContext( + "obj", + method.AppContext.SystemTypes.SystemIntPtrType, + ParameterAttributes.None, + 1, + method)); + } + + private static void AddNormalAndGenericParameters(InjectedMethodAnalysisContext method, int parameterCount, TypeAnalysisContext iil2CppValueType) + { + for (var i = 0; i < parameterCount; i++) + { + var genericParameter = new GenericParameterTypeAnalysisContext( + "T" + i, + i, + LibCpp2IL.BinaryStructures.Il2CppTypeEnum.IL2CPP_TYPE_MVAR, + GenericParameterAttributes.None, + method); + method.GenericParameters.Add(genericParameter); + + genericParameter.ConstraintTypes.Add(iil2CppValueType); + + var parameter = new InjectedParameterAnalysisContext( + "parameter_" + i, + genericParameter, + ParameterAttributes.None, + i + ParameterOffset, + method); + method.Parameters.Add(parameter); + } + } + + private static void AddReturnGenericParameterAndSetReturnType(InjectedMethodAnalysisContext method, TypeAnalysisContext iil2CppValueType) + { + var genericParameter = new GenericParameterTypeAnalysisContext( + "TResult", + method.GenericParameters.Count, + LibCpp2IL.BinaryStructures.Il2CppTypeEnum.IL2CPP_TYPE_MVAR, + GenericParameterAttributes.None, + method); + method.GenericParameters.Add(genericParameter); + + genericParameter.ConstraintTypes.Add(iil2CppValueType); + + method.SetDefaultReturnType(genericParameter); + } +} diff --git a/Il2CppInterop.Generator/ObjectInterfaceProcessingLayer.cs b/Il2CppInterop.Generator/ObjectInterfaceProcessingLayer.cs new file mode 100644 index 00000000..39b70fc7 --- /dev/null +++ b/Il2CppInterop.Generator/ObjectInterfaceProcessingLayer.cs @@ -0,0 +1,63 @@ +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public class ObjectInterfaceProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Object Interface Processor"; + public override string Id => "object_interface_processor"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var il2CppMscorlib = appContext.Il2CppMscorlib; + + var il2CppSystemObject = il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Object"); + var il2CppSystemValueType = il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.ValueType"); + var il2CppSystemEnum = il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Enum"); + + var il2CppSystemIObject = InjectInterface(appContext, "IObject"); + var il2CppSystemIValueType = InjectInterface(appContext, "IValueType"); + var il2CppSystemIEnum = InjectInterface(appContext, "IEnum"); + + il2CppSystemIEnum.InterfaceContexts.Add(il2CppSystemIValueType); + + il2CppSystemValueType.InterfaceContexts.Add(il2CppSystemIValueType); + il2CppSystemEnum.InterfaceContexts.Add(il2CppSystemIEnum); + + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly || assembly.IsInjected) + continue; + + foreach (var type in assembly.Types) + { + if (type.IsInjected) + continue; + + if (type != il2CppSystemIObject) + { + type.InterfaceContexts.Add(il2CppSystemIObject); + } + + if (type.DefaultBaseType == il2CppSystemValueType) + { + type.InterfaceContexts.Add(il2CppSystemIValueType); + } + else if (type.DefaultBaseType == il2CppSystemEnum) + { + type.InterfaceContexts.Add(il2CppSystemIValueType); + type.InterfaceContexts.Add(il2CppSystemIEnum); + } + } + } + } + + private static InjectedTypeAnalysisContext InjectInterface(ApplicationAnalysisContext appContext, string name) + { + var result = appContext.Il2CppMscorlib.InjectType("Il2CppSystem", name, appContext.SystemTypes.SystemObjectType, + TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract); + result.IsInjected = true; + return result; + } +} diff --git a/Il2CppInterop.Generator/Operands/EndLabel.cs b/Il2CppInterop.Generator/Operands/EndLabel.cs new file mode 100644 index 00000000..bfcf3f5c --- /dev/null +++ b/Il2CppInterop.Generator/Operands/EndLabel.cs @@ -0,0 +1,9 @@ +namespace Il2CppInterop.Generator.Operands; + +public sealed class EndLabel : ILabel +{ + public static readonly EndLabel Instance = new(); + private EndLabel() + { + } +} diff --git a/Il2CppInterop.Generator/Operands/ExceptionHandler.cs b/Il2CppInterop.Generator/Operands/ExceptionHandler.cs new file mode 100644 index 00000000..0dfcc9f4 --- /dev/null +++ b/Il2CppInterop.Generator/Operands/ExceptionHandler.cs @@ -0,0 +1,15 @@ +using AsmResolver.DotNet.Code.Cil; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator.Operands; + +public sealed record class ExceptionHandler +{ + public CilExceptionHandlerType HandlerType { get; set; } + public ILabel? TryStart { get; set; } + public ILabel? TryEnd { get; set; } + public ILabel? HandlerStart { get; set; } + public ILabel? HandlerEnd { get; set; } + public ILabel? FilterStart { get; set; } + public TypeAnalysisContext? ExceptionType { get; set; } +} diff --git a/Il2CppInterop.Generator/Operands/ILabel.cs b/Il2CppInterop.Generator/Operands/ILabel.cs new file mode 100644 index 00000000..74699d15 --- /dev/null +++ b/Il2CppInterop.Generator/Operands/ILabel.cs @@ -0,0 +1,5 @@ +namespace Il2CppInterop.Generator.Operands; + +public interface ILabel +{ +} diff --git a/Il2CppInterop.Generator/Operands/Instruction.cs b/Il2CppInterop.Generator/Operands/Instruction.cs new file mode 100644 index 00000000..94f2240c --- /dev/null +++ b/Il2CppInterop.Generator/Operands/Instruction.cs @@ -0,0 +1,22 @@ +namespace Il2CppInterop.Generator.Operands; + +public sealed class Instruction : ILabel +{ + public OpCode Code { get; set; } + public object? Operand { get; set; } + + public Instruction() + { + } + + public Instruction(OpCode code) + { + Code = code; + } + + public Instruction(OpCode code, object? operand) + { + Code = code; + Operand = operand; + } +} diff --git a/Il2CppInterop.Generator/Operands/LocalVariable.cs b/Il2CppInterop.Generator/Operands/LocalVariable.cs new file mode 100644 index 00000000..4e13a78d --- /dev/null +++ b/Il2CppInterop.Generator/Operands/LocalVariable.cs @@ -0,0 +1,19 @@ +using System.Diagnostics.CodeAnalysis; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator.Operands; + +public sealed class LocalVariable +{ + public required TypeAnalysisContext Type { get; init; } + + public LocalVariable() + { + } + + [SetsRequiredMembers] + public LocalVariable(TypeAnalysisContext type) + { + Type = type; + } +} diff --git a/Il2CppInterop.Generator/Operands/MultiDimensionalArrayMethod.cs b/Il2CppInterop.Generator/Operands/MultiDimensionalArrayMethod.cs new file mode 100644 index 00000000..cdbe3512 --- /dev/null +++ b/Il2CppInterop.Generator/Operands/MultiDimensionalArrayMethod.cs @@ -0,0 +1,33 @@ +using AsmResolver.DotNet; +using AsmResolver.DotNet.Signatures; +using Cpp2IL.Core.Model.Contexts; +using Cpp2IL.Core.Utils.AsmResolver; + +namespace Il2CppInterop.Generator.Operands; + +public sealed record class MultiDimensionalArrayMethod(ArrayTypeAnalysisContext ArrayType, MultiDimensionalArrayMethodType MethodType) +{ + public IMethodDescriptor ToMethodDescriptor(ModuleDefinition module) + { + var arrayTypeSignature = ArrayType.ToTypeSignature(module); + var elementTypeSignature = arrayTypeSignature.BaseType; + var indexParameters = Enumerable.Repeat(module.CorLibTypeFactory.Int32, ArrayType.Rank); + var methodSignature = MethodType switch + { + MultiDimensionalArrayMethodType.Get => MethodSignature.CreateInstance(elementTypeSignature, indexParameters), + MultiDimensionalArrayMethodType.Set => MethodSignature.CreateInstance(module.CorLibTypeFactory.Void, indexParameters.Append(elementTypeSignature)), + MultiDimensionalArrayMethodType.Constructor => MethodSignature.CreateInstance(module.CorLibTypeFactory.Void, indexParameters), + MultiDimensionalArrayMethodType.Address => MethodSignature.CreateInstance(elementTypeSignature.MakeByReferenceType(), indexParameters), + _ => throw new InvalidOperationException($"Unknown {nameof(MultiDimensionalArrayMethodType)}: {MethodType}"), + }; + var methodName = MethodType switch + { + MultiDimensionalArrayMethodType.Get => "Get", + MultiDimensionalArrayMethodType.Set => "Set", + MultiDimensionalArrayMethodType.Constructor => ".ctor", + MultiDimensionalArrayMethodType.Address => "Address", + _ => null, + }; + return new MemberReference(arrayTypeSignature.ToTypeDefOrRef(), methodName, methodSignature); + } +} diff --git a/Il2CppInterop.Generator/Operands/MultiDimensionalArrayMethodType.cs b/Il2CppInterop.Generator/Operands/MultiDimensionalArrayMethodType.cs new file mode 100644 index 00000000..6d3c47da --- /dev/null +++ b/Il2CppInterop.Generator/Operands/MultiDimensionalArrayMethodType.cs @@ -0,0 +1,21 @@ +namespace Il2CppInterop.Generator.Operands; + +public enum MultiDimensionalArrayMethodType +{ + /// + /// call instance bool bool[0..., 0...]::Get(int32, int32) + /// + Get, + /// + /// call instance void bool[0..., 0...]::Set(int32, int32, bool) + /// + Set, + /// + /// newobj instance void bool[0..., 0...]::.ctor(int32, int32) + /// + Constructor, + /// + /// call instance bool& bool[0..., 0...]::Address(int32, int32) + /// + Address, +} diff --git a/Il2CppInterop.Generator/Operands/This.cs b/Il2CppInterop.Generator/Operands/This.cs new file mode 100644 index 00000000..1aced9d7 --- /dev/null +++ b/Il2CppInterop.Generator/Operands/This.cs @@ -0,0 +1,9 @@ +namespace Il2CppInterop.Generator.Operands; + +public sealed record class This +{ + public static This Instance { get; } = new This(); + private This() + { + } +} diff --git a/Il2CppInterop.Generator/OriginalMethodBody.cs b/Il2CppInterop.Generator/OriginalMethodBody.cs new file mode 100644 index 00000000..3d0f2312 --- /dev/null +++ b/Il2CppInterop.Generator/OriginalMethodBody.cs @@ -0,0 +1,158 @@ +using System.Diagnostics.CodeAnalysis; +using AsmResolver.DotNet; +using AsmResolver.DotNet.Code.Cil; +using AsmResolver.DotNet.Collections; +using AsmResolver.PE.DotNet.Cil; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator; + +public class OriginalMethodBody : MethodBodyBase +{ + public static bool MaybeStoreOriginalMethodBody(MethodDefinition originalMethod, MethodAnalysisContext methodContext) + { + if (TryResolveOriginalMethodBody(originalMethod, methodContext, out var originalMethodBody)) + { + methodContext.PutExtraData(originalMethodBody); + return true; + } + else + { + return false; + } + } + + private static bool TryResolveOriginalMethodBody(MethodDefinition method, MethodAnalysisContext methodContext, [NotNullWhen(true)] out OriginalMethodBody? originalMethodBody) + { + var body = method.CilMethodBody; + if (body is null) + { + originalMethodBody = null; + return false; + } + + var resolver = new ContextResolver(methodContext); + + var originalInstructions = body.Instructions; + originalInstructions.ExpandMacros(); + + var newInstructions = new Instruction[originalInstructions.Count]; + for (var i = 0; i < newInstructions.Length; i++) + { + newInstructions[i] = new Instruction + { + Code = originalInstructions[i].OpCode, + }; + } + + var newLocalVariables = new LocalVariable[body.LocalVariables.Count]; + for (var i = 0; i < newLocalVariables.Length; i++) + { + var localVariable = body.LocalVariables[i]; + var localVariableType = resolver.Resolve(localVariable.VariableType); + if (localVariableType is null) + { + originalMethodBody = default; + return false; + } + newLocalVariables[i] = new LocalVariable + { + Type = localVariableType, + }; + } + + var newExceptionHandlers = new ExceptionHandler[body.ExceptionHandlers.Count]; + for (var i = 0; i < newExceptionHandlers.Length; i++) + { + var exceptionHandler = body.ExceptionHandlers[i]; + var handlerType = exceptionHandler.HandlerType; + + var tryStart = ResolveLabel(newInstructions, originalInstructions, exceptionHandler.TryStart); + var tryEnd = ResolveLabel(newInstructions, originalInstructions, exceptionHandler.TryEnd); + var handlerStart = ResolveLabel(newInstructions, originalInstructions, exceptionHandler.HandlerStart); + var handlerEnd = ResolveLabel(newInstructions, originalInstructions, exceptionHandler.HandlerEnd); + var filterStart = ResolveLabel(newInstructions, originalInstructions, exceptionHandler.FilterStart); + TypeAnalysisContext? exceptionType; + if (exceptionHandler.ExceptionType is null) + { + exceptionType = null; + } + else + { + exceptionType = resolver.Resolve(exceptionHandler.ExceptionType.ToTypeSignature()); + if (exceptionType is null) + { + originalMethodBody = default; + return false; + } + } + newExceptionHandlers[i] = new ExceptionHandler + { + HandlerType = handlerType, + TryStart = tryStart, + TryEnd = tryEnd, + HandlerStart = handlerStart, + HandlerEnd = handlerEnd, + FilterStart = filterStart, + ExceptionType = exceptionType, + }; + } + + for (var i = 0; i < originalInstructions.Count; i++) + { + var instruction = originalInstructions[i]; + var operand = instruction.Operand; + var resolved = operand switch + { + null or byte or sbyte or short or ushort or int or uint or long or ulong or float or double or bool or char => operand, + string @string => @string, + AsmResolver.Utf8String utf8String => utf8String.ToString(), + CilLocalVariable localVariable => newLocalVariables[localVariable.Index], + Parameter parameter => parameter == method.Parameters.ThisParameter ? This.Instance : methodContext.Parameters[parameter.Index], + ITypeDescriptor typeDescriptor => resolver.Resolve(typeDescriptor.ToTypeSignature()), + IFieldDescriptor { Signature: not null } fieldDescriptor => resolver.Resolve(fieldDescriptor), + IMethodDescriptor { Signature: not null } methodDescriptor => resolver.Resolve(methodDescriptor), + ICilLabel label => ResolveLabel(newInstructions, originalInstructions, label), + IReadOnlyList labels => ResolveOperand(labels, originalInstructions, newInstructions), + StandAloneSignature => null,// Not currently supported + _ => null, + }; + if (resolved is null && operand is not null) + { + originalMethodBody = default; + return false; + } + newInstructions[i].Operand = resolved; + } + + originalMethodBody = new OriginalMethodBody + { + Instructions = newInstructions, + LocalVariables = newLocalVariables, + ExceptionHandlers = newExceptionHandlers, + }; + return true; + } + + private static ILabel[] ResolveOperand(IReadOnlyList labels, CilInstructionCollection originalInstructions, Instruction[] newInstructions) + { + var resolved = new ILabel[labels.Count]; + for (var i = 0; i < labels.Count; i++) + { + resolved[i] = ResolveLabel(newInstructions, originalInstructions, labels[i]); + } + return resolved; + } + + [return: NotNullIfNotNull(nameof(label))] + private static ILabel? ResolveLabel(Instruction[] newInstructions, CilInstructionCollection originalInstructions, ICilLabel? label) => label switch + { + null => null, + CilInstructionLabel instructionLabel => instructionLabel.Instruction is not null + ? newInstructions[originalInstructions.IndexOf(instructionLabel.Instruction)] + : throw new ArgumentException("Instruction label must reference an instruction", nameof(label)), + _ when label.GetType().Name == "CilEndLabel" => EndLabel.Instance, + _ => throw new ArgumentException($"Label is an unsupported type: {label.GetType()}", nameof(label)), + }; +} diff --git a/Il2CppInterop.Generator/PointerConstructorProcessingLayer.cs b/Il2CppInterop.Generator/PointerConstructorProcessingLayer.cs new file mode 100644 index 00000000..d6fc7d1c --- /dev/null +++ b/Il2CppInterop.Generator/PointerConstructorProcessingLayer.cs @@ -0,0 +1,100 @@ +using System.Diagnostics; +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; +using Il2CppInterop.Runtime.InteropTypes; + +namespace Il2CppInterop.Generator; + +public class PointerConstructorProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Pointer Constructor Processor"; + public override string Id => "pointer_constructor_processor"; + + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var objectPointerType = appContext.ResolveTypeOrThrow(typeof(ObjectPointer)); + + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly || assembly.IsInjected) + continue; + + foreach (var type in assembly.Types) + { + if (type.IsInjected || type.IsInterface) + continue; + + Debug.Assert(!type.IsStatic, "Static types should have been marked as instance types by now."); + + var typeInfo = type.GetExtraData(); + Debug.Assert(typeInfo is not null); + + if (typeInfo.Blittability != TypeBlittability.ReferenceType) + continue; + + // Constructors for formerly static types should be private + var attributes = type.DefaultAttributes.HasFlag(TypeAttributes.Abstract) && type.DefaultAttributes.HasFlag(TypeAttributes.Sealed) + ? MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.SpecialName + : MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName; + + var constructor = new InjectedMethodAnalysisContext( + type, + ".ctor", + appContext.SystemTypes.SystemVoidType, + attributes, + [objectPointerType]) + { + IsInjected = true, + }; + type.Methods.Add(constructor); + + type.PointerConstructor = constructor; + } + } + + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly) + continue; + + foreach (var type in assembly.Types) + { + var constructor = type.PointerConstructor; + if (constructor is null) + continue; + + var baseType = type.BaseType; + if (baseType is null) + continue; + + MethodAnalysisContext? baseConstructor; + if (baseType is GenericInstanceTypeAnalysisContext genericInstanceType) + { + var m = genericInstanceType.GenericType.PointerConstructor; + if (m is null) + continue; + baseConstructor = new ConcreteGenericMethodAnalysisContext(m, genericInstanceType.GenericArguments, []); + } + else + { + baseConstructor = baseType.PointerConstructor; + if (baseConstructor is null) + continue; + } + + var methodBody = new NativeMethodBody() + { + Instructions = [ + new Instruction(OpCodes.Ldarg_0), + new Instruction(OpCodes.Ldarg_1), + new Instruction(OpCodes.Call, baseConstructor), + new Instruction(OpCodes.Ret) + ] + }; + constructor.PutExtraData(methodBody); + } + } + } +} diff --git a/Il2CppInterop.Generator/PrimitiveImplicitConversionProcessingLayer.cs b/Il2CppInterop.Generator/PrimitiveImplicitConversionProcessingLayer.cs new file mode 100644 index 00000000..ccf44988 --- /dev/null +++ b/Il2CppInterop.Generator/PrimitiveImplicitConversionProcessingLayer.cs @@ -0,0 +1,193 @@ +using System.Diagnostics; +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; +using Il2CppInterop.Runtime; +using Il2CppInterop.Runtime.InteropTypes; + +namespace Il2CppInterop.Generator; + +public class PrimitiveImplicitConversionProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Id => "primitive_implicit_conversions"; + public override string Name => "Primitive Implicit Conversions"; + + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var il2CppMscorlib = appContext.Il2CppMscorlib; + var mscorlib = appContext.Mscorlib; + + // Il2CppSystem.String + { + var il2CppType = il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.String"); + var monoType = mscorlib.GetTypeByFullNameOrThrow("System.String"); + var typeInfo = il2CppType.GetExtraData()!; + foreach (var instanceField in typeInfo.InstanceFields) + { + il2CppType.Fields.Remove(instanceField); + } + typeInfo.InstanceFields.Clear(); + + var objectPointerType = appContext.ResolveTypeOrThrow(typeof(ObjectPointer)); + var objectPointerConversionFromIntPtr = objectPointerType.GetExplicitConversionFrom(appContext.SystemTypes.SystemIntPtrType); + + var il2CppStaticType = appContext.ResolveTypeOrThrow(typeof(IL2CPP)); + var managedStringToIl2Cpp = il2CppStaticType.Methods.First(m => m.Name == nameof(IL2CPP.ManagedStringToIl2Cpp)); + var il2CppObjectBaseToPointer = il2CppStaticType.Methods.First(m => m.Name == nameof(IL2CPP.Il2CppObjectBaseToPtr)); + var il2CppStringToManaged = il2CppStaticType.Methods.First(m => m.Name == nameof(IL2CPP.Il2CppStringToManaged)); + + // Il2Cpp -> Mono + { + var implicitConversion = new InjectedMethodAnalysisContext( + il2CppType, + "op_Implicit", + monoType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Static, + [il2CppType]); + implicitConversion.IsInjected = true; + il2CppType.Methods.Add(implicitConversion); + + var createStringNop = new Instruction(OpCodes.Nop); + + implicitConversion.PutExtraData(new TranslatedMethodBody() + { + Instructions = [ + new Instruction(OpCodes.Ldarg_0), + new Instruction(OpCodes.Call, il2CppObjectBaseToPointer), + new Instruction(OpCodes.Dup), + new Instruction(OpCodes.Brtrue, createStringNop), + new Instruction(OpCodes.Pop), + new Instruction(OpCodes.Ldnull), + new Instruction(OpCodes.Ret), + createStringNop, + new Instruction(OpCodes.Call, il2CppStringToManaged), + new Instruction(OpCodes.Ret), + ] + }); + } + + // Mono -> Il2Cpp + { + var implicitConversion = new InjectedMethodAnalysisContext( + il2CppType, + "op_Implicit", + il2CppType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Static, + [monoType]); + implicitConversion.IsInjected = true; + il2CppType.Methods.Add(implicitConversion); + + var createIl2CppStringNop = new Instruction(OpCodes.Nop); + + implicitConversion.PutExtraData(new TranslatedMethodBody() + { + Instructions = [ + new Instruction(OpCodes.Ldarg_0), + new Instruction(OpCodes.Dup), + new Instruction(OpCodes.Brtrue, createIl2CppStringNop), + new Instruction(OpCodes.Pop), + new Instruction(OpCodes.Ldnull), + new Instruction(OpCodes.Ret), + createIl2CppStringNop, + new Instruction(OpCodes.Call, managedStringToIl2Cpp), + new Instruction(OpCodes.Call, objectPointerConversionFromIntPtr), + new Instruction(OpCodes.Newobj, il2CppType.PointerConstructor!), + new Instruction(OpCodes.Ret), + ] + }); + } + } + + ReadOnlySpan<(string, string)> numericPairs = + [ + ("Il2CppSystem.SByte", "System.SByte"), + ("Il2CppSystem.Byte", "System.Byte"), + ("Il2CppSystem.Int16", "System.Int16"), + ("Il2CppSystem.UInt16", "System.UInt16"), + ("Il2CppSystem.Int32", "System.Int32"), + ("Il2CppSystem.UInt32", "System.UInt32"), + ("Il2CppSystem.Int64", "System.Int64"), + ("Il2CppSystem.UInt64", "System.UInt64"), + ("Il2CppSystem.Single", "System.Single"), + ("Il2CppSystem.Double", "System.Double"), + ("Il2CppSystem.Char", "System.Char"), + ("Il2CppSystem.Boolean", "System.Boolean"), + ("Il2CppSystem.IntPtr", "System.IntPtr"), + ("Il2CppSystem.UIntPtr", "System.UIntPtr"), + ]; + + foreach (var (il2CppTypeName, monoTypeName) in numericPairs) + { + var il2CppType = il2CppMscorlib.GetTypeByFullNameOrThrow(il2CppTypeName); + var monoType = mscorlib.GetTypeByFullNameOrThrow(monoTypeName); + var typeInfo = il2CppType.GetExtraData()!; + Debug.Assert(typeInfo.InstanceFields.Count == 1, $"Expected exactly one instance field for {il2CppTypeName}"); + var field = typeInfo.InstanceFields[0]; + field.OverrideFieldType = monoType; + + // Il2Cpp -> Mono + { + var implicitConversion = new InjectedMethodAnalysisContext( + il2CppType, + "op_Implicit", + monoType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Static, + [il2CppType]); + implicitConversion.IsInjected = true; + implicitConversion.PutExtraData(new TranslatedMethodBody() + { + Instructions = [ + new Instruction(OpCodes.Ldarg, implicitConversion.Parameters[0]), + new Instruction(OpCodes.Ldfld, field), + new Instruction(OpCodes.Ret), + ] + }); + il2CppType.Methods.Add(implicitConversion); + } + + // Mono -> Il2Cpp + { + var implicitConversion = new InjectedMethodAnalysisContext( + il2CppType, + "op_Implicit", + il2CppType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Static, + [monoType]); + implicitConversion.IsInjected = true; + implicitConversion.PutExtraData(new TranslatedMethodBody() + { + Instructions = [ + new Instruction(OpCodes.Ldarga, implicitConversion.Parameters[0]), + new Instruction(OpCodes.Conv_U), + new Instruction(OpCodes.Ldobj, il2CppType), + new Instruction(OpCodes.Ret), + ] + }); + il2CppType.Methods.Add(implicitConversion); + } + + // Mono -> Il2Cpp, ByRef + { + // Might not be necessary + + var method = new InjectedMethodAnalysisContext( + il2CppType, + "ConvertReference", + il2CppType.MakeByReferenceType(), + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, + [monoType.MakeByReferenceType()]); + method.IsInjected = true; + method.PutExtraData(new TranslatedMethodBody() + { + Instructions = [ + new Instruction(OpCodes.Ldarg_0), + new Instruction(OpCodes.Ret), + ] + }); + il2CppType.Methods.Add(method); + } + } + } + +} diff --git a/Il2CppInterop.Generator/PropertyAnalysisContextExtensions.cs b/Il2CppInterop.Generator/PropertyAnalysisContextExtensions.cs new file mode 100644 index 00000000..0def3bc5 --- /dev/null +++ b/Il2CppInterop.Generator/PropertyAnalysisContextExtensions.cs @@ -0,0 +1,17 @@ +using System.Diagnostics.CodeAnalysis; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +internal static class PropertyAnalysisContextExtensions +{ + extension(PropertyAnalysisContext property) + { + [MaybeNull] + public FieldAnalysisContext OriginalField + { + get => property.GetExtraData("OriginalField"); + set => property.PutExtraData("OriginalField", value); + } + } +} diff --git a/Il2CppInterop.Generator/PublicizerProcessingLayer.cs b/Il2CppInterop.Generator/PublicizerProcessingLayer.cs new file mode 100644 index 00000000..c5d5d6e0 --- /dev/null +++ b/Il2CppInterop.Generator/PublicizerProcessingLayer.cs @@ -0,0 +1,57 @@ +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public class PublicizerProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Id => "publicizer"; + public override string Name => "Publicizer"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly || assembly.IsInjected) + { + continue; + } + + foreach (var type in assembly.Types) + { + if (type.IsInjected) + { + continue; + } + + type.Visibility = type.DeclaringType is null ? TypeAttributes.Public : TypeAttributes.NestedPublic; + + foreach (var field in type.Fields) + { + if (!field.IsInjected) + { + field.Visibility = FieldAttributes.Public; + } + } + + foreach (var method in type.Methods) + { + if (method.Visibility != MethodAttributes.Public) + { + if (method.IsStaticConstructor || method.IsInjected) + { + continue; + } + + if (method.ImplementsAnInterfaceMethod) + { + continue; + } + + method.Visibility = MethodAttributes.Public; + } + } + } + } + } +} diff --git a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs new file mode 100644 index 00000000..f9981205 --- /dev/null +++ b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs @@ -0,0 +1,69 @@ +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Runtime; +using Il2CppInterop.Runtime.InteropTypes; +using Il2CppInterop.Runtime.InteropTypes.Arrays; + +namespace Il2CppInterop.Generator; + +public class ReferenceAssemblyInjectionProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Id => "reference_assembly_injector"; + public override string Name => "Inject required references into the Cpp2IL context system"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + Type[] il2CppInteropCommonTypes = + [ + typeof(ObjectPointer), + ]; + InjectTypes(appContext, typeof(ObjectPointer).Assembly, il2CppInteropCommonTypes); + + Type[] il2CppInteropRuntimeTypes = + [ + typeof(Il2CppArrayBase), + typeof(Il2CppArrayBase<>), + typeof(Il2CppUnmanagedArray<>), + typeof(Il2CppStringArray), + typeof(Il2CppException), + typeof(IL2CPP), + typeof(Il2CppClassPointerStore<>), + typeof(DelegateSupport), + typeof(Pointer<>), + typeof(ByReference<>), + typeof(Il2CppType), + typeof(FieldAccessHelper), + typeof(IIl2CppObjectBase), + typeof(IIl2CppValueType), + typeof(IIl2CppException), + typeof(RuntimeInvokeHelper), + typeof(IIl2CppValueTypeExtensions), + ]; + InjectTypes(appContext, typeof(Il2CppArrayBase).Assembly, il2CppInteropRuntimeTypes); + } + + /// + /// Injects the given assembly and some of its types into the . + /// + /// The + /// The assembly + /// The types to be injected from . Must be in order of inheritance + private static void InjectTypes(ApplicationAnalysisContext appContext, Assembly assembly, Type[] types) + { + var il2CppInteropRuntime = appContext.InjectAssembly(assembly); + + il2CppInteropRuntime.IsReferenceAssembly = true; + + var typeContextArray = new InjectedTypeAnalysisContext[types.Length]; + + for (var i = 0; i < types.Length; i++) + { + typeContextArray[i] = il2CppInteropRuntime.InjectType(types[i]); + } + + for (var index = 0; index < types.Length; index++) + { + typeContextArray[index].InjectContentFromSourceType(); + } + } +} diff --git a/Il2CppInterop.Generator/ReferenceReplacementProcessingLayer.cs b/Il2CppInterop.Generator/ReferenceReplacementProcessingLayer.cs new file mode 100644 index 00000000..43e9a1a4 --- /dev/null +++ b/Il2CppInterop.Generator/ReferenceReplacementProcessingLayer.cs @@ -0,0 +1,124 @@ +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public class ReferenceReplacementProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Id => "reference_replacement"; + public override string Name => "Reference Replacement"; + + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var il2CppMscorlib = appContext.AssembliesByName["Il2Cppmscorlib"]; + var mscorlib = appContext.AssembliesByName["mscorlib"]; + + var monoSystemObject = mscorlib.GetTypeByFullNameOrThrow("System.Object"); + var monoSystemValueType = mscorlib.GetTypeByFullNameOrThrow("System.ValueType"); + var monoSystemVoid = mscorlib.GetTypeByFullNameOrThrow("System.Void"); + + var il2CppSystemObject = il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Object"); + var il2CppSystemVoid = il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Void"); + var il2CppSystemEnum = il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Enum"); + var il2CppSystemValueType = il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.ValueType"); + + var visitor = TypeConversionVisitor.Create(appContext); + + il2CppSystemObject.OverrideBaseType = monoSystemObject; + + foreach (var type in appContext.AllTypes) + { + if (type.CustomAttributeAssembly.IsReferenceAssembly) + { + continue; + } + + if (type.IsStatic || type.IsInterface) + { + type.OverrideBaseType = monoSystemObject; + } + else if (type == il2CppSystemObject || type == il2CppSystemEnum || type == il2CppSystemValueType) + { + } + else if (type.BaseType is null || type.BaseType == il2CppSystemObject) + { + type.OverrideBaseType = il2CppSystemObject; + } + else if (type.BaseType == il2CppSystemValueType) + { + type.OverrideBaseType = monoSystemValueType; + } + else if (type.BaseType == il2CppSystemEnum) + { + type.OverrideBaseType = monoSystemValueType; + } + else + { + type.OverrideBaseType = visitor.Replace(type.BaseType); + } + + visitor.Replace(type.InterfaceContexts); + foreach (var genericParameter in type.GenericParameters) + { + visitor.Replace(genericParameter.ConstraintTypes); + } + + foreach (var field in type.Fields) + { + field.OverrideFieldType = visitor.Replace(field.FieldType); + } + + foreach (var method in type.Methods) + { + if (method.ReturnType == il2CppSystemVoid) + { + // Special case for void return type. + method.OverrideReturnType = monoSystemVoid; + } + else + { + method.OverrideReturnType = visitor.Replace(method.ReturnType); + } + foreach (var parameter in method.Parameters) + { + parameter.OverrideParameterType = ReplaceExceptTopLevelByRef(visitor, parameter.ParameterType); + } + foreach (var genericParameter in method.GenericParameters) + { + visitor.Replace(genericParameter.ConstraintTypes); + } + } + + foreach (var property in type.Properties) + { + property.OverridePropertyType = ReplaceExceptTopLevelByRef(visitor, property.PropertyType); + } + + foreach (var @event in type.Events) + { + @event.OverrideEventType = visitor.Replace(@event.EventType); + } + } + } + + private static TypeAnalysisContext ReplaceExceptTopLevelByRef(TypeConversionVisitor visitor, TypeAnalysisContext type) + { + if (type is ByRefTypeAnalysisContext byRefType) + { + var elementType = byRefType.ElementType; + var replacedElementType = visitor.Replace(elementType); + if (replacedElementType == elementType) + { + return byRefType; + } + else + { + return replacedElementType.MakeByReferenceType(); + } + } + else + { + return visitor.Replace(type); + } + } +} diff --git a/Il2CppInterop.Generator/StaticConstructorProcessingLayer.cs b/Il2CppInterop.Generator/StaticConstructorProcessingLayer.cs new file mode 100644 index 00000000..e021f35b --- /dev/null +++ b/Il2CppInterop.Generator/StaticConstructorProcessingLayer.cs @@ -0,0 +1,50 @@ +using System.Diagnostics; +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator; + +public class StaticConstructorProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Static Constructor Processor"; + public override string Id => "static_constructor_processor"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + foreach (var type in appContext.AllTypes) + { + var instructions = type.StaticConstructorInstructions; + if (instructions is null or { Count: 0 }) + continue; + + for (var i = type.Methods.Count - 1; i >= 0; i--) + { + if (type.Methods[i].IsStaticConstructor) + { + Debug.Fail($"Type {type.FullName} already has a static constructor defined. It should have been renamed in an earlier processing layer."); + } + } + + // Add a final instruction to return from the static constructor. + instructions.Add(new Instruction(OpCodes.Ret)); + + var staticConstructor = new InjectedMethodAnalysisContext( + type, + ".cctor", + type.AppContext.SystemTypes.SystemVoidType, + MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, + []) + { + IsInjected = true + }; + type.Methods.Add(staticConstructor); + + var nativeMethodBody = new NativeMethodBody() + { + Instructions = instructions, + }; + staticConstructor.PutExtraData(nativeMethodBody); + } + } +} diff --git a/Il2CppInterop.Generator/TranslatedMethodBody.cs b/Il2CppInterop.Generator/TranslatedMethodBody.cs new file mode 100644 index 00000000..6b88785d --- /dev/null +++ b/Il2CppInterop.Generator/TranslatedMethodBody.cs @@ -0,0 +1,751 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using AsmResolver.PE.DotNet.Cil; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; +using Il2CppInterop.Runtime; +using Il2CppInterop.Runtime.InteropTypes.Arrays; + +namespace Il2CppInterop.Generator; + +public class TranslatedMethodBody : MethodBodyBase +{ + public static bool MaybeStoreTranslatedMethodBody(MethodAnalysisContext method) + { + if (TryTranslateOriginalMethodBody(method, out var translatedMethodBody)) + { + method.PutExtraData(translatedMethodBody); + return true; + } + else + { + return false; + } + } + + // Notes: + // + // There are subtle flaws in this implementation, in regards to exception handling. + // Certain instructions (eg `castclass` and `callvirt`) can throw exceptions. + // These exceptions will have System types, not Il2Cpp types. + // + // + + private static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodContext, [NotNullWhen(true)] out TranslatedMethodBody? translatedMethodBody) + { + if (!methodContext.TryGetExtraData(out OriginalMethodBody? originalMethodBody)) + { + translatedMethodBody = null; + return false; + } + + TypeConversionVisitor visitor = TypeConversionVisitor.Create(methodContext.AppContext); + + var localVariableList = new List(originalMethodBody.LocalVariables.Count); + var localVariableDictionary = new Dictionary(originalMethodBody.LocalVariables.Count); + foreach (var originalLocalVariable in originalMethodBody.LocalVariables) + { + var translatedLocalVariable = new LocalVariable + { + Type = visitor.Replace(originalLocalVariable.Type), + }; + localVariableList.Add(translatedLocalVariable); + localVariableDictionary.Add(originalLocalVariable, translatedLocalVariable); + } + + var instructionDictionary = new Dictionary(originalMethodBody.Instructions.Count); + foreach (var originalInstruction in originalMethodBody.Instructions) + { + instructionDictionary[originalInstruction] = new Instruction(); + } + + var translatedInstructions = new List(originalMethodBody.Instructions.Count); + foreach (var originalInstruction in originalMethodBody.Instructions) + { + var translatedInstruction = instructionDictionary[originalInstruction]; + + translatedInstructions.Add(translatedInstruction); + + var originalCode = originalInstruction.Code; + var originalOperand = originalInstruction.Operand; + + if (originalOperand is null) + { + switch (originalCode.Code) + { + case CilCode.Arglist: + return False(out translatedMethodBody); + + case CilCode.Ldlen: + // This is Il2CppArrayBase.Length + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext.ResolveTypeOrThrow(typeof(Il2CppArrayBase)).GetMethodByName($"get_{nameof(Il2CppArrayBase.Length)}"); + } + break; + + case CilCode.Ldelem_I1: + // This is Il2CppArrayBase.LoadElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.LoadElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemSByteType]); + } + break; + + case CilCode.Ldelem_I2: + // This is Il2CppArrayBase.LoadElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.LoadElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemInt16Type]); + } + break; + + case CilCode.Ldelem_I4: + // This is Il2CppArrayBase.LoadElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.LoadElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemInt32Type]); + } + break; + + case CilCode.Ldelem_I8: + // This is Il2CppArrayBase.LoadElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.LoadElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemInt64Type]); + } + break; + + case CilCode.Ldelem_U1: + // This is Il2CppArrayBase.LoadElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.LoadElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemByteType]); + } + break; + + case CilCode.Ldelem_U2: + // This is Il2CppArrayBase.LoadElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.LoadElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemUInt16Type]); + } + break; + + case CilCode.Ldelem_U4: + // This is Il2CppArrayBase.LoadElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.LoadElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemUInt32Type]); + } + break; + + case CilCode.Ldelem_I: + // This is Il2CppArrayBase.LoadElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.LoadElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemIntPtrType]); + } + break; + + case CilCode.Ldelem_R4: + // This is Il2CppArrayBase.LoadElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.LoadElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemSingleType]); + } + break; + + case CilCode.Ldelem_R8: + // This is Il2CppArrayBase.LoadElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.LoadElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemDoubleType]); + } + break; + + case CilCode.Stelem_I1: + // This is Il2CppArrayBase.StoreElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.StoreElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemSByteType]); + } + break; + + case CilCode.Stelem_I2: + // This is Il2CppArrayBase.StoreElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.StoreElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemInt16Type]); + } + break; + + case CilCode.Stelem_I4: + // This is Il2CppArrayBase.StoreElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.StoreElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemInt32Type]); + } + break; + + case CilCode.Stelem_I8: + // This is Il2CppArrayBase.StoreElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.StoreElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemInt64Type]); + } + break; + + case CilCode.Stelem_I: + // This is Il2CppArrayBase.StoreElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.StoreElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemIntPtrType]); + } + break; + + case CilCode.Stelem_R4: + // This is Il2CppArrayBase.StoreElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.StoreElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemSingleType]); + } + break; + + case CilCode.Stelem_R8: + // This is Il2CppArrayBase.StoreElementUnsafe + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.StoreElementUnsafe)) + .MakeGenericInstanceMethod([methodContext.AppContext.SystemTypes.SystemDoubleType]); + } + break; + + case CilCode.Ldelem_Ref: + // This is Il2CppReferenceArray.get_Item but the T is not known because the operand is null. + return False(out translatedMethodBody); + + case CilCode.Stelem_Ref: + // This is Il2CppReferenceArray.set_Item but the T is not known because the operand is null. + return False(out translatedMethodBody); + + case >= CilCode.Ldind_I1 and <= CilCode.Ldind_Ref: + // This is for by ref parameters + goto default; + + case >= CilCode.Stind_Ref and <= CilCode.Stind_R8: + // This is for by ref parameters + goto default; + + case CilCode.Refanytype: + // Not implemented yet + return False(out translatedMethodBody); + + case CilCode.Throw: + { + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext.ResolveTypeOrThrow(typeof(IIl2CppException)).GetMethodByName(nameof(IIl2CppException.CreateSystemException)); + translatedInstructions.Add(new Instruction(originalCode)); + } + break; + + case CilCode.Ret: + if (MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, methodContext.ReturnType)) + { + translatedInstruction.Code = OpCodes.Nop; + + translatedInstructions.Add(new Instruction(originalCode)); + } + else + { + translatedInstruction.Code = originalCode; + } + break; + + case CilCode.Volatile: + // This op code can be ignored. + translatedInstruction.Code = OpCodes.Nop; + break; + + default: + // nop, ldnull, ldarg_0, mul, add, etc. + translatedInstruction.Code = originalCode; + break; + } + } + else if (originalOperand is byte or sbyte or short or ushort or int or uint or long or ulong or float or double or bool or char) + { + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = originalOperand; + } + else if (originalOperand is string) + { + Debug.Assert(originalCode == OpCodes.Ldstr); + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = originalOperand; + + MonoIl2CppConversion.AddMonoToIl2CppStringConversion(translatedInstructions, methodContext.AppContext); + } + else if (originalOperand is IReadOnlyList labels) + { + Debug.Assert(originalCode == OpCodes.Switch); + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = ResolveLabels(labels, instructionDictionary); + } + else if (originalOperand is ILabel label) + { + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = ResolveLabel(label, instructionDictionary); + } + else if (originalOperand is This) + { + Debug.Assert(originalCode == OpCodes.Ldarg); + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = originalOperand; + } + else if (originalOperand is ParameterAnalysisContext parameter) + { + if (originalCode == OpCodes.Ldarg) + { + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = originalOperand; + MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, parameter.ParameterType); + } + else if (originalCode == OpCodes.Starg) + { + if (MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, parameter.ParameterType)) + { + translatedInstruction.Code = OpCodes.Nop; + + translatedInstructions.Add(new Instruction(originalCode, originalOperand)); + } + else + { + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = originalOperand; + } + } + else if (originalCode == OpCodes.Ldarga) + { + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = originalOperand; + } + else + { + Debug.Fail($"Unexpected CIL code: {originalCode}"); + return False(out translatedMethodBody); + } + } + else if (originalOperand is LocalVariable localVariable) + { + var translatedLocalVariable = localVariableDictionary[localVariable]; + + if (originalCode == OpCodes.Ldloc) + { + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = translatedLocalVariable; + MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, translatedLocalVariable.Type); + } + else if (originalCode == OpCodes.Stloc) + { + if (MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, translatedLocalVariable.Type)) + { + translatedInstruction.Code = OpCodes.Nop; + + translatedInstructions.Add(new Instruction(originalCode, translatedLocalVariable)); + } + else + { + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = translatedLocalVariable; + } + } + else if (originalCode == OpCodes.Ldloca) + { + // Everything is fine. No conversion needed. + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = translatedLocalVariable; + } + else + { + Debug.Fail($"Unexpected CIL code: {originalCode}"); + return False(out translatedMethodBody); + } + } + else if (originalOperand is TypeAnalysisContext type) + { + var translatedType = visitor.Replace(type); + + if (originalCode.Code is CilCode.Castclass or CilCode.Constrained or CilCode.Cpobj or CilCode.Initobj or CilCode.Isinst or CilCode.Ldobj or CilCode.Sizeof or CilCode.Stobj or CilCode.Unbox_Any) + { + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = translatedType; + } + else if (originalCode == OpCodes.Box) + { + if (MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, translatedType)) + { + translatedInstruction.Code = OpCodes.Nop; + + translatedInstructions.Add(new Instruction(originalCode, translatedType)); + } + else + { + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = translatedType; + } + } + else if (originalCode == OpCodes.Unbox) + { + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = translatedType; + MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, translatedType); + } + else if (originalCode == OpCodes.Ldtoken) + { + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = translatedType; + + translatedInstructions.Add(new Instruction(OpCodes.Call, methodContext.AppContext.SystemTypes.SystemTypeType.GetMethodByName(nameof(Type.GetTypeFromHandle)))); + + var systemTypeToIl2CppTypeMethod = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppType)) + .Methods.First(m => m.Name == nameof(Il2CppType.From) && m.Parameters.Count == 1); + + translatedInstructions.Add(new Instruction(OpCodes.Call, systemTypeToIl2CppTypeMethod)); + + var getTypeHandleMethod = methodContext.AppContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Type").GetMethodByName("get_TypeHandle"); + + translatedInstructions.Add(new Instruction(OpCodes.Callvirt, getTypeHandleMethod)); + } + else if (originalCode == OpCodes.Newarr) + { + // Not implemented yet + return False(out translatedMethodBody); + } + else if (originalCode == OpCodes.Ldelem) + { + var genericMethod = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase<>)) + .GetMethodByName("get_Item"); + translatedInstruction.Code = OpCodes.Callvirt; + translatedInstruction.Operand = new ConcreteGenericMethodAnalysisContext(genericMethod, [translatedType], []); + MonoIl2CppConversion. + AddIl2CppToMonoConversion(translatedInstructions, translatedType); + } + else if (originalCode == OpCodes.Stelem) + { + translatedInstruction.Code = OpCodes.Nop; + + var genericMethod = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase<>)) + .GetMethodByName("set_Item"); + var concreteGenericMethod = new ConcreteGenericMethodAnalysisContext(genericMethod, [translatedType], []); + MonoIl2CppConversion. + AddMonoToIl2CppConversion(translatedInstructions, translatedType); + + translatedInstructions.Add(new Instruction(OpCodes.Callvirt, concreteGenericMethod)); + } + else if (originalCode == OpCodes.Ldelema) + { + // Not implemented yet + return False(out translatedMethodBody); + } + else if (originalCode.Code is CilCode.Mkrefany or CilCode.Refanyval) + { + // Not implemented yet + return False(out translatedMethodBody); + } + else + { + Debug.Fail($"Unexpected CIL code: {originalCode}"); + return False(out translatedMethodBody); + } + } + else if (originalOperand is MethodAnalysisContext method) + { + if (originalCode.Code is CilCode.Call or CilCode.Callvirt or CilCode.Newobj) + { + translatedInstruction.Code = OpCodes.Nop; + + var temporaryVariables = new LocalVariable[method.Parameters.Count]; + for (var i = method.Parameters.Count - 1; i >= 0; i--) // Order matters + { + var methodParameter = method.Parameters[i]; + MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, methodParameter.ParameterType); + var temporaryVariable = new LocalVariable + { + Type = methodParameter.ParameterType, + }; + translatedInstructions.Add(new Instruction(OpCodes.Stloc, temporaryVariable)); + + temporaryVariables[i] = temporaryVariable; + localVariableList.Add(temporaryVariable); + } + + foreach (var temporaryVariable in temporaryVariables) + { + translatedInstructions.Add(new Instruction(OpCodes.Ldloc, temporaryVariable)); + } + + // Todo: If this is an instance method on Il2CppSystem Object/ValueType/Enum, + // we need to redirect it to the corresponding IObject/IValueType/IEnum method. + translatedInstructions.Add(new Instruction(originalCode, method)); + MonoIl2CppConversion. + AddIl2CppToMonoConversion(translatedInstructions, method.ReturnType); + } + else if (originalCode == OpCodes.Ldtoken) + { + // Not sure this can happen in normal CIL code, but we check for it just in case. + return False(out translatedMethodBody); + } + else if (originalCode == OpCodes.Ldftn || originalCode == OpCodes.Ldvirtftn) + { + return False(out translatedMethodBody); + } + else if (originalCode == OpCodes.Jmp) + { + // This shouldn't happen in normal CIL code, but we check for it just in case. + return False(out translatedMethodBody); + } + else + { + Debug.Fail($"Unexpected CIL code: {originalCode}"); + return False(out translatedMethodBody); + } + } + else if (originalOperand is FieldAnalysisContext field) + { + var baseField = (field as ConcreteGenericFieldAnalysisContext)?.BaseFieldContext ?? field; + + if (originalCode == OpCodes.Ldfld || originalCode == OpCodes.Ldsfld) + { + // Load field value + if (baseField.PropertyAccessor is not null) + { + var accessorMethod = field is ConcreteGenericFieldAnalysisContext + ? new ConcreteGenericMethodAnalysisContext(baseField.PropertyAccessor!.Getter!, ((GenericInstanceTypeAnalysisContext)field.DeclaringType).GenericArguments, []) + : baseField.PropertyAccessor!.Getter!; + translatedInstruction.Code = originalCode == OpCodes.Ldfld ? OpCodes.Callvirt : OpCodes.Call; + translatedInstruction.Operand = accessorMethod; + } + else if (baseField.DeclaringType.Fields.Contains(baseField)) + { + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = originalOperand; + } + else + { + // This should only occur for special cases like String::_firstChar. + return False(out translatedMethodBody); + } + + MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, field.FieldType); + } + else if (originalCode == OpCodes.Stfld || originalCode == OpCodes.Stsfld) + { + // Store field value + + translatedInstruction.Code = OpCodes.Nop; + MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, field.FieldType); + + if (baseField.PropertyAccessor is not null) + { + var accessorMethod = field is ConcreteGenericFieldAnalysisContext + ? new ConcreteGenericMethodAnalysisContext(baseField.PropertyAccessor!.Setter!, ((GenericInstanceTypeAnalysisContext)field.DeclaringType).GenericArguments, []) + : baseField.PropertyAccessor!.Setter!; + + translatedInstructions.Add(new Instruction(originalCode == OpCodes.Stfld ? OpCodes.Callvirt : OpCodes.Call, accessorMethod)); + } + else if (baseField.DeclaringType.Fields.Contains(baseField)) + { + translatedInstructions.Add(new Instruction(originalCode, originalOperand)); + } + else + { + // This should only occur for special cases like String::_firstChar. + return False(out translatedMethodBody); + } + } + else if (originalCode == OpCodes.Ldflda || originalCode == OpCodes.Ldsflda) + { + // Load field address + // Not implemented yet + return False(out translatedMethodBody); + } + else if (originalCode == OpCodes.Ldtoken) + { + // Not sure this can happen in normal CIL code, but we check for it just in case. + return False(out translatedMethodBody); + } + else + { + Debug.Fail($"Unexpected CIL code: {originalCode}"); + return False(out translatedMethodBody); + } + } + else if (originalOperand is MultiDimensionalArrayMethod) + { + // Not implemented yet + return False(out translatedMethodBody); + } + else + { + return False(out translatedMethodBody); + } + } + + var exceptionHandlers = new ExceptionHandler[originalMethodBody.ExceptionHandlers.Count]; + for (var i = 0; i < exceptionHandlers.Length; i++) + { + var originalExceptionHandler = originalMethodBody.ExceptionHandlers[i]; + + var handlerStart = ResolveLabel(originalExceptionHandler.HandlerStart, instructionDictionary); + + TypeAnalysisContext? exceptionType; + if (originalExceptionHandler.ExceptionType is null) + { + exceptionType = null; + } + else if (IsIl2CppPrimitive(originalExceptionHandler.ExceptionType, "Object")) + { + exceptionType = methodContext.AppContext.SystemTypes.SystemObjectType; + } + else + { + if (originalExceptionHandler.ExceptionType is GenericInstanceTypeAnalysisContext genericInstance) + { + exceptionType = genericInstance.GenericType.SystemExceptionType!.MakeGenericInstanceType(genericInstance.GenericArguments); + } + else + { + exceptionType = originalExceptionHandler.ExceptionType.SystemExceptionType; + Debug.Assert(exceptionType is not null); + } + + // The system exception wrapper contains a reference to the underlying Il2Cpp object. + // We need to load the object reference after entering the exception handler. + + Debug.Assert(handlerStart is Instruction); + var handlerStartIndex = translatedInstructions.IndexOf((Instruction)handlerStart); + + var loadObjectInstruction = new Instruction(OpCodes.Ldfld, methodContext.AppContext.ResolveTypeOrThrow(typeof(Il2CppException)).GetFieldByName(nameof(Il2CppException.Il2cppObject))); + var castInstruction = new Instruction(OpCodes.Castclass, originalExceptionHandler.ExceptionType); + translatedInstructions.Insert(handlerStartIndex, loadObjectInstruction); + translatedInstructions.Insert(handlerStartIndex + 1, castInstruction); + + handlerStart = loadObjectInstruction; + } + + var translatedExceptionHandler = new ExceptionHandler + { + HandlerType = originalExceptionHandler.HandlerType, + TryStart = ResolveLabel(originalExceptionHandler.TryStart, instructionDictionary), + TryEnd = ResolveLabel(originalExceptionHandler.TryEnd, instructionDictionary), + HandlerStart = handlerStart, + HandlerEnd = ResolveLabel(originalExceptionHandler.HandlerEnd, instructionDictionary), + FilterStart = ResolveLabel(originalExceptionHandler.FilterStart, instructionDictionary), + ExceptionType = exceptionType, + }; + exceptionHandlers[i] = translatedExceptionHandler; + } + + translatedMethodBody = new TranslatedMethodBody + { + Instructions = translatedInstructions, + LocalVariables = localVariableList, + ExceptionHandlers = exceptionHandlers, + }; + return true; + + static ILabel[] ResolveLabels(IReadOnlyList labels, Dictionary instructionDictionary) + { + var resolvedLabels = new ILabel[labels.Count]; + for (var i = 0; i < labels.Count; i++) + { + resolvedLabels[i] = ResolveLabel(labels[i], instructionDictionary); + } + return resolvedLabels; + } + + [return: NotNullIfNotNull(nameof(label))] + static ILabel? ResolveLabel(ILabel? label, Dictionary instructionDictionary) + { + if (label is null or EndLabel) + return label; + + return instructionDictionary[(Instruction)label]; + } + + static bool False([NotNullWhen(true)] out TranslatedMethodBody? translatedMethodBody) + { + translatedMethodBody = null; + return false; + } + } + + private static bool IsIl2CppPrimitive(TypeAnalysisContext type, string name) + { + if (type is ReferencedTypeAnalysisContext) + return false; + + if (type.DeclaringType is not null) + return false; + + if (type.DeclaringAssembly != type.AppContext.Il2CppMscorlib) + return false; + + return type.Namespace == "Il2CppSystem" && type.Name == name; + } +} diff --git a/Il2CppInterop.Generator/TypeAnalysisContextEqualityComparer.cs b/Il2CppInterop.Generator/TypeAnalysisContextEqualityComparer.cs new file mode 100644 index 00000000..b4d69a0f --- /dev/null +++ b/Il2CppInterop.Generator/TypeAnalysisContextEqualityComparer.cs @@ -0,0 +1,364 @@ +using AsmResolver.DotNet; +using AsmResolver.DotNet.Signatures; +using Cpp2IL.Core.Model.Contexts; +using LibCpp2IL.BinaryStructures; + +namespace Il2CppInterop.Generator; + +public class TypeAnalysisContextEqualityComparer : IEqualityComparer, IEqualityComparer, IEqualityComparer, IEqualityComparer, IEqualityComparer, IEqualityComparer, IEqualityComparer, IEqualityComparer, IEqualityComparer, IEqualityComparer, IEqualityComparer +{ + public static TypeAnalysisContextEqualityComparer Instance { get; } = new(); + + public bool Equals(TypeAnalysisContext? x, TypeAnalysisContext? y) + { + if (ReferenceEquals(x, y)) + return true; + if (x is null || y is null) + return false; + if (x.Type != y.Type) + return false; + + return x.Type switch + { + Il2CppTypeEnum.IL2CPP_TYPE_ARRAY => Equals(x as ArrayTypeAnalysisContext, y as ArrayTypeAnalysisContext), + Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY => Equals(x as SzArrayTypeAnalysisContext, y as SzArrayTypeAnalysisContext), + Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST => Equals(x as GenericInstanceTypeAnalysisContext, y as GenericInstanceTypeAnalysisContext), + Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_MVAR => Equals(x as GenericParameterTypeAnalysisContext, y as GenericParameterTypeAnalysisContext), + Il2CppTypeEnum.IL2CPP_TYPE_SENTINEL => Equals(x as SentinelTypeAnalysisContext, y as SentinelTypeAnalysisContext), + Il2CppTypeEnum.IL2CPP_TYPE_PINNED => Equals(x as PinnedTypeAnalysisContext, y as PinnedTypeAnalysisContext), + Il2CppTypeEnum.IL2CPP_TYPE_PTR => Equals(x as PointerTypeAnalysisContext, y as PointerTypeAnalysisContext), + Il2CppTypeEnum.IL2CPP_TYPE_BYREF => Equals(x as ByRefTypeAnalysisContext, y as ByRefTypeAnalysisContext), + Il2CppTypeEnum.IL2CPP_TYPE_BOXED => Equals(x as BoxedTypeAnalysisContext, y as BoxedTypeAnalysisContext), + Il2CppTypeEnum.IL2CPP_TYPE_CMOD_OPT or Il2CppTypeEnum.IL2CPP_TYPE_CMOD_REQD => Equals(x as CustomModifierTypeAnalysisContext, y as CustomModifierTypeAnalysisContext), + Il2CppTypeEnum.IL2CPP_TYPE_FNPTR => false,// Function pointers are not part of the Cpp2IL context system + _ => false,// Type definitions have unique instances + }; + } + public bool Equals(GenericInstanceTypeAnalysisContext? x, GenericInstanceTypeAnalysisContext? y) + { + if (ReferenceEquals(x, y)) + return true; + if (x is null || y is null) + return false; + + return Equals(x.GenericType, y.GenericType) && x.GenericArguments.SequenceEqual(y.GenericArguments, this); + } + public bool Equals(GenericParameterTypeAnalysisContext? x, GenericParameterTypeAnalysisContext? y) + { + return ReferenceEquals(x, y); // Generic parameters have unique instances + } + public bool Equals(SentinelTypeAnalysisContext? x, SentinelTypeAnalysisContext? y) + { + if (x is null || y is null) + return ReferenceEquals(x, y); + + return true; // Sentinel types are always equal + } + public bool Equals(CustomModifierTypeAnalysisContext? x, CustomModifierTypeAnalysisContext? y) + { + if (ReferenceEquals(x, y)) + return true; + if (x is null || y is null) + return false; + + return Equals(x.ElementType, y.ElementType) && Equals(x.ModifierType, y.ModifierType); + } + public bool Equals(PointerTypeAnalysisContext? x, PointerTypeAnalysisContext? y) + { + if (ReferenceEquals(x, y)) + return true; + if (x is null || y is null) + return false; + + return Equals(x.ElementType, y.ElementType); + } + public bool Equals(ByRefTypeAnalysisContext? x, ByRefTypeAnalysisContext? y) + { + if (ReferenceEquals(x, y)) + return true; + if (x is null || y is null) + return false; + + return Equals(x.ElementType, y.ElementType); + } + public bool Equals(BoxedTypeAnalysisContext? x, BoxedTypeAnalysisContext? y) + { + if (ReferenceEquals(x, y)) + return true; + if (x is null || y is null) + return false; + + return Equals(x.ElementType, y.ElementType); + } + public bool Equals(SzArrayTypeAnalysisContext? x, SzArrayTypeAnalysisContext? y) + { + if (ReferenceEquals(x, y)) + return true; + if (x is null || y is null) + return false; + + return Equals(x.ElementType, y.ElementType); + } + public bool Equals(ArrayTypeAnalysisContext? x, ArrayTypeAnalysisContext? y) + { + if (ReferenceEquals(x, y)) + return true; + if (x is null || y is null) + return false; + + return Equals(x.ElementType, y.ElementType) && x.Rank == y.Rank; + } + public bool Equals(PinnedTypeAnalysisContext? x, PinnedTypeAnalysisContext? y) + { + if (ReferenceEquals(x, y)) + return true; + if (x is null || y is null) + return false; + + return Equals(x.ElementType, y.ElementType); + } + + public int GetHashCode(TypeAnalysisContext type) => type.Type switch + { + Il2CppTypeEnum.IL2CPP_TYPE_ARRAY => GetHashCode((ArrayTypeAnalysisContext)type), + Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY => GetHashCode((SzArrayTypeAnalysisContext)type), + Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST => GetHashCode((GenericInstanceTypeAnalysisContext)type), + Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_MVAR => GetHashCode((GenericParameterTypeAnalysisContext)type), + Il2CppTypeEnum.IL2CPP_TYPE_SENTINEL => GetHashCode((SentinelTypeAnalysisContext)type), + Il2CppTypeEnum.IL2CPP_TYPE_PINNED => GetHashCode((PinnedTypeAnalysisContext)type), + Il2CppTypeEnum.IL2CPP_TYPE_PTR => GetHashCode((PointerTypeAnalysisContext)type), + Il2CppTypeEnum.IL2CPP_TYPE_BYREF => GetHashCode((ByRefTypeAnalysisContext)type), + Il2CppTypeEnum.IL2CPP_TYPE_BOXED => GetHashCode((BoxedTypeAnalysisContext)type), + Il2CppTypeEnum.IL2CPP_TYPE_CMOD_OPT or Il2CppTypeEnum.IL2CPP_TYPE_CMOD_REQD => GetHashCode((CustomModifierTypeAnalysisContext)type), + Il2CppTypeEnum.IL2CPP_TYPE_FNPTR => 0, // Function pointers are not part of the Cpp2IL context system + _ => HashCode.Combine(type.Type, type), // Type definitions have unique instances + }; + + public int GetHashCode(GenericInstanceTypeAnalysisContext type) + { + HashCode hash = new HashCode(); + hash.Add(type.Type); + hash.Add(type.GenericType, this); + foreach (var genericArgument in type.GenericArguments) + { + hash.Add(genericArgument, this); + } + return hash.ToHashCode(); + } + + public int GetHashCode(GenericParameterTypeAnalysisContext type) + { + return HashCode.Combine(type.Type, type); // Generic parameters have unique instances, so we can use the instance itself as the hash code. + } + + public int GetHashCode(SentinelTypeAnalysisContext type) + { + return HashCode.Combine(type.Type); + } + + public int GetHashCode(CustomModifierTypeAnalysisContext type) + { + HashCode hash = new HashCode(); + hash.Add(type.Type); + hash.Add(type.ElementType, this); + hash.Add(type.ModifierType, this); + return hash.ToHashCode(); + } + + public int GetHashCode(PointerTypeAnalysisContext type) + { + HashCode hash = new HashCode(); + hash.Add(type.Type); + hash.Add(type.ElementType, this); + return hash.ToHashCode(); + } + + public int GetHashCode(ByRefTypeAnalysisContext type) + { + HashCode hash = new HashCode(); + hash.Add(type.Type); + hash.Add(type.ElementType, this); + return hash.ToHashCode(); + } + + public int GetHashCode(BoxedTypeAnalysisContext type) + { + HashCode hash = new HashCode(); + hash.Add(type.Type); + hash.Add(type.ElementType, this); + return hash.ToHashCode(); + } + + public int GetHashCode(SzArrayTypeAnalysisContext type) + { + HashCode hash = new HashCode(); + hash.Add(type.Type); + hash.Add(type.ElementType, this); + return hash.ToHashCode(); + } + + public int GetHashCode(ArrayTypeAnalysisContext type) + { + HashCode hash = new HashCode(); + hash.Add(type.Type); + hash.Add(type.ElementType, this); + hash.Add(type.Rank); + return hash.ToHashCode(); + } + + public int GetHashCode(PinnedTypeAnalysisContext type) + { + HashCode hash = new HashCode(); + hash.Add(type.Type); + hash.Add(type.ElementType, this); + return hash.ToHashCode(); + } + + public bool Equals(TypeAnalysisContext? x, TypeSignature? y) + { + if (x is null) + return y is null; + if (y is null) + return false; + + return x.Type switch + { + Il2CppTypeEnum.IL2CPP_TYPE_ARRAY => Equals(x as ArrayTypeAnalysisContext, y as ArrayTypeSignature), + Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY => Equals(x as SzArrayTypeAnalysisContext, y as SzArrayTypeSignature), + Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST => Equals(x as GenericInstanceTypeAnalysisContext, y as GenericInstanceTypeSignature), + Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_MVAR => Equals(x as GenericParameterTypeAnalysisContext, y as GenericParameterSignature), + Il2CppTypeEnum.IL2CPP_TYPE_SENTINEL => Equals(x as SentinelTypeAnalysisContext, y as SentinelTypeSignature), + Il2CppTypeEnum.IL2CPP_TYPE_PINNED => Equals(x as PinnedTypeAnalysisContext, y as PinnedTypeSignature), + Il2CppTypeEnum.IL2CPP_TYPE_PTR => Equals(x as PointerTypeAnalysisContext, y as PointerTypeSignature), + Il2CppTypeEnum.IL2CPP_TYPE_BYREF => Equals(x as ByRefTypeAnalysisContext, y as ByReferenceTypeSignature), + Il2CppTypeEnum.IL2CPP_TYPE_BOXED => Equals(x as BoxedTypeAnalysisContext, y as BoxedTypeSignature), + Il2CppTypeEnum.IL2CPP_TYPE_CMOD_OPT or Il2CppTypeEnum.IL2CPP_TYPE_CMOD_REQD => Equals(x as CustomModifierTypeAnalysisContext, y as CustomModifierTypeSignature), + _ => SimpleTypeEquals(x, y), + }; + + bool SimpleTypeEquals(TypeAnalysisContext x, TypeSignature y) + { + if (x.Name != y.Name || x.Namespace != y.Namespace) + return false; + + if (x.DeclaringType is not null) + return Equals(x.DeclaringType, y.DeclaringType); + else if (y.DeclaringType is not null) + return false; + + //AssemblyDescriptor assemblyDescriptor = y.Scope as AssemblyDescriptor ?? (y.Scope as ModuleReference)?. + return false; + } + } + + public bool Equals(TypeAnalysisContext? x, ITypeDescriptor? y) + { + return Equals(x, y?.ToTypeSignature()); + } + + public bool Equals(GenericInstanceTypeAnalysisContext? x, GenericInstanceTypeSignature? y) + { + if (x is null) + return y is null; + if (y is null) + return false; + if (!Equals(x.GenericType, y.GenericType)) + return false; + if (x.GenericArguments.Count != y.TypeArguments.Count) + return false; + for (var i = 0; i < x.GenericArguments.Count; i++) + { + if (!Equals(x.GenericArguments[i], y.TypeArguments[i])) + return false; + } + return true; + } + + public bool Equals(GenericParameterTypeAnalysisContext? x, GenericParameterSignature? y) + { + if (x is null) + return y is null; + if (y is null) + return false; + return x.Index == y.Index && Equals(x.Type, y.ParameterType); + } + + private static bool Equals(Il2CppTypeEnum x, GenericParameterType y) => (x, y) switch + { + (Il2CppTypeEnum.IL2CPP_TYPE_VAR, GenericParameterType.Type) => true, + (Il2CppTypeEnum.IL2CPP_TYPE_MVAR, GenericParameterType.Method) => true, + _ => false, + }; + + public bool Equals(SentinelTypeAnalysisContext? x, SentinelTypeSignature? y) + { + if (x is null) + return y is null; + if (y is null) + return false; + return true; + } + + public bool Equals(CustomModifierTypeAnalysisContext? x, CustomModifierTypeSignature? y) + { + if (x is null) + return y is null; + if (y is null) + return false; + return (x.Required == y.IsRequired) && Equals(x.ElementType, y.BaseType) && Equals(x.ModifierType, y.ModifierType); + } + + public bool Equals(PointerTypeAnalysisContext? x, PointerTypeSignature? y) + { + if (x is null) + return y is null; + if (y is null) + return false; + return Equals(x.ElementType, y.BaseType); + } + + public bool Equals(ByRefTypeAnalysisContext? x, ByReferenceTypeSignature? y) + { + if (x is null) + return y is null; + if (y is null) + return false; + return Equals(x.ElementType, y.BaseType); + } + + public bool Equals(BoxedTypeAnalysisContext? x, BoxedTypeSignature? y) + { + if (x is null) + return y is null; + if (y is null) + return false; + return Equals(x.ElementType, y.BaseType); + } + + public bool Equals(SzArrayTypeAnalysisContext? x, SzArrayTypeSignature? y) + { + if (x is null) + return y is null; + if (y is null) + return false; + return Equals(x.ElementType, y.BaseType); + } + + public bool Equals(ArrayTypeAnalysisContext? x, ArrayTypeSignature? y) + { + if (x is null) + return y is null; + if (y is null) + return false; + return x.Rank == y.Rank && Equals(x.ElementType, y.BaseType); + } + + public bool Equals(PinnedTypeAnalysisContext? x, PinnedTypeSignature? y) + { + if (x is null) + return y is null; + if (y is null) + return false; + return Equals(x.ElementType, y.BaseType); + } +} diff --git a/Il2CppInterop.Generator/TypeAnalysisContextExtensions.cs b/Il2CppInterop.Generator/TypeAnalysisContextExtensions.cs new file mode 100644 index 00000000..b856208d --- /dev/null +++ b/Il2CppInterop.Generator/TypeAnalysisContextExtensions.cs @@ -0,0 +1,182 @@ +using System.Diagnostics.CodeAnalysis; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator; + +internal static class TypeAnalysisContextExtensions +{ + extension(TypeAnalysisContext type) + { + public bool IsModuleType => type.DeclaringType is null && string.IsNullOrEmpty(type.DefaultNamespace) && type.DefaultName == ""; + public bool IsPrivateImplementationDetailsType => type.DeclaringType is null && string.IsNullOrEmpty(type.DefaultNamespace) && type.DefaultName == ""; + public bool HasGenericParameters => type.GenericParameters.Count > 0; + + [MaybeNull] + public Type SourceType + { + get => type.GetExtraData("SourceType"); + set => type.PutExtraData("SourceType", value); + } + + [MaybeNull] + public MethodAnalysisContext PointerConstructor + { + get => type.GetExtraData("PointerConstructor"); + set => type.PutExtraData("PointerConstructor", value); + } + + [MaybeNull] + public TypeAnalysisContext InitializationType + { + get => type.GetExtraData("InitializationType"); + set => type.PutExtraData("InitializationType", value); + } + + [MaybeNull] + public FieldAnalysisContext SizeStorage + { + get => type.GetExtraData("SizeStorage"); + set => type.PutExtraData("SizeStorage", value); + } + + [MaybeNull] + public TypeAnalysisContext EnumIl2CppUnderlyingType + { + get => type.GetExtraData("EnumIl2CppUnderlyingType"); + set => type.PutExtraData("EnumIl2CppUnderlyingType", value); + } + + [MaybeNull] + public TypeAnalysisContext EnumMonoUnderlyingType + { + get => type.GetExtraData("EnumMonoUnderlyingType"); + set => type.PutExtraData("EnumMonoUnderlyingType", value); + } + + [MaybeNull] + public InjectedTypeAnalysisContext SystemExceptionType + { + get => type.GetExtraData("SystemExceptionType"); + set => type.PutExtraData("SystemExceptionType", value); + } + + [MaybeNull] + public List StaticConstructorInstructions + { + get => type.GetExtraData>("StaticConstructorInstructions"); + set => type.PutExtraData("StaticConstructorInstructions", value); + } + + public List GetOrCreateStaticConstructorInstructions() + { + var instructions = type.StaticConstructorInstructions; + if (instructions is null) + { + instructions = []; + type.StaticConstructorInstructions = instructions; + } + return instructions; + } + + public MethodAnalysisContext GetMethodByName(string name) + { + for (var i = type.Methods.Count - 1; i >= 0; i--) + { + var method = type.Methods[i]; + if (method.Name == name) + { + return method; + } + } + throw new Exception($"Method {name} not found in type {type.Name}"); + } + + public FieldAnalysisContext GetFieldByName(string? name) + { + for (var i = type.Fields.Count - 1; i >= 0; i--) + { + var field = type.Fields[i]; + if (field.Name == name) + { + return field; + } + } + throw new Exception($"Field {name} not found in type {type.Name}"); + } + + public FieldAnalysisContext? TryGetFieldByName(string? name) + { + for (var i = type.Fields.Count - 1; i >= 0; i--) + { + var field = type.Fields[i]; + if (field.Name == name) + { + return field; + } + } + return null; + } + + public bool TryGetFieldByName(string? name, [NotNullWhen(true)] out FieldAnalysisContext? field) + { + field = type.TryGetFieldByName(name); + return field is not null; + } + + public bool TryGetPropertyByName(string? name, [NotNullWhen(true)] out PropertyAnalysisContext? property) + { + for (var i = type.Properties.Count - 1; i >= 0; i--) + { + var prop = type.Properties[i]; + if (prop.Name == name) + { + property = prop; + return true; + } + } + property = null; + return false; + } + + public MethodAnalysisContext GetImplicitConversionFrom(TypeAnalysisContext sourceType) + { + return GetConversion("op_Implicit", type, sourceType, type); + } + + public MethodAnalysisContext GetImplicitConversionTo(TypeAnalysisContext targetType) + { + return GetConversion("op_Implicit", type, type, targetType); + } + + public MethodAnalysisContext GetExplicitConversionFrom(TypeAnalysisContext sourceType) + { + return GetConversion("op_Explicit", type, sourceType, type); + } + + public MethodAnalysisContext GetExplicitConversionTo(TypeAnalysisContext targetType) + { + return GetConversion("op_Explicit", type, type, targetType); + } + + public TypeAnalysisContext SelfInstantiateIfGeneric() + { + if (type.GenericParameters.Count == 0) + { + return type; + } + else + { + return type.MakeGenericInstanceType(type.GenericParameters); + } + } + } + + private static MethodAnalysisContext GetConversion([ConstantExpected] string name, TypeAnalysisContext declaringType, TypeAnalysisContext sourceType, TypeAnalysisContext targetType) + { + return declaringType.Methods.First(m => + { + return m.Name == name && m.IsStatic && m.ReturnType == targetType && m.Parameters.Count == 1 && m.Parameters[0].ParameterType == sourceType; + }); + } +} diff --git a/Il2CppInterop.Generator/TypeBlittability.cs b/Il2CppInterop.Generator/TypeBlittability.cs new file mode 100644 index 00000000..abf81f13 --- /dev/null +++ b/Il2CppInterop.Generator/TypeBlittability.cs @@ -0,0 +1,9 @@ +namespace Il2CppInterop.Generator; + +public enum TypeBlittability +{ + Unknown, + ReferenceType, + BlittableValueType, + NonBlittableValueType, +} diff --git a/Il2CppInterop.Generator/TypeConversionVisitor.cs b/Il2CppInterop.Generator/TypeConversionVisitor.cs new file mode 100644 index 00000000..e4f21063 --- /dev/null +++ b/Il2CppInterop.Generator/TypeConversionVisitor.cs @@ -0,0 +1,81 @@ +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Runtime.InteropTypes; +using Il2CppInterop.Runtime.InteropTypes.Arrays; + +namespace Il2CppInterop.Generator; + +internal sealed class TypeConversionVisitor : TypeReplacementVisitor +{ + private TypeConversionVisitor(Dictionary replacements) : base(replacements) + { + } + + public required TypeAnalysisContext Il2CppArrayBase { get; init; } + public required TypeAnalysisContext Pointer { get; init; } + public required TypeAnalysisContext ByRef { get; init; } + + public static TypeConversionVisitor Create(ApplicationAnalysisContext appContext) + { + var il2CppMscorlib = appContext.AssembliesByName["Il2Cppmscorlib"]; + var mscorlib = appContext.AssembliesByName["mscorlib"]; + var il2CppInteropRuntime = appContext.AssembliesByName["Il2CppInterop.Runtime"]; + + var il2CppArrayBase = il2CppInteropRuntime.GetTypeByFullNameOrThrow(typeof(Il2CppArrayBase<>)); + var pointer = il2CppInteropRuntime.GetTypeByFullNameOrThrow(typeof(Pointer<>)); + var byRef = il2CppInteropRuntime.GetTypeByFullNameOrThrow(typeof(ByReference<>)); + + (string, string)[] replacements = + [ + ("Il2CppSystem.Object", "Il2CppSystem.IObject"), + ("Il2CppSystem.Enum", "Il2CppSystem.IEnum"), + ("Il2CppSystem.ValueType", "Il2CppSystem.IValueType"), + //("Il2CppSystem.Object", "System.Object"), + //("Il2CppSystem.Void", "System.Void"), + //("Il2CppSystem.Enum", "System.Enum"), + //("Il2CppSystem.ValueType", "System.ValueType"), + //("Il2CppSystem.Boolean", "System.Boolean"), + //("Il2CppSystem.Char", "System.Char"), + //("Il2CppSystem.SByte", "System.SByte"), + //("Il2CppSystem.Byte", "System.Byte"), + //("Il2CppSystem.Int16", "System.Int16"), + //("Il2CppSystem.UInt16", "System.UInt16"), + //("Il2CppSystem.Int32", "System.Int32"), + //("Il2CppSystem.UInt32", "System.UInt32"), + //("Il2CppSystem.Int64", "System.Int64"), + //("Il2CppSystem.UInt64", "System.UInt64"), + //("Il2CppSystem.Single", "System.Single"), + //("Il2CppSystem.Double", "System.Double"), + //("Il2CppSystem.IntPtr", "System.IntPtr"), + //("Il2CppSystem.UIntPtr", "System.UIntPtr"), + ]; + + var replacementDictionary = replacements.ToDictionary(pair => il2CppMscorlib.GetTypeByFullNameOrThrow(pair.Item1), pair => il2CppMscorlib.GetTypeByFullNameOrThrow(pair.Item2)); + + return new TypeConversionVisitor(replacementDictionary) + { + Il2CppArrayBase = il2CppArrayBase, + Pointer = pointer, + ByRef = byRef + }; + } + + protected override TypeAnalysisContext CombineResults(ArrayTypeAnalysisContext type, TypeAnalysisContext elementResult) + { + return base.CombineResults(type, elementResult); + } + + protected override TypeAnalysisContext CombineResults(SzArrayTypeAnalysisContext type, TypeAnalysisContext elementResult) + { + return Il2CppArrayBase.MakeGenericInstanceType([elementResult]); + } + + protected override TypeAnalysisContext CombineResults(PointerTypeAnalysisContext type, TypeAnalysisContext elementResult) + { + return Pointer.MakeGenericInstanceType([elementResult]); + } + + protected override TypeAnalysisContext CombineResults(ByRefTypeAnalysisContext type, TypeAnalysisContext elementResult) + { + return ByRef.MakeGenericInstanceType([elementResult]); + } +} diff --git a/Il2CppInterop.Generator/TypeInfoProcessingLayer.cs b/Il2CppInterop.Generator/TypeInfoProcessingLayer.cs new file mode 100644 index 00000000..7f92cbc7 --- /dev/null +++ b/Il2CppInterop.Generator/TypeInfoProcessingLayer.cs @@ -0,0 +1,121 @@ +using System.Diagnostics; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Logging; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public class TypeInfoProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Record information about each type"; + + public override string Id => "type_info"; + + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + Logger.InfoNewline("Processing type information...", nameof(TypeInfoProcessingLayer)); + + foreach (var type in appContext.AllTypes) + { + var typeInfo = new Il2CppTypeInfo(); + if (!type.IsValueType) + { + typeInfo.Blittability = TypeBlittability.ReferenceType; + } + foreach (var field in type.Fields) + { + if (field.IsStatic) + { + typeInfo.StaticFields.Add(field); + } + else + { + typeInfo.InstanceFields.Add(field); + } + } + type.PutExtraData(typeInfo); + } + bool changed; + do + { + changed = false; + + foreach (var type in appContext.AllTypes) + { + var typeInfo = type.GetExtraData()!; + if (typeInfo.Blittability is not TypeBlittability.Unknown) + continue; + + Debug.Assert(type.IsValueType); + + var anyNonBlittable = false; + var anyUnknown = false; + foreach (var field in typeInfo.InstanceFields) + { + var fieldType = GetUnderlyingType(field.FieldType); + + if (fieldType is ArrayTypeAnalysisContext or SzArrayTypeAnalysisContext or PointerTypeAnalysisContext or ByRefTypeAnalysisContext) + { + // Reference types are "blittable" because they are represented as pointers in C++. + continue; + } + + Debug.Assert(fieldType is not PinnedTypeAnalysisContext and not BoxedTypeAnalysisContext and not SentinelTypeAnalysisContext); + + if (fieldType is GenericParameterTypeAnalysisContext genericParameter) + { + if (genericParameter.Attributes.HasFlag(System.Reflection.GenericParameterAttributes.ReferenceTypeConstraint)) + { + // Reference types are "blittable" because they are represented as pointers in C++. + } + else if (genericParameter.Attributes.HasFlag(System.Reflection.GenericParameterAttributes.NotNullableValueTypeConstraint) && + genericParameter.HasCustomAttributeWithFullName("System.Runtime.CompilerServices.IsUnmanagedAttribute")) + { + // Blittable + } + else + { + // Non-blittable because a non-blittable struct could be used as the generic argument. + anyNonBlittable = true; + break; + } + } + else if (fieldType == type) + { + // Corlib primitives reference themselves. We can ignore this. + } + else + { + var fieldTypeInfo = fieldType.GetExtraData()!; + if (fieldTypeInfo.Blittability == TypeBlittability.NonBlittableValueType) + { + anyNonBlittable = true; + break; + } + else if (fieldTypeInfo.Blittability == TypeBlittability.Unknown) + { + anyUnknown = true; + } + } + } + if (anyNonBlittable) + { + typeInfo.Blittability = TypeBlittability.NonBlittableValueType; + changed = true; + } + else if (!anyUnknown) + { + typeInfo.Blittability = TypeBlittability.BlittableValueType; + changed = true; + } + } + } while (changed); + } + + private static TypeAnalysisContext GetUnderlyingType(TypeAnalysisContext type) => type switch + { + GenericInstanceTypeAnalysisContext genericInstance => GetUnderlyingType(genericInstance.GenericType), + CustomModifierTypeAnalysisContext customModifier => GetUnderlyingType(customModifier.ElementType), + _ => type, + }; +} diff --git a/Il2CppInterop.Generator/TypeReplacementVisitor.cs b/Il2CppInterop.Generator/TypeReplacementVisitor.cs new file mode 100644 index 00000000..58503022 --- /dev/null +++ b/Il2CppInterop.Generator/TypeReplacementVisitor.cs @@ -0,0 +1,82 @@ +using System.Diagnostics.CodeAnalysis; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +internal class TypeReplacementVisitor(Dictionary replacements) : DefaultTypeVisitor +{ + private readonly Dictionary _replacements = replacements; + + [return: NotNullIfNotNull(nameof(type))] + public TypeAnalysisContext? Replace(TypeAnalysisContext? type) + { + return type is null ? null : Visit(type); + } + + public void Replace(List types) + { + for (var i = 0; i < types.Count; i++) + { + types[i] = Replace(types[i]); + } + } + + protected override TypeAnalysisContext VisitSimpleType(TypeAnalysisContext type) + { + return _replacements.TryGetValue(type, out var replacement) ? replacement : type; + } + + protected override TypeAnalysisContext CombineResults(ArrayTypeAnalysisContext type, TypeAnalysisContext elementResult) + { + return type.ElementType == elementResult ? type : elementResult.MakeArrayType(type.Rank); + } + + protected override TypeAnalysisContext CombineResults(BoxedTypeAnalysisContext type, TypeAnalysisContext elementResult) + { + return type.ElementType == elementResult ? type : elementResult.MakeBoxedType(); + } + + protected override TypeAnalysisContext CombineResults(ByRefTypeAnalysisContext type, TypeAnalysisContext elementResult) + { + return type.ElementType == elementResult ? type : elementResult.MakeByReferenceType(); + } + + protected override TypeAnalysisContext CombineResults(CustomModifierTypeAnalysisContext type, TypeAnalysisContext elementResult, TypeAnalysisContext modifierResult) + { + if (type.ElementType == elementResult && type.ModifierType == modifierResult) + return type; + return elementResult.MakeCustomModifierType(modifierResult, type.Required); + } + + protected override TypeAnalysisContext CombineResults(GenericInstanceTypeAnalysisContext type, TypeAnalysisContext genericTypeResult, TypeAnalysisContext[] genericArgumentsResults) + { + if (type.GenericType == genericTypeResult && type.GenericArguments.SequenceEqual(genericArgumentsResults)) + return type; + return genericTypeResult.MakeGenericInstanceType(genericArgumentsResults!); + } + + public override TypeAnalysisContext Visit(GenericParameterTypeAnalysisContext type) + { + return _replacements.TryGetValue(type, out var replacement) ? replacement : type; + } + + protected override TypeAnalysisContext CombineResults(PinnedTypeAnalysisContext type, TypeAnalysisContext elementResult) + { + return type.ElementType == elementResult ? type : elementResult.MakePinnedType(); + } + + protected override TypeAnalysisContext CombineResults(PointerTypeAnalysisContext type, TypeAnalysisContext elementResult) + { + return type.ElementType == elementResult ? type : elementResult.MakePointerType(); + } + + public override TypeAnalysisContext Visit(SentinelTypeAnalysisContext type) + { + return _replacements.TryGetValue(type, out var replacement) ? replacement : type; + } + + protected override TypeAnalysisContext CombineResults(SzArrayTypeAnalysisContext type, TypeAnalysisContext elementResult) + { + return type.ElementType == elementResult ? type : elementResult.MakeSzArrayType(); + } +} diff --git a/Il2CppInterop.Generator/TypeVisitor.cs b/Il2CppInterop.Generator/TypeVisitor.cs new file mode 100644 index 00000000..ed7536b4 --- /dev/null +++ b/Il2CppInterop.Generator/TypeVisitor.cs @@ -0,0 +1,42 @@ +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public abstract class TypeVisitor +{ + public virtual T Visit(TypeAnalysisContext type) => type switch + { + ReferencedTypeAnalysisContext referencedType => Visit(referencedType), + _ => VisitSimpleType(type), + }; + protected virtual T Visit(ReferencedTypeAnalysisContext type) => type switch + { + WrappedTypeAnalysisContext wrappedType => Visit(wrappedType), + GenericInstanceTypeAnalysisContext genericInstanceType => Visit(genericInstanceType), + GenericParameterTypeAnalysisContext genericParameterType => Visit(genericParameterType), + SentinelTypeAnalysisContext sentinelType => Visit(sentinelType), + _ => throw new ArgumentOutOfRangeException(nameof(type), type, "Type is not supported"), + }; + public virtual T Visit(WrappedTypeAnalysisContext type) => type switch + { + ArrayTypeAnalysisContext arrayType => Visit(arrayType), + BoxedTypeAnalysisContext boxedType => Visit(boxedType), + ByRefTypeAnalysisContext byRefType => Visit(byRefType), + CustomModifierTypeAnalysisContext customModifierType => Visit(customModifierType), + PinnedTypeAnalysisContext pinnedType => Visit(pinnedType), + PointerTypeAnalysisContext pointerType => Visit(pointerType), + SzArrayTypeAnalysisContext szArrayType => Visit(szArrayType), + _ => throw new ArgumentOutOfRangeException(nameof(type), type, "Type is not supported"), + }; + public abstract T Visit(ArrayTypeAnalysisContext type); + public abstract T Visit(BoxedTypeAnalysisContext type); + public abstract T Visit(ByRefTypeAnalysisContext type); + public abstract T Visit(CustomModifierTypeAnalysisContext type); + public abstract T Visit(GenericInstanceTypeAnalysisContext type); + public abstract T Visit(GenericParameterTypeAnalysisContext type); + public abstract T Visit(PinnedTypeAnalysisContext type); + public abstract T Visit(PointerTypeAnalysisContext type); + public abstract T Visit(SentinelTypeAnalysisContext type); + public abstract T Visit(SzArrayTypeAnalysisContext type); + protected abstract T VisitSimpleType(TypeAnalysisContext type); +} diff --git a/Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs b/Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs new file mode 100644 index 00000000..8685d462 --- /dev/null +++ b/Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs @@ -0,0 +1,495 @@ +using System.Diagnostics.CodeAnalysis; +using AsmResolver.DotNet; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Logging; +using Cpp2IL.Core.Model.Contexts; +using Cpp2IL.Core.Model.CustomAttributes; +using LibCpp2IL.BinaryStructures; + +namespace Il2CppInterop.Generator; + +public abstract class UnstripBaseProcessingLayer : Cpp2IlProcessingLayer +{ + public const string AssembliesKey = "unstrip-assemblies"; + public const string DirectoryKey = "unstrip-directory"; + + protected static void InjectAssemblies(ApplicationAnalysisContext appContext, IReadOnlyList assemblyList, bool storeMethodBodies) + { + // Inject assemblies + var assemblyDictionary = new Dictionary(assemblyList.Count); + foreach (var assembly in assemblyList) + { + if (IsEmpty(assembly.ManifestModule!)) + continue; // Skip empty assemblies + + if (!appContext.AssembliesByName.TryGetValue(assembly.Name!, out var assemblyContext)) + { + assemblyContext = appContext.InjectAssembly(assembly.Name!, assembly.Version, (uint)assembly.HashAlgorithm, (uint)assembly.Attributes, assembly.Culture, null, assembly.PublicKey); + assemblyContext.IsUnstripped = true; + } + assemblyDictionary.Add(assembly.ManifestModule!, assemblyContext); + } + + // Inject types + var injectedTypes = new List<(TypeDefinition, InjectedTypeAnalysisContext)>(); + var existingTypes = new List<(TypeDefinition, TypeAnalysisContext)>(); + foreach ((var module, var assemblyContext) in assemblyDictionary) + { + foreach (var type in module.TopLevelTypes) + { + var typeContext = assemblyContext.GetTypeByFullName(type.FullName); + if (typeContext is null) + { + typeContext = assemblyContext.InjectType((string?)type.Namespace ?? "", (string?)type.Name ?? "", null, (System.Reflection.TypeAttributes)type.Attributes); + foreach (var genericParameter in type.GenericParameters) + { + var genericParameterContext = new GenericParameterTypeAnalysisContext( + genericParameter.Name!, + genericParameter.Number, + Il2CppTypeEnum.IL2CPP_TYPE_VAR, + (System.Reflection.GenericParameterAttributes)genericParameter.Attributes, + typeContext); + typeContext.GenericParameters.Add(genericParameterContext); + } + injectedTypes.Add((type, (InjectedTypeAnalysisContext)typeContext)); + typeContext.IsUnstripped = true; + } + else + { + existingTypes.Add((type, typeContext)); + } + InjectNestedTypes(type, typeContext, injectedTypes, existingTypes); + } + } + + // Set up type hierarchy + foreach (var (type, typeContext) in injectedTypes) + { + var resolver = new ContextResolver(typeContext); + if (type.BaseType is not null) + { + if (resolver.TryResolve(type.BaseType, out var baseTypeContext)) + { + typeContext.SetDefaultBaseType(baseTypeContext); + } + else + { + throw new InvalidOperationException($"Unable to resolve base type {type.BaseType} for type {type.FullName}"); + } + } + + foreach (var interfaceType in type.Interfaces.Select(t => t.Interface)) + { + if (resolver.TryResolve(interfaceType, out var interfaceTypeContext)) + { + typeContext.InterfaceContexts.Add(interfaceTypeContext); + } + else + { + throw new InvalidOperationException($"Unable to resolve interface type {interfaceType} for type {type.FullName}"); + } + } + + for (var i = 0; i < type.GenericParameters.Count; i++) + { + var genericParameter = type.GenericParameters[i]; + var genericParameterContext = typeContext.GenericParameters[i]; + foreach (var constraint in genericParameter.Constraints) + { + if (resolver.TryResolve(constraint.Constraint, out var constraintType)) + { + genericParameterContext.ConstraintTypes.Add(constraintType); + } + else + { + throw new InvalidOperationException($"Unable to resolve generic parameter constraint {constraint.Constraint} for type {type.FullName}"); + } + } + } + } + + // Inject members + List<(InjectedMethodAnalysisContext, IMethodDefOrRef)> methodsNeedingOverrides = new(); + List<(MethodAnalysisContext, MethodDefinition)> methodsNeedingBodies = new(); + foreach (var (type, typeContext) in injectedTypes) + { + CopyCustomAttributes(type, typeContext, typeContext.DeclaringAssembly); + + for (var i = 0; i < type.GenericParameters.Count; i++) + { + CopyCustomAttributes(type.GenericParameters[i], typeContext.GenericParameters[i], typeContext.DeclaringAssembly); + } + + foreach (var field in type.Fields) + { + TryInjectField(field, typeContext); + } + + Dictionary methodLookup = new(); + foreach (var method in type.Methods) + { + if (TryInjectMethod(method, typeContext, out var methodContext)) + { + methodLookup.Add(method, methodContext); + methodsNeedingBodies.Add((methodContext, method)); + } + } + + foreach (var property in type.Properties) + { + TryInjectProperty(property, typeContext, methodLookup); + } + + foreach (var @event in type.Events) + { + TryInjectEvent(@event, typeContext, methodLookup); + } + + foreach (var implementation in type.MethodImplementations) + { + if (implementation.Body is not MethodDefinition method || implementation.Declaration is null || !methodLookup.TryGetValue(method, out var methodContext)) + continue; + + methodsNeedingOverrides.Add(((InjectedMethodAnalysisContext)methodContext, implementation.Declaration)); + } + } + foreach (var (type, typeContext) in existingTypes) + { + // We shouldn't inject static fields. + // Even though it's not like instance fields where state gets changed, + // we can't guarantee that the static fields will be initialized properly. + // However, we can still inject constant fields. + foreach (var field in type.Fields) + { + if (!field.IsStatic) + continue; // Instance fields cannot be unstripped + + if (typeContext.Fields.Any(f => f.Name == field.Name)) + continue; // Already present + + if (field.Constant is null) + continue; // Skip fields without a constant value + + TryInjectField(field, typeContext); + } + + Dictionary methodLookup = new(); + foreach (var method in type.Methods) + { + var existingMethodContext = new ContextResolver(typeContext).ResolveInType(method); + if (existingMethodContext is not null) + { + methodLookup.Add(method, existingMethodContext); + if (method.GenericParameters.Count > 0 || type.GenericParameters.Count > 0) + { + // We inject the method if it's generic because we want to support generic instantiations + // that were not present in the original game. We abstain from non-generic methods because + // of performance, memory usage, output size, and risk of breaking the game. + // + // Counterargument: injecting as much as possible allows for more transpilers to be written. + + methodsNeedingBodies.Add((existingMethodContext, method)); + } + continue; + } + + if (!TryInjectMethod(method, typeContext, out var methodContext)) + continue; + + methodLookup.Add(method, methodContext); + methodsNeedingBodies.Add((methodContext, method)); + + foreach (var implementation in type.MethodImplementations) + { + if (implementation.Body != method || implementation.Declaration is null) + continue; + methodsNeedingOverrides.Add((methodContext, implementation.Declaration)); + } + } + + foreach (var property in type.Properties) + { + if (typeContext.Properties.Any(p => p.Name == property.Name)) + continue; // Already present + + TryInjectProperty(property, typeContext, methodLookup); + } + + foreach (var @event in type.Events) + { + if (typeContext.Events.Any(e => e.Name == @event.Name)) + continue; // Already present + + TryInjectEvent(@event, typeContext, methodLookup); + } + } + + // Assign method overrides + foreach (var (methodContext, declaration) in methodsNeedingOverrides) + { + var declarationContext = new ContextResolver(methodContext.DeclaringType!).Resolve(declaration); + if (declarationContext is not null) + { + methodContext.OverridesList.Add((MethodAnalysisContext)declarationContext); + } + } + + // Assign method bodies + if (storeMethodBodies) + { + var successfulCount = 0; + foreach (var (methodContext, methodDefinition) in methodsNeedingBodies) + { + var successful = OriginalMethodBody.MaybeStoreOriginalMethodBody(methodDefinition, methodContext); + if (successful) + { + successfulCount++; + } + } + + // Report how many method bodies were successfully stored. + Logger.InfoNewline($"Recovered the original method body for {successfulCount}/{methodsNeedingBodies.Count} attempts.", nameof(UnstripBaseProcessingLayer)); + } + } + + private static void InjectNestedTypes(TypeDefinition declaringType, TypeAnalysisContext declaringTypeContext, List<(TypeDefinition, InjectedTypeAnalysisContext)> injectedTypes, List<(TypeDefinition, TypeAnalysisContext)> existingTypes) + { + foreach (var nestedType in declaringType.NestedTypes) + { + var nestedTypeContext = declaringTypeContext.NestedTypes.FirstOrDefault(t => t.Name == nestedType.Name); + if (nestedTypeContext is null) + { + nestedTypeContext = declaringTypeContext.InjectNestedType((string?)nestedType.Name ?? "", null, (System.Reflection.TypeAttributes)nestedType.Attributes); + foreach (var genericParameter in nestedType.GenericParameters) + { + var genericParameterContext = new GenericParameterTypeAnalysisContext( + genericParameter.Name!, + genericParameter.Number, + Il2CppTypeEnum.IL2CPP_TYPE_VAR, + (System.Reflection.GenericParameterAttributes)genericParameter.Attributes, + nestedTypeContext); + nestedTypeContext.GenericParameters.Add(genericParameterContext); + } + injectedTypes.Add((nestedType, (InjectedTypeAnalysisContext)nestedTypeContext)); + + nestedTypeContext.IsUnstripped = true; + } + else + { + existingTypes.Add((nestedType, nestedTypeContext)); + } + InjectNestedTypes(nestedType, nestedTypeContext, injectedTypes, existingTypes); + } + } + + private static bool TryInjectField(FieldDefinition field, TypeAnalysisContext typeContext) + { + if (field.Name is not null && new ContextResolver(typeContext).TryResolve(field.Signature?.FieldType, out var fieldTypeContext)) + { + var fieldContext = new InjectedFieldAnalysisContext( + field.Name!, + fieldTypeContext, + (System.Reflection.FieldAttributes)field.Attributes, + typeContext); + typeContext.Fields.Add(fieldContext); + + if (field.Constant is { Type: not AsmResolver.PE.DotNet.Metadata.Tables.ElementType.Class }) + { + fieldContext.OverrideConstantValue = field.Constant.Value?.InterpretData(field.Constant.Type); + } + // https://github.com/Washi1337/AsmResolver/pull/627 + //fieldContext.OverrideConstantValue = field.Constant?.InterpretData(); + + CopyCustomAttributes(field, fieldContext, typeContext.DeclaringAssembly); + + fieldContext.IsUnstripped = true; + + return true; + } + + return false; + } + + private static bool TryInjectMethod(MethodDefinition method, TypeAnalysisContext typeContext, [NotNullWhen(true)] out InjectedMethodAnalysisContext? methodContext) + { + // Due to an unfortunate reality of resolving types, we need to create a method and add it to our target type before we can resolve its signature. + // This is because the method signature can reference the method's generic parameters, so we need to create the method first. + methodContext = new InjectedMethodAnalysisContext( + typeContext, + method.Name!, + typeContext.AppContext.SystemTypes.SystemObjectType, + (System.Reflection.MethodAttributes)method.Attributes, + Enumerable.Repeat(typeContext.AppContext.SystemTypes.SystemObjectType, method.Parameters.Count).ToArray(), + method.Parameters.Select(p => p.Name).ToArray(), + method.Parameters.Select(p => (System.Reflection.ParameterAttributes)p.GetOrCreateDefinition().Attributes).ToArray(), + (System.Reflection.MethodImplAttributes)method.ImplAttributes); + + foreach (var genericParameter in method.GenericParameters) + { + var genericParameterContext = new GenericParameterTypeAnalysisContext(genericParameter.Name!, genericParameter.Number, Il2CppTypeEnum.IL2CPP_TYPE_MVAR, (System.Reflection.GenericParameterAttributes)genericParameter.Attributes, methodContext); + methodContext.GenericParameters.Add(genericParameterContext); + } + + typeContext.Methods.Add(methodContext); + + var methodResolver = new ContextResolver(methodContext); + + if (!methodResolver.TryResolve(method.Signature?.ReturnType, out var returnTypeContext)) + { + typeContext.Methods.Remove(methodContext); + return false; + } + else + { + methodContext.SetDefaultReturnType(returnTypeContext); + } + + if (!methodResolver.TryResolve(method.Parameters.Select(p => p.ParameterType), out var parameterTypeContexts)) + { + typeContext.Methods.Remove(methodContext); + return false; + } + else + { + for (var i = 0; i < parameterTypeContexts.Count; i++) + { + var parameter = (InjectedParameterAnalysisContext)methodContext.Parameters[i]; + parameter.SetDefaultParameterType(parameterTypeContexts[i]); + } + } + + if (!TryAddGenericConstraints(method, methodContext)) + { + typeContext.Methods.Remove(methodContext); + return false; + } + + CopyCustomAttributes(method, methodContext, typeContext.DeclaringAssembly); + for (var i = 0; i < method.Parameters.Count; i++) + { + CopyCustomAttributes(method.Parameters[i].GetOrCreateDefinition(), methodContext.Parameters[i], typeContext.DeclaringAssembly); + } + for (var i = 0; i < method.GenericParameters.Count; i++) + { + CopyCustomAttributes(method.GenericParameters[i], methodContext.GenericParameters[i], typeContext.DeclaringAssembly); + } + + methodContext.IsUnstripped = true; + + return true; + + static bool TryAddGenericConstraints(MethodDefinition method, InjectedMethodAnalysisContext methodContext) + { + var methodResolver = new ContextResolver(methodContext); + var anyInvalidConstraints = false; + for (var i = 0; i < method.GenericParameters.Count; i++) + { + var genericParameter = method.GenericParameters[i]; + var genericParameterContext = methodContext.GenericParameters[i]; + foreach (var constraint in genericParameter.Constraints) + { + if (methodResolver.TryResolve(constraint.Constraint, out var constraintType)) + { + genericParameterContext.ConstraintTypes.Add(constraintType); + } + else + { + anyInvalidConstraints = true; + break; + } + } + if (anyInvalidConstraints) + break; + } + + return !anyInvalidConstraints; + } + } + + private static bool TryInjectProperty(PropertyDefinition property, TypeAnalysisContext typeContext, Dictionary methodLookup) + { + var resolver = new ContextResolver(typeContext); + + if (!resolver.TryResolve(property.Signature?.ReturnType, out var propertyTypeContext)) + return false; + + var getMethodContext = methodLookup.TryGetValue(property.GetMethod); + if (getMethodContext is null && property.GetMethod is not null) + return false; + + var setMethodContext = methodLookup.TryGetValue(property.SetMethod); + if (setMethodContext is null && property.SetMethod is not null) + return false; + + var propertyContext = new InjectedPropertyAnalysisContext( + property.Name!, + propertyTypeContext, + getMethodContext, + setMethodContext, + (System.Reflection.PropertyAttributes)property.Attributes, + typeContext); + typeContext.Properties.Add(propertyContext); + + CopyCustomAttributes(property, propertyContext, typeContext.DeclaringAssembly); + + propertyContext.IsUnstripped = true; + + return true; + } + + private static bool TryInjectEvent(EventDefinition @event, TypeAnalysisContext typeContext, Dictionary methodLookup) + { + var resolver = new ContextResolver(typeContext); + + if (!resolver.TryResolve(@event.EventType!.ToTypeSignature(), out var eventTypeContext)) + return false; + + var addMethodContext = methodLookup.TryGetValue(@event.AddMethod); + if (addMethodContext is null && @event.AddMethod is not null) + return false; + + var removeMethodContext = methodLookup.TryGetValue(@event.RemoveMethod); + if (removeMethodContext is null && @event.RemoveMethod is not null) + return false; + + var fireMethodContext = methodLookup.TryGetValue(@event.FireMethod); + if (fireMethodContext is null && @event.FireMethod is not null) + return false; + + var eventContext = new InjectedEventAnalysisContext( + @event.Name!, + eventTypeContext, + addMethodContext, + removeMethodContext, + fireMethodContext, + (System.Reflection.EventAttributes)@event.Attributes, + typeContext); + typeContext.Events.Add(eventContext); + + CopyCustomAttributes(@event, eventContext, typeContext.DeclaringAssembly); + + eventContext.IsUnstripped = true; + + return true; + } + + private static void CopyCustomAttributes(IHasCustomAttribute source, HasCustomAttributes destination, AssemblyAnalysisContext assembly) + { + foreach (var customAttribute in source.CustomAttributes) + { + if (customAttribute.Constructor is null or { Signature: null or { ParameterTypes.Count: > 0 } }) + continue; // Skip custom attributes with parameters or an invalid constructor + + if (!new ContextResolver(assembly).TryResolve(customAttribute.Constructor, out var constructorContext)) + continue; // Skip custom attributes with an invalid constructor + + destination.CustomAttributes ??= []; + destination.CustomAttributes.Add(new AnalyzedCustomAttribute((MethodAnalysisContext)constructorContext)); + } + } + + private static bool IsEmpty(ModuleDefinition module) + { + return module.TopLevelTypes.Count == 0 || (module.TopLevelTypes.Count == 1 && module.TopLevelTypes[0].IsModuleType); + } +} diff --git a/Il2CppInterop.Generator/UnstripProcessingLayer.cs b/Il2CppInterop.Generator/UnstripProcessingLayer.cs new file mode 100644 index 00000000..b4549be0 --- /dev/null +++ b/Il2CppInterop.Generator/UnstripProcessingLayer.cs @@ -0,0 +1,40 @@ +using AsmResolver.DotNet; +using Cpp2IL.Core.Logging; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public class UnstripProcessingLayer : UnstripBaseProcessingLayer +{ + public override string Name => "Unstrip external assemblies into the Cpp2IL context system"; + + public override string Id => "unstrip"; + + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var assemblyList = appContext.GetExtraData>(AssembliesKey); + if (assemblyList is null) + { + var directoryPath = appContext.GetExtraData(DirectoryKey); + if (directoryPath is null) + { + Logger.WarnNewline($"No assemblies specified - processor will not run. You need to provide the {DirectoryKey}, either by programmatically adding it as extra data in the app context, or by specifying it in the --processor-config command line option.", nameof(UnstripProcessingLayer)); + return; + } + + assemblyList = Directory.GetFiles(directoryPath, "*.dll", SearchOption.AllDirectories) + .Select(AssemblyDefinition.FromFile) + .ToList(); + } + + if (assemblyList.Count == 0) + { + Logger.WarnNewline("No assemblies provided - processor will not run.", nameof(UnstripProcessingLayer)); + return; + } + + Logger.InfoNewline($"Unstripping {assemblyList.Count} assemblies...", nameof(UnstripProcessingLayer)); + + InjectAssemblies(appContext, assemblyList, true); + } +} diff --git a/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj b/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj index 6e8e09f1..12273716 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj +++ b/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj @@ -2,7 +2,7 @@ Module to allow using Harmony with Il2CppInterop assemblies - net6.0 + net9.0 Il2CppInterop.HarmonySupport diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index 5299beff..4d29f31c 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -7,7 +7,6 @@ using System.Text; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Injection; -using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.Runtime; using Microsoft.Extensions.Logging; using Object = Il2CppSystem.Object; @@ -247,11 +246,11 @@ private static void LogError(string message) var nativeDelegateInvokeMethod = il2CppDelegateType.GetMethod("Invoke"); var nativeParameters = nativeDelegateInvokeMethod.GetParameters(); - if (nativeParameters.Count != parameterInfos.Length) + if (nativeParameters.Length != parameterInfos.Length) throw new ArgumentException( - $"Managed delegate has {parameterInfos.Length} parameters, native has {nativeParameters.Count}, these should match"); + $"Managed delegate has {parameterInfos.Length} parameters, native has {nativeParameters.Length}, these should match"); - for (var i = 0; i < nativeParameters.Count; i++) + for (var i = 0; i < nativeParameters.Length; i++) { var nativeType = nativeParameters[i].ParameterType; var managedType = parameterInfos[i].ParameterType; @@ -311,7 +310,7 @@ private static void LogError(string message) { // U2021.2.0+ hack in case the constructor did the wrong thing anyway converted.invoke_impl = converted.method_ptr; - converted.method_code = converted.m_target.Pointer; + converted.method_code = delegateReference.Pointer; } return converted.Cast(); diff --git a/Il2CppInterop.Runtime/IL2CPP.cs b/Il2CppInterop.Runtime/IL2CPP.cs index 0cb5acac..25822c4e 100644 --- a/Il2CppInterop.Runtime/IL2CPP.cs +++ b/Il2CppInterop.Runtime/IL2CPP.cs @@ -1,16 +1,12 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Text; using System.Text.RegularExpressions; using Il2CppInterop.Common; -using Il2CppInterop.Common.Attributes; using Il2CppInterop.Runtime.InteropTypes; -using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppInterop.Runtime.Runtime; using Microsoft.Extensions.Logging; @@ -192,6 +188,22 @@ public static IntPtr GetIl2CppMethod(IntPtr clazz, bool isGeneric, string method string.Join(", ", argTypes) + ")"); } + public static IntPtr GetIl2CppGenericInstanceMethod(IntPtr methodInfoPointer, IntPtr declaringTypeClassPointer, params IntPtr[] genericMethodArguments) + { + var types = new Il2CppSystem.Type[genericMethodArguments.Length]; + for (var i = 0; i < genericMethodArguments.Length; i++) + { + types[i] = Il2CppSystem.Type.internal_from_handle(il2cpp_class_get_type(genericMethodArguments[i])); + } + var methodInfo = new Il2CppSystem.Reflection.MethodInfo(il2cpp_method_get_object(methodInfoPointer, declaringTypeClassPointer)); + return il2cpp_method_get_from_reflection(Il2CppObjectBaseToPtrNotNull(methodInfo.MakeGenericMethod(types))); + } + + public static ObjectPointer NewObjectPointer() + { + return (ObjectPointer)il2cpp_object_new(Il2CppClassPointerStore.NativeClassPtr); + } + public static string? Il2CppStringToManaged(IntPtr il2CppString) { if (il2CppString == IntPtr.Zero) return null; @@ -245,12 +257,6 @@ public static IntPtr GetIl2CppNestedType(IntPtr enclosingType, string nestedType return IntPtr.Zero; } - public static void ThrowIfNull(object arg) - { - if (arg == null) - throw new NullReferenceException(); - } - public static T ResolveICall(string signature) where T : Delegate { var icallPtr = il2cpp_resolve_icall(signature); @@ -272,7 +278,7 @@ private static T GenerateDelegateForMissingICall(string signature) where T : var bodyBuilder = trampoline.GetILGenerator(); bodyBuilder.Emit(OpCodes.Ldstr, $"ICall with signature {signature} was not resolved"); - bodyBuilder.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor(new[] { typeof(string) })!); + bodyBuilder.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor([typeof(string)])!); bodyBuilder.Emit(OpCodes.Throw); return (T)trampoline.CreateDelegate(typeof(T)); @@ -292,7 +298,7 @@ private static T GenerateDelegateForMissingICall(string signature) where T : objectPointer = il2cpp_value_box(Il2CppClassPointerStore.NativeClassPtr, objectPointer); if (typeof(T) == typeof(string)) - return (T)(object)Il2CppStringToManaged(objectPointer); + return (T?)(object?)Il2CppStringToManaged(objectPointer); if (objectPointer == IntPtr.Zero) return default; @@ -303,64 +309,6 @@ private static T GenerateDelegateForMissingICall(string signature) where T : return Il2CppObjectPool.Get(objectPointer); } - public static string RenderTypeName(bool addRefMarker = false) - { - return RenderTypeName(typeof(T), addRefMarker); - } - - public static string RenderTypeName(Type t, bool addRefMarker = false) - { - if (addRefMarker) return RenderTypeName(t) + "&"; - if (t.IsArray) return RenderTypeName(t.GetElementType()) + "[]"; - if (t.IsByRef) return RenderTypeName(t.GetElementType()) + "&"; - if (t.IsPointer) return RenderTypeName(t.GetElementType()) + "*"; - if (t.IsGenericParameter) return t.Name; - - if (t.IsGenericType) - { - if (t.TypeHasIl2CppArrayBase()) - return RenderTypeName(t.GetGenericArguments()[0]) + "[]"; - - var builder = new StringBuilder(); - builder.Append(t.GetGenericTypeDefinition().FullNameObfuscated().TrimIl2CppPrefix()); - builder.Append('<'); - var genericArguments = t.GetGenericArguments(); - for (var i = 0; i < genericArguments.Length; i++) - { - if (i != 0) builder.Append(','); - builder.Append(RenderTypeName(genericArguments[i])); - } - - builder.Append('>'); - return builder.ToString(); - } - - if (t == typeof(Il2CppStringArray)) - return "System.String[]"; - - return t.FullNameObfuscated().TrimIl2CppPrefix(); - } - - private static string FullNameObfuscated(this Type t) - { - var obfuscatedNameAnnotations = t.GetCustomAttribute(); - if (obfuscatedNameAnnotations == null) return t.FullName; - return obfuscatedNameAnnotations.ObfuscatedName; - } - - private static string TrimIl2CppPrefix(this string s) - { - return s.StartsWith("Il2Cpp") ? s.Substring("Il2Cpp".Length) : s; - } - - private static bool TypeHasIl2CppArrayBase(this Type type) - { - if (type == null) return false; - if (type.IsConstructedGenericType) type = type.GetGenericTypeDefinition(); - if (type == typeof(Il2CppArrayBase<>)) return true; - return TypeHasIl2CppArrayBase(type.BaseType); - } - // this is called if there's no actual il2cpp_gc_wbarrier_set_field() [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void FieldWriteWbarrierStub(IntPtr obj, IntPtr targetAddress, IntPtr value) diff --git a/Il2CppInterop.Runtime/Il2CppException.cs b/Il2CppInterop.Runtime/Il2CppException.cs index 3411ae98..7006cb06 100644 --- a/Il2CppInterop.Runtime/Il2CppException.cs +++ b/Il2CppInterop.Runtime/Il2CppException.cs @@ -1,21 +1,37 @@ using System; +using System.Diagnostics; using System.Text; +using Il2CppInterop.Runtime.Runtime; namespace Il2CppInterop.Runtime; +public interface IIl2CppException +{ + Exception CreateSystemException(); +} public class Il2CppException : Exception { - [ThreadStatic] private static byte[] ourMessageBytes; + [ThreadStatic] + private static byte[]? ourMessageBytes; + + public static Func? ParseMessageHook; - public static Func ParseMessageHook; + public readonly Il2CppSystem.Exception Il2cppObject; - public Il2CppException(IntPtr exception) : base(BuildMessage(exception)) + public Il2CppException(Il2CppSystem.Exception il2cppObject) { + Il2cppObject = il2cppObject; } - private static unsafe string BuildMessage(IntPtr exception) + public override string Message => BuildMessage(Il2cppObject); + + private static unsafe string BuildMessage(Il2CppSystem.Exception il2cppException) { - if (ParseMessageHook != null) return ParseMessageHook(exception); + var exception = il2cppException.Pointer; + + if (ParseMessageHook != null) + return ParseMessageHook(exception); + ourMessageBytes ??= new byte[65536]; fixed (byte* message = ourMessageBytes) { @@ -23,16 +39,23 @@ private static unsafe string BuildMessage(IntPtr exception) } var builtMessage = Encoding.UTF8.GetString(ourMessageBytes, 0, Array.IndexOf(ourMessageBytes, (byte)0)); - Il2CppSystem.Exception il2cppException = new(exception); - return builtMessage + "\n" + - "--- BEGIN IL2CPP STACK TRACE ---\n" + - $"{il2cppException.ToString(false, true)}\n" + - "--- END IL2CPP STACK TRACE ---\n"; + return $""" + {builtMessage} + --- BEGIN IL2CPP STACK TRACE --- + {il2cppException.ToString(false, true)} + --- END IL2CPP STACK TRACE --- + + """; } public static void RaiseExceptionIfNecessary(IntPtr returnedException) { - if (returnedException == IntPtr.Zero) return; - throw new Il2CppException(returnedException); + if (returnedException == IntPtr.Zero) + return; + + var il2cppException = (IIl2CppException?)Il2CppObjectPool.Get(returnedException); + Debug.Assert(il2cppException is not null); + + throw il2cppException.CreateSystemException(); } } diff --git a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj index ad13e94a..e8b85e5b 100644 --- a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj +++ b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj @@ -4,7 +4,7 @@ Il2CppInterop.Runtime knah, BepInEx et al. Runtime tools for bridging .NET and Il2Cpp together - net6.0 + net9.0 true Il2CppInterop.Runtime Debug;Release @@ -21,26 +21,11 @@ - - false - Libs\Il2Cppmscorlib.dll - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/Il2CppInterop.Runtime/Il2CppType.cs b/Il2CppInterop.Runtime/Il2CppType.cs index 481b3a1b..2292079a 100644 --- a/Il2CppInterop.Runtime/Il2CppType.cs +++ b/Il2CppInterop.Runtime/Il2CppType.cs @@ -8,7 +8,7 @@ public static class Il2CppType { public static Type TypeFromPointer(IntPtr classPointer, string typeName = "") { - return TypeFromPointerInternal(classPointer, typeName, true); + return TypeFromPointerInternal(classPointer, typeName, true)!; } private static Type? TypeFromPointerInternal(IntPtr classPointer, string typeName, bool throwOnFailure) @@ -33,10 +33,10 @@ public static Type TypeFromPointer(IntPtr classPointer, string typeName = "() { - return Of(true); + return Of(true)!; } - public static Type Of(bool throwOnFailure) + public static Type? Of(bool throwOnFailure) { var classPointer = Il2CppClassPointerStore.NativeClassPtr; return TypeFromPointerInternal(classPointer, typeof(T).Name, throwOnFailure); diff --git a/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs index 943a9ad0..e2e99756 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs @@ -37,7 +37,7 @@ private IntPtr FindGetTypeInfoFromTypeDefinitionIndex(bool forceICallMethod = fa // https://github.com/Unity-Technologies/mono/blob/unity-2018.2/mcs/class/corlib/System.Runtime.CompilerServices/RuntimeHelpers.cs#L53-L54 IntPtr runtimeHelpersInitializeArray = InjectorHelpers.GetIl2CppMethodPointer( typeof(Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers) - .GetMethod("InitializeArray", new Type[] { typeof(Il2CppSystem.Array), typeof(IntPtr) }) + .GetMethod(nameof(Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers.InitializeArray), new Type[] { typeof(Il2CppSystem.Array), typeof(IntPtr) }) ); Logger.Instance.LogTrace("Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers::InitializeArray: 0x{RuntimeHelpersInitializeArrayAddress}", runtimeHelpersInitializeArray.ToInt64().ToString("X2")); diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs index 3fbf4b69..fd3ccdfa 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs @@ -2,13 +2,17 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using Il2CppInterop.Runtime.Runtime; namespace Il2CppInterop.Runtime.InteropTypes.Arrays; -public abstract class Il2CppArrayBase : Il2CppObjectBase, IEnumerable +public abstract class Il2CppArrayBase : Il2CppSystem.Array, IEnumerable, ICollection { - protected Il2CppArrayBase(IntPtr pointer) : base(pointer) + private protected Il2CppArrayBase(IntPtr pointer) : base(pointer) + { + } + private protected Il2CppArrayBase(ObjectPointer pointer) : base((nint)pointer) { } @@ -19,6 +23,12 @@ protected Il2CppArrayBase(IntPtr pointer) : base(pointer) public int Length => (int)IL2CPP.il2cpp_array_length(Pointer); + int ICollection.Count => Length; + + bool ICollection.IsSynchronized => false; + + object ICollection.SyncRoot => throw new NotSupportedException(); + public abstract IEnumerator GetEnumerator(); private protected static bool ThrowImmutableLength() @@ -32,10 +42,47 @@ private protected void ThrowIfIndexOutOfRange(int index) throw new ArgumentOutOfRangeException(nameof(index), "Array index may not be negative or above length of the array"); } + + public T LoadElementUnsafe(int index) where T : unmanaged + { + ThrowIfIndexOutOfRange(index); + return Unsafe.As(ref GetUnsafeSpanForElement(index)[0]); + } + + public void StoreElementUnsafe(int index, T value) where T : unmanaged + { + ThrowIfIndexOutOfRange(index); + ref var element = ref Unsafe.As(ref GetUnsafeSpanForElement(index)[0]); + element = value; + } + + private protected virtual Span GetUnsafeSpanForElement(int index) => throw new NotSupportedException("This array type does not support unsafe element access"); + + private protected abstract void CopyTo(Array array, int index); + + void ICollection.CopyTo(Array array, int index) => CopyTo(array, index); + + private static Il2CppUnmanagedArray Get() + { + Set(0, 1, 2); + return [0, 1, 2]; + } + + private static void Set(params Il2CppUnmanagedArray arr) + { + } + + public static Il2CppUnmanagedArray CreateUnmanaged(ReadOnlySpan arr) where T : unmanaged + { + return new Il2CppUnmanagedArray(arr); + } } public abstract class Il2CppArrayBase : Il2CppArrayBase, IList, IReadOnlyList { - protected Il2CppArrayBase(IntPtr pointer) : base(pointer) + private protected Il2CppArrayBase(IntPtr pointer) : base(pointer) + { + } + private protected Il2CppArrayBase(ObjectPointer pointer) : base(pointer) { } @@ -61,8 +108,8 @@ public bool Contains(T item) public void CopyTo(T[] array, int arrayIndex) { - if (array == null) throw new ArgumentNullException(nameof(array)); - if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex)); + ArgumentNullException.ThrowIfNull(array); + ArgumentOutOfRangeException.ThrowIfNegative(arrayIndex); if (array.Length - arrayIndex < Length) throw new ArgumentException( $"Not enough space in target array: need {Length} slots, have {array.Length - arrayIndex}"); @@ -71,13 +118,15 @@ public void CopyTo(T[] array, int arrayIndex) array[i + arrayIndex] = this[i]; } + private protected sealed override void CopyTo(Array array, int index) => CopyTo((T[])array, index); + bool ICollection.Remove(T item) { return ThrowImmutableLength(); } - public new int Length => base.Length;// For binary compatibility - public int Count => Length; + int ICollection.Count => Length; + int IReadOnlyCollection.Count => Length; bool ICollection.IsReadOnly => false; public int IndexOf(T item) @@ -101,7 +150,7 @@ void IList.RemoveAt(int index) public abstract T this[int index] { get; set; } - protected static void StaticCtorBody(Type ownType) + private protected static void StaticCtorBody(Type ownType) { var nativeClassPtr = Il2CppClassPointerStore.NativeClassPtr; if (nativeClassPtr == IntPtr.Zero) @@ -131,22 +180,21 @@ protected static void StaticCtorBody(Type ownType) public static Il2CppArrayBase? WrapNativeGenericArrayPointer(IntPtr pointer) { - if (pointer == IntPtr.Zero) return null; + if (pointer == IntPtr.Zero) + return null; if (typeof(T) == typeof(string)) return new Il2CppStringArray(pointer) as Il2CppArrayBase; if (typeof(T).IsValueType) // can't construct required types here directly because of unfulfilled generic constraint - return Activator.CreateInstance(typeof(Il2CppStructArray<>).MakeGenericType(typeof(T)), pointer) as - Il2CppArrayBase; + return Activator.CreateInstance(typeof(Il2CppStructArray<>).MakeGenericType(typeof(T)), pointer) as Il2CppArrayBase; if (typeof(Il2CppObjectBase).IsAssignableFrom(typeof(T))) - return Activator.CreateInstance(typeof(Il2CppReferenceArray<>).MakeGenericType(typeof(T)), pointer) as - Il2CppArrayBase; + return Activator.CreateInstance(typeof(Il2CppReferenceArray<>).MakeGenericType(typeof(T)), pointer) as Il2CppArrayBase; throw new ArgumentException( $"{typeof(T)} is not a value type, not a string and not an IL2CPP object; it can't be used in IL2CPP arrays"); } - private class IndexEnumerator : IEnumerator + private sealed class IndexEnumerator : IEnumerator { private Il2CppArrayBase myArray; private int myIndex = -1; @@ -163,7 +211,7 @@ public void Dispose() public bool MoveNext() { - return ++myIndex < myArray.Count; + return ++myIndex < ((ICollection)myArray).Count; } public void Reset() diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppMultiArrayBase.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppMultiArrayBase.cs new file mode 100644 index 00000000..0b0d3fce --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppMultiArrayBase.cs @@ -0,0 +1,23 @@ +using System; + +namespace Il2CppInterop.Runtime.InteropTypes.Arrays; + +public abstract class Il2CppMultiArrayBase : Il2CppObjectBase // Should this be inheriting from Il2CppSystem.Array? +{ + private protected Il2CppMultiArrayBase(ObjectPointer pointer) : base((nint)pointer) + { + } + + public int Rank => throw new NotImplementedException(); + + public T this[params ReadOnlySpan indices] + { + get => throw new NotImplementedException(); + set => throw new NotImplementedException(); + } + + public ref T GetElementAddress(params ReadOnlySpan indices) + { + throw new NotImplementedException(); + } +} diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppNonBlittableArray.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppNonBlittableArray.cs new file mode 100644 index 00000000..d2d5df43 --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppNonBlittableArray.cs @@ -0,0 +1,75 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Il2CppInterop.Runtime.InteropTypes.Arrays; + +public sealed class Il2CppNonBlittableArray : Il2CppArrayBase where T : IIl2CppType +{ + static Il2CppNonBlittableArray() + { + StaticCtorBody(typeof(Il2CppNonBlittableArray)); + } + + public Il2CppNonBlittableArray(IntPtr nativeObject) : base(nativeObject) + { + } + public Il2CppNonBlittableArray(ObjectPointer nativeObject) : base(nativeObject) + { + } + + public Il2CppNonBlittableArray(long size) : base(AllocateArray(size)) + { + } + + public Il2CppNonBlittableArray(T[] arr) : base(AllocateArray(arr.Length)) + { + for (var i = 0; i < arr.Length; i++) + this[i] = arr[i]; + } + + public override T this[int index] + { + get + { + ThrowIfIndexOutOfRange(index); + return T.ReadFromSpan(AsSpan().Slice(index * T.Size, T.Size)); + } + set + { + ThrowIfIndexOutOfRange(index); + T.WriteToSpan(value, AsSpan().Slice(index * T.Size, T.Size)); + } + } + + private unsafe Span AsSpan() + { + return new Span(ArrayStartPointer.ToPointer(), Length * T.Size); + } + + private protected override unsafe Span GetUnsafeSpanForElement(int index) + { + ThrowIfIndexOutOfRange(index); + return new Span((byte*)ArrayStartPointer.ToPointer() + index * T.Size, T.Size); + } + + [return: NotNullIfNotNull(nameof(arr))] + public static implicit operator Il2CppNonBlittableArray?(T[]? arr) + { + if (arr == null) + return null; + + return new Il2CppNonBlittableArray(arr); + } + + private static IntPtr AllocateArray(long size) + { + if (size < 0) + throw new ArgumentOutOfRangeException(nameof(size), "Array size must not be negative"); + + var elementTypeClassPointer = Il2CppClassPointerStore.NativeClassPtr; + if (elementTypeClassPointer == IntPtr.Zero) + throw new ArgumentException( + $"{nameof(Il2CppNonBlittableArray)} requires an Il2Cpp type, which {typeof(T)} isn't"); + return IL2CPP.il2cpp_array_new(elementTypeClassPointer, (ulong)size); + } +} diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppObjectArray.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppObjectArray.cs new file mode 100644 index 00000000..327d71f4 --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppObjectArray.cs @@ -0,0 +1,61 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Il2CppInterop.Runtime.InteropTypes.Arrays; + +public sealed class Il2CppObjectArray : Il2CppArrayBase +{ + static Il2CppObjectArray() + { + StaticCtorBody(typeof(Il2CppObjectArray)); + } + + public Il2CppObjectArray(IntPtr pointer) : base(pointer) + { + } + public Il2CppObjectArray(ObjectPointer pointer) : base(pointer) + { + } + + public Il2CppObjectArray(long size) : base(AllocateArray(size)) + { + } + + public Il2CppObjectArray(object?[] arr) : base(AllocateArray(arr.Length)) + { + for (var i = 0; i < arr.Length; i++) + this[i] = arr[i]; + } +#nullable disable + public override unsafe object this[int index] + { + get => throw new NotImplementedException(); + set => throw new NotImplementedException(); + } +#nullable enable + private unsafe IntPtr* GetElementPointer(int index) + { + ThrowIfIndexOutOfRange(index); + return (IntPtr*)IntPtr.Add(ArrayStartPointer, index * IntPtr.Size).ToPointer(); + } + + [return: NotNullIfNotNull(nameof(arr))] + public static implicit operator Il2CppObjectArray?(object?[]? arr) + { + if (arr == null) + return null; + + return new Il2CppObjectArray(arr); + } + + private static IntPtr AllocateArray(long size) + { + if (size < 0) + throw new ArgumentOutOfRangeException(nameof(size), "Array size must not be negative"); + + var elementTypeClassPointer = Il2CppClassPointerStore.NativeClassPtr; + if (elementTypeClassPointer == IntPtr.Zero) + throw new ArgumentException("String class pointer is missing, something is very wrong"); + return IL2CPP.il2cpp_array_new(elementTypeClassPointer, (ulong)size); + } +} diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppReferenceArray.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppReferenceArray.cs index b2d9b181..2195e0ef 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppReferenceArray.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppReferenceArray.cs @@ -5,7 +5,7 @@ namespace Il2CppInterop.Runtime.InteropTypes.Arrays; -public class Il2CppReferenceArray : Il2CppArrayBase where T : Il2CppObjectBase? +public sealed class Il2CppReferenceArray : Il2CppArrayBase where T : Il2CppObjectBase? { private static readonly int ourElementTypeSize; private static readonly bool ourElementIsValueType; diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppStringArray.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppStringArray.cs index 834f24e2..21f0b40c 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppStringArray.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppStringArray.cs @@ -3,7 +3,7 @@ namespace Il2CppInterop.Runtime.InteropTypes.Arrays; -public class Il2CppStringArray : Il2CppArrayBase +public sealed class Il2CppStringArray : Il2CppArrayBase { static Il2CppStringArray() { diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppStructArray.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppStructArray.cs index 044928d9..29ed288f 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppStructArray.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppStructArray.cs @@ -1,9 +1,10 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.InteropTypes.Arrays; -public class Il2CppStructArray : Il2CppArrayBase where T : unmanaged +public sealed class Il2CppStructArray : Il2CppArrayBase where T : unmanaged { static Il2CppStructArray() { @@ -34,6 +35,11 @@ public unsafe Span AsSpan() return new Span(ArrayStartPointer.ToPointer(), Length); } + private protected override Span GetUnsafeSpanForElement(int index) + { + return MemoryMarshal.AsBytes(AsSpan().Slice(index, 1)); + } + [return: NotNullIfNotNull(nameof(arr))] public static implicit operator Il2CppStructArray?(T[]? arr) { diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppUnmanagedArray.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppUnmanagedArray.cs new file mode 100644 index 00000000..791037ae --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppUnmanagedArray.cs @@ -0,0 +1,77 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Il2CppInterop.Runtime.InteropTypes.Arrays; + +[CollectionBuilder(typeof(Il2CppArrayBase), nameof(CreateUnmanaged))] +public sealed class Il2CppUnmanagedArray : Il2CppArrayBase where T : unmanaged +{ + static Il2CppUnmanagedArray() + { + StaticCtorBody(typeof(Il2CppUnmanagedArray)); + } + + public Il2CppUnmanagedArray(IntPtr nativeObject) : base(nativeObject) + { + } + public Il2CppUnmanagedArray(ObjectPointer nativeObject) : base(nativeObject) + { + } + + public Il2CppUnmanagedArray(long size) : base(AllocateArray(size)) + { + } + + public Il2CppUnmanagedArray(ReadOnlySpan arr) : base(AllocateArray(arr.Length)) + { + arr.CopyTo(this); + } + + public override T this[int index] + { + get => AsSpan()[index]; + set => AsSpan()[index] = value; + } + + public unsafe Span AsSpan() + { + return new Span(ArrayStartPointer.ToPointer(), Length); + } + + private protected override Span GetUnsafeSpanForElement(int index) + { + return MemoryMarshal.AsBytes(AsSpan().Slice(index, 1)); + } + + [return: NotNullIfNotNull(nameof(arr))] + public static implicit operator Il2CppUnmanagedArray?(T[]? arr) + { + if (arr == null) return null; + + return new Il2CppUnmanagedArray(arr); + } + + public static implicit operator Span(Il2CppUnmanagedArray? il2CppArray) + { + return il2CppArray is not null ? il2CppArray.AsSpan() : default; + } + + public static implicit operator ReadOnlySpan(Il2CppUnmanagedArray? il2CppArray) + { + return il2CppArray is not null ? il2CppArray.AsSpan() : default; + } + + private static IntPtr AllocateArray(long size) + { + if (size < 0) + throw new ArgumentOutOfRangeException(nameof(size), "Array size must not be negative"); + + var elementTypeClassPointer = Il2CppClassPointerStore.NativeClassPtr; + if (elementTypeClassPointer == IntPtr.Zero) + throw new ArgumentException( + $"{nameof(Il2CppUnmanagedArray)} requires an Il2Cpp type, which {typeof(T)} isn't"); + return IL2CPP.il2cpp_array_new(elementTypeClassPointer, (ulong)size); + } +} diff --git a/Il2CppInterop.Runtime/InteropTypes/ByReference.cs b/Il2CppInterop.Runtime/InteropTypes/ByReference.cs new file mode 100644 index 00000000..21e53153 --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/ByReference.cs @@ -0,0 +1,85 @@ +using System; +using System.Runtime.CompilerServices; +using Il2CppInterop.Runtime.Runtime; + +namespace Il2CppInterop.Runtime.InteropTypes; + +#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type +public unsafe struct ByReference(T* value) : IIl2CppValueType, IIl2CppByReference + where T : IIl2CppValueType +{ + static ByReference() + { + // Todo: set Il2CppClassPointerStore>.NativeClassPtr + } + + private T* _value = value; + + readonly int IIl2CppByReference.ReferenceSize => typeof(T).IsValueType ? default(T)!.Size : IntPtr.Size; + + readonly nint IIl2CppByReference.ReferenceObjectClass => Il2CppClassPointerStore.NativeClassPtr; + + readonly int IIl2CppValueType.Size => IntPtr.Size; + + readonly nint IIl2CppValueType.ObjectClass => Il2CppClassPointerStore>.NativeClassPtr; + + public static implicit operator ByReference(T* value) => new(value); + public static implicit operator T*(ByReference pointer) => pointer._value; + + public static ByReference FromRef(ref T value) + { + return new ByReference((T*)Unsafe.AsPointer(ref value)); + } + + public static ref T ToRef(ByReference value) + { + return ref Unsafe.AsRef(value._value); + } + + readonly void IIl2CppByReference.WriteReferenceToSpan(Span span) + { + if (typeof(T).IsValueType) + { + if (_value is null) + { + span.Slice(0, default(T)!.Size).Clear(); + } + else + { + (*_value).WriteToSpan(span); + } + } + else + { + if (_value is null) + { + Il2CppTypeHelper.WritePointer(IntPtr.Zero, span); + } + else + { + Il2CppTypeHelper.WritePointer((*_value).Box(), span); + } + } + } + + void IIl2CppByReference.ReadReferenceFromSpan(ReadOnlySpan span) + { + if (_value is null) + { + // Cannot read a reference into a null pointer + } + else if (typeof(T).IsValueType) + { + (*_value).ReadFromSpan(span); + } + else + { + var pointer = Il2CppTypeHelper.ReadPointer(span); + *_value = pointer == IntPtr.Zero ? default : (T?)Il2CppObjectPool.Get(pointer); + } + } + + readonly void IIl2CppValueType.WriteToSpan(Span span) => Il2CppTypeHelper.WritePointer((IntPtr)_value, span); + void IIl2CppValueType.ReadFromSpan(ReadOnlySpan span) => _value = (T*)Il2CppTypeHelper.ReadPointer(span); +} +#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type diff --git a/Il2CppInterop.Runtime/InteropTypes/FieldAccessHelper.cs b/Il2CppInterop.Runtime/InteropTypes/FieldAccessHelper.cs new file mode 100644 index 00000000..b8f64ed8 --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/FieldAccessHelper.cs @@ -0,0 +1,82 @@ +using System; +using Il2CppInterop.Runtime.Runtime; + +namespace Il2CppInterop.Runtime.InteropTypes; + +public static unsafe class FieldAccessHelper +{ + public static T? GetStaticFieldValue(IntPtr fieldInfoPtr) where T : IIl2CppValueType + { + if (typeof(T).IsValueType) + { + T result = default!; + byte* data = stackalloc byte[result.Size]; + IL2CPP.il2cpp_field_static_get_value(fieldInfoPtr, data); + result.ReadFromSpan(new ReadOnlySpan(data, result.Size)); + return result; + } + else + { + IntPtr returnedPtr = default; + IL2CPP.il2cpp_field_static_get_value(fieldInfoPtr, &returnedPtr); + return (T?)Il2CppObjectPool.Get(returnedPtr); + } + } + + public static void SetStaticFieldValue(IntPtr fieldInfoPtr, T? value) where T : IIl2CppValueType + { + if (typeof(T).IsValueType) + { + byte* data = stackalloc byte[value!.Size]; + value!.WriteToPointer(data); + IL2CPP.il2cpp_field_static_set_value(fieldInfoPtr, data); + } + else + { + IL2CPP.il2cpp_field_static_set_value(fieldInfoPtr, (void*)value.Box()); + } + } + + public static T? GetInstanceFieldValue(IIl2CppObjectBase instance, int fieldOffset) where T : IIl2CppValueType + { + if (typeof(T).IsValueType) + { + T result = default!; + byte* data = (byte*)instance.Pointer + fieldOffset; + result.ReadFromSpan(new ReadOnlySpan(data, result.Size)); + return result; + } + else + { + byte* data = (byte*)instance.Pointer + fieldOffset; + IntPtr returnedPtr = *(IntPtr*)data; + return (T?)Il2CppObjectPool.Get(returnedPtr); + } + } + + public static void SetInstanceFieldValue_Wbarrior(IIl2CppObjectBase instance, int fieldOffset, T? value) where T : IIl2CppValueType + { + byte* data = (byte*)instance.Pointer + fieldOffset; + if (typeof(T).IsValueType) + { + value!.WriteToPointer(data); + } + else + { + IL2CPP.il2cpp_gc_wbarrier_set_field(instance.Pointer, (IntPtr)data, value.Box()); + } + } + + public static void SetInstanceFieldValue_Pointer(IIl2CppObjectBase instance, int fieldOffset, T? value) where T : IIl2CppValueType + { + byte* data = (byte*)instance.Pointer + fieldOffset; + if (typeof(T).IsValueType) + { + value!.WriteToPointer(data); + } + else + { + *(IntPtr*)data = value.Box(); + } + } +} diff --git a/Il2CppInterop.Runtime/InteropTypes/IIl2CppObjectBase.cs b/Il2CppInterop.Runtime/InteropTypes/IIl2CppObjectBase.cs new file mode 100644 index 00000000..2ffe0045 --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/IIl2CppObjectBase.cs @@ -0,0 +1,14 @@ +using System; + +namespace Il2CppInterop.Runtime.InteropTypes; + +public interface IIl2CppObjectBase : IIl2CppValueType +{ + IntPtr Pointer { get; } + IntPtr IIl2CppValueType.ObjectClass => IL2CPP.il2cpp_object_get_class(Pointer); + bool WasCollected { get; } +} +public interface IIl2CppObjectBase : IIl2CppObjectBase where TSelf : IIl2CppObjectBase +{ + static abstract TSelf Create(IntPtr ptr); +} diff --git a/Il2CppInterop.Runtime/InteropTypes/IIl2CppType.cs b/Il2CppInterop.Runtime/InteropTypes/IIl2CppType.cs new file mode 100644 index 00000000..fa6ba8a0 --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/IIl2CppType.cs @@ -0,0 +1,130 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Il2CppInterop.Runtime.Runtime; + +namespace Il2CppInterop.Runtime.InteropTypes; + +public interface IIl2CppType +{ + static abstract int Size { get; } +} +internal interface IObject2 : IIl2CppValueType +{ + +} +internal class Object2 : IObject2 +{ + int IIl2CppValueType.Size => throw new NotImplementedException(); + + nint IIl2CppValueType.ObjectClass => throw new NotImplementedException(); + + void IIl2CppValueType.ReadFromSpan(ReadOnlySpan span) => throw new NotImplementedException(); + void IIl2CppValueType.WriteToSpan(Span span) => throw new NotImplementedException(); +} +public interface IIl2CppType : IIl2CppType where TSelf : notnull, IIl2CppType +{ + static abstract void WriteToSpan(TSelf? value, Span span); + static abstract TSelf? ReadFromSpan(ReadOnlySpan span); +} +public interface IIl2CppValueType +{ + int Size { get; } + IntPtr ObjectClass { get; } + void WriteToSpan(Span span); + void ReadFromSpan(ReadOnlySpan span); +} +internal interface IIl2CppByReference +{ + int ReferenceSize { get; } + IntPtr ReferenceObjectClass { get; } + void WriteReferenceToSpan(Span span); + void ReadReferenceFromSpan(ReadOnlySpan span); +} +internal struct ValueTuple2 : IIl2CppType> where T1 : IIl2CppType where T2 : IIl2CppType +{ + public T1 Item1; + public T2 Item2; + + static int IIl2CppType.Size => Il2CppInternals_ValueTuple2.Size; + + static ValueTuple2 IIl2CppType>.ReadFromSpan(ReadOnlySpan span) + { + if (Il2CppTypeHelper.IsBlittable>()) + { + return MemoryMarshal.Read>(span); + } + else + { + ValueTuple2 result = default; + result.Item1 = Il2CppTypeHelper.ReadFromSpan(span.Slice(Il2CppInternals_ValueTuple2.FieldOffset_Instance_0, Il2CppTypeHelper.SizeOf())); + result.Item2 = Il2CppTypeHelper.ReadFromSpan(span.Slice(Il2CppInternals_ValueTuple2.FieldOffset_Instance_1, Il2CppTypeHelper.SizeOf())); + return result; + } + } + + static void IIl2CppType>.WriteToSpan(ValueTuple2 value, Span span) + { + if (Il2CppTypeHelper.IsBlittable>()) + { + MemoryMarshal.Write(span, in value); + } + else + { + Il2CppTypeHelper.WriteToSpan(value.Item1, span.Slice(Il2CppInternals_ValueTuple2.FieldOffset_Instance_0, Il2CppTypeHelper.SizeOf())); + Il2CppTypeHelper.WriteToSpan(value.Item2, span.Slice(Il2CppInternals_ValueTuple2.FieldOffset_Instance_1, Il2CppTypeHelper.SizeOf())); + } + } +} +internal class Class : IIl2CppType, IIl2CppObjectBase +{ + public IntPtr Pointer; + + static int IIl2CppType.Size => IntPtr.Size; + + nint IIl2CppObjectBase.Pointer => throw new NotImplementedException(); + + bool IIl2CppObjectBase.WasCollected => throw new NotImplementedException(); + + int IIl2CppValueType.Size => throw new NotImplementedException(); + + static Class? IIl2CppType.ReadFromSpan(ReadOnlySpan span) + { + return Il2CppTypeHelper.ReadClass(span); + } + + static void IIl2CppType.WriteToSpan(Class? value, Span span) + { + Il2CppTypeHelper.WriteClass(value, span); + } + + void IIl2CppValueType.ReadFromSpan(ReadOnlySpan span) => throw new NotImplementedException(); + void IIl2CppValueType.WriteToSpan(Span span) => throw new NotImplementedException(); +} +internal struct Int48 : IIl2CppType +{ + private uint _low; + private ushort _high; + + static int IIl2CppType.Size => 6; + static Int48 IIl2CppType.ReadFromSpan(ReadOnlySpan span) + { + return MemoryMarshal.Read(span); + } + static void IIl2CppType.WriteToSpan(Int48 value, Span span) + { + MemoryMarshal.Write(span, in value); + } +} +internal static class Il2CppInternals_ValueTuple2 +{ + internal static readonly int Size; + + internal static readonly IntPtr FieldInfoPtr_Instance_0; + + internal static readonly int FieldOffset_Instance_0; + + internal static readonly IntPtr FieldInfoPtr_Instance_1; + + internal static readonly int FieldOffset_Instance_1; +} diff --git a/Il2CppInterop.Runtime/InteropTypes/IIl2CppValueTypeExtensions.cs b/Il2CppInterop.Runtime/InteropTypes/IIl2CppValueTypeExtensions.cs new file mode 100644 index 00000000..c2c7ec1d --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/IIl2CppValueTypeExtensions.cs @@ -0,0 +1,39 @@ +using System; + +namespace Il2CppInterop.Runtime.InteropTypes; + +public static unsafe class IIl2CppValueTypeExtensions +{ + public static void WriteToPointer(this T value, void* data) where T : IIl2CppValueType + { + value.WriteToSpan(new Span(data, value.Size)); + } + + public static void ReadFromPointer(this ref T value, void* data) where T : struct, IIl2CppValueType + { + value.ReadFromSpan(new ReadOnlySpan(data, value.Size)); + } + + public static IntPtr Box(this T? value) where T : IIl2CppValueType + { + if (value is null) + { + return IntPtr.Zero; + } + else if (value is IIl2CppObjectBase @object) + { + return @object.Pointer; + } + else if (value.GetType().IsValueType) + { + byte* data = stackalloc byte[value.Size]; + value.WriteToSpan(new Span(data, value.Size)); + IntPtr boxedPtr = IL2CPP.il2cpp_value_box(value.ObjectClass, (IntPtr)data); + return boxedPtr; + } + else + { + throw new InvalidCastException(); + } + } +} diff --git a/Il2CppInterop.Runtime/InteropTypes/Il2CppObjectBase.cs b/Il2CppInterop.Runtime/InteropTypes/Il2CppObjectBase.cs index 7cbc0f1a..19817ece 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Il2CppObjectBase.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Il2CppObjectBase.cs @@ -1,174 +1 @@ -using System; -using System.Reflection; -using System.Reflection.Emit; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using Il2CppInterop.Runtime.Runtime; - -namespace Il2CppInterop.Runtime.InteropTypes; - -public class Il2CppObjectBase -{ - private static readonly MethodInfo _unboxMethod = typeof(Il2CppObjectBase).GetMethod(nameof(Unbox)); - internal bool isWrapped; - internal IntPtr pooledPtr; - - private nint myGcHandle; - - public Il2CppObjectBase(IntPtr pointer) - { - CreateGCHandle(pointer); - } - - public IntPtr ObjectClass => IL2CPP.il2cpp_object_get_class(Pointer); - - public IntPtr Pointer - { - get - { - var handleTarget = IL2CPP.il2cpp_gchandle_get_target(myGcHandle); - if (handleTarget == IntPtr.Zero) - throw new ObjectCollectedException("Object was garbage collected in IL2CPP domain"); - return handleTarget; - } - } - - public bool WasCollected - { - get - { - var handleTarget = IL2CPP.il2cpp_gchandle_get_target(myGcHandle); - if (handleTarget == IntPtr.Zero) return true; - return false; - } - } - - internal void CreateGCHandle(IntPtr objHdl) - { - if (objHdl == IntPtr.Zero) - throw new NullReferenceException(); - - // This object already wraps an Il2Cpp object, skip the pointer and let it be GC'd - if (isWrapped) - return; - - myGcHandle = IL2CPP.il2cpp_gchandle_new(objHdl, false); - } - - public T Cast() where T : Il2CppObjectBase - { - return TryCast() ?? throw new InvalidCastException( - $"Can't cast object of type {IL2CPP.il2cpp_class_get_name_(IL2CPP.il2cpp_object_get_class(Pointer))} to type {typeof(T)}"); - } - - internal static unsafe T UnboxUnsafe(IntPtr pointer) - { - var nestedTypeClassPointer = Il2CppClassPointerStore.NativeClassPtr; - if (nestedTypeClassPointer == IntPtr.Zero) - throw new ArgumentException($"{typeof(T)} is not an Il2Cpp reference type"); - - var ownClass = IL2CPP.il2cpp_object_get_class(pointer); - if (!IL2CPP.il2cpp_class_is_assignable_from(nestedTypeClassPointer, ownClass)) - throw new InvalidCastException( - $"Can't cast object of type {IL2CPP.il2cpp_class_get_name_(ownClass)} to type {typeof(T)}"); - - return Unsafe.AsRef(IL2CPP.il2cpp_object_unbox(pointer).ToPointer()); - } - - public T Unbox() where T : unmanaged - { - return UnboxUnsafe(Pointer); - } - - private static readonly Type[] _intPtrTypeArray = { typeof(IntPtr) }; - private static readonly MethodInfo _getUninitializedObject = typeof(RuntimeHelpers).GetMethod(nameof(RuntimeHelpers.GetUninitializedObject))!; - private static readonly MethodInfo _getTypeFromHandle = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle))!; - private static readonly MethodInfo _createGCHandle = typeof(Il2CppObjectBase).GetMethod(nameof(CreateGCHandle), BindingFlags.Instance | BindingFlags.NonPublic)!; - private static readonly FieldInfo _isWrapped = typeof(Il2CppObjectBase).GetField(nameof(isWrapped), BindingFlags.Instance | BindingFlags.NonPublic)!; - - internal static class InitializerStore - { - private static Func? _initializer; - - private static Func Create() - { - var type = Il2CppClassPointerStore.CreatedTypeRedirect ?? typeof(T); - - var dynamicMethod = new DynamicMethod($"Initializer<{typeof(T).AssemblyQualifiedName}>", type, _intPtrTypeArray); - dynamicMethod.DefineParameter(0, ParameterAttributes.None, "pointer"); - - var il = dynamicMethod.GetILGenerator(); - - if (type.GetConstructor(new[] { typeof(IntPtr) }) is { } pointerConstructor) - { - // Base case: Il2Cpp constructor => call it directly - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Newobj, pointerConstructor); - } - else - { - // Special case: We have a parameterless constructor - // However, it could be be user-made or implicit - // In that case we set the GCHandle and then call the ctor and let GC destroy any objects created by DerivedConstructorPointer - - // var obj = (T)RuntimeHelpers.GetUninitializedObject(type); - il.Emit(OpCodes.Ldtoken, type); - il.Emit(OpCodes.Call, _getTypeFromHandle); - il.Emit(OpCodes.Call, _getUninitializedObject); - il.Emit(OpCodes.Castclass, type); - - // obj.CreateGCHandle(pointer); - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Callvirt, _createGCHandle); - - // obj.isWrapped = true; - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Ldc_I4_1); - il.Emit(OpCodes.Stfld, _isWrapped); - - var parameterlessConstructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.EmptyTypes); - if (parameterlessConstructor != null) - { - // obj..ctor(); - il.Emit(OpCodes.Dup); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Callvirt, parameterlessConstructor); - } - } - - il.Emit(OpCodes.Ret); - - return dynamicMethod.CreateDelegate>(); - } - - public static Func Initializer => _initializer ??= Create(); - } - - public T? TryCast() where T : Il2CppObjectBase - { - var nestedTypeClassPointer = Il2CppClassPointerStore.NativeClassPtr; - if (nestedTypeClassPointer == IntPtr.Zero) - throw new ArgumentException($"{typeof(T)} is not an Il2Cpp reference type"); - - var ownClass = IL2CPP.il2cpp_object_get_class(Pointer); - if (!IL2CPP.il2cpp_class_is_assignable_from(nestedTypeClassPointer, ownClass)) - return null; - - if (RuntimeSpecificsStore.IsInjected(ownClass)) - { - if (ClassInjectorBase.GetMonoObjectFromIl2CppPointer(Pointer) is T monoObject) return monoObject; - } - - return InitializerStore.Initializer(Pointer); - } - - ~Il2CppObjectBase() - { - IL2CPP.il2cpp_gchandle_free(myGcHandle); - - if (pooledPtr == IntPtr.Zero) return; - Il2CppObjectPool.Remove(pooledPtr); - } -} +global using Il2CppObjectBase = Il2CppSystem.Object; diff --git a/Il2CppInterop.Runtime/InteropTypes/Il2CppTypeHelper.cs b/Il2CppInterop.Runtime/InteropTypes/Il2CppTypeHelper.cs new file mode 100644 index 00000000..09f67cc5 --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/Il2CppTypeHelper.cs @@ -0,0 +1,77 @@ +using System; +using System.Buffers.Binary; +using System.Runtime.CompilerServices; +using Il2CppInterop.Runtime.Runtime; + +namespace Il2CppInterop.Runtime.InteropTypes; + +public static class Il2CppTypeHelper +{ + public static bool IsBlittable() where T : IIl2CppType + { + return T.Size == Unsafe.SizeOf() + && !RuntimeHelpers.IsReferenceOrContainsReferences() + && !typeof(T).IsGenericType; + } + + public static int SizeOf() where T : IIl2CppType + { + return T.Size; + } + + public static void WriteToSpan(T value, Span span) where T : IIl2CppType + { + T.WriteToSpan(value, span); + } + + public static T ReadFromSpan(ReadOnlySpan span) where T : IIl2CppType + { + return T.ReadFromSpan(span); + } + + public static unsafe T ReadFromPointer(IntPtr ptr) where T : IIl2CppType + { + return T.ReadFromSpan(new ReadOnlySpan(ptr.ToPointer(), T.Size)); + } + + public static T? ReadClass(ReadOnlySpan span) where T : class, IIl2CppObjectBase + { + return (T?)Il2CppObjectPool.Get(ReadPointer(span)); + } + + public static void WriteClass(T? value, Span span) where T : class, IIl2CppObjectBase + { + if (value == null) + { + WritePointer(IntPtr.Zero, span); + } + else + { + WritePointer(value.Pointer, span); + } + } + + public static nint ReadPointer(ReadOnlySpan span) + { + if (BitConverter.IsLittleEndian) + { + return BinaryPrimitives.ReadIntPtrLittleEndian(span); + } + else + { + return BinaryPrimitives.ReadIntPtrBigEndian(span); + } + } + + public static void WritePointer(nint pointer, Span span) + { + if (BitConverter.IsLittleEndian) + { + BinaryPrimitives.WriteIntPtrLittleEndian(span, pointer); + } + else + { + BinaryPrimitives.WriteIntPtrBigEndian(span, pointer); + } + } +} diff --git a/Il2CppInterop.Runtime/InteropTypes/Pointer.cs b/Il2CppInterop.Runtime/InteropTypes/Pointer.cs new file mode 100644 index 00000000..aad7df58 --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/Pointer.cs @@ -0,0 +1,26 @@ +using System; + +namespace Il2CppInterop.Runtime.InteropTypes; + +#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type +public unsafe struct Pointer(T* value) : IIl2CppValueType + where T : IIl2CppValueType +{ + static Pointer() + { + // Todo: set Il2CppClassPointerStore>.NativeClassPtr + } + + private T* _value = value; + + readonly int IIl2CppValueType.Size => IntPtr.Size; + + readonly nint IIl2CppValueType.ObjectClass => Il2CppClassPointerStore>.NativeClassPtr; + + void IIl2CppValueType.ReadFromSpan(ReadOnlySpan span) => _value = (T*)Il2CppTypeHelper.ReadPointer(span); + readonly void IIl2CppValueType.WriteToSpan(Span span) => Il2CppTypeHelper.WritePointer((IntPtr)_value, span); + + public static implicit operator Pointer(T* value) => new(value); + public static implicit operator T*(Pointer pointer) => pointer._value; +} +#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type diff --git a/Il2CppInterop.Runtime/InteropTypes/RuntimeInvokeHelper.cs b/Il2CppInterop.Runtime/InteropTypes/RuntimeInvokeHelper.cs new file mode 100644 index 00000000..59099338 --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/RuntimeInvokeHelper.cs @@ -0,0 +1,208 @@ +using System; +using System.Runtime.CompilerServices; +using Il2CppInterop.Runtime.Runtime; + +namespace Il2CppInterop.Runtime.InteropTypes; + +public static unsafe class RuntimeInvokeHelper +{ + private static IntPtr Il2CppRuntimeInvoke(IntPtr method, IntPtr obj, void** parameters) + { + IntPtr exception = default; + IntPtr result = IL2CPP.il2cpp_runtime_invoke(method, obj, parameters, ref exception); + Il2CppException.RaiseExceptionIfNecessary(exception); + return result; + } + + public static void InvokeAction(IntPtr method, IntPtr obj, void** parameters) + { + Il2CppRuntimeInvoke(method, obj, parameters); + } + + public static TResult? InvokeFunction(IntPtr method, IntPtr obj, void** parameters) + where TResult : IIl2CppValueType + { + IntPtr result = Il2CppRuntimeInvoke(method, obj, parameters); + if (IsPointerOrByRef()) + { + // Pointers and by refs are returned directly. + return Unsafe.As(ref result); + } + else if (IsValueType()) + { + // This is a performance optimization. The other code path would also return the correct result. + TResult returnValue = default!; + byte* data = (byte*)IL2CPP.il2cpp_object_unbox(result); + returnValue.ReadFromSpan(new ReadOnlySpan(data, returnValue.Size)); + return returnValue; + } + else + { + return (TResult?)Il2CppObjectPool.Get(result); + } + } + + private static bool IsPointerOrByRef() + { + return IsPointer() || IsByRef(); + } + + private static bool IsPointer() + { + return typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Pointer<>); + } + + private static bool IsByRef() + { + return typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(ByReference<>); + } + + private static bool IsValueType() + { + return typeof(T).IsValueType; + } + + public static int RequiredStackAllocationSize() + where T : IIl2CppValueType + { + if (IsPointer()) + { + return default; + } + else if (IsByRef()) + { + return ((IIl2CppByReference)default(T)!).ReferenceSize; + } + else if (IsValueType()) + { + return default(T)!.Size; + } + else + { + return default; + } + } + + public static IntPtr PrepareParameter(T? parameter, byte* parameter_stackAllocData) + where T : IIl2CppValueType + { + if (IsPointer()) + { + return Unsafe.As(ref parameter!); + } + else if (IsByRef()) + { + var il2CppByRef = ((IIl2CppByReference)parameter!); + il2CppByRef.WriteReferenceToSpan(new Span(parameter_stackAllocData, il2CppByRef.ReferenceSize)); + return (IntPtr)parameter_stackAllocData; + } + else if (IsValueType()) + { + parameter!.WriteToPointer(parameter_stackAllocData); + return (IntPtr)parameter_stackAllocData; + } + else + { + return parameter.Box(); + } + } + + public static void CleanupParameter(T? parameter, byte* parameter_stackAllocData) + where T : IIl2CppValueType + { + if (IsByRef()) + { + var il2CppByRef = ((IIl2CppByReference)parameter!); + il2CppByRef.ReadReferenceFromSpan(new ReadOnlySpan(parameter_stackAllocData, il2CppByRef.ReferenceSize)); + } + } + + private static void ExampleInvokeAction(IntPtr method, IntPtr obj, T1? param1, T2? param2) + where T1 : IIl2CppValueType + where T2 : IIl2CppValueType + { + IntPtr* parameters = stackalloc IntPtr[2]; + + // Parameter 1 + int param1_stackAllocSize = RequiredStackAllocationSize(); + byte* param1_stackAllocData; + if (param1_stackAllocSize > 0) + { + byte* temp = stackalloc byte[param1_stackAllocSize]; + param1_stackAllocData = temp; + } + else + { + param1_stackAllocData = null; + } + parameters[0] = PrepareParameter(param1, param1_stackAllocData); + + // Parameter 2 + int param2_stackAllocSize = RequiredStackAllocationSize(); + byte* param2_stackAllocData; + if (param2_stackAllocSize > 0) + { + byte* temp = stackalloc byte[param2_stackAllocSize]; + param2_stackAllocData = temp; + } + else + { + param2_stackAllocData = null; + } + parameters[1] = PrepareParameter(param2, param2_stackAllocData); + + InvokeAction(method, obj, (void**)parameters); + + CleanupParameter(param1, param1_stackAllocData); + CleanupParameter(param2, param2_stackAllocData); + } + + private static TResult? ExampleInvokeFunction(IntPtr method, IntPtr obj, T1? param1, T2? param2) + where T1 : IIl2CppValueType + where T2 : IIl2CppValueType + where TResult : IIl2CppValueType + { + IntPtr* parameters = stackalloc IntPtr[2]; + + // Parameter 1 + int param1_stackAllocSize = RequiredStackAllocationSize(); + byte* param1_stackAllocData; + if (param1_stackAllocSize > 0) + { + byte* temp = stackalloc byte[param1_stackAllocSize]; + param1_stackAllocData = temp; + } + else + { + param1_stackAllocData = null; + } + parameters[0] = PrepareParameter(param1, param1_stackAllocData); + + // Parameter 2 + int param2_stackAllocSize = RequiredStackAllocationSize(); + byte* param2_stackAllocData; + if (param2_stackAllocSize > 0) + { + byte* temp = stackalloc byte[param2_stackAllocSize]; + param2_stackAllocData = temp; + } + else + { + param2_stackAllocData = null; + } + parameters[1] = PrepareParameter(param2, param2_stackAllocData); + + var result = InvokeFunction(method, obj, (void**)parameters); + + CleanupParameter(param1, param1_stackAllocData); + CleanupParameter(param2, param2_stackAllocData); + + return result; + } + + private static TResult? ExampleInvokeFunction(IntPtr method, IntPtr obj) + where TResult : IIl2CppValueType + { + return InvokeFunction(method, obj, null); + } +} diff --git a/Il2CppInterop.Runtime/Libs/Il2Cppmscorlib.dll b/Il2CppInterop.Runtime/Libs/Il2Cppmscorlib.dll deleted file mode 100644 index 0a5715c313bf6c26452502b44a7a59f6e3249a86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2960896 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®crfi8o^Q#xwT>h9b9(Cgzmax1$0!-| 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 z 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 (jbDi=()7iS4oSx(HJp2!VIduVmS^2mBPD#6 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

LEVU;!3 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�+x(IPZtyq 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

+ /// Get the class pointer for this type + /// + /// + /// This can be null if the type doesn't have a corresponding class, such as generic type instance not used in the game. + /// + /// The class pointer for this type + public nint ToClassPointer() + { + return IL2CPP.il2cpp_class_from_type(type.ToTypePointer()); + } + } +} diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index 188c556d..ebccffb5 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -1,9 +1,12 @@ using System; using System.ComponentModel; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Exceptions; +using Il2CppInterop.Runtime.Extensions; +using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.Runtime; using Microsoft.Extensions.Logging; @@ -47,13 +50,7 @@ public static Il2CppSystem.Type ManagedTypeToIl2CppType(Type type) throw new ArgumentException($"{type} does not have a corresponding IL2CPP class pointer"); } - var il2CppType = IL2CPP.il2cpp_class_get_type(classPointer); - if (il2CppType == IntPtr.Zero) - { - throw new ArgumentException($"{type} does not have a corresponding IL2CPP type pointer"); - } - - return Il2CppSystem.Type.internal_from_handle(il2CppType); + return Il2CppSystem.Type.FromClassPointer(classPointer); } public static nint Il2CppGCHandleGetTargetOrThrow(nint gchandle) @@ -70,6 +67,30 @@ public static bool Il2CppGCHandleGetTargetWasCollected(nint gchandle) return obj == nint.Zero; } + /// + /// Get the class pointer for a generic instance type + /// + /// The class pointer for the generic type definition + /// The class pointers for the generic type arguments + /// The class pointer for the generic instance type + public static nint GetIl2CppGenericInstanceType(nint typeClassPointer, params nint[] genericTypeArguments) + { + var types = new Il2CppSystem.Type[genericTypeArguments.Length]; + for (var i = 0; i < genericTypeArguments.Length; i++) + { + types[i] = Il2CppSystem.Type.FromClassPointer(genericTypeArguments[i]); + } + var genericTypeInstance = Il2CppSystem.Type.FromClassPointer(typeClassPointer).MakeGenericType(types); + var result = genericTypeInstance.ToClassPointer(); + if (result == nint.Zero) + { + var className = IL2CPP.il2cpp_class_get_name(typeClassPointer); + Logger.Instance.LogTrace("Could not get class pointer for generic instance type {ClassName}`{TypeArgumentCount}. Creating one...", className, genericTypeArguments.Length); + result = GenericTypeInflater.InflateGenericType(typeClassPointer, genericTypeArguments); + } + return result; + } + public static nint GetIl2CppMethodByToken(nint clazz, int token) { if (clazz == nint.Zero) diff --git a/Il2CppInterop.Runtime/IL2CPP.cs b/Il2CppInterop.Runtime/IL2CPP.cs index 98c5559f..e7c6e6ed 100644 --- a/Il2CppInterop.Runtime/IL2CPP.cs +++ b/Il2CppInterop.Runtime/IL2CPP.cs @@ -2,6 +2,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Il2CppInterop.Common; +using Il2CppInterop.Runtime.Extensions; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.Runtime; using Microsoft.Extensions.Logging; @@ -49,32 +50,16 @@ public static int GetIl2CppValueSize(nint klass) public static nint GetIl2CppGenericInstanceMethod(nint methodInfoPointer, nint declaringTypeClassPointer, params nint[] genericMethodArguments) { - // Ensure Il2CppSystem.RuntimeType is initialized before we call Il2CppSystem.Type.internal_from_handle - RuntimeHelpers.RunClassConstructor(typeof(Il2CppSystem.RuntimeType).TypeHandle); - var types = new Il2CppSystem.Type[genericMethodArguments.Length]; for (var i = 0; i < genericMethodArguments.Length; i++) { - types[i] = Il2CppSystem.Type.internal_from_handle(il2cpp_class_get_type(genericMethodArguments[i])); + types[i] = Il2CppSystem.Type.FromClassPointer(genericMethodArguments[i]); } var methodInfoObject = (Il2CppSystem.Reflection.MethodInfo)Il2CppObjectPool.Get(il2cpp_method_get_object(methodInfoPointer, declaringTypeClassPointer))!; var methodInfoGeneric = methodInfoObject.MakeGenericMethod(types); return il2cpp_method_get_from_reflection(methodInfoGeneric?.Pointer ?? throw new NullReferenceException()); } - public static nint GetIl2CppGenericInstanceType(nint typeClassPointer, params nint[] genericTypeArguments) - { - // Ensure Il2CppSystem.RuntimeType is initialized before we call Il2CppSystem.Type.internal_from_handle - RuntimeHelpers.RunClassConstructor(typeof(Il2CppSystem.RuntimeType).TypeHandle); - - var types = new Il2CppSystem.Type[genericTypeArguments.Length]; - for (var i = 0; i < genericTypeArguments.Length; i++) - { - types[i] = Il2CppSystem.Type.internal_from_handle(il2cpp_class_get_type(genericTypeArguments[i])); - } - return il2cpp_class_from_type(Il2CppSystem.Type.internal_from_handle(il2cpp_class_get_type(typeClassPointer)).MakeGenericType(types).TypeHandle.value); - } - public static ObjectPointer NewObjectPointer() { return (ObjectPointer)il2cpp_object_new(Il2CppClassPointerStore.NativeClassPointer); @@ -82,7 +67,8 @@ public static ObjectPointer NewObjectPointer() public static nint GetIl2CppNestedType(nint enclosingType, string nestedTypeName) { - if (enclosingType == nint.Zero) return nint.Zero; + if (enclosingType == nint.Zero) + return nint.Zero; var iter = nint.Zero; nint nestedTypePtr; @@ -104,10 +90,10 @@ public static nint GetIl2CppNestedType(nint enclosingType, string nestedTypeName static IntPtr GetNestedTypeViaReflection(nint enclosingClass, string nestedTypeName) { - var reflectionType = Il2CppSystem.Type.internal_from_handle(il2cpp_class_get_type(enclosingClass)); + var reflectionType = Il2CppSystem.Type.FromClassPointer(enclosingClass); var nestedType = reflectionType.GetNestedType(nestedTypeName, Il2CppSystem.Reflection.BindingFlags.Public | Il2CppSystem.Reflection.BindingFlags.NonPublic); - return nestedType != null ? il2cpp_class_from_system_type(nestedType.Pointer) : IntPtr.Zero; + return nestedType?.ToClassPointer() ?? nint.Zero; } } diff --git a/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs b/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs new file mode 100644 index 00000000..64d84ac8 --- /dev/null +++ b/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs @@ -0,0 +1,70 @@ +using System; +using Il2CppInterop.Runtime.Runtime; +using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class; +using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; + +namespace Il2CppInterop.Runtime.Injection; + +internal static unsafe class GenericTypeInflater +{ + internal static nint InflateGenericType(nint genericClassPointer, nint[] genericArgClassPtrs) + { + return InflateGenericType(UnityVersionHandler.Wrap((Il2CppClass*)genericClassPointer), genericArgClassPtrs); + } + + private static nint InflateGenericType(INativeClassStruct genericClassPointer, nint[] genericArgClassPtrs) + { + var inflatedClassPointer = UnityVersionHandler.NewClass(genericClassPointer.VTableCount); + + CopyFrom(inflatedClassPointer.ByValArg, genericClassPointer.ByValArg); + CopyFrom(inflatedClassPointer.ThisArg, genericClassPointer.ThisArg); + + inflatedClassPointer.InstanceSize = genericClassPointer.InstanceSize; + inflatedClassPointer.VTableCount = genericClassPointer.VTableCount; + inflatedClassPointer.InterfaceCount = genericClassPointer.InterfaceCount; + inflatedClassPointer.InterfaceOffsetsCount = genericClassPointer.InterfaceOffsetsCount; + inflatedClassPointer.TypeHierarchyDepth = genericClassPointer.TypeHierarchyDepth; + inflatedClassPointer.NativeSize = genericClassPointer.NativeSize; + inflatedClassPointer.ActualSize = genericClassPointer.ActualSize; + inflatedClassPointer.MethodCount = genericClassPointer.MethodCount; + inflatedClassPointer.FieldCount = genericClassPointer.FieldCount; + inflatedClassPointer.Flags = genericClassPointer.Flags; + inflatedClassPointer.Name = genericClassPointer.Name; + inflatedClassPointer.Namespace = genericClassPointer.Namespace; + inflatedClassPointer.Image = genericClassPointer.Image; + inflatedClassPointer.Parent = genericClassPointer.Parent; + inflatedClassPointer.ElementClass = genericClassPointer.ElementClass; + inflatedClassPointer.CastClass = genericClassPointer.CastClass; + inflatedClassPointer.DeclaringType = genericClassPointer.DeclaringType; + inflatedClassPointer.Class = inflatedClassPointer.Class; + inflatedClassPointer.Fields = genericClassPointer.Fields; + inflatedClassPointer.Methods = genericClassPointer.Methods; + inflatedClassPointer.ImplementedInterfaces = genericClassPointer.ImplementedInterfaces; + inflatedClassPointer.InterfaceOffsets = genericClassPointer.InterfaceOffsets; + inflatedClassPointer.TypeHierarchy = genericClassPointer.TypeHierarchy; + inflatedClassPointer.ValueType = genericClassPointer.ValueType; + inflatedClassPointer.Initialized = true; + inflatedClassPointer.EnumType = genericClassPointer.EnumType; + inflatedClassPointer.IsGeneric = true; + inflatedClassPointer.HasReferences = genericClassPointer.HasReferences; + inflatedClassPointer.SizeInited = true; + inflatedClassPointer.HasFinalize = genericClassPointer.HasFinalize; + inflatedClassPointer.IsVtableInitialized = true; + inflatedClassPointer.InitializedAndNoError = true; + + new ReadOnlySpan(genericClassPointer.VTable, genericClassPointer.VTableCount) + .CopyTo(new Span(inflatedClassPointer.VTable, inflatedClassPointer.VTableCount)); + + return inflatedClassPointer.Pointer; + } + + private static void CopyFrom(INativeTypeStruct destination, INativeTypeStruct source) + { + destination.Data = source.Data; + destination.Attrs = source.Attrs; + destination.Type = source.Type; + destination.ByRef = source.ByRef; + destination.Pinned = source.Pinned; + destination.ValueType = source.ValueType; + } +} diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 966d7048..f5d960b5 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -9,6 +9,7 @@ using System.Runtime.InteropServices; using Il2CppInterop.Common; using Il2CppInterop.Common.Attributes; +using Il2CppInterop.Runtime.Extensions; using Il2CppInterop.Runtime.Runtime; using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class; using Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo; @@ -655,7 +656,7 @@ private static Il2CppSystem.String GetFullName(Type type) private static Il2CppSystem.String GetFullName(Il2CppTypeStruct* type) { - return Il2CppSystem.Type.internal_from_handle((nint)type).FullName; + return Il2CppSystem.Type.FromTypePointer((nint)type).FullName; } private static ReadOnlySpan GetSpan(Il2CppSystem.String? str) @@ -886,7 +887,7 @@ static Il2CppSystem.Type TypeFromClassPointer(nint classPointer, string? typeNam throw new ArgumentException($"{typeName} does not have a corresponding IL2CPP type pointer"); } - return Il2CppSystem.Type.internal_from_handle(il2CppType); + return Il2CppSystem.Type.FromTypePointer(il2CppType); } } diff --git a/Il2CppInterop.Runtime/InteropTypes/Pointer.cs b/Il2CppInterop.Runtime/InteropTypes/Pointer.cs index 780d923f..44a0962e 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Pointer.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Pointer.cs @@ -1,5 +1,6 @@ using System; using Il2CppInterop.Common; +using Il2CppInterop.Runtime.Extensions; namespace Il2CppInterop.Runtime.InteropTypes; @@ -48,7 +49,7 @@ private readonly void ThrowIfNull() static Pointer() { - var elementType = Il2CppSystem.Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(Il2CppClassPointerStore.NativeClassPointer)); - Il2CppClassPointerStore>.NativeClassPointer = IL2CPP.il2cpp_class_from_type(elementType.MakePointerType().TypeHandle.value); + var elementType = Il2CppSystem.Type.FromClassPointer(Il2CppClassPointerStore.NativeClassPointer); + Il2CppClassPointerStore>.NativeClassPointer = elementType.MakePointerType().ToClassPointer(); } } From a431b63b89e7e54bc222fb5f07bc96df27594b3e Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 3 May 2026 10:51:31 -0700 Subject: [PATCH 370/486] Update NuGet dependencies to latest versions Updated Microsoft.Extensions.Logging and NUnit package versions across multiple project files to ensure compatibility and access to the latest features and fixes. No other code changes were made. --- Il2CppInterop.CLI/Il2CppInterop.CLI.csproj | 4 ++-- Il2CppInterop.Common/Il2CppInterop.Common.csproj | 2 +- .../Il2CppInterop.SourceGenerator.Tests.csproj | 2 +- .../Il2CppInterop.StructGenerator.csproj | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj b/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj index 8a797f6c..4c5343e3 100644 --- a/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj +++ b/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj @@ -20,8 +20,8 @@ - - + + diff --git a/Il2CppInterop.Common/Il2CppInterop.Common.csproj b/Il2CppInterop.Common/Il2CppInterop.Common.csproj index 80c899bc..1b5bb793 100644 --- a/Il2CppInterop.Common/Il2CppInterop.Common.csproj +++ b/Il2CppInterop.Common/Il2CppInterop.Common.csproj @@ -11,7 +11,7 @@ - + diff --git a/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj b/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj index 2bad3752..8803fde3 100644 --- a/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj +++ b/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj @@ -13,7 +13,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj b/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj index 6d01babf..f8f1e8b7 100644 --- a/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj +++ b/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj @@ -12,7 +12,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 70b5269cc25f423acbfc36accf43d970a5fbcf10 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 3 May 2026 11:18:08 -0700 Subject: [PATCH 371/486] Move Il2CppObjectPool to root in Il2CppInterop.Runtime --- .../InitializationClassProcessingLayer.cs | 1 - Il2CppInterop.Generator/ObjectInternalsProcessingLayer.cs | 1 - .../ReferenceAssemblyInjectionProcessingLayer.cs | 1 - Il2CppInterop.Runtime/Exceptions/Il2CppException.cs | 1 - Il2CppInterop.Runtime/{Runtime => }/Il2CppObjectPool.cs | 2 +- Il2CppInterop.Runtime/Il2CppType.cs | 1 - .../InteropTypes/Arrays/Il2CppArrayRank1.cs | 1 - .../InteropTypes/Arrays/Il2CppArrayRank2.cs | 1 - .../InteropTypes/Arrays/Il2CppArrayRank3.cs | 1 - Il2CppInterop.Runtime/RuntimeInvoke.cs | 1 - Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs | 6 +++--- Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs | 4 ++-- 12 files changed, 6 insertions(+), 15 deletions(-) rename Il2CppInterop.Runtime/{Runtime => }/Il2CppObjectPool.cs (98%) diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index 3dbafb5e..2d8d5f6b 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -15,7 +15,6 @@ using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; -using Il2CppInterop.Runtime.Runtime; namespace Il2CppInterop.Generator; diff --git a/Il2CppInterop.Generator/ObjectInternalsProcessingLayer.cs b/Il2CppInterop.Generator/ObjectInternalsProcessingLayer.cs index c9a91557..fd60bfac 100644 --- a/Il2CppInterop.Generator/ObjectInternalsProcessingLayer.cs +++ b/Il2CppInterop.Generator/ObjectInternalsProcessingLayer.cs @@ -4,7 +4,6 @@ using Cpp2IL.Core.Model.Contexts; using Il2CppInterop.Generator.Operands; using Il2CppInterop.Runtime; -using Il2CppInterop.Runtime.Runtime; namespace Il2CppInterop.Generator; diff --git a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs index 9c1bf4a7..04f075ac 100644 --- a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs +++ b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs @@ -8,7 +8,6 @@ using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; -using Il2CppInterop.Runtime.Runtime; namespace Il2CppInterop.Generator; diff --git a/Il2CppInterop.Runtime/Exceptions/Il2CppException.cs b/Il2CppInterop.Runtime/Exceptions/Il2CppException.cs index cd605d72..01cdba23 100644 --- a/Il2CppInterop.Runtime/Exceptions/Il2CppException.cs +++ b/Il2CppInterop.Runtime/Exceptions/Il2CppException.cs @@ -2,7 +2,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text; -using Il2CppInterop.Runtime.Runtime; namespace Il2CppInterop.Runtime.Exceptions; diff --git a/Il2CppInterop.Runtime/Runtime/Il2CppObjectPool.cs b/Il2CppInterop.Runtime/Il2CppObjectPool.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/Il2CppObjectPool.cs rename to Il2CppInterop.Runtime/Il2CppObjectPool.cs index 47a2cc7d..b4310f9b 100644 --- a/Il2CppInterop.Runtime/Runtime/Il2CppObjectPool.cs +++ b/Il2CppInterop.Runtime/Il2CppObjectPool.cs @@ -2,7 +2,7 @@ using System.Collections.Concurrent; using Il2CppInterop.Common; -namespace Il2CppInterop.Runtime.Runtime; +namespace Il2CppInterop.Runtime; public static class Il2CppObjectPool { diff --git a/Il2CppInterop.Runtime/Il2CppType.cs b/Il2CppInterop.Runtime/Il2CppType.cs index 506046da..cd19da69 100644 --- a/Il2CppInterop.Runtime/Il2CppType.cs +++ b/Il2CppInterop.Runtime/Il2CppType.cs @@ -3,7 +3,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Il2CppInterop.Common; -using Il2CppInterop.Runtime.Runtime; namespace Il2CppInterop.Runtime; diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank1.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank1.cs index 254572e5..0501fa77 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank1.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank1.cs @@ -5,7 +5,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Il2CppInterop.Common; -using Il2CppInterop.Runtime.Runtime; namespace Il2CppInterop.Runtime.InteropTypes.Arrays; diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs index dbe7d0f0..030a2fb7 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; using Il2CppInterop.Common; -using Il2CppInterop.Runtime.Runtime; namespace Il2CppInterop.Runtime.InteropTypes.Arrays; diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs index 84133bae..cad76508 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs @@ -1,7 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; using Il2CppInterop.Common; -using Il2CppInterop.Runtime.Runtime; namespace Il2CppInterop.Runtime.InteropTypes.Arrays; diff --git a/Il2CppInterop.Runtime/RuntimeInvoke.cs b/Il2CppInterop.Runtime/RuntimeInvoke.cs index bcf85939..85c5211c 100644 --- a/Il2CppInterop.Runtime/RuntimeInvoke.cs +++ b/Il2CppInterop.Runtime/RuntimeInvoke.cs @@ -6,7 +6,6 @@ using Il2CppInterop.Common; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; -using Il2CppInterop.Runtime.Runtime; using Microsoft.Extensions.Logging; using Il2CppException = Il2CppInterop.Runtime.Exceptions.Il2CppException; diff --git a/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs b/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs index 0a3779aa..70685c65 100644 --- a/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs +++ b/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs @@ -31,12 +31,12 @@ public Sample(global::Il2CppInterop.Common.ObjectPointer obj0) : base(obj0) static Sample? global::Il2CppInterop.Common.IIl2CppType.ReadFromSpan(global::System.ReadOnlySpan span) { - return global::Il2CppInterop.Runtime.InteropTypes.Il2CppType.ReadReference(span); + return global::Il2CppInterop.Runtime.Il2CppType.ReadReference(span); } static void global::Il2CppInterop.Common.IIl2CppType.WriteToSpan(Sample? value, global::System.Span span) { - global::Il2CppInterop.Runtime.InteropTypes.Il2CppType.WriteReference(value, span); + global::Il2CppInterop.Runtime.Il2CppType.WriteReference(value, span); } static Sample() @@ -51,7 +51,7 @@ file static class Il2CppInternals static Il2CppInternals() { global::Il2CppInterop.Runtime.Injection.TypeInjector.RegisterTypeInIl2Cpp(); - global::Il2CppInterop.Runtime.Runtime.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Runtime.Il2CppClassPointerStore.NativeClassPointer, ptr => new Sample(ptr)); + global::Il2CppInterop.Runtime.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Runtime.Il2CppClassPointerStore.NativeClassPointer, ptr => new Sample(ptr)); } } diff --git a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs index 3982347a..d04dae22 100644 --- a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs +++ b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs @@ -423,11 +423,11 @@ private static void EmitInternalsClass(IndentedTextWriter writer, TypeModel mode if (isValueType) { writer.WriteLine($"Size = global::Il2CppInterop.Runtime.IL2CPP.GetIl2CppValueSize(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer);"); - writer.WriteLine($"global::Il2CppInterop.Runtime.Runtime.Il2CppObjectPool.RegisterValueTypeInitializer<{model.TypeName}>();"); + writer.WriteLine($"global::Il2CppInterop.Runtime.Il2CppObjectPool.RegisterValueTypeInitializer<{model.TypeName}>();"); } else if (!model.IsAbstract) { - writer.WriteLine($"global::Il2CppInterop.Runtime.Runtime.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer, ptr => new {model.TypeName}(ptr));"); + writer.WriteLine($"global::Il2CppInterop.Runtime.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer, ptr => new {model.TypeName}(ptr));"); } writer.Indent--; From fddd5d07b63704df71d49bd26bb5a0662340ce2f Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 3 May 2026 11:22:32 -0700 Subject: [PATCH 372/486] Refactor Il2CppObjectPool to not reference Il2CppSystem.Object --- Il2CppInterop.Runtime/Il2CppObjectPool.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Il2CppInterop.Runtime/Il2CppObjectPool.cs b/Il2CppInterop.Runtime/Il2CppObjectPool.cs index b4310f9b..1b91694e 100644 --- a/Il2CppInterop.Runtime/Il2CppObjectPool.cs +++ b/Il2CppInterop.Runtime/Il2CppObjectPool.cs @@ -6,9 +6,7 @@ namespace Il2CppInterop.Runtime; public static class Il2CppObjectPool { - internal static bool DisableCaching { get; set; } - - private static readonly ConcurrentDictionary> s_cache = new(); + private static readonly ConcurrentDictionary> s_cache = new(); private static readonly ConcurrentDictionary> s_initializers = new(); @@ -35,12 +33,9 @@ public static void Remove(nint ptr) } var newObj = initializer((ObjectPointer)ptr); - if (newObj is Object @object) + if (!newObj.GetType().IsValueType) { - if (!DisableCaching) - { - s_cache[ptr] = new WeakReference(@object); - } + s_cache[ptr] = new WeakReference(newObj); } return newObj; From 811c1f015f327b61c8fb41d808e3c645377b897b Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 3 May 2026 12:26:52 -0700 Subject: [PATCH 373/486] Move IL2CPP to the Common project --- .../IL2CPP.cs | 109 +----------------- .../InitializationClassProcessingLayer.cs | 20 ++-- .../MethodInvokerProcessingLayer.cs | 4 +- .../ObjectInternalsProcessingLayer.cs | 1 + ...ferenceAssemblyInjectionProcessingLayer.cs | 4 +- .../Il2CppInteropDetour.cs | 2 +- .../Exceptions/Il2CppException.cs | 1 + .../Extensions/Il2CppSystemTypeExtensions.cs | 1 + Il2CppInterop.Runtime/FieldAccess.cs | 37 ++++-- Il2CppInterop.Runtime/GenerationInternals.cs | 69 +++++++++++ Il2CppInterop.Runtime/Il2CppType.cs | 6 + .../Il2CppTypePointerStore.cs | 1 + .../Injection/TrampolineHelpers.cs | 3 +- .../Injection/TypeInjector.cs | 2 +- .../Il2CppToMonoDelegateReference.cs | 2 +- .../AnalyzerTests.cs | 2 +- .../SourceGenerationTests.cs | 2 +- .../Il2CppTypeGenerator.cs | 6 +- 18 files changed, 136 insertions(+), 136 deletions(-) rename {Il2CppInterop.Runtime => Il2CppInterop.Common}/IL2CPP.cs (90%) diff --git a/Il2CppInterop.Runtime/IL2CPP.cs b/Il2CppInterop.Common/IL2CPP.cs similarity index 90% rename from Il2CppInterop.Runtime/IL2CPP.cs rename to Il2CppInterop.Common/IL2CPP.cs index e7c6e6ed..3891eb9c 100644 --- a/Il2CppInterop.Runtime/IL2CPP.cs +++ b/Il2CppInterop.Common/IL2CPP.cs @@ -1,103 +1,13 @@ -using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using Il2CppInterop.Common; -using Il2CppInterop.Runtime.Extensions; -using Il2CppInterop.Runtime.Injection; -using Il2CppInterop.Runtime.Runtime; -using Microsoft.Extensions.Logging; -namespace Il2CppInterop.Runtime; +namespace Il2CppInterop.Common; +/// +/// IL2CPP Functions +/// public static unsafe partial class IL2CPP { - public static void Il2CppRuntimeClassInit(nint @class) - { - if (@class != nint.Zero) - il2cpp_runtime_class_init(@class); - } - - public static nint GetIl2CppClass(string assemblyName, string namespaze, string className) - { - return il2cpp_class_from_name(AssemblyInjector.GetOrCreateImage(assemblyName).Pointer, namespaze, className); - } - - public static nint GetIl2CppField(nint clazz, string fieldName) - { - if (clazz == nint.Zero) - return nint.Zero; - - var field = il2cpp_class_get_field_from_name(clazz, fieldName); - if (field == nint.Zero) - Logger.Instance.LogError( - "Field {FieldName} was not found on class {ClassName}", fieldName, il2cpp_class_get_name(clazz)); - return field; - } - - public static int GetIl2CppFieldOffset(nint field) - { - if (field == nint.Zero) - return -1; - return (int)il2cpp_field_get_offset(field); - } - - public static int GetIl2CppValueSize(nint klass) - { - if (klass == nint.Zero) - return 0; - return il2cpp_class_value_size(klass, out _); - } - - public static nint GetIl2CppGenericInstanceMethod(nint methodInfoPointer, nint declaringTypeClassPointer, params nint[] genericMethodArguments) - { - var types = new Il2CppSystem.Type[genericMethodArguments.Length]; - for (var i = 0; i < genericMethodArguments.Length; i++) - { - types[i] = Il2CppSystem.Type.FromClassPointer(genericMethodArguments[i]); - } - var methodInfoObject = (Il2CppSystem.Reflection.MethodInfo)Il2CppObjectPool.Get(il2cpp_method_get_object(methodInfoPointer, declaringTypeClassPointer))!; - var methodInfoGeneric = methodInfoObject.MakeGenericMethod(types); - return il2cpp_method_get_from_reflection(methodInfoGeneric?.Pointer ?? throw new NullReferenceException()); - } - - public static ObjectPointer NewObjectPointer() - { - return (ObjectPointer)il2cpp_object_new(Il2CppClassPointerStore.NativeClassPointer); - } - - public static nint GetIl2CppNestedType(nint enclosingType, string nestedTypeName) - { - if (enclosingType == nint.Zero) - return nint.Zero; - - var iter = nint.Zero; - nint nestedTypePtr; - if (il2cpp_class_is_inflated(enclosingType)) - { - Logger.Instance.LogTrace("Original class was inflated, falling back to reflection"); - - return GetNestedTypeViaReflection(enclosingType, nestedTypeName); - } - - while ((nestedTypePtr = il2cpp_class_get_nested_types(enclosingType, ref iter)) != nint.Zero) - if (il2cpp_class_get_name(nestedTypePtr) == nestedTypeName) - return nestedTypePtr; - - Logger.Instance.LogError( - "Nested type {NestedTypeName} on {EnclosingTypeName} not found!", nestedTypeName, il2cpp_class_get_name(enclosingType)); - - return nint.Zero; - - static IntPtr GetNestedTypeViaReflection(nint enclosingClass, string nestedTypeName) - { - var reflectionType = Il2CppSystem.Type.FromClassPointer(enclosingClass); - var nestedType = reflectionType.GetNestedType(nestedTypeName, Il2CppSystem.Reflection.BindingFlags.Public | Il2CppSystem.Reflection.BindingFlags.NonPublic); - - return nestedType?.ToClassPointer() ?? nint.Zero; - } - } - - // IL2CPP Functions [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void il2cpp_init(nint domain_name); @@ -560,16 +470,9 @@ static IntPtr GetNestedTypeViaReflection(nint enclosingClass, string nestedTypeN [return: MarshalAs(UnmanagedType.LPUTF8Str)] public static partial string il2cpp_method_get_name(nint method); - public static nint il2cpp_method_get_from_reflection(nint method) - { - if (UnityVersionHandler.HasGetMethodFromReflection) return _il2cpp_method_get_from_reflection(method); - Il2CppReflectionMethod* reflectionMethod = (Il2CppReflectionMethod*)method; - return (nint)reflectionMethod->method; - } - - [LibraryImport("GameAssembly", EntryPoint = "il2cpp_method_get_from_reflection")] + [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - private static partial nint _il2cpp_method_get_from_reflection(nint method); + public static partial nint il2cpp_method_get_from_reflection(nint method); [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index 2d8d5f6b..09c5fc9a 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -30,14 +30,9 @@ public override void Process(ApplicationAnalysisContext appContext, Action)); var classPointerField = il2CppClassPointerStore.GetFieldByName(nameof(Il2CppClassPointerStore<>.NativeClassPointer)); - var il2CppStaticClass = appContext.ResolveTypeOrThrow(typeof(IL2CPP)); - var getIl2CppNestedType = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.GetIl2CppNestedType)); - var getIl2CppClass = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.GetIl2CppClass)); - var il2CppRuntimeClassInit = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.Il2CppRuntimeClassInit)); - var getIl2CppField = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.GetIl2CppField)); - var getIl2CppFieldOffset = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.GetIl2CppFieldOffset)); - var getIl2CppGenericInstanceMethod = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.GetIl2CppGenericInstanceMethod)); - var getIl2CppValueSize = il2CppStaticClass.GetMethodByName(nameof(IL2CPP.GetIl2CppValueSize)); + var fieldAccessClass = appContext.ResolveTypeOrThrow(typeof(FieldAccess)); + var getFieldInfo = fieldAccessClass.GetMethodByName(nameof(FieldAccess.GetFieldInfo)); + var getFieldOffset = fieldAccessClass.GetMethodByName(nameof(FieldAccess.GetFieldOffset)); var resolveICall = appContext.ResolveTypeOrThrow(typeof(RuntimeInvoke)).GetMethodByName(nameof(RuntimeInvoke.ResolveICall)); @@ -45,6 +40,11 @@ public override void Process(ApplicationAnalysisContext appContext, Action @@ -235,10 +235,10 @@ public override void Process(ApplicationAnalysisContext appContext, Action), typeof(Il2CppArrayRank3<>), - typeof(Runtime.Exceptions.Il2CppException), - typeof(IL2CPP), + typeof(Il2CppException), typeof(Il2CppClassPointerStore<>), typeof(Il2CppObjectPool), typeof(TypeInjector), diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs index 3ba9303b..80a30163 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs @@ -223,7 +223,7 @@ private DynamicMethodDefinition GenerateNativeToManagedThunk() var isReturnValueType = managedReturnType.IsValueType; if (isReturnValueType) { - returnSize = IL2CPP.GetIl2CppValueSize(Il2CppClassPointerStore.GetNativeClassPointer(managedReturnType)); + returnSize = IL2CPP.il2cpp_class_value_size(Il2CppClassPointerStore.GetNativeClassPointer(managedReturnType), out _); } var hasReturnBuffer = isReturnValueType && IsReturnBufferNeeded(returnSize); diff --git a/Il2CppInterop.Runtime/Exceptions/Il2CppException.cs b/Il2CppInterop.Runtime/Exceptions/Il2CppException.cs index 01cdba23..89e14df3 100644 --- a/Il2CppInterop.Runtime/Exceptions/Il2CppException.cs +++ b/Il2CppInterop.Runtime/Exceptions/Il2CppException.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text; +using Il2CppInterop.Common; namespace Il2CppInterop.Runtime.Exceptions; diff --git a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs index 03f2223b..6ccaa241 100644 --- a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs +++ b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs @@ -1,4 +1,5 @@ using System.Runtime.CompilerServices; +using Il2CppInterop.Common; using Il2CppSystem; namespace Il2CppInterop.Runtime.Extensions; diff --git a/Il2CppInterop.Runtime/FieldAccess.cs b/Il2CppInterop.Runtime/FieldAccess.cs index da0884d9..45901f30 100644 --- a/Il2CppInterop.Runtime/FieldAccess.cs +++ b/Il2CppInterop.Runtime/FieldAccess.cs @@ -1,31 +1,32 @@ using System; using System.Runtime.InteropServices; using Il2CppInterop.Common; +using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime; public static unsafe class FieldAccess { - public static T? GetStaticFieldValue(IntPtr fieldInfoPtr) where T : IIl2CppType + public static T? GetStaticFieldValue(nint fieldInfo) where T : IIl2CppType { - ArgumentNullException.ThrowIfNull(fieldInfoPtr.ToPointer(), nameof(fieldInfoPtr)); + ArgumentNullException.ThrowIfNull(fieldInfo.ToPointer(), nameof(fieldInfo)); var data = stackalloc byte[T.Size]; - IL2CPP.il2cpp_field_static_get_value(fieldInfoPtr, data); + IL2CPP.il2cpp_field_static_get_value(fieldInfo, data); return T.ReadFromSpan(new ReadOnlySpan(data, T.Size)); } - public static void SetStaticFieldValue(IntPtr fieldInfoPtr, T? value) where T : IIl2CppType + public static void SetStaticFieldValue(nint fieldInfo, T? value) where T : IIl2CppType { - ArgumentNullException.ThrowIfNull(fieldInfoPtr.ToPointer(), nameof(fieldInfoPtr)); + ArgumentNullException.ThrowIfNull(fieldInfo.ToPointer(), nameof(fieldInfo)); if (typeof(T).IsValueType) { var data = stackalloc byte[T.Size]; value.WriteToPointer(data); - IL2CPP.il2cpp_field_static_set_value(fieldInfoPtr, data); + IL2CPP.il2cpp_field_static_set_value(fieldInfo, data); } else { - IL2CPP.il2cpp_field_static_set_value(fieldInfoPtr, (void*)value.Box()); + IL2CPP.il2cpp_field_static_set_value(fieldInfo, (void*)value.Box()); } } @@ -51,7 +52,7 @@ public static void SetInstanceFieldValue_Wbarrior(Object instance, int fieldO } else { - IL2CPP.il2cpp_gc_wbarrier_set_field(instance.Pointer, (IntPtr)data, value.Box()); + IL2CPP.il2cpp_gc_wbarrier_set_field(instance.Pointer, (nint)data, value.Box()); } } @@ -65,10 +66,28 @@ public static void SetInstanceFieldValue_Pointer(Object instance, int fieldOf } else { - *(IntPtr*)data = value.Box(); + *(nint*)data = value.Box(); } } + public static nint GetFieldInfo(nint classPointer, string fieldName) + { + if (classPointer == nint.Zero) + return nint.Zero; + + var field = IL2CPP.il2cpp_class_get_field_from_name(classPointer, fieldName); + if (field == nint.Zero) + Logger.Instance.LogError("Field {FieldName} was not found on class {ClassName}", fieldName, IL2CPP.il2cpp_class_get_name(classPointer)); + return field; + } + + public static int GetFieldOffset(nint field) + { + if (field == nint.Zero) + return -1; + return (int)IL2CPP.il2cpp_field_get_offset(field); + } + private static bool HasWbarriorSupport() { if (NativeLibrary.TryLoad("GameAssembly", out var handle)) diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index ebccffb5..f95926ea 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -213,6 +213,75 @@ private static IntPtr GetMethodInfoForMissingMethod(string methodName) methodInfo.Slot = ushort.MaxValue; return methodInfo.Pointer; } + public static void Il2CppRuntimeClassInit(nint @class) + { + if (@class != nint.Zero) + IL2CPP.il2cpp_runtime_class_init(@class); + } + + public static nint GetIl2CppClass(string assemblyName, string namespaze, string className) + { + return IL2CPP.il2cpp_class_from_name(AssemblyInjector.GetOrCreateImage(assemblyName).Pointer, namespaze, className); + } + + public static int GetIl2CppValueSize(nint klass) + { + if (klass == nint.Zero) + return 0; + return IL2CPP.il2cpp_class_value_size(klass, out _); + } + + public static nint GetIl2CppGenericInstanceMethod(nint methodInfoPointer, nint declaringTypeClassPointer, params nint[] genericMethodArguments) + { + var types = new Il2CppSystem.Type[genericMethodArguments.Length]; + for (var i = 0; i < genericMethodArguments.Length; i++) + { + types[i] = Il2CppSystem.Type.FromClassPointer(genericMethodArguments[i]); + } + var methodInfoObject = (Il2CppSystem.Reflection.MethodInfo)Il2CppObjectPool.Get(IL2CPP.il2cpp_method_get_object(methodInfoPointer, declaringTypeClassPointer))!; + var methodInfoGeneric = methodInfoObject.MakeGenericMethod(types); + return il2cpp_method_get_from_reflection(methodInfoGeneric?.Pointer ?? throw new NullReferenceException()); + + static unsafe nint il2cpp_method_get_from_reflection(nint method) + { + if (UnityVersionHandler.HasGetMethodFromReflection) + return IL2CPP.il2cpp_method_get_from_reflection(method); + Il2CppReflectionMethod* reflectionMethod = (Il2CppReflectionMethod*)method; + return (nint)reflectionMethod->method; + } + } + + public static nint GetIl2CppNestedType(nint enclosingType, string nestedTypeName) + { + if (enclosingType == nint.Zero) + return nint.Zero; + + var iter = nint.Zero; + nint nestedTypePtr; + if (IL2CPP.il2cpp_class_is_inflated(enclosingType)) + { + Logger.Instance.LogTrace("Original class was inflated, falling back to reflection"); + + return GetNestedTypeViaReflection(enclosingType, nestedTypeName); + } + + while ((nestedTypePtr = IL2CPP.il2cpp_class_get_nested_types(enclosingType, ref iter)) != nint.Zero) + if (IL2CPP.il2cpp_class_get_name(nestedTypePtr) == nestedTypeName) + return nestedTypePtr; + + Logger.Instance.LogError( + "Nested type {NestedTypeName} on {EnclosingTypeName} not found!", nestedTypeName, IL2CPP.il2cpp_class_get_name(enclosingType)); + + return nint.Zero; + + static IntPtr GetNestedTypeViaReflection(nint enclosingClass, string nestedTypeName) + { + var reflectionType = Il2CppSystem.Type.FromClassPointer(enclosingClass); + var nestedType = reflectionType.GetNestedType(nestedTypeName, Il2CppSystem.Reflection.BindingFlags.Public | Il2CppSystem.Reflection.BindingFlags.NonPublic); + + return nestedType?.ToClassPointer() ?? nint.Zero; + } + } [GeneratedRegex(@"\`\d+")] private static partial Regex GenericArityRegex { get; } diff --git a/Il2CppInterop.Runtime/Il2CppType.cs b/Il2CppInterop.Runtime/Il2CppType.cs index cd19da69..6830560c 100644 --- a/Il2CppInterop.Runtime/Il2CppType.cs +++ b/Il2CppInterop.Runtime/Il2CppType.cs @@ -171,4 +171,10 @@ public static unsafe IntPtr Box(this T? value) where T : IIl2CppType throw new InvalidCastException(); } } + + // Temporary location for this method + public static ObjectPointer NewObjectPointer() + { + return (ObjectPointer)IL2CPP.il2cpp_object_new(Il2CppClassPointerStore.NativeClassPointer); + } } diff --git a/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs b/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs index edfdacfb..c46881ed 100644 --- a/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs +++ b/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs @@ -1,3 +1,4 @@ +using Il2CppInterop.Common; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.Runtime; diff --git a/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs b/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs index b3a986d1..ac2bb675 100644 --- a/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs +++ b/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs @@ -4,6 +4,7 @@ using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; +using Il2CppInterop.Common; using Il2CppInterop.Runtime.InteropTypes; namespace Il2CppInterop.Runtime.Injection; @@ -81,7 +82,7 @@ internal static Type NativeType(this Type managedType) throw new NotSupportedException($"Type {managedType.FullName} is not an Il2Cpp type."); } - var fixedSize = IL2CPP.GetIl2CppValueSize(nativeClassPtr); + var fixedSize = IL2CPP.il2cpp_class_value_size(nativeClassPtr, out _); return GetFixedSizeStructType(fixedSize); } } diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index f5d960b5..3128ff38 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -514,7 +514,7 @@ static void SetFields(Type type, INativeClassStruct classPointer) fieldInfo.Offset = fieldOffset; if (IL2CPP.il2cpp_class_is_valuetype(fieldInfoClass)) { - var fieldSize = IL2CPP.GetIl2CppValueSize(fieldInfoClass); + var fieldSize = IL2CPP.il2cpp_class_value_size(fieldInfoClass, out _); fieldOffset += fieldSize; } else diff --git a/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs index 5395d4e1..cfcc19dd 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs @@ -14,7 +14,7 @@ internal sealed partial class Il2CppToMonoDelegateReference : Object [ManagedField] public partial Delegate ReferencedDelegate { get; set; } - public Il2CppToMonoDelegateReference(Delegate referencedDelegate, IntPtr methodInfo) : this(IL2CPP.NewObjectPointer()) + public Il2CppToMonoDelegateReference(Delegate referencedDelegate, IntPtr methodInfo) : this(Il2CppType.NewObjectPointer()) { ReferencedDelegate = referencedDelegate; MethodInfo = methodInfo; diff --git a/Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs b/Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs index 3452e7c8..87d111f2 100644 --- a/Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs +++ b/Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs @@ -18,7 +18,7 @@ public void Setup() }; Context.TestState.AdditionalReferences.Add(typeof(InjectedTypeAttribute).Assembly); Context.TestState.AdditionalReferences.Add(typeof(Il2CppSystem.Object).Assembly); - Context.TestState.AdditionalReferences.Add(typeof(IL2CPP).Assembly); + Context.TestState.AdditionalReferences.Add(typeof(RuntimeInvoke).Assembly); } protected async Task TestDiagnostic(string testCode, DiagnosticResult expectedDiagnostic) diff --git a/Il2CppInterop.SourceGenerator.Tests/SourceGenerationTests.cs b/Il2CppInterop.SourceGenerator.Tests/SourceGenerationTests.cs index 09554704..08df653b 100644 --- a/Il2CppInterop.SourceGenerator.Tests/SourceGenerationTests.cs +++ b/Il2CppInterop.SourceGenerator.Tests/SourceGenerationTests.cs @@ -20,7 +20,7 @@ public void Setup() }; Context.TestState.AdditionalReferences.Add(typeof(InjectedTypeAttribute).Assembly); Context.TestState.AdditionalReferences.Add(typeof(Il2CppSystem.Object).Assembly); - Context.TestState.AdditionalReferences.Add(typeof(IL2CPP).Assembly); + Context.TestState.AdditionalReferences.Add(typeof(RuntimeInvoke).Assembly); } protected async Task TestGeneration(string testCode, string expectedFileName, string expectedGeneratedCode) diff --git a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs index d04dae22..ebf4489d 100644 --- a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs +++ b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs @@ -415,14 +415,14 @@ private static void EmitInternalsClass(IndentedTextWriter writer, TypeModel mode foreach (var member in model.Members) { if (member.IsStatic) - writer.WriteLine($"FieldInfoPtr_{member.Index} = global::Il2CppInterop.Runtime.IL2CPP.GetIl2CppField(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer, \"{member.Name}\");"); + writer.WriteLine($"FieldInfoPtr_{member.Index} = global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer, \"{member.Name}\");"); else - writer.WriteLine($"FieldOffset_{member.Index} = (int)global::Il2CppInterop.Runtime.IL2CPP.il2cpp_field_get_offset(global::Il2CppInterop.Runtime.IL2CPP.GetIl2CppField(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer, \"{member.Name}\"));"); + writer.WriteLine($"FieldOffset_{member.Index} = global::Il2CppInterop.Runtime.FieldAccess.GetFieldOffset(global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer, \"{member.Name}\"));"); } if (isValueType) { - writer.WriteLine($"Size = global::Il2CppInterop.Runtime.IL2CPP.GetIl2CppValueSize(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer);"); + writer.WriteLine($"Size = global::Il2CppInterop.Common.IL2CPP.il2cpp_class_value_size(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer, out _);"); writer.WriteLine($"global::Il2CppInterop.Runtime.Il2CppObjectPool.RegisterValueTypeInitializer<{model.TypeName}>();"); } else if (!model.IsAbstract) From 4c177ef8acf1dfda9645b7ba0707eccaff3cb07a Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 3 May 2026 13:49:55 -0700 Subject: [PATCH 374/486] Ensure we're using the image name in the generation process --- Il2CppInterop.Common/IIl2CppType.cs | 4 ++++ .../AssemblyAnalysisContextExtensions.cs | 17 +++++++++++++++++ .../InitializationClassProcessingLayer.cs | 7 +------ .../MarshallingProcessingLayer.cs | 4 ++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/Il2CppInterop.Common/IIl2CppType.cs b/Il2CppInterop.Common/IIl2CppType.cs index 63688169..a0bab848 100644 --- a/Il2CppInterop.Common/IIl2CppType.cs +++ b/Il2CppInterop.Common/IIl2CppType.cs @@ -13,6 +13,10 @@ public interface IIl2CppType : IIl2CppType where TSelf : notnull, IIl2Cpp /// /// The file name of the assembly that the type is defined in /// + /// + /// Technically, this is the image name, not the assembly name. + /// In practice, the assembly name has no file extension, whereas the image name does. + /// static virtual string AssemblyName { get diff --git a/Il2CppInterop.Generator/Extensions/AssemblyAnalysisContextExtensions.cs b/Il2CppInterop.Generator/Extensions/AssemblyAnalysisContextExtensions.cs index eb530e84..78025f9b 100644 --- a/Il2CppInterop.Generator/Extensions/AssemblyAnalysisContextExtensions.cs +++ b/Il2CppInterop.Generator/Extensions/AssemblyAnalysisContextExtensions.cs @@ -43,5 +43,22 @@ public TypeAnalysisContext GetTypeByFullNameOrThrow(Type type) { return assembly.GetTypeByFullName(type) ?? throw new($"Unable to find type by full name {type.FullName}"); } + + public string ImageName + { + get + { + var result = assembly.Definition?.Image.Name; + if (string.IsNullOrEmpty(result)) + { + result = assembly.DefaultName; + if (!result.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) + { + result = $"{result}.dll"; + } + } + return result; + } + } } } diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index 09c5fc9a..c0273931 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -150,12 +150,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action.NativeClassPointer = IL2CPP.GetIl2CppClass("Assembly-CSharp.dll", "", "Class"); - var assemblyName = assembly.DefaultName; - if (!assemblyName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) && assemblyName is not "__Generated") - { - assemblyName += ".dll"; - } - instructions.Add(new Instruction(CilOpCodes.Ldstr, assemblyName)); + instructions.Add(new Instruction(CilOpCodes.Ldstr, assembly.ImageName)); instructions.Add(new Instruction(CilOpCodes.Ldstr, type.DefaultNamespace)); instructions.Add(new Instruction(CilOpCodes.Ldstr, type.DefaultName)); instructions.Add(new Instruction(CilOpCodes.Call, getIl2CppClass)); diff --git a/Il2CppInterop.Generator/MarshallingProcessingLayer.cs b/Il2CppInterop.Generator/MarshallingProcessingLayer.cs index 0d0c8c25..aa5f652b 100644 --- a/Il2CppInterop.Generator/MarshallingProcessingLayer.cs +++ b/Il2CppInterop.Generator/MarshallingProcessingLayer.cs @@ -252,7 +252,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action.AssemblyName)}"; @@ -272,7 +272,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action Date: Sun, 3 May 2026 14:31:31 -0700 Subject: [PATCH 375/486] Update il2cpp_domain_get_assemblies to use out param Changed il2cpp_domain_get_assemblies to use an out parameter for the assemblies count instead of ref. Updated AssemblyInjector to match the new method signature and simplify variable assignment. --- Il2CppInterop.Common/IL2CPP.cs | 2 +- Il2CppInterop.Runtime/Injection/AssemblyInjector.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Il2CppInterop.Common/IL2CPP.cs b/Il2CppInterop.Common/IL2CPP.cs index 3891eb9c..83d36377 100644 --- a/Il2CppInterop.Common/IL2CPP.cs +++ b/Il2CppInterop.Common/IL2CPP.cs @@ -316,7 +316,7 @@ public static unsafe partial class IL2CPP [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial nint* il2cpp_domain_get_assemblies(nint domain, ref uint size); + public static partial nint* il2cpp_domain_get_assemblies(nint domain, out uint size); [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] diff --git a/Il2CppInterop.Runtime/Injection/AssemblyInjector.cs b/Il2CppInterop.Runtime/Injection/AssemblyInjector.cs index e8720bf5..673dac70 100644 --- a/Il2CppInterop.Runtime/Injection/AssemblyInjector.cs +++ b/Il2CppInterop.Runtime/Injection/AssemblyInjector.cs @@ -25,8 +25,7 @@ internal static INativeImageStruct GetOrCreateImage(string name) } else { - uint assembliesCount = 0; - var assemblies = IL2CPP.il2cpp_domain_get_assemblies(domain, ref assembliesCount); + var assemblies = IL2CPP.il2cpp_domain_get_assemblies(domain, out var assembliesCount); for (var i = 0; i < assembliesCount; i++) { var image = UnityVersionHandler.Wrap((Il2CppImage*)IL2CPP.il2cpp_assembly_get_image(assemblies[i])); From be0535186c3d24c2d331c014e73a66667837091e Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 3 May 2026 19:17:39 -0700 Subject: [PATCH 376/486] Merge Il2CppClassPointerStore into Il2CppType --- .../InitializationClassProcessingLayer.cs | 53 +++++++-------- .../MarshallingProcessingLayer.cs | 6 +- .../ObjectInterfaceProcessingLayer.cs | 34 ++++++++++ ...ferenceAssemblyInjectionProcessingLayer.cs | 1 - .../Il2CppInteropDetour.cs | 2 +- Il2CppInterop.Runtime/DelegateSupport.cs | 9 +-- Il2CppInterop.Runtime/GenerationInternals.cs | 2 +- .../Il2CppClassPointerStore.cs | 51 -------------- Il2CppInterop.Runtime/Il2CppObjectPool.cs | 2 +- Il2CppInterop.Runtime/Il2CppType.cs | 67 +++++++++++++++++-- .../Il2CppTypePointerStore.cs | 4 +- .../Injection/InjectorHelpers.cs | 2 +- .../Injection/TrampolineHelpers.cs | 2 +- .../Injection/TypeInjector.cs | 59 ++++++++-------- .../InteropTypes/Arrays/Il2CppArrayBase.cs | 4 +- .../InteropTypes/Arrays/Il2CppArrayRank1.cs | 6 +- .../InteropTypes/Arrays/Il2CppArrayRank2.cs | 6 +- .../InteropTypes/Arrays/Il2CppArrayRank3.cs | 6 +- Il2CppInterop.Runtime/InteropTypes/Pointer.cs | 6 +- .../InjectedClassTests.cs | 4 +- .../Il2CppTypeGenerator.cs | 10 +-- Il2Cppmscorlib/Enum.cs | 10 ++- Il2Cppmscorlib/Object.cs | 8 ++- Il2Cppmscorlib/ValueType.cs | 10 ++- 24 files changed, 206 insertions(+), 158 deletions(-) delete mode 100644 Il2CppInterop.Runtime/Il2CppClassPointerStore.cs diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index c0273931..20673dc4 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -27,8 +27,6 @@ public override void Process(ApplicationAnalysisContext appContext, Action m.Name == nameof(RuntimeHelpers.RunClassConstructor) && m.Parameters[0].ParameterType != appContext.SystemTypes.SystemIntPtrType); - var il2CppClassPointerStore = appContext.ResolveTypeOrThrow(typeof(Il2CppClassPointerStore<>)); - var classPointerField = il2CppClassPointerStore.GetFieldByName(nameof(Il2CppClassPointerStore<>.NativeClassPointer)); var fieldAccessClass = appContext.ResolveTypeOrThrow(typeof(FieldAccess)); var getFieldInfo = fieldAccessClass.GetMethodByName(nameof(FieldAccess.GetFieldInfo)); @@ -61,7 +59,10 @@ public override void Process(ApplicationAnalysisContext appContext, Action.CopyTo)); var byReference_Constructor = byReference.GetMethodByName(".ctor"); - var il2CppTypeHelper_SizeOf = appContext.ResolveTypeOrThrow(typeof(Il2CppType)).GetMethodByName(nameof(Il2CppType.SizeOf)); + var il2CppType = appContext.ResolveTypeOrThrow(typeof(Il2CppType)); + var il2CppType_SizeOf = il2CppType.GetMethodByName(nameof(Il2CppType.SizeOf)); + var il2CppType_GetClassPointer = il2CppType.Methods.Single(m => m.Name == nameof(Il2CppType.GetClassPointer) && m.GenericParameters.Count == 1); + var il2CppType_SetClassPointer = il2CppType.Methods.Single(m => m.Name == nameof(Il2CppType.SetClassPointer) && m.GenericParameters.Count == 1); var il2CppObjectPool = appContext.ResolveTypeOrThrow(typeof(Il2CppObjectPool)); var il2CppObjectPool_RegisterInitializer = il2CppObjectPool.GetMethodByName(nameof(Il2CppObjectPool.RegisterInitializer)); @@ -128,7 +129,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action.NativeClassPointer = IL2CPP.GetIl2CppNestedType(Il2CppClassPointerStore.NativeClassPointer, "NestedClass"); - var declaringTypeClassPointerField = new ConcreteGenericFieldAnalysisContext(classPointerField, il2CppClassPointerStore.MakeGenericInstanceType([typeToInitialize.DeclaringType])); - instructions.Add(new Instruction(CilOpCodes.Ldsfld, declaringTypeClassPointerField)); + // Il2CppType.SetClassPointer(IL2CPP.GetIl2CppNestedType(Il2CppType.GetClassPointer(), "NestedClass")); + instructions.Add(new Instruction(CilOpCodes.Call, il2CppType_GetClassPointer.MakeGenericInstanceMethod(typeToInitialize.DeclaringType))); instructions.Add(new Instruction(CilOpCodes.Ldstr, type.DefaultName));// typeToInitialize can have the wrong DefaultName instructions.Add(new Instruction(CilOpCodes.Call, getIl2CppNestedType)); } else { - // Il2CppClassPointerStore.NativeClassPointer = IL2CPP.GetIl2CppClass("Assembly-CSharp.dll", "", "Class"); + // Il2CppType.SetClassPointer(IL2CPP.GetIl2CppClass("Assembly-CSharp.dll", "", "Class")); instructions.Add(new Instruction(CilOpCodes.Ldstr, assembly.ImageName)); instructions.Add(new Instruction(CilOpCodes.Ldstr, type.DefaultNamespace)); instructions.Add(new Instruction(CilOpCodes.Ldstr, type.DefaultName)); @@ -163,21 +163,19 @@ public override void Process(ApplicationAnalysisContext appContext, Action.NativeClassPointer); - instructions.Add(new Instruction(CilOpCodes.Ldsfld, concreteClassPointerField)); + // Il2CppRuntimeClassInit(Il2CppType.GetClassPointer()); + instructions.Add(new Instruction(CilOpCodes.Call, getClassPointerMethodInstantiated)); instructions.Add(new Instruction(CilOpCodes.Call, il2CppRuntimeClassInit)); } - // Size = IL2CPP.il2cpp_class_value_size(Il2CppClassPointerStore.NativeClassPointer, ref align); + // Size = GetIl2CppValueSize(Il2CppType.GetClassPointer()); if (type.IsValueType) { var sizeStore = initializationType.InjectFieldContext( @@ -190,12 +188,12 @@ public override void Process(ApplicationAnalysisContext appContext, Action.NativeClassPointer, "field_name")); + // FieldOffset_0 = FieldAccess.GetFieldOffset(FieldAccess.GetFieldInfo(Il2CppType.GetClassPointer(), "field_name")); for (var index = 0; index < type.Fields.Count; index++) { var field = type.Fields[index]; @@ -228,7 +226,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action(); instructions2.Add(new Instruction(CilOpCodes.Ldsfld, concreteMethodInfoStore2)); - instructions2.Add(new Instruction(CilOpCodes.Ldsfld, concreteClassPointerField)); + instructions2.Add(new Instruction(CilOpCodes.Call, getClassPointerMethodInstantiated)); instructions2.Add(new Instruction(CilOpCodes.Ldc_I4, method.GenericParameters.Count)); instructions2.Add(new Instruction(CilOpCodes.Newarr, appContext.SystemTypes.SystemIntPtrType)); for (var j = 0; j < method.GenericParameters.Count; j++) { + var genericParameter = methodInfoPtrGenericClass.GenericParameters[j + initializationType.GenericParameters.Count]; instructions2.Add(new Instruction(CilOpCodes.Dup)); instructions2.Add(new Instruction(CilOpCodes.Ldc_I4, j)); - var genericParameter = methodInfoPtrGenericClass.GenericParameters[j + initializationType.GenericParameters.Count]; - var classPointerForGenericParameter = new ConcreteGenericFieldAnalysisContext(classPointerField, il2CppClassPointerStore.MakeGenericInstanceType([genericParameter])); - instructions2.Add(new Instruction(CilOpCodes.Ldsfld, classPointerForGenericParameter)); + instructions2.Add(new Instruction(CilOpCodes.Call, il2CppType_GetClassPointer.MakeGenericInstanceMethod(genericParameter))); instructions2.Add(new Instruction(CilOpCodes.Stelem_I)); } instructions2.Add(new Instruction(CilOpCodes.Call, getIl2CppGenericInstanceMethod)); @@ -459,7 +456,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action(TypeAnalysisContextEqualityComparer.Instance); // Ensure all generic instantiations are initialized - foreach (var il2CppType in appContext.Binary.AllTypes) + foreach (var typeToResolve in appContext.Binary.AllTypes) { - var typeContext = injectedAssembly.ResolveIl2CppType(il2CppType); + var typeContext = injectedAssembly.ResolveIl2CppType(typeToResolve); if (typeContext is not ReferencedTypeAnalysisContext && typeContext.GenericParameters.Count > 0) continue; // Skip open generics diff --git a/Il2CppInterop.Generator/MarshallingProcessingLayer.cs b/Il2CppInterop.Generator/MarshallingProcessingLayer.cs index aa5f652b..6c7ad291 100644 --- a/Il2CppInterop.Generator/MarshallingProcessingLayer.cs +++ b/Il2CppInterop.Generator/MarshallingProcessingLayer.cs @@ -25,9 +25,6 @@ public override void Process(ApplicationAnalysisContext appContext, Action.ReadFromSpan)); var iil2CppTypeGeneric_WriteToSpan = iil2CppTypeGeneric.GetMethodByName(nameof(IIl2CppType<>.WriteToSpan)); - var il2CppClassPointerStore = appContext.ResolveTypeOrThrow(typeof(Il2CppClassPointerStore<>)); - var il2CppClassPointerStore_NativeClassPointer = il2CppClassPointerStore.GetFieldByName(nameof(Il2CppClassPointerStore<>.NativeClassPointer)); - var il2CppTypeHelper = appContext.ResolveTypeOrThrow(typeof(Il2CppType)); var il2CppTypeHelper_ReadReference = il2CppTypeHelper.GetMethodByName(nameof(Il2CppType.ReadReference)); var il2CppTypeHelper_WriteReference = il2CppTypeHelper.GetMethodByName(nameof(Il2CppType.WriteReference)); @@ -36,6 +33,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action m.Name == nameof(Il2CppType.GetClassPointer) && m.GenericParameters.Count == 1); var intPtr_get_Size = appContext.SystemTypes.SystemIntPtrType.GetMethodByName($"get_{nameof(IntPtr.Size)}"); @@ -145,7 +143,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action m.Name == nameof(Il2CppType.GetClassPointer) && m.GenericParameters.Count == 1); + var setClassPointerMethod = il2CppType.Methods.Single(m => m.Name == nameof(Il2CppType.SetClassPointer) && m.GenericParameters.Count == 1); + + var cctor = new InjectedMethodAnalysisContext( + interfaceType, + ".cctor", + interfaceType.AppContext.SystemTypes.SystemVoidType, + MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, + []) + { + IsInjected = true, + }; + interfaceType.Methods.Add(cctor); + cctor.PutExtraData(new NativeMethodBody() + { + Instructions = + [ + new Instruction(CilOpCodes.Call, getClassPointerMethod.MakeGenericInstanceMethod(classType)), + new Instruction(CilOpCodes.Call, setClassPointerMethod.MakeGenericInstanceMethod(interfaceType)), + new Instruction(CilOpCodes.Ret), + ], + }); + } } diff --git a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs index 6336446e..1f8ddae7 100644 --- a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs +++ b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs @@ -43,7 +43,6 @@ public override void Process(ApplicationAnalysisContext appContext, Action), typeof(Il2CppException), - typeof(Il2CppClassPointerStore<>), typeof(Il2CppObjectPool), typeof(TypeInjector), typeof(DelegateSupport), diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs index 80a30163..4ed6d674 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs @@ -223,7 +223,7 @@ private DynamicMethodDefinition GenerateNativeToManagedThunk() var isReturnValueType = managedReturnType.IsValueType; if (isReturnValueType) { - returnSize = IL2CPP.il2cpp_class_value_size(Il2CppClassPointerStore.GetNativeClassPointer(managedReturnType), out _); + returnSize = IL2CPP.il2cpp_class_value_size(Il2CppType.GetClassPointer(managedReturnType), out _); } var hasReturnBuffer = isReturnValueType && IsReturnBufferNeeded(returnSize); diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index c286b6e5..8458c204 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -178,14 +178,11 @@ private static unsafe TNative ConvertReturnValue(TManaged? va return result; } - public static TIl2Cpp? ConvertDelegate(Delegate @delegate) where TIl2Cpp : Il2CppSystem.Delegate + public static TIl2Cpp? ConvertDelegate(Delegate @delegate) where TIl2Cpp : Il2CppSystem.Delegate, IIl2CppType { if (@delegate == null) return null; - if (!typeof(Il2CppSystem.Delegate).IsAssignableFrom(typeof(TIl2Cpp))) - throw new ArgumentException($"{typeof(TIl2Cpp)} is not a delegate"); - var managedInvokeMethod = @delegate.GetType().GetMethod("Invoke")!; var parameterInfos = managedInvokeMethod.GetParameters(); foreach (var parameterInfo in parameterInfos) @@ -196,7 +193,7 @@ private static unsafe TNative ConvertReturnValue(TManaged? va $"Delegate has unsubstituted generic parameter ({parameterType}) which is not supported"); } - var classTypePtr = Il2CppClassPointerStore.NativeClassPointer; + var classTypePtr = Il2CppType.GetClassPointer(); if (classTypePtr == IntPtr.Zero) throw new ArgumentException($"Type {typeof(TIl2Cpp)} has uninitialized class pointer"); @@ -213,7 +210,7 @@ private static unsafe TNative ConvertReturnValue(TManaged? va var nativeType = nativeParameters[i].ParameterType; var managedType = parameterInfos[i].ParameterType; - var classPointerFromManagedType = Il2CppClassPointerStore.GetNativeClassPointer(managedType); + var classPointerFromManagedType = Il2CppType.GetClassPointer(managedType); var classPointerFromNativeType = IL2CPP.il2cpp_class_from_type(nativeType._impl.value); diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index f95926ea..c4b575e8 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -44,7 +44,7 @@ public static partial class GenerationInternals public static Il2CppSystem.Type ManagedTypeToIl2CppType(Type type) { - var classPointer = Il2CppClassPointerStore.GetNativeClassPointer(type); + var classPointer = Il2CppType.GetClassPointer(type); if (classPointer == IntPtr.Zero) { throw new ArgumentException($"{type} does not have a corresponding IL2CPP class pointer"); diff --git a/Il2CppInterop.Runtime/Il2CppClassPointerStore.cs b/Il2CppInterop.Runtime/Il2CppClassPointerStore.cs deleted file mode 100644 index b27c6970..00000000 --- a/Il2CppInterop.Runtime/Il2CppClassPointerStore.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.Runtime.CompilerServices; -using Il2CppSystem; - -namespace Il2CppInterop.Runtime; - -public static class Il2CppClassPointerStore -{ - public static nint GetNativeClassPointer(System.Type type) - { - if (type == typeof(void)) - return Il2CppClassPointerStore.NativeClassPointer; - - return (nint)typeof(Il2CppClassPointerStore<>) - .MakeGenericType(type) - .GetField(nameof(Il2CppClassPointerStore<>.NativeClassPointer))! - .GetValue(null)!; - } - - internal static void SetNativeClassPointer(System.Type type, nint value) - { - typeof(Il2CppClassPointerStore<>) - .MakeGenericType(type) - .GetField(nameof(Il2CppClassPointerStore<>.NativeClassPointer))! - .SetValue(null, value); - } -} - -public static class Il2CppClassPointerStore -{ - public static nint NativeClassPointer; - - static Il2CppClassPointerStore() - { - if (typeof(T) == typeof(IObject)) - { - NativeClassPointer = Il2CppClassPointerStore.NativeClassPointer; - } - else if (typeof(T) == typeof(IValueType)) - { - NativeClassPointer = Il2CppClassPointerStore.NativeClassPointer; - } - else if (typeof(T) == typeof(IEnum)) - { - NativeClassPointer = Il2CppClassPointerStore.NativeClassPointer; - } - else - { - RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); - } - } -} diff --git a/Il2CppInterop.Runtime/Il2CppObjectPool.cs b/Il2CppInterop.Runtime/Il2CppObjectPool.cs index 1b91694e..193d87ef 100644 --- a/Il2CppInterop.Runtime/Il2CppObjectPool.cs +++ b/Il2CppInterop.Runtime/Il2CppObjectPool.cs @@ -53,7 +53,7 @@ public static void RegisterInitializer(nint classPtr, Func() where T : struct, IIl2CppType { - RegisterInitializer(Il2CppClassPointerStore.NativeClassPointer, ValueTypeInitializer); + RegisterInitializer(Il2CppType.GetClassPointer(), ValueTypeInitializer); } public static unsafe object ValueTypeInitializer(ObjectPointer obj) where T : struct, IIl2CppType diff --git a/Il2CppInterop.Runtime/Il2CppType.cs b/Il2CppInterop.Runtime/Il2CppType.cs index 6830560c..d41e9608 100644 --- a/Il2CppInterop.Runtime/Il2CppType.cs +++ b/Il2CppInterop.Runtime/Il2CppType.cs @@ -8,11 +8,27 @@ namespace Il2CppInterop.Runtime; public static class Il2CppType { - public static bool IsBlittable() where T : IIl2CppType + private static readonly nint Il2CppSystemVoidClassPointer = GetIl2CppSystemVoidClassPointer(); + + private static unsafe nint GetIl2CppSystemVoidClassPointer() { - return T.Size == Unsafe.SizeOf() - && !RuntimeHelpers.IsReferenceOrContainsReferences() - && !typeof(T).IsGenericType; + var domain = IL2CPP.il2cpp_domain_get(); + if (domain == nint.Zero) + { + return nint.Zero; + } + + var assemblies = IL2CPP.il2cpp_domain_get_assemblies(domain, out var assembliesCount); + for (var i = 0; i < assembliesCount; i++) + { + var image = IL2CPP.il2cpp_assembly_get_image(assemblies[i]); + var imageName = IL2CPP.il2cpp_image_get_name(image); + if (imageName == "mscorlib.dll") + { + return IL2CPP.il2cpp_class_from_name(image, "System", "Void"); + } + } + return nint.Zero; } public static int SizeOf() where T : IIl2CppType @@ -172,9 +188,48 @@ public static unsafe IntPtr Box(this T? value) where T : IIl2CppType } } + public static nint GetClassPointer(Type type) + { + if (type == typeof(void)) + return Il2CppSystemVoidClassPointer; + + return (nint)typeof(Il2CppType) + .GetMethod(nameof(GetClassPointer), 1, [])! + .MakeGenericMethod(type) + .Invoke(null, null)!; + } + + public static nint GetClassPointer() where T : IIl2CppType + { + return Il2CppClassPointerStore.NativeClassPointer; + } + + internal static void SetClassPointer(Type type, nint classPointer) + { + typeof(Il2CppType) + .GetMethod(nameof(SetClassPointer), 1, [typeof(nint)])! + .MakeGenericMethod(type) + .Invoke(null, [classPointer]); + } + + public static void SetClassPointer(nint classPointer) where T : IIl2CppType + { + Il2CppClassPointerStore.NativeClassPointer = classPointer; + } + + private static class Il2CppClassPointerStore where T : IIl2CppType + { + public static nint NativeClassPointer; + + static Il2CppClassPointerStore() + { + RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); + } + } + // Temporary location for this method - public static ObjectPointer NewObjectPointer() + public static ObjectPointer NewObjectPointer() where T : IIl2CppType { - return (ObjectPointer)IL2CPP.il2cpp_object_new(Il2CppClassPointerStore.NativeClassPointer); + return (ObjectPointer)IL2CPP.il2cpp_object_new(GetClassPointer()); } } diff --git a/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs b/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs index c46881ed..24d6d563 100644 --- a/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs +++ b/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs @@ -18,7 +18,7 @@ public static nint GetNativeTypePointer(System.Type type) } } -internal static unsafe class Il2CppTypePointerStore +internal static unsafe class Il2CppTypePointerStore where T : IIl2CppType { public static nint NativeTypePointer { @@ -26,7 +26,7 @@ public static nint NativeTypePointer { if (field == default) { - var classPointer = Il2CppClassPointerStore.NativeClassPointer; + var classPointer = Il2CppType.GetClassPointer(); if (classPointer != default) { field = IL2CPP.il2cpp_class_get_type(classPointer); diff --git a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs index c3cebdca..6513ffbf 100644 --- a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs +++ b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs @@ -72,7 +72,7 @@ internal static IntPtr GetIl2CppMethodPointer(MethodBase? proxyMethod) ?? throw new ArgumentException($"Couldn't find the generated method info pointer for {proxyMethod.Name}"); // Il2CppClassPointerStore calls the static constructor for the type - Il2CppClassPointerStore.GetNativeClassPointer(proxyMethod.DeclaringType); + Il2CppType.GetClassPointer(proxyMethod.DeclaringType); var methodInfoPointer = (IntPtr)methodInfoPointerField.GetValue(null)!; if (methodInfoPointer == IntPtr.Zero) diff --git a/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs b/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs index ac2bb675..e6d0923b 100644 --- a/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs +++ b/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs @@ -76,7 +76,7 @@ internal static Type NativeType(this Type managedType) { // Struct that's passed on the stack => handle as general struct - var nativeClassPtr = Il2CppClassPointerStore.GetNativeClassPointer(managedType); + var nativeClassPtr = Il2CppType.GetClassPointer(managedType); if (nativeClassPtr == IntPtr.Zero) { throw new NotSupportedException($"Type {managedType.FullName} is not an Il2Cpp type."); diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 3128ff38..7aa613c5 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -38,7 +38,7 @@ public static unsafe class TypeInjector /// True if the type is preexisting, false otherwise. public static bool IsPreexistingType(Type type) { - return Il2CppClassPointerStore.GetNativeClassPointer(type) is not 0 && !RegisteredTypes.Contains(type); + return Il2CppType.GetClassPointer(type) is not 0 && !RegisteredTypes.Contains(type); } public static void RegisterTypeInIl2Cpp() where T : IIl2CppType @@ -48,7 +48,7 @@ public static void RegisterTypeInIl2Cpp() where T : IIl2CppType private static void RegisterTypeInIl2Cpp(Type type) { - if (Il2CppClassPointerStore.GetNativeClassPointer(type) is not 0) + if (Il2CppType.GetClassPointer(type) is not 0) { // Already registered return; @@ -91,13 +91,13 @@ private static void RegisterTypeInIl2Cpp(Type type) classPointer.Flags = TypeAttributesToClassAttributes(type.Attributes); - // This guarantees that any future calls to GetNativeClassPointer will return the class pointer, + // This guarantees that any future calls to GetClassPointer will return the class pointer, // even if the class is not fully registered yet, which allows us to handle circular dependencies between types. RegisteredTypes.Add(type); NeedsInitialized.Add(type); NeedsVTableSet.Add(type, vtableUpperBound); NeedsFieldsSet.Add(type); - Il2CppClassPointerStore.SetNativeClassPointer(type, (nint)classPointer.ClassPointer); + Il2CppType.SetClassPointer(type, (nint)classPointer.ClassPointer); InjectorHelpers.AddTypeToLookup(assemblyName, @namespace, name, (nint)classPointer.ClassPointer); // Ensure that all other types that this type depends on are at least registered @@ -148,16 +148,16 @@ private static void RegisterTypeInIl2Cpp(Type type) SetFields(type, classPointer); } - static void EnsureNativeClassPointerNotNull(Type type) => GetNativeClassPointerNotNull(type); + static void EnsureNativeClassPointerNotNull(Type type) => GetClassPointerNotNull(type); - static nint GetNativeClassPointerNotNull(Type type) + static nint GetClassPointerNotNull(Type type) { - var classPointer = Il2CppClassPointerStore.GetNativeClassPointer(type); + var classPointer = Il2CppType.GetClassPointer(type); if (classPointer is 0) { Logger.Instance.LogWarning("The static constructor of {Type} is malformed and did not call RegisterTypeInIl2Cpp. Registering it now.", type.FullName); RegisterTypeInIl2Cpp(type); - classPointer = Il2CppClassPointerStore.GetNativeClassPointer(type); + classPointer = Il2CppType.GetClassPointer(type); Debug.Assert(classPointer is not 0); } else if (!RegisteredTypes.Contains(type)) @@ -172,14 +172,14 @@ static void SetClassData(Type type, INativeClassStruct classPointer) { if (type.BaseType is not null && NeedsInitialized.Contains(type.BaseType)) { - SetClassData(type.BaseType, UnityVersionHandler.Wrap((Il2CppClass*)GetNativeClassPointerNotNull(type.BaseType))); + SetClassData(type.BaseType, UnityVersionHandler.Wrap((Il2CppClass*)GetClassPointerNotNull(type.BaseType))); } var baseClassPointer = type switch { { BaseType: null } => null, - { IsValueType: true } => UnityVersionHandler.Wrap((Il2CppClass*)Il2CppClassPointerStore.NativeClassPointer), - _ => UnityVersionHandler.Wrap((Il2CppClass*)GetNativeClassPointerNotNull(type.BaseType)), + { IsValueType: true } => UnityVersionHandler.Wrap((Il2CppClass*)Il2CppType.GetClassPointer()), + _ => UnityVersionHandler.Wrap((Il2CppClass*)GetClassPointerNotNull(type.BaseType)), }; // Static classes get unsealed during generation so that they can be used as generic parameters, which might mislead users into thinking they can inherit from them. @@ -238,7 +238,7 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i { baseType = type.IsValueType ? typeof(Il2CppSystem.ValueType) : type.BaseType; interfaceTypesNotImplementedByBaseType = type.GetInterfaces().Where(IsIl2CppInterface).Where(i => !i.IsAssignableFrom(baseType)).ToArray(); - baseClassPointer = UnityVersionHandler.Wrap((Il2CppClass*)GetNativeClassPointerNotNull(baseType)); + baseClassPointer = UnityVersionHandler.Wrap((Il2CppClass*)GetClassPointerNotNull(baseType)); if (NeedsVTableSet.TryGetValue(baseType, out var baseTypeVTableMaxSize)) { SetVTableAndInterfaces(baseType, baseClassPointer, baseTypeVTableMaxSize); @@ -248,7 +248,7 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i { if (NeedsVTableSet.TryGetValue(@interface, out var interfaceVTableMaxSize)) { - var interfaceClassPointer = UnityVersionHandler.Wrap((Il2CppClass*)GetNativeClassPointerNotNull(@interface)); + var interfaceClassPointer = UnityVersionHandler.Wrap((Il2CppClass*)GetClassPointerNotNull(@interface)); SetVTableAndInterfaces(@interface, interfaceClassPointer, interfaceVTableMaxSize); } } @@ -260,7 +260,7 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i for (var i = 0; i < interfaceTypesNotImplementedByBaseType.Length; i++) { var interfaceType = interfaceTypesNotImplementedByBaseType[i]; - classPointer.ImplementedInterfaces[i] = (Il2CppClass*)GetNativeClassPointerNotNull(interfaceType); + classPointer.ImplementedInterfaces[i] = (Il2CppClass*)GetClassPointerNotNull(interfaceType); } } else @@ -271,11 +271,11 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i for (var i = 0; i < interfaceTypesNotImplementedByBaseType.Length; i++) { var interfaceType = interfaceTypesNotImplementedByBaseType[i]; - classPointer.ImplementedInterfaces[baseClassPointer.InterfaceCount + i] = (Il2CppClass*)GetNativeClassPointerNotNull(interfaceType); + classPointer.ImplementedInterfaces[baseClassPointer.InterfaceCount + i] = (Il2CppClass*)GetClassPointerNotNull(interfaceType); } } - var pointersToInterfaces = type.GetInterfaces().Where(IsIl2CppInterface).ToDictionary(Il2CppClassPointerStore.GetNativeClassPointer); + var pointersToInterfaces = type.GetInterfaces().Where(IsIl2CppInterface).ToDictionary(Il2CppType.GetClassPointer); var interfaceOffsets = new List(); @@ -393,7 +393,7 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i foreach (var interfaceType in interfaceTypesNotImplementedByBaseType) { - var interfaceClassPointer = UnityVersionHandler.Wrap((Il2CppClass*)GetNativeClassPointerNotNull(interfaceType)); + var interfaceClassPointer = UnityVersionHandler.Wrap((Il2CppClass*)GetClassPointerNotNull(interfaceType)); var interfaceOffset = index; var interfaceVtableCount = LowestInterfaceOffset(interfaceClassPointer); // Not sure this is correct @@ -463,13 +463,13 @@ static void SetFields(Type type, INativeClassStruct classPointer) { if (fieldType.IsValueType && NeedsFieldsSet.Contains(fieldType)) { - SetFields(fieldType, UnityVersionHandler.Wrap((Il2CppClass*)GetNativeClassPointerNotNull(fieldType))); + SetFields(fieldType, UnityVersionHandler.Wrap((Il2CppClass*)GetClassPointerNotNull(fieldType))); } } if (type.BaseType is not null && NeedsFieldsSet.Contains(type.BaseType)) { - SetFields(type.BaseType, UnityVersionHandler.Wrap((Il2CppClass*)GetNativeClassPointerNotNull(type.BaseType))); + SetFields(type.BaseType, UnityVersionHandler.Wrap((Il2CppClass*)GetClassPointerNotNull(type.BaseType))); } var fieldsToInject = GetIl2CppFields(type).ToArray(); @@ -481,7 +481,7 @@ static void SetFields(Type type, INativeClassStruct classPointer) { var (fieldType, fieldAttributes, fieldName) = fieldsToInject[i]; - var fieldInfoClass = Il2CppClassPointerStore.GetNativeClassPointer(fieldType); + var fieldInfoClass = Il2CppType.GetClassPointer(fieldType); if (fieldInfoClass == IntPtr.Zero) throw new Exception($"Type {fieldType} in {type}.{fieldName} doesn't exist in Il2Cpp"); if (!_injectedFieldTypes.TryGetValue((fieldType, fieldAttributes), out var fieldTypePtr)) @@ -803,7 +803,7 @@ private static int CalculateVTableUpperBoundUsingReflection(Type type) } if (type.IsValueType) { - count += UnityVersionHandler.Wrap((Il2CppClass*)Il2CppClassPointerStore.NativeClassPointer).VTableCount; + count += UnityVersionHandler.Wrap((Il2CppClass*)Il2CppType.GetClassPointer()).VTableCount; } return int.Min(count, ushort.MaxValue); @@ -822,7 +822,7 @@ public static void InjectEnumValues(Type type, Dictionary values if (!typeof(Il2CppSystem.IEnum).IsAssignableFrom(type)) throw new ArgumentException("Type argument needs to be an enum", nameof(type)); - var enumPtr = Il2CppClassPointerStore.GetNativeClassPointer(type); + var enumPtr = Il2CppType.GetClassPointer(type); if (enumPtr == IntPtr.Zero) throw new ArgumentException("Type needs to be an Il2Cpp enum", nameof(type)); @@ -893,14 +893,14 @@ static Il2CppSystem.Type TypeFromClassPointer(nint classPointer, string? typeNam private static void RegisterEnumInIl2Cpp(Type type) { - var baseEnum = UnityVersionHandler.Wrap((Il2CppClass*)Il2CppClassPointerStore.NativeClassPointer); + var baseEnum = UnityVersionHandler.Wrap((Il2CppClass*)Il2CppType.GetClassPointer()); InjectorHelpers.ClassInit(baseEnum.ClassPointer); var il2cppEnum = UnityVersionHandler.NewClass(baseEnum.VTableCount); var elementClass = UnityVersionHandler.Wrap( - (Il2CppClass*)Il2CppClassPointerStore.GetNativeClassPointer(GetEnumUnderlyingType(type))); + (Il2CppClass*)Il2CppType.GetClassPointer(GetEnumUnderlyingType(type))); (var assemblyName, var @namespace, var name) = GetFullyQualifiedName(type); il2cppEnum.Image = AssemblyInjector.GetOrCreateImage(assemblyName).ImagePointer; @@ -983,7 +983,7 @@ private static void RegisterEnumInIl2Cpp(Type type) il2cppEnum.TypeHierarchy[i] = baseEnum.TypeHierarchy[i]; il2cppEnum.TypeHierarchy[il2cppEnum.TypeHierarchyDepth - 1] = il2cppEnum.ClassPointer; - Il2CppClassPointerStore.SetNativeClassPointer(type, il2cppEnum.Pointer); + Il2CppType.SetClassPointer(type, il2cppEnum.Pointer); InjectorHelpers.AddTypeToLookup(assemblyName, @namespace, name, il2cppEnum.Pointer); } @@ -1051,7 +1051,7 @@ private static IEnumerable GetMethodTypes(MethodInfo method) converted.InvokerMethod = (nint)invoker; converted.MethodPointer = (nint)(delegate* unmanaged)&Method; converted.Slot = ushort.MaxValue; - converted.ReturnType = (Il2CppTypeStruct*)IL2CPP.il2cpp_class_get_type(Il2CppClassPointerStore.NativeClassPointer); + converted.ReturnType = (Il2CppTypeStruct*)IL2CPP.il2cpp_class_get_type(Il2CppType.GetClassPointer()); converted.Flags = Il2CppMethodFlags.METHOD_ATTRIBUTE_PUBLIC | Il2CppMethodFlags.METHOD_ATTRIBUTE_HIDE_BY_SIG | @@ -1222,9 +1222,10 @@ private static Delegate CreateInvoker(MethodInfo monoMethod) // Those get returned as-is, so we don't want to box them. var returnValue = body.DeclareLocal(nativeReturnType); body.Emit(OpCodes.Stloc, returnValue); - var classField = typeof(Il2CppClassPointerStore<>).MakeGenericType(monoMethod.ReturnType) - .GetField(nameof(Il2CppClassPointerStore<>.NativeClassPointer))!; - body.Emit(OpCodes.Ldsfld, classField); + var getClassPointer = typeof(Il2CppType) + .GetMethod(nameof(Il2CppType.GetClassPointer), 1, [])! + .MakeGenericMethod(monoMethod.ReturnType); + body.Emit(OpCodes.Call, getClassPointer); body.Emit(OpCodes.Ldloca, returnValue); body.Emit(OpCodes.Call, typeof(IL2CPP).GetMethod(nameof(IL2CPP.il2cpp_value_box))!); } diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs index 6fb291ad..3f89deea 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs @@ -96,10 +96,10 @@ private protected long IndexFromIndices(ReadOnlySpan indices) } private protected static void SetClassPointer(uint rank) - where TArray : Il2CppArrayBase + where TArray : Il2CppArrayBase, IIl2CppType where TElement : IIl2CppType { - Il2CppClassPointerStore.NativeClassPointer = IL2CPP.il2cpp_array_class_get(Il2CppClassPointerStore.NativeClassPointer, rank); + Il2CppType.SetClassPointer(IL2CPP.il2cpp_array_class_get(Il2CppType.GetClassPointer(), rank)); } } public abstract class Il2CppArrayBase : Il2CppArrayBase diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank1.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank1.cs index 0501fa77..46c6de82 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank1.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank1.cs @@ -32,7 +32,7 @@ public sealed class Il2CppArrayRank1 : Il2CppArrayBase, IIl2CppType, T>(1); - Il2CppObjectPool.RegisterInitializer(Il2CppClassPointerStore>.NativeClassPointer, static (ptr) => new Il2CppArrayRank1(ptr)); + Il2CppObjectPool.RegisterInitializer(Il2CppType.GetClassPointer>(), static (ptr) => new Il2CppArrayRank1(ptr)); } public Il2CppArrayRank1(ObjectPointer pointer) : base(pointer) @@ -55,7 +55,7 @@ private static ObjectPointer AllocateArray(int length) { ArgumentOutOfRangeException.ThrowIfNegative(length); - var elementTypeClassPointer = Il2CppClassPointerStore.NativeClassPointer; + var elementTypeClassPointer = Il2CppType.GetClassPointer(); if (elementTypeClassPointer == IntPtr.Zero) throw new ArgumentException($"{nameof(Il2CppArrayRank1<>)} requires an Il2Cpp type, which {typeof(T)} isn't"); return (ObjectPointer)IL2CPP.il2cpp_array_new(elementTypeClassPointer, (ulong)length); @@ -164,7 +164,7 @@ public static explicit operator Span(Il2CppArrayRank1? array) #region IIl2CppType Implementation static int IIl2CppType>.Size => IntPtr.Size; - nint IIl2CppType.ObjectClass => Il2CppClassPointerStore>.NativeClassPointer; + nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); static void IIl2CppType>.WriteToSpan(Il2CppArrayRank1? value, Span span) => Il2CppType.WriteReference(value, span); static Il2CppArrayRank1? IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => Il2CppType.ReadReference>(span); #endregion diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs index 030a2fb7..93d82186 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs @@ -9,19 +9,19 @@ public sealed class Il2CppArrayRank2 : Il2CppArrayBase, IIl2CppType>.Size => IntPtr.Size; - nint IIl2CppType.ObjectClass => Il2CppClassPointerStore>.NativeClassPointer; + nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); static Il2CppArrayRank2() { SetClassPointer, T>(2); - Il2CppObjectPool.RegisterInitializer(Il2CppClassPointerStore>.NativeClassPointer, static (ptr) => new Il2CppArrayRank2(ptr)); + Il2CppObjectPool.RegisterInitializer(Il2CppType.GetClassPointer>(), static (ptr) => new Il2CppArrayRank2(ptr)); } public Il2CppArrayRank2(ObjectPointer pointer) : base(pointer) { } - public Il2CppArrayRank2(int length0, int length1) : base([length0, length1], Il2CppClassPointerStore>.NativeClassPointer) + public Il2CppArrayRank2(int length0, int length1) : base([length0, length1], Il2CppType.GetClassPointer>()) { } diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs index cad76508..643bd8be 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs @@ -9,19 +9,19 @@ public sealed class Il2CppArrayRank3 : Il2CppArrayBase, IIl2CppType>.Size => IntPtr.Size; - nint IIl2CppType.ObjectClass => Il2CppClassPointerStore>.NativeClassPointer; + nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); static Il2CppArrayRank3() { SetClassPointer, T>(3); - Il2CppObjectPool.RegisterInitializer(Il2CppClassPointerStore>.NativeClassPointer, static (ptr) => new Il2CppArrayRank3(ptr)); + Il2CppObjectPool.RegisterInitializer(Il2CppType.GetClassPointer>(), static (ptr) => new Il2CppArrayRank3(ptr)); } public Il2CppArrayRank3(ObjectPointer pointer) : base(pointer) { } - public Il2CppArrayRank3(int length0, int length1, int length2) : base([length0, length1, length2], Il2CppClassPointerStore>.NativeClassPointer) + public Il2CppArrayRank3(int length0, int length1, int length2) : base([length0, length1, length2], Il2CppType.GetClassPointer>()) { } diff --git a/Il2CppInterop.Runtime/InteropTypes/Pointer.cs b/Il2CppInterop.Runtime/InteropTypes/Pointer.cs index 44a0962e..bf47a0d5 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Pointer.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Pointer.cs @@ -39,7 +39,7 @@ private readonly void ThrowIfNull() static int IIl2CppType>.Size => IntPtr.Size; - readonly nint IIl2CppType.ObjectClass => Il2CppClassPointerStore>.NativeClassPointer; + readonly nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); static Pointer IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => (Pointer)(void*)Il2CppType.ReadPointer(span); static void IIl2CppType>.WriteToSpan(Pointer value, Span span) => Il2CppType.WritePointer((IntPtr)value._pointer, span); @@ -49,7 +49,7 @@ private readonly void ThrowIfNull() static Pointer() { - var elementType = Il2CppSystem.Type.FromClassPointer(Il2CppClassPointerStore.NativeClassPointer); - Il2CppClassPointerStore>.NativeClassPointer = elementType.MakePointerType().ToClassPointer(); + var elementType = Il2CppSystem.Type.FromClassPointer(Il2CppType.GetClassPointer()); + Il2CppType.SetClassPointer>(elementType.MakePointerType().ToClassPointer()); } } diff --git a/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs b/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs index 70685c65..23d93037 100644 --- a/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs +++ b/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs @@ -27,7 +27,7 @@ public Sample(global::Il2CppInterop.Common.ObjectPointer obj0) : base(obj0) static int global::Il2CppInterop.Common.IIl2CppType.Size => nint.Size; - nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Runtime.Il2CppClassPointerStore.NativeClassPointer; + nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer(); static Sample? global::Il2CppInterop.Common.IIl2CppType.ReadFromSpan(global::System.ReadOnlySpan span) { @@ -51,7 +51,7 @@ file static class Il2CppInternals static Il2CppInternals() { global::Il2CppInterop.Runtime.Injection.TypeInjector.RegisterTypeInIl2Cpp(); - global::Il2CppInterop.Runtime.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Runtime.Il2CppClassPointerStore.NativeClassPointer, ptr => new Sample(ptr)); + global::Il2CppInterop.Runtime.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer(), ptr => new Sample(ptr)); } } diff --git a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs index ebf4489d..63f1783c 100644 --- a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs +++ b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs @@ -352,7 +352,7 @@ private static void EmitStaticInterfaceMembers(IndentedTextWriter writer, TypeMo writer.WriteLine($"static int global::Il2CppInterop.Common.IIl2CppType<{tn}>.Size => nint.Size;"); writer.WriteLineNoTabs(); - writer.WriteLine($"nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{tn}>.NativeClassPointer;"); + writer.WriteLine($"nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer<{tn}>();"); writer.WriteLineNoTabs(); writer.WriteLine($"static {tn}? global::Il2CppInterop.Common.IIl2CppType<{tn}>.ReadFromSpan(global::System.ReadOnlySpan span)"); @@ -415,19 +415,19 @@ private static void EmitInternalsClass(IndentedTextWriter writer, TypeModel mode foreach (var member in model.Members) { if (member.IsStatic) - writer.WriteLine($"FieldInfoPtr_{member.Index} = global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer, \"{member.Name}\");"); + writer.WriteLine($"FieldInfoPtr_{member.Index} = global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer<{model.TypeName}>(), \"{member.Name}\");"); else - writer.WriteLine($"FieldOffset_{member.Index} = global::Il2CppInterop.Runtime.FieldAccess.GetFieldOffset(global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer, \"{member.Name}\"));"); + writer.WriteLine($"FieldOffset_{member.Index} = global::Il2CppInterop.Runtime.FieldAccess.GetFieldOffset(global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer<{model.TypeName}>(), \"{member.Name}\"));"); } if (isValueType) { - writer.WriteLine($"Size = global::Il2CppInterop.Common.IL2CPP.il2cpp_class_value_size(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer, out _);"); + writer.WriteLine($"Size = global::Il2CppInterop.Common.IL2CPP.il2cpp_class_value_size(global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer<{model.TypeName}>(), out _);"); writer.WriteLine($"global::Il2CppInterop.Runtime.Il2CppObjectPool.RegisterValueTypeInitializer<{model.TypeName}>();"); } else if (!model.IsAbstract) { - writer.WriteLine($"global::Il2CppInterop.Runtime.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer, ptr => new {model.TypeName}(ptr));"); + writer.WriteLine($"global::Il2CppInterop.Runtime.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer<{model.TypeName}>(), ptr => new {model.TypeName}(ptr));"); } writer.Indent--; diff --git a/Il2Cppmscorlib/Enum.cs b/Il2Cppmscorlib/Enum.cs index 29a8acef..984a5f2d 100644 --- a/Il2Cppmscorlib/Enum.cs +++ b/Il2Cppmscorlib/Enum.cs @@ -1,5 +1,11 @@ -namespace Il2CppSystem; +using Il2CppInterop.Common; -public abstract class Enum : ValueType +namespace Il2CppSystem; + +public abstract class Enum : ValueType, IIl2CppType { + static int IIl2CppType.Size => throw new System.NotImplementedException(); + + static Enum IIl2CppType.ReadFromSpan(System.ReadOnlySpan span) => throw new System.NotImplementedException(); + static void IIl2CppType.WriteToSpan(Enum value, System.Span span) => throw new System.NotImplementedException(); } diff --git a/Il2Cppmscorlib/Object.cs b/Il2Cppmscorlib/Object.cs index 35b9f3a2..d3885905 100644 --- a/Il2Cppmscorlib/Object.cs +++ b/Il2Cppmscorlib/Object.cs @@ -2,7 +2,7 @@ namespace Il2CppSystem; -public class Object : IObject +public class Object : IObject, IIl2CppType { protected Object() { @@ -12,10 +12,16 @@ protected Object(ObjectPointer ptr) { } + static int IIl2CppType.Size => throw new System.NotImplementedException(); + public nint Pointer => default; public bool WasCollected => default; + nint IIl2CppType.ObjectClass => throw new System.NotImplementedException(); + + static Object IIl2CppType.ReadFromSpan(System.ReadOnlySpan span) => throw new System.NotImplementedException(); + static void IIl2CppType.WriteToSpan(Object value, System.Span span) => throw new System.NotImplementedException(); public virtual Boolean Equals(IObject @object) => default; public virtual Int32 GetIl2CppHashCode() => default; public virtual void Il2CppFinalize() diff --git a/Il2Cppmscorlib/ValueType.cs b/Il2Cppmscorlib/ValueType.cs index 21efb1f4..80883c45 100644 --- a/Il2Cppmscorlib/ValueType.cs +++ b/Il2Cppmscorlib/ValueType.cs @@ -1,5 +1,11 @@ -namespace Il2CppSystem; +using Il2CppInterop.Common; -public abstract class ValueType : Object +namespace Il2CppSystem; + +public abstract class ValueType : Object, IIl2CppType { + static int IIl2CppType.Size => throw new System.NotImplementedException(); + + static ValueType IIl2CppType.ReadFromSpan(System.ReadOnlySpan span) => throw new System.NotImplementedException(); + static void IIl2CppType.WriteToSpan(ValueType value, System.Span span) => throw new System.NotImplementedException(); } From 694ca6bdbd618ba52ed0929ac9b785f8c32a9166 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Mon, 4 May 2026 17:55:20 -0700 Subject: [PATCH 377/486] Fix incorrect unstripping of unbox and unbox.any --- Il2CppInterop.Generator/MonoIl2CppConversion.cs | 3 +-- Il2CppInterop.Generator/TranslatedMethodBody.cs | 13 +++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Il2CppInterop.Generator/MonoIl2CppConversion.cs b/Il2CppInterop.Generator/MonoIl2CppConversion.cs index 6f56483d..cc35ba6e 100644 --- a/Il2CppInterop.Generator/MonoIl2CppConversion.cs +++ b/Il2CppInterop.Generator/MonoIl2CppConversion.cs @@ -1,5 +1,4 @@ using Cpp2IL.Core.Model.Contexts; -using Il2CppInterop.Generator; using Il2CppInterop.Generator.Operands; using Il2CppInterop.Runtime.InteropTypes; @@ -13,7 +12,7 @@ internal static class MonoIl2CppConversion public static bool AddIl2CppToMonoConversion(List instructions, TypeAnalysisContext il2CppType) { // Depending on the type of the local variable, we may need to convert it. - // If the local variable is Pointer, we need to convert it to T*. + // If the local variable is Pointer or ByReference, we need to convert it to void*. // If the local variable is an Il2Cpp primitive (like Il2CppSystem.Int32), we need to convert it to the corresponding C# type. // If the local variable is an Il2Cpp enum, we need to convert it to the underlying C# primitive type. diff --git a/Il2CppInterop.Generator/TranslatedMethodBody.cs b/Il2CppInterop.Generator/TranslatedMethodBody.cs index f1a4819f..7e3ed054 100644 --- a/Il2CppInterop.Generator/TranslatedMethodBody.cs +++ b/Il2CppInterop.Generator/TranslatedMethodBody.cs @@ -580,15 +580,20 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo break; case CilCode.Unbox: { - translatedInstruction.Code = originalCode; - translatedInstruction.Operand = translatedType; - MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, translatedType); + // The unbox instruction extracts a pointer to the value type data from the boxed object. + // To unstrip this, add `byte* backingData = stackalloc byte[Il2CppType.SizeOf()];` to the beginning of the method. + // Replace this instruction with the following: + // * unbox.any translatedType + // * ldloc backingData + // * call Il2CppType.WriteToPointer<> + // * ldloc backingData + return false; } - break; case CilCode.Unbox_Any: { translatedInstruction.Code = originalCode; translatedInstruction.Operand = translatedType; + MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, translatedType); } break; case CilCode.Ldtoken: From 9fa6b9c153efae3da8bb3dc3020402837eea22d7 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Tue, 5 May 2026 12:22:31 -0700 Subject: [PATCH 378/486] Fix some naming issues with FieldAccess --- .../FieldAccessorProcessingLayer.cs | 4 ++-- Il2CppInterop.Runtime/FieldAccess.cs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Il2CppInterop.Generator/FieldAccessorProcessingLayer.cs b/Il2CppInterop.Generator/FieldAccessorProcessingLayer.cs index 75da569c..e9c288de 100644 --- a/Il2CppInterop.Generator/FieldAccessorProcessingLayer.cs +++ b/Il2CppInterop.Generator/FieldAccessorProcessingLayer.cs @@ -20,11 +20,11 @@ public override void Process(ApplicationAnalysisContext appContext, Action pair.Key == "il2cpp_gc_wbarrier_set_field") - ? setInstanceFieldValue_Wbarrior + ? setInstanceFieldValue_WriteBarrier : setInstanceFieldValue_Pointer; var il2CppFieldAttribute = appContext.ResolveTypeOrThrow(typeof(Il2CppFieldAttribute)); diff --git a/Il2CppInterop.Runtime/FieldAccess.cs b/Il2CppInterop.Runtime/FieldAccess.cs index 45901f30..4542f071 100644 --- a/Il2CppInterop.Runtime/FieldAccess.cs +++ b/Il2CppInterop.Runtime/FieldAccess.cs @@ -42,7 +42,7 @@ public static void SetInstanceFieldValue(Object instance, int fieldOffset, T? FunctionPointerCache.SetInstanceFieldValue(instance, fieldOffset, value); } - public static void SetInstanceFieldValue_Wbarrior(Object instance, int fieldOffset, T? value) where T : IIl2CppType + public static void SetInstanceFieldValue_WriteBarrier(Object instance, int fieldOffset, T? value) where T : IIl2CppType { ArgumentOutOfRangeException.ThrowIfNegative(fieldOffset); var data = (byte*)instance.Pointer + fieldOffset; @@ -81,14 +81,14 @@ public static nint GetFieldInfo(nint classPointer, string fieldName) return field; } - public static int GetFieldOffset(nint field) + public static int GetFieldOffset(nint fieldInfo) { - if (field == nint.Zero) + if (fieldInfo == nint.Zero) return -1; - return (int)IL2CPP.il2cpp_field_get_offset(field); + return (int)IL2CPP.il2cpp_field_get_offset(fieldInfo); } - private static bool HasWbarriorSupport() + private static bool HasWriteBarrierSupport() { if (NativeLibrary.TryLoad("GameAssembly", out var handle)) { @@ -99,12 +99,12 @@ private static bool HasWbarriorSupport() return false; } - private static bool WbarriorSupport { get; } = HasWbarriorSupport(); + private static bool WriteBarrierSupport { get; } = HasWriteBarrierSupport(); private static class FunctionPointerCache where T : IIl2CppType { - public static readonly delegate* SetInstanceFieldValue = WbarriorSupport - ? &FieldAccess.SetInstanceFieldValue_Wbarrior + public static readonly delegate* SetInstanceFieldValue = WriteBarrierSupport + ? &FieldAccess.SetInstanceFieldValue_WriteBarrier : &FieldAccess.SetInstanceFieldValue_Pointer; } } From 57075187827d978c1575cbc1c03cdfcc9f909e1d Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Tue, 5 May 2026 14:35:49 -0700 Subject: [PATCH 379/486] Validate that class pointer is only being set once --- Il2CppInterop.Runtime/Il2CppType.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Il2CppInterop.Runtime/Il2CppType.cs b/Il2CppInterop.Runtime/Il2CppType.cs index d41e9608..fd3c59e5 100644 --- a/Il2CppInterop.Runtime/Il2CppType.cs +++ b/Il2CppInterop.Runtime/Il2CppType.cs @@ -201,6 +201,7 @@ public static nint GetClassPointer(Type type) public static nint GetClassPointer() where T : IIl2CppType { + RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); return Il2CppClassPointerStore.NativeClassPointer; } @@ -214,17 +215,23 @@ internal static void SetClassPointer(Type type, nint classPointer) public static void SetClassPointer(nint classPointer) where T : IIl2CppType { - Il2CppClassPointerStore.NativeClassPointer = classPointer; + RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); + if (Il2CppClassPointerStore.NativeClassPointer != classPointer) + { + if (Il2CppClassPointerStore.NativeClassPointer == nint.Zero) + { + Il2CppClassPointerStore.NativeClassPointer = classPointer; + } + else + { + throw new InvalidOperationException($"Class pointer for type {typeof(T).FullName} has already been set."); + } + } } private static class Il2CppClassPointerStore where T : IIl2CppType { public static nint NativeClassPointer; - - static Il2CppClassPointerStore() - { - RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); - } } // Temporary location for this method From 0a3454cfe84c6dc09705c39d57f6d6d41f65af04 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 6 May 2026 10:28:52 -0700 Subject: [PATCH 380/486] Improved boxing support Resolves #8 --- Il2CppInterop.CLI/Program.cs | 1 + Il2CppInterop.Common/IIl2CppType.cs | 62 +++++ .../BoxingProcessingLayer.cs | 223 ++++++++++++++++++ .../MarshallingProcessingLayer.cs | 126 ---------- ...ferenceAssemblyInjectionProcessingLayer.cs | 1 + .../TranslatedMethodBody.cs | 3 + Il2CppInterop.Runtime/FieldAccess.cs | 10 +- Il2CppInterop.Runtime/GenerationInternals.cs | 26 ++ Il2CppInterop.Runtime/Il2CppType.cs | 52 +--- .../InteropTypes/ByReference.cs | 1 + Il2CppInterop.Runtime/InteropTypes/Pointer.cs | 1 + Il2CppInterop.Runtime/NativeBoxing.cs | 40 ++++ Il2CppInterop.Runtime/RuntimeInvoke.cs | 7 +- Il2Cppmscorlib/Boolean.cs | 1 + Il2Cppmscorlib/IValueType.cs | 2 - Il2Cppmscorlib/Int32.cs | 1 + Il2Cppmscorlib/IntPtr.cs | 1 + Il2Cppmscorlib/Nullable.cs | 17 ++ Il2Cppmscorlib/Object.cs | 1 + Il2Cppmscorlib/Void.cs | 1 + 20 files changed, 393 insertions(+), 184 deletions(-) create mode 100644 Il2CppInterop.Generator/BoxingProcessingLayer.cs create mode 100644 Il2CppInterop.Runtime/NativeBoxing.cs create mode 100644 Il2Cppmscorlib/Nullable.cs diff --git a/Il2CppInterop.CLI/Program.cs b/Il2CppInterop.CLI/Program.cs index a61d0019..e0362eb7 100644 --- a/Il2CppInterop.CLI/Program.cs +++ b/Il2CppInterop.CLI/Program.cs @@ -36,6 +36,7 @@ new Il2CppTypeConstraintProcessingLayer(), new InitializationClassProcessingLayer(), new MarshallingProcessingLayer(), + new BoxingProcessingLayer(), new PrimitiveImplicitConversionProcessingLayer(), new EnumProcessingLayer(), new ObjectOverridesProcessingLayer(), diff --git a/Il2CppInterop.Common/IIl2CppType.cs b/Il2CppInterop.Common/IIl2CppType.cs index a0bab848..084a0498 100644 --- a/Il2CppInterop.Common/IIl2CppType.cs +++ b/Il2CppInterop.Common/IIl2CppType.cs @@ -3,6 +3,24 @@ namespace Il2CppInterop.Common; public interface IIl2CppType { IntPtr ObjectClass { get; } + /// + /// Box this managed object as a native Il2Cpp object + /// + /// + /// For classes, this returns a pointer to the existing Il2Cpp object.
+ /// For value types, this creates a new boxed Il2Cpp object. + ///
+ /// The pointer to the boxed Il2Cpp object + ObjectPointer BoxNative(); + /// + /// Box this managed object + /// + /// + /// This method is necessary for semantically accurate boxing of Il2CppSystem.Nullable<T> in unstripped code.
+ /// All other types are expected to use the default implementation. + ///
+ /// The boxed object + object Box() => this; } public interface IIl2CppType : IIl2CppType where TSelf : notnull, IIl2CppType { @@ -49,4 +67,48 @@ static virtual string AssemblyName /// The span to read the value from. /// The value read from the span. static abstract TSelf? ReadFromSpan(ReadOnlySpan span); + /// + /// Unboxes the provided native Il2Cpp object to the type + /// + /// + /// This always returns -typed objects, not subclasses of . + /// Callers are expected to know that this is the exact type of the object being unboxed. + /// Otherwise, they should use and . + /// + /// The pointer to the native Il2Cpp object. + /// The unboxed value. + /// is an interface or abstract class. + /// did not implement this method. + static virtual unsafe TSelf? UnboxNative(ObjectPointer pointer) + { + if (typeof(TSelf).IsValueType) + { + var unboxed = IL2CPP.il2cpp_object_unbox((nint)pointer); + return TSelf.ReadFromSpan(new ReadOnlySpan((void*)unboxed, TSelf.Size)); + } + else if (typeof(TSelf).IsInterface) + { + throw new NotSupportedException("Interfaces cannot be unboxed because they are not concrete types."); + } + else if (typeof(TSelf).IsAbstract) + { + throw new NotSupportedException("Abstract classes cannot be unboxed because they are not concrete types."); + } + else + { + throw new NotImplementedException($"{typeof(TSelf).FullName} did not implement this method."); + } + } + /// + /// Unboxes the provided object to the type + /// + /// + /// This is only intended to be overridden by Il2CppSystem.Nullable<T>, which has special unboxing behavior. + /// + /// The object to unbox. + /// The unboxed value. + static virtual TSelf? Unbox(object? obj) + { + return (TSelf?)obj; + } } diff --git a/Il2CppInterop.Generator/BoxingProcessingLayer.cs b/Il2CppInterop.Generator/BoxingProcessingLayer.cs new file mode 100644 index 00000000..cfe6d74a --- /dev/null +++ b/Il2CppInterop.Generator/BoxingProcessingLayer.cs @@ -0,0 +1,223 @@ +using System.Reflection; +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Common; +using Il2CppInterop.Generator.Operands; +using Il2CppInterop.Runtime; + +namespace Il2CppInterop.Generator; + +public sealed class BoxingProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Boxing Implementations"; + public override string Id => "boxing_implementations"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + var iil2CppType = appContext.ResolveTypeOrThrow(typeof(IIl2CppType)); + var iil2CppType_BoxNative = iil2CppType.GetMethodByName(nameof(IIl2CppType.BoxNative)); + var iil2CppType_Box = iil2CppType.GetMethodByName(nameof(IIl2CppType.Box)); + + var iil2CppTypeGeneric = appContext.ResolveTypeOrThrow(typeof(IIl2CppType<>)); + var iil2CppTypeGeneric_UnboxNative = iil2CppTypeGeneric.GetMethodByName(nameof(IIl2CppType<>.UnboxNative)); + var iil2CppTypeGeneric_Unbox = iil2CppTypeGeneric.GetMethodByName(nameof(IIl2CppType<>.Unbox)); + + var nativeBoxing = appContext.ResolveTypeOrThrow(typeof(NativeBoxing)); + var nativeBoxing_BoxReferenceType = nativeBoxing.GetMethodByName(nameof(NativeBoxing.BoxReferenceType)); + var nativeBoxing_BoxValueType = nativeBoxing.GetMethodByName(nameof(NativeBoxing.BoxValueType)); + var nativeBoxing_BoxNullableValueType = nativeBoxing.GetMethodByName(nameof(NativeBoxing.BoxNullableValueType)); + var nativeBoxing_UnboxNullableValueType = nativeBoxing.GetMethodByName(nameof(NativeBoxing.UnboxNullableValueType)); + + var generationInternals = appContext.ResolveTypeOrThrow(typeof(GenerationInternals)); + var generationInternals_BoxNullableValueType = generationInternals.GetMethodByName(nameof(GenerationInternals.BoxNullableValueType)); + var generationInternals_UnboxNullableValueType = generationInternals.GetMethodByName(nameof(GenerationInternals.UnboxNullableValueType)); + + var objectPointer = appContext.ResolveTypeOrThrow(typeof(ObjectPointer)); + + var il2CppSystemObject = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Object"); + var il2CppSystemNullable = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.Nullable`1"); + + // Il2CppSystem.Object needs to implement BoxNative + { + var method = new InjectedMethodAnalysisContext( + il2CppSystemObject, + $"{iil2CppType.FullName}.{iil2CppType_BoxNative.Name}", + iil2CppType_BoxNative.ReturnType, + MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot, + []) + { + IsInjected = true, + }; + method.Overrides.Add(iil2CppType_BoxNative); + il2CppSystemObject.Methods.Add(method); + method.PutExtraData(new NativeMethodBody() + { + Instructions = + [ + new Instruction(CilOpCodes.Ldarg_0), + new Instruction(CilOpCodes.Call, nativeBoxing_BoxReferenceType), + new Instruction(CilOpCodes.Ret), + ] + }); + } + + // Il2CppSystem.Nullable needs to implement UnboxNative + { + var interfaceMethod = iil2CppTypeGeneric_UnboxNative.MakeConcreteGeneric([il2CppSystemNullable.SelfInstantiateIfGeneric()], []); + var method = new InjectedMethodAnalysisContext( + il2CppSystemNullable, + $"{interfaceMethod.DeclaringType!.FullName}.{interfaceMethod.Name}", + interfaceMethod.ReturnType, + MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static, + [objectPointer]) + { + IsInjected = true, + }; + method.Overrides.Add(interfaceMethod); + il2CppSystemNullable.Methods.Add(method); + method.PutExtraData(new NativeMethodBody() + { + Instructions = + [ + new Instruction(CilOpCodes.Ldarg_0), + new Instruction(CilOpCodes.Call, nativeBoxing_UnboxNullableValueType.MakeConcreteGeneric([], il2CppSystemNullable.GenericParameters)), + new Instruction(CilOpCodes.Ret), + ] + }); + } + + // Il2CppSystem.Nullable needs to implement Box + { + var method = new InjectedMethodAnalysisContext( + il2CppSystemNullable, + $"{iil2CppType.FullName}.{iil2CppType_Box.Name}", + iil2CppType_Box.ReturnType, + MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot, + []) + { + IsInjected = true, + }; + method.Overrides.Add(iil2CppType_Box); + il2CppSystemNullable.Methods.Add(method); + method.PutExtraData(new NativeMethodBody() + { + Instructions = + [ + new Instruction(CilOpCodes.Ldarg_0), + new Instruction(CilOpCodes.Call, generationInternals_BoxNullableValueType.MakeGenericInstanceMethod(il2CppSystemNullable.GenericParameters)), + new Instruction(CilOpCodes.Ret), + ] + }); + } + + // Il2CppSystem.Nullable needs to implement Unbox + { + var interfaceMethod = iil2CppTypeGeneric_Unbox.MakeConcreteGeneric([il2CppSystemNullable.SelfInstantiateIfGeneric()], []); + var method = new InjectedMethodAnalysisContext( + il2CppSystemNullable, + $"{interfaceMethod.DeclaringType!.FullName}.{interfaceMethod.Name}", + interfaceMethod.ReturnType, + MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static, + [objectPointer]) + { + IsInjected = true, + }; + method.Overrides.Add(interfaceMethod); + il2CppSystemNullable.Methods.Add(method); + method.PutExtraData(new NativeMethodBody() + { + Instructions = + [ + new Instruction(CilOpCodes.Ldarg_0), + new Instruction(CilOpCodes.Call, generationInternals_UnboxNullableValueType.MakeGenericInstanceMethod(il2CppSystemNullable.GenericParameters)), + new Instruction(CilOpCodes.Ret), + ] + }); + } + + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly || assembly.IsInjected) + continue; + + foreach (var type in assembly.Types) + { + if (type.IsInjected) + continue; + + if (type.IsValueType) + { + // Value types need to implement BoxNative + var method = new InjectedMethodAnalysisContext( + type, + $"{iil2CppType.FullName}.{iil2CppType_BoxNative.Name}", + iil2CppType_BoxNative.ReturnType, + MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot, + []) + { + IsInjected = true, + }; + method.Overrides.Add(iil2CppType_BoxNative); + type.Methods.Add(method); + + var boxMethod = type == il2CppSystemNullable + ? nativeBoxing_BoxNullableValueType.MakeConcreteGeneric([], type.GenericParameters) + : nativeBoxing_BoxValueType.MaybeMakeConcreteGeneric([], [type.SelfInstantiateIfGeneric()]); + + method.PutExtraData(new NativeMethodBody() + { + Instructions = + [ + new Instruction(CilOpCodes.Ldarg_0), + new Instruction(CilOpCodes.Call, boxMethod), + new Instruction(CilOpCodes.Ret), + ] + }); + } + else if (!type.IsAbstract && !type.IsInterface) + { + // Concrete reference types need to implement UnboxNative + var interfaceMethod = iil2CppTypeGeneric_UnboxNative.MakeConcreteGeneric([type.SelfInstantiateIfGeneric()], []); + var method = new InjectedMethodAnalysisContext( + type, + $"{interfaceMethod.DeclaringType!.FullName}.{interfaceMethod.Name}", + interfaceMethod.ReturnType, + MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static, + [objectPointer]) + { + IsInjected = true, + }; + method.Overrides.Add(interfaceMethod); + type.Methods.Add(method); + + method.PutExtraData(new NativeMethodBody() + { + Instructions = + [ + new Instruction(CilOpCodes.Ldarg_0), + new Instruction(CilOpCodes.Newobj, GetObjectPointerConstructor(type, objectPointer)), + new Instruction(CilOpCodes.Ret), + ] + }); + } + } + } + } + + private static MethodAnalysisContext GetObjectPointerConstructor(TypeAnalysisContext declaringType, TypeAnalysisContext objectPointer) + { + MethodAnalysisContext? constructor = null; + foreach (var method in declaringType.Methods) + { + if (method.IsInstanceConstructor && method.Parameters.Count is 1 && method.Parameters[0].ParameterType == objectPointer) + { + constructor = method; + break; + } + } + if (constructor == null) + { + throw new InvalidOperationException($"No suitable constructor found on {declaringType.FullName} that takes an ObjectPointer"); + } + return constructor.MaybeMakeConcreteGeneric(declaringType.GenericParameters, []); + } +} diff --git a/Il2CppInterop.Generator/MarshallingProcessingLayer.cs b/Il2CppInterop.Generator/MarshallingProcessingLayer.cs index 6c7ad291..1507d94e 100644 --- a/Il2CppInterop.Generator/MarshallingProcessingLayer.cs +++ b/Il2CppInterop.Generator/MarshallingProcessingLayer.cs @@ -43,49 +43,6 @@ public override void Process(ApplicationAnalysisContext appContext, Action) - MethodAnalysisContext il2cppSystemIValueType_WriteToSpan; - { - var spanOfByteType = il2CppTypeHelper_WriteToSpan.Parameters[^1].ParameterType; - il2cppSystemIValueType_WriteToSpan = new InjectedMethodAnalysisContext( - il2CppSystemIValueType, - nameof(Il2CppSystem.IValueType.WriteToSpan), - appContext.SystemTypes.SystemVoidType, - MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Abstract | MethodAttributes.Virtual | MethodAttributes.NewSlot, - [spanOfByteType]) - { - IsInjected = true, - }; - il2CppSystemIValueType.Methods.Add(il2cppSystemIValueType_WriteToSpan); - } - foreach (var assembly in appContext.Assemblies) { if (assembly.IsReferenceAssembly || assembly.IsInjected) @@ -208,45 +165,6 @@ public override void Process(ApplicationAnalysisContext appContext, Action p.ParameterType).ToArray()) - { - IsInjected = true, - }; - type.Methods.Add(method); - method.Overrides.Add(il2cppSystemIValueType_WriteToSpan); - - if (type.IsValueType) - { - method.PutExtraData(new NativeMethodBody() - { - Instructions = - [ - new Instruction(CilOpCodes.Ldarg_0), - new Instruction(CilOpCodes.Ldobj, instantiatedType), - new Instruction(CilOpCodes.Ldarg_1), - new Instruction(CilOpCodes.Call, il2CppTypeHelper_WriteToSpan.MakeGenericInstanceMethod(instantiatedType)), - new Instruction(CilOpCodes.Ret), - ], - }); - } - else - { - method.PutExtraData(new NativeMethodBody() - { - Instructions = - [ - new Instruction(CilOpCodes.Ldarg_0), - new Instruction(CilOpCodes.Ldarg_1), - new Instruction(CilOpCodes.Call, il2CppTypeHelper_WriteReference.MakeGenericInstanceMethod(instantiatedType)), - new Instruction(CilOpCodes.Ret), - ], - }); - } - } } } } diff --git a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs index 1f8ddae7..ac5f67e2 100644 --- a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs +++ b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs @@ -53,6 +53,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action, either known or as a generic parameter if (MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, translatedType)) { translatedInstruction.Code = CilOpCodes.Nop; @@ -594,6 +595,8 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo translatedInstruction.Code = originalCode; translatedInstruction.Operand = translatedType; MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, translatedType); + + // This doesn't properly handle unboxing Nullable<>, either known or as a generic parameter } break; case CilCode.Ldtoken: diff --git a/Il2CppInterop.Runtime/FieldAccess.cs b/Il2CppInterop.Runtime/FieldAccess.cs index 4542f071..d206152c 100644 --- a/Il2CppInterop.Runtime/FieldAccess.cs +++ b/Il2CppInterop.Runtime/FieldAccess.cs @@ -26,7 +26,7 @@ public static void SetStaticFieldValue(nint fieldInfo, T? value) where T : II } else { - IL2CPP.il2cpp_field_static_set_value(fieldInfo, (void*)value.Box()); + IL2CPP.il2cpp_field_static_set_value(fieldInfo, (void*)NativeBoxing.Box(value)); } } @@ -48,11 +48,11 @@ public static void SetInstanceFieldValue_WriteBarrier(Object instance, int fi var data = (byte*)instance.Pointer + fieldOffset; if (typeof(T).IsValueType) { - value!.WriteToPointer(data); + value.WriteToPointer(data); } else { - IL2CPP.il2cpp_gc_wbarrier_set_field(instance.Pointer, (nint)data, value.Box()); + IL2CPP.il2cpp_gc_wbarrier_set_field(instance.Pointer, (nint)data, (nint)NativeBoxing.Box(value)); } } @@ -62,11 +62,11 @@ public static void SetInstanceFieldValue_Pointer(Object instance, int fieldOf var data = (byte*)instance.Pointer + fieldOffset; if (typeof(T).IsValueType) { - value!.WriteToPointer(data); + value.WriteToPointer(data); } else { - *(nint*)data = value.Box(); + *(nint*)data = (nint)NativeBoxing.Box(value); } } diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index c4b575e8..2c40157d 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -53,6 +53,32 @@ public static Il2CppSystem.Type ManagedTypeToIl2CppType(Type type) return Il2CppSystem.Type.FromClassPointer(classPointer); } + public static object? BoxNullableValueType(in Il2CppSystem.Nullable nullable) where T : struct, IIl2CppType, Il2CppSystem.IValueType + { + return nullable.hasValue + ? nullable.value.Box() + : null; + } + + public static Il2CppSystem.Nullable UnboxNullableValueType(object? obj) where T : struct, IIl2CppType, Il2CppSystem.IValueType + { + return obj switch + { + null => default, + T value => Constructor(true, value), + Il2CppSystem.Nullable nullable => nullable, + _ => throw new InvalidCastException(), + }; + + static Il2CppSystem.Nullable Constructor(bool hasValue, T value) + { + Il2CppSystem.Nullable result = default; + result.hasValue = hasValue; + result.value = value; + return result; + } + } + public static nint Il2CppGCHandleGetTargetOrThrow(nint gchandle) { var obj = IL2CPP.il2cpp_gchandle_get_target(gchandle); diff --git a/Il2CppInterop.Runtime/Il2CppType.cs b/Il2CppInterop.Runtime/Il2CppType.cs index fd3c59e5..1738d2c7 100644 --- a/Il2CppInterop.Runtime/Il2CppType.cs +++ b/Il2CppInterop.Runtime/Il2CppType.cs @@ -111,26 +111,15 @@ public static unsafe void WriteToPointer(this T? value, void* ptr) where T : return T.ReadFromSpan(new ReadOnlySpan(ptr, T.Size)); } - public static T? ReadReference(ReadOnlySpan span) where T : IIl2CppType + public static T? ReadReference(ReadOnlySpan span) where T : class, IIl2CppType { - return (T?)Il2CppObjectPool.Get(ReadPointer(span)); + return T.Unbox(Il2CppObjectPool.Get(ReadPointer(span))); } - public static void WriteReference(T? value, Span span) where T : IIl2CppType + public static void WriteReference(T? value, Span span) where T : class, IIl2CppType { - WritePointer(value.Box(), span); - } - - public static void WriteClass(Object? value, Span span) - { - if (value == null) - { - WritePointer(IntPtr.Zero, span); - } - else - { - WritePointer(value.Pointer, span); - } + var objectPointer = value?.BoxNative() ?? ObjectPointer.Null; + WritePointer((nint)objectPointer, span); } public static nint ReadPointer(ReadOnlySpan span) @@ -157,37 +146,6 @@ public static void WritePointer(nint pointer, Span span) } } - public static unsafe IntPtr Box(this T? value) where T : IIl2CppType - { - if (typeof(T).IsValueType) - { - byte* data = stackalloc byte[T.Size]; - WriteToPointer(value, data); - IntPtr boxedPtr = IL2CPP.il2cpp_value_box(value!.ObjectClass, (IntPtr)data); - return boxedPtr; - } - else if (value is null) - { - return IntPtr.Zero; - } - else if (value is Object @object) - { - return @object.Pointer; - } - else if (value is Il2CppSystem.IValueType valueType) - { - int size = valueType.Size; - byte* data = stackalloc byte[size]; - valueType.WriteToSpan(new Span(data, size)); - IntPtr boxedPtr = IL2CPP.il2cpp_value_box(value.ObjectClass, (IntPtr)data); - return boxedPtr; - } - else - { - throw new InvalidCastException(); - } - } - public static nint GetClassPointer(Type type) { if (type == typeof(void)) diff --git a/Il2CppInterop.Runtime/InteropTypes/ByReference.cs b/Il2CppInterop.Runtime/InteropTypes/ByReference.cs index ff397e34..979d4f7a 100644 --- a/Il2CppInterop.Runtime/InteropTypes/ByReference.cs +++ b/Il2CppInterop.Runtime/InteropTypes/ByReference.cs @@ -98,6 +98,7 @@ private readonly void ThrowIfNull() } } + ObjectPointer IIl2CppType.BoxNative() => throw new NotSupportedException("Boxing is not supported for by reference types."); static void IIl2CppType>.WriteToSpan(ByReference value, Span span) => Il2CppType.WritePointer((IntPtr)value._pointer, span); static ByReference IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => (ByReference)(void*)Il2CppType.ReadPointer(span); } diff --git a/Il2CppInterop.Runtime/InteropTypes/Pointer.cs b/Il2CppInterop.Runtime/InteropTypes/Pointer.cs index bf47a0d5..96a01727 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Pointer.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Pointer.cs @@ -43,6 +43,7 @@ private readonly void ThrowIfNull() static Pointer IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => (Pointer)(void*)Il2CppType.ReadPointer(span); static void IIl2CppType>.WriteToSpan(Pointer value, Span span) => Il2CppType.WritePointer((IntPtr)value._pointer, span); + public ObjectPointer BoxNative() => throw new NotSupportedException("Boxing is not supported for pointer types."); public static explicit operator Pointer(void* value) => new(value); public static explicit operator void*(Pointer pointer) => pointer._pointer; diff --git a/Il2CppInterop.Runtime/NativeBoxing.cs b/Il2CppInterop.Runtime/NativeBoxing.cs new file mode 100644 index 00000000..6431dd34 --- /dev/null +++ b/Il2CppInterop.Runtime/NativeBoxing.cs @@ -0,0 +1,40 @@ +using Il2CppInterop.Common; +using Il2CppSystem; + +namespace Il2CppInterop.Runtime; + +public static class NativeBoxing +{ + internal static ObjectPointer Box(T? value) where T : IIl2CppType + { + return value?.BoxNative() ?? ObjectPointer.Null; + } + + public static ObjectPointer BoxReferenceType(Object? value) + { + return (ObjectPointer?)value?.Pointer ?? ObjectPointer.Null; + } + + public static unsafe ObjectPointer BoxValueType(in T value) where T : struct, IIl2CppType + { + var data = stackalloc byte[T.Size]; + Il2CppType.WriteToPointer(value, data); + return (ObjectPointer)IL2CPP.il2cpp_value_box(value.ObjectClass, (nint)data); + } + + public static ObjectPointer BoxNullableValueType(in Nullable value) where T : struct, IIl2CppType, IValueType + { + return value.hasValue ? BoxValueType(value.value) : ObjectPointer.Null; + } + + public static Nullable UnboxNullableValueType(ObjectPointer pointer) where T : struct, IIl2CppType, IValueType + { + Nullable result = default; + if (pointer != ObjectPointer.Null) + { + result.hasValue = true; + result.value = T.UnboxNative(pointer); + } + return result; + } +} diff --git a/Il2CppInterop.Runtime/RuntimeInvoke.cs b/Il2CppInterop.Runtime/RuntimeInvoke.cs index 85c5211c..769ae416 100644 --- a/Il2CppInterop.Runtime/RuntimeInvoke.cs +++ b/Il2CppInterop.Runtime/RuntimeInvoke.cs @@ -39,12 +39,11 @@ public static void InvokeAction(IntPtr method, IntPtr obj, void** parameters) else if (IsValueType()) { // This is a performance optimization. The other code path would also return the correct result. - var data = (byte*)IL2CPP.il2cpp_object_unbox(result); - return Il2CppType.ReadFromPointer(data); + return TResult.UnboxNative((ObjectPointer)result); } else { - return (TResult?)Il2CppObjectPool.Get(result); + return TResult.Unbox(Il2CppObjectPool.Get(result)); } } @@ -57,7 +56,7 @@ public static IntPtr GetPointerForThis(ByReference @this) } else { - return @this.GetValue().Box(); + return (IntPtr)NativeBoxing.Box(@this.GetValue()); } } diff --git a/Il2Cppmscorlib/Boolean.cs b/Il2Cppmscorlib/Boolean.cs index 416a9859..8866c95c 100644 --- a/Il2Cppmscorlib/Boolean.cs +++ b/Il2Cppmscorlib/Boolean.cs @@ -8,6 +8,7 @@ public struct Boolean : IIl2CppType readonly nint IIl2CppType.ObjectClass => throw null; static Boolean IIl2CppType.ReadFromSpan(System.ReadOnlySpan span) => throw null; static void IIl2CppType.WriteToSpan(Boolean value, System.Span span) => throw null; + ObjectPointer IIl2CppType.BoxNative() => throw new System.NotImplementedException(); public static implicit operator bool(Boolean value) => throw null; public static implicit operator Boolean(bool value) => throw null; diff --git a/Il2Cppmscorlib/IValueType.cs b/Il2Cppmscorlib/IValueType.cs index fb63b240..f73f321a 100644 --- a/Il2Cppmscorlib/IValueType.cs +++ b/Il2Cppmscorlib/IValueType.cs @@ -2,6 +2,4 @@ public interface IValueType : IObject { - int Size { get; } - void WriteToSpan(System.Span span); } diff --git a/Il2Cppmscorlib/Int32.cs b/Il2Cppmscorlib/Int32.cs index 8455cb53..b442c941 100644 --- a/Il2Cppmscorlib/Int32.cs +++ b/Il2Cppmscorlib/Int32.cs @@ -8,6 +8,7 @@ public struct Int32 : IIl2CppType readonly nint IIl2CppType.ObjectClass => throw null; static Int32 IIl2CppType.ReadFromSpan(System.ReadOnlySpan span) => throw null; static void IIl2CppType.WriteToSpan(Int32 value, System.Span span) => throw null; + ObjectPointer IIl2CppType.BoxNative() => throw new System.NotImplementedException(); public static implicit operator int(Int32 value) => throw null; public static implicit operator Int32(int value) => throw null; diff --git a/Il2Cppmscorlib/IntPtr.cs b/Il2Cppmscorlib/IntPtr.cs index 928786ad..9d72d890 100644 --- a/Il2Cppmscorlib/IntPtr.cs +++ b/Il2Cppmscorlib/IntPtr.cs @@ -8,6 +8,7 @@ public struct IntPtr : IIl2CppType readonly nint IIl2CppType.ObjectClass => throw null; static IntPtr IIl2CppType.ReadFromSpan(System.ReadOnlySpan span) => throw null; static void IIl2CppType.WriteToSpan(IntPtr value, System.Span span) => throw null; + ObjectPointer IIl2CppType.BoxNative() => throw new System.NotImplementedException(); public static implicit operator nint(IntPtr value) => throw null; public static implicit operator IntPtr(nint value) => throw null; diff --git a/Il2Cppmscorlib/Nullable.cs b/Il2Cppmscorlib/Nullable.cs new file mode 100644 index 00000000..cb359bc4 --- /dev/null +++ b/Il2Cppmscorlib/Nullable.cs @@ -0,0 +1,17 @@ +using Il2CppInterop.Common; + +namespace Il2CppSystem; + +public struct Nullable : IObject, IValueType, IIl2CppType, IIl2CppType> + where T : struct, IValueType, IIl2CppType, IObject +{ + public Boolean hasValue; + + public T value; + + static int IIl2CppType>.Size => throw new System.NotImplementedException(); + nint IIl2CppType.ObjectClass => throw new System.NotImplementedException(); + static Nullable IIl2CppType>.ReadFromSpan(System.ReadOnlySpan span) => throw new System.NotImplementedException(); + static void IIl2CppType>.WriteToSpan(Nullable value, System.Span span) => throw new System.NotImplementedException(); + ObjectPointer IIl2CppType.BoxNative() => throw new System.NotImplementedException(); +} diff --git a/Il2Cppmscorlib/Object.cs b/Il2Cppmscorlib/Object.cs index d3885905..b9efe3a7 100644 --- a/Il2Cppmscorlib/Object.cs +++ b/Il2Cppmscorlib/Object.cs @@ -29,4 +29,5 @@ public virtual void Il2CppFinalize() } public virtual String ToIl2CppString() => default; + ObjectPointer IIl2CppType.BoxNative() => throw new System.NotImplementedException(); } diff --git a/Il2Cppmscorlib/Void.cs b/Il2Cppmscorlib/Void.cs index bd1e5213..0c4148a5 100644 --- a/Il2Cppmscorlib/Void.cs +++ b/Il2Cppmscorlib/Void.cs @@ -8,4 +8,5 @@ public struct Void : IIl2CppType readonly nint IIl2CppType.ObjectClass => throw null; static Void IIl2CppType.ReadFromSpan(System.ReadOnlySpan span) => throw null; static void IIl2CppType.WriteToSpan(Void value, System.Span span) => throw null; + ObjectPointer IIl2CppType.BoxNative() => throw new System.NotImplementedException(); } From 45daa0f04acabb03adc994c7aef3c7251fbb4df3 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 6 May 2026 11:41:53 -0700 Subject: [PATCH 381/486] Fix issues unstripping box and unbox.any for Nullable<> --- .../TranslatedMethodBody.cs | 27 ++++++++++++++----- Il2CppInterop.Runtime/GenerationInternals.cs | 12 +++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/Il2CppInterop.Generator/TranslatedMethodBody.cs b/Il2CppInterop.Generator/TranslatedMethodBody.cs index f674d212..1281b274 100644 --- a/Il2CppInterop.Generator/TranslatedMethodBody.cs +++ b/Il2CppInterop.Generator/TranslatedMethodBody.cs @@ -566,17 +566,22 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo } break; case CilCode.Box: - // This doesn't properly handle unboxing Nullable<>, either known or as a generic parameter if (MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, translatedType)) { + // Conversion happens before boxing translatedInstruction.Code = CilOpCodes.Nop; - translatedInstructions.Add(new Instruction(originalCode, translatedType)); + // Since this is an Il2Cpp primitive type, we can use the normal box instruction with the translated type. + translatedInstructions.Add(originalCode, translatedType); } else { - translatedInstruction.Code = originalCode; - translatedInstruction.Operand = translatedType; + // This ensures that we properly box Nullable<> + translatedInstruction.Code = CilOpCodes.Call; + translatedInstruction.Operand = appContext + .ResolveTypeOrThrow(typeof(GenerationInternals)) + .GetMethodByName(nameof(GenerationInternals.Box)) + .MakeGenericInstanceMethod(translatedType); } break; case CilCode.Unbox: @@ -591,12 +596,20 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo return false; } case CilCode.Unbox_Any: + if (MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, translatedType)) { + // Since this is an Il2Cpp primitive type, we can use the normal unbox.any instruction with the translated type. translatedInstruction.Code = originalCode; translatedInstruction.Operand = translatedType; - MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, translatedType); - - // This doesn't properly handle unboxing Nullable<>, either known or as a generic parameter + } + else + { + // This ensures that we properly unbox Nullable<> + translatedInstruction.Code = CilOpCodes.Call; + translatedInstruction.Operand = appContext + .ResolveTypeOrThrow(typeof(GenerationInternals)) + .GetMethodByName(nameof(GenerationInternals.Unbox)) + .MakeGenericInstanceMethod(translatedType); } break; case CilCode.Ldtoken: diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index 2c40157d..9b982699 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -53,6 +53,18 @@ public static Il2CppSystem.Type ManagedTypeToIl2CppType(Type type) return Il2CppSystem.Type.FromClassPointer(classPointer); } + // For unstripping the box instruction + public static object? Box(T? value) where T : IIl2CppType + { + return value?.Box() ?? null; + } + + // For unstripping the unbox.any instruction + public static T? Unbox(object? obj) where T : IIl2CppType + { + return T.Unbox(obj); + } + public static object? BoxNullableValueType(in Il2CppSystem.Nullable nullable) where T : struct, IIl2CppType, Il2CppSystem.IValueType { return nullable.hasValue From 7d9a987ecc25eba86dae53c02d47d78e46ebe88b Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 6 May 2026 15:41:56 -0700 Subject: [PATCH 382/486] Update source generation to account for changes in the IIl2CppType interfaces --- .../InjectedClassTests.cs | 8 ++- .../Il2CppTypeGenerator.cs | 65 +++++++++---------- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs b/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs index 23d93037..b4ea9321 100644 --- a/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs +++ b/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs @@ -21,14 +21,16 @@ public partial class Sample : Il2CppSystem.Object [global::Il2CppInterop.Common.Attributes.Il2CppType(typeof(Il2CppInternals))] public partial class Sample : global::Il2CppInterop.Common.IIl2CppType { - public Sample(global::Il2CppInterop.Common.ObjectPointer obj0) : base(obj0) + public Sample(global::Il2CppInterop.Common.ObjectPointer pointer) : base(pointer) { } - static int global::Il2CppInterop.Common.IIl2CppType.Size => nint.Size; - nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer(); + + static Sample global::Il2CppInterop.Common.IIl2CppType.UnboxNative(global::Il2CppInterop.Common.ObjectPointer pointer) => new Sample(pointer); + static int global::Il2CppInterop.Common.IIl2CppType.Size => nint.Size; + static Sample? global::Il2CppInterop.Common.IIl2CppType.ReadFromSpan(global::System.ReadOnlySpan span) { return global::Il2CppInterop.Runtime.Il2CppType.ReadReference(span); diff --git a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs index 63f1783c..1f85927a 100644 --- a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs +++ b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs @@ -105,8 +105,6 @@ private static void EmitPartialType(IndentedTextWriter writer, TypeModel model) { EmitValueTypeBridgeMethods(writer); writer.WriteLineNoTabs(); - EmitValueTypeInstanceInterfaceMembers(writer, model); - writer.WriteLineNoTabs(); } foreach (var member in model.Members) { @@ -133,7 +131,7 @@ private static void EmitPartialType(IndentedTextWriter writer, TypeModel model) writer.WriteLineNoTabs(); } - EmitStaticInterfaceMembers(writer, model); + EmitInterfaceMembers(writer, model); writer.Indent--; writer.WriteLine("}"); @@ -170,23 +168,6 @@ private static void EmitValueTypeBridgeMethods(IndentedTextWriter writer) writer.WriteLine("}"); } - private static void EmitValueTypeInstanceInterfaceMembers(IndentedTextWriter writer, TypeModel model) - { - writer.WriteLine("readonly nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass =>"); - writer.Indent++; - writer.WriteLine($"global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer;"); - writer.Indent--; - writer.WriteLineNoTabs(); - - writer.WriteLine("readonly int global::Il2CppSystem.IValueType.Size => Il2CppInternals.Size;"); - writer.WriteLineNoTabs(); - - writer.WriteLine("readonly void global::Il2CppSystem.IValueType.WriteToSpan(global::System.Span span) =>"); - writer.Indent++; - writer.WriteLine("global::Il2CppInterop.Runtime.Il2CppType.WriteToSpan(this, span);"); - writer.Indent--; - } - #endregion #region Class/interface-only emit @@ -255,7 +236,7 @@ private static void EmitManagedProperty(IndentedTextWriter writer, MemberModel m private static void EmitConstructor(IndentedTextWriter writer, TypeModel model) { - writer.WriteLine($"public {model.TypeName}(global::Il2CppInterop.Common.ObjectPointer obj0) : base(obj0)"); + writer.WriteLine($"public {model.TypeName}(global::Il2CppInterop.Common.ObjectPointer pointer) : base(pointer)"); writer.WriteLine("{"); writer.WriteLine("}"); } @@ -312,20 +293,32 @@ private static void EmitLogErrorFinalizer(IndentedTextWriter writer) #region Shared emit - private static void EmitStaticInterfaceMembers(IndentedTextWriter writer, TypeModel model) + private static void EmitInterfaceMembers(IndentedTextWriter writer, TypeModel model) { - var tn = model.TypeName; + var typeName = model.TypeName; + + // ObjectClass + writer.WriteLine($"nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer<{typeName}>();"); + writer.WriteLineNoTabs(); + if (model.TypeKind == TypeKind.Struct) { - writer.WriteLine($"static int global::Il2CppInterop.Common.IIl2CppType<{tn}>.Size => Il2CppInternals.Size;"); + // BoxNative + writer.WriteLine("readonly global::Il2CppInterop.Common.ObjectPointer global::Il2CppInterop.Common.IIl2CppType.BoxNative() =>"); + writer.Indent++; + writer.WriteLine($"global::Il2CppInterop.Runtime.NativeBoxing.BoxValueType<{typeName}>(in this);"); + writer.Indent--; + + // Size + writer.WriteLine($"static int global::Il2CppInterop.Common.IIl2CppType<{typeName}>.Size => Il2CppInternals.Size;"); writer.WriteLineNoTabs(); // ReadFromSpan — constructs via object initializer, one field per offset - writer.WriteLine($"static {tn} global::Il2CppInterop.Common.IIl2CppType<{tn}>.ReadFromSpan(global::System.ReadOnlySpan span)"); + writer.WriteLine($"static {typeName} global::Il2CppInterop.Common.IIl2CppType<{typeName}>.ReadFromSpan(global::System.ReadOnlySpan span)"); writer.WriteLine("{"); writer.Indent++; writer.WriteLine("#nullable disable"); - writer.WriteLine($"return new {tn}"); + writer.WriteLine($"return new {typeName}"); writer.WriteLine("{"); writer.Indent++; foreach (var member in model.Members.Where(x => !x.IsStatic)) @@ -338,7 +331,7 @@ private static void EmitStaticInterfaceMembers(IndentedTextWriter writer, TypeMo writer.WriteLineNoTabs(); // WriteToSpan — one WriteToSpanAtOffset call per field - writer.WriteLine($"static void global::Il2CppInterop.Common.IIl2CppType<{tn}>.WriteToSpan({tn} value, global::System.Span span)"); + writer.WriteLine($"static void global::Il2CppInterop.Common.IIl2CppType<{typeName}>.WriteToSpan({typeName} value, global::System.Span span)"); writer.WriteLine("{"); writer.Indent++; foreach (var member in model.Members.Where(x => !x.IsStatic)) @@ -349,21 +342,25 @@ private static void EmitStaticInterfaceMembers(IndentedTextWriter writer, TypeMo } else { - writer.WriteLine($"static int global::Il2CppInterop.Common.IIl2CppType<{tn}>.Size => nint.Size;"); + // UnboxNative + writer.WriteLine($"static {typeName} global::Il2CppInterop.Common.IIl2CppType<{typeName}>.UnboxNative(global::Il2CppInterop.Common.ObjectPointer pointer) => new {typeName}(pointer);"); writer.WriteLineNoTabs(); - writer.WriteLine($"nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer<{tn}>();"); + // Size + writer.WriteLine($"static int global::Il2CppInterop.Common.IIl2CppType<{typeName}>.Size => nint.Size;"); writer.WriteLineNoTabs(); - writer.WriteLine($"static {tn}? global::Il2CppInterop.Common.IIl2CppType<{tn}>.ReadFromSpan(global::System.ReadOnlySpan span)"); + // ReadFromSpan + writer.WriteLine($"static {typeName}? global::Il2CppInterop.Common.IIl2CppType<{typeName}>.ReadFromSpan(global::System.ReadOnlySpan span)"); writer.WriteLine("{"); writer.Indent++; - writer.WriteLine($"return global::Il2CppInterop.Runtime.Il2CppType.ReadReference<{tn}>(span);"); + writer.WriteLine($"return global::Il2CppInterop.Runtime.Il2CppType.ReadReference<{typeName}>(span);"); writer.Indent--; writer.WriteLine("}"); writer.WriteLineNoTabs(); - writer.WriteLine($"static void global::Il2CppInterop.Common.IIl2CppType<{tn}>.WriteToSpan({tn}? value, global::System.Span span)"); + // WriteToSpan + writer.WriteLine($"static void global::Il2CppInterop.Common.IIl2CppType<{typeName}>.WriteToSpan({typeName}? value, global::System.Span span)"); writer.WriteLine("{"); writer.Indent++; writer.WriteLine("global::Il2CppInterop.Runtime.Il2CppType.WriteReference(value, span);"); @@ -374,11 +371,11 @@ private static void EmitStaticInterfaceMembers(IndentedTextWriter writer, TypeMo if (!string.IsNullOrEmpty(model.AssemblyName)) { - writer.WriteLine($"static string global::Il2CppInterop.Common.IIl2CppType<{tn}>.AssemblyName => \"{model.AssemblyName}\";"); + writer.WriteLine($"static string global::Il2CppInterop.Common.IIl2CppType<{typeName}>.AssemblyName => \"{model.AssemblyName}\";"); writer.WriteLineNoTabs(); } - writer.WriteLine($"static {tn}()"); + writer.WriteLine($"static {typeName}()"); writer.WriteLine("{"); writer.Indent++; writer.WriteLine("global::System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(Il2CppInternals).TypeHandle);"); From 375d9f9de3bee4469d30ac21a2379adb586993e5 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 6 May 2026 17:17:47 -0700 Subject: [PATCH 383/486] Fix trampolines in TypeInjector for value types --- .../Injection/TypeInjector.cs | 67 ++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 7aa613c5..31c4d576 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -1273,11 +1273,35 @@ private static Delegate CreateTrampoline(MethodInfo monoMethod, bool callVirt) body.BeginExceptionBlock(); + // Value types boxed as interfaces can be modified during the execution of the method. + List<(LocalBuilder Local, int ArgumentIndex)> interfaceArguments = []; + + LocalBuilder? thisVariable = null; if (!monoMethod.IsStatic) { body.Emit(OpCodes.Ldarg_0); - body.Emit(OpCodes.Call, typeof(Il2CppObjectPool).GetMethod(nameof(Il2CppObjectPool.Get))!); - body.Emit(OpCodes.Castclass, monoMethod.DeclaringType); + if (monoMethod.DeclaringType.IsValueType) + { + // Need to store the value in a local variable so that we can pass a reference to the managed method + thisVariable = body.DeclareLocal(monoMethod.DeclaringType); + body.Emit(OpCodes.Conv_U); + body.Emit(OpCodes.Call, typeof(Il2CppType).GetMethod(nameof(Il2CppType.ReadFromPointer), BindingFlags.Public | BindingFlags.Static)!.MakeGenericMethod(monoMethod.DeclaringType)); + body.Emit(OpCodes.Stloc, thisVariable); + body.Emit(OpCodes.Ldloca, thisVariable); + } + else + { + body.Emit(OpCodes.Call, typeof(Il2CppObjectPool).GetMethod(nameof(Il2CppObjectPool.Get))!); + body.Emit(OpCodes.Castclass, monoMethod.DeclaringType); + + if (monoMethod.DeclaringType.IsInterface) + { + var local = body.DeclareLocal(monoMethod.DeclaringType); + body.Emit(OpCodes.Stloc, local); + body.Emit(OpCodes.Ldloc, local); + interfaceArguments.Add((local, 0)); + } + } } var argOffset = method.IsStatic ? 0 : 1; @@ -1286,6 +1310,13 @@ private static Delegate CreateTrampoline(MethodInfo monoMethod, bool callVirt) { body.Emit(OpCodes.Ldarg, i); body.Emit(OpCodes.Call, typeof(TypeInjector).GetMethod(nameof(ConvertNativeToManaged), BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(nativeParameterTypes[i], managedParameters[i])); + if (managedParameters[i].IsInterface) + { + var local = body.DeclareLocal(managedParameters[i]); + body.Emit(OpCodes.Stloc, local); + body.Emit(OpCodes.Ldloc, local); + interfaceArguments.Add((local, i)); + } } body.Emit(callVirt ? OpCodes.Callvirt : OpCodes.Call, monoMethod); @@ -1297,6 +1328,24 @@ private static Delegate CreateTrampoline(MethodInfo monoMethod, bool callVirt) body.Emit(OpCodes.Stloc, nativeReturnVariable); } + if (thisVariable != null) + { + // Copy any changes to the value type back to the pointer passed by il2cpp + Debug.Assert(monoMethod.DeclaringType.IsValueType); + body.Emit(OpCodes.Ldloc, thisVariable); + body.Emit(OpCodes.Ldarg_0); + body.Emit(OpCodes.Conv_U); + body.Emit(OpCodes.Call, typeof(Il2CppType).GetMethod(nameof(Il2CppType.WriteToPointer), BindingFlags.Public | BindingFlags.Static)!.MakeGenericMethod(monoMethod.DeclaringType)); + } + + // Update boxed value types passed as interfaces + foreach ((var local, var argumentIndex) in interfaceArguments) + { + body.Emit(OpCodes.Ldarg, argumentIndex); + body.Emit(OpCodes.Ldloc, local); + body.Emit(OpCodes.Call, typeof(TypeInjector).GetMethod(nameof(UpdateBoxedValue), BindingFlags.Static | BindingFlags.NonPublic)!); + } + body.BeginCatchBlock(typeof(Exception)); body.Emit(OpCodes.Call, typeof(TypeInjector).GetMethod(nameof(LogError), BindingFlags.Static | BindingFlags.NonPublic)!); @@ -1319,6 +1368,20 @@ private static void LogError(Exception exception) Logger.Instance.LogError("Exception in IL2CPP-to-Managed trampoline, not passing it to il2cpp: {Exception}", exception); } + private static void UpdateBoxedValue(IntPtr objectPointer, IIl2CppType? @object) + { + if (objectPointer == IntPtr.Zero || @object == null) + return; + + if (!@object.GetType().IsValueType) + return; + + var size = IL2CPP.il2cpp_class_value_size(@object.ObjectClass, out _); + var sourceSpan = new ReadOnlySpan((void*)IL2CPP.il2cpp_object_unbox((nint)@object.BoxNative()), size); + var destinationSpan = new Span((void*)IL2CPP.il2cpp_object_unbox(objectPointer), size); + sourceSpan.CopyTo(destinationSpan); + } + private static TManaged? ConvertNativeToManaged(TNative value) where TNative : unmanaged where TManaged : IIl2CppType From b2576c528aa6521fc549116a47e4cda1ad29afa3 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 6 May 2026 19:06:44 -0700 Subject: [PATCH 384/486] Move Il2CppObjectPool and Il2CppType to Common project --- .../Il2CppObjectPool.cs | 6 ++---- .../Il2CppType.cs | 6 ++---- .../ByRefParameterOverloadProcessingLayer.cs | 2 +- .../InitializationClassProcessingLayer.cs | 5 +++-- .../MarshallingProcessingLayer.cs | 1 - .../MethodInvokerProcessingLayer.cs | 2 +- .../ObjectInterfaceProcessingLayer.cs | 2 +- ...ferenceAssemblyInjectionProcessingLayer.cs | 4 ++-- .../TranslatedMethodBody.cs | 1 + .../InjectedClassTests.cs | 8 ++++---- .../Il2CppTypeGenerator.cs | 20 +++++++++---------- 11 files changed, 27 insertions(+), 30 deletions(-) rename {Il2CppInterop.Runtime => Il2CppInterop.Common}/Il2CppObjectPool.cs (94%) rename {Il2CppInterop.Runtime => Il2CppInterop.Common}/Il2CppType.cs (97%) diff --git a/Il2CppInterop.Runtime/Il2CppObjectPool.cs b/Il2CppInterop.Common/Il2CppObjectPool.cs similarity index 94% rename from Il2CppInterop.Runtime/Il2CppObjectPool.cs rename to Il2CppInterop.Common/Il2CppObjectPool.cs index 193d87ef..efc2361e 100644 --- a/Il2CppInterop.Runtime/Il2CppObjectPool.cs +++ b/Il2CppInterop.Common/Il2CppObjectPool.cs @@ -1,8 +1,6 @@ -using System; -using System.Collections.Concurrent; -using Il2CppInterop.Common; +using System.Collections.Concurrent; -namespace Il2CppInterop.Runtime; +namespace Il2CppInterop.Common; public static class Il2CppObjectPool { diff --git a/Il2CppInterop.Runtime/Il2CppType.cs b/Il2CppInterop.Common/Il2CppType.cs similarity index 97% rename from Il2CppInterop.Runtime/Il2CppType.cs rename to Il2CppInterop.Common/Il2CppType.cs index 1738d2c7..38c48f50 100644 --- a/Il2CppInterop.Runtime/Il2CppType.cs +++ b/Il2CppInterop.Common/Il2CppType.cs @@ -1,10 +1,8 @@ -using System; using System.Buffers.Binary; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using Il2CppInterop.Common; -namespace Il2CppInterop.Runtime; +namespace Il2CppInterop.Common; public static class Il2CppType { @@ -163,7 +161,7 @@ public static nint GetClassPointer() where T : IIl2CppType return Il2CppClassPointerStore.NativeClassPointer; } - internal static void SetClassPointer(Type type, nint classPointer) + public static void SetClassPointer(Type type, nint classPointer) { typeof(Il2CppType) .GetMethod(nameof(SetClassPointer), 1, [typeof(nint)])! diff --git a/Il2CppInterop.Generator/ByRefParameterOverloadProcessingLayer.cs b/Il2CppInterop.Generator/ByRefParameterOverloadProcessingLayer.cs index 9d0b38b5..39737541 100644 --- a/Il2CppInterop.Generator/ByRefParameterOverloadProcessingLayer.cs +++ b/Il2CppInterop.Generator/ByRefParameterOverloadProcessingLayer.cs @@ -2,9 +2,9 @@ using System.Reflection; using Cpp2IL.Core.Api; using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Common; using Il2CppInterop.Generator.Operands; using Il2CppInterop.Generator.Visitors; -using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; namespace Il2CppInterop.Generator; diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index 20673dc4..dd34af44 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -5,16 +5,17 @@ using System.Runtime.InteropServices; using System.Security.Cryptography; using Cpp2IL.Core.Api; -using Cpp2IL.Core.Logging; using Cpp2IL.Core.Model.Contexts; using Cpp2IL.Core.Model.CustomAttributes; using Cpp2IL.Core.Utils; +using Il2CppInterop.Common; using Il2CppInterop.Common.Attributes; using Il2CppInterop.Generator.Operands; using Il2CppInterop.Generator.Visitors; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; +using Microsoft.Extensions.Logging; namespace Il2CppInterop.Generator; @@ -504,7 +505,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action), typeof(Il2CppException), - typeof(Il2CppObjectPool), typeof(TypeInjector), typeof(DelegateSupport), typeof(Pointer<>), @@ -52,7 +53,6 @@ public override void Process(ApplicationAnalysisContext appContext, Action global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer(); + nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Common.Il2CppType.GetClassPointer(); static Sample global::Il2CppInterop.Common.IIl2CppType.UnboxNative(global::Il2CppInterop.Common.ObjectPointer pointer) => new Sample(pointer); @@ -33,12 +33,12 @@ public Sample(global::Il2CppInterop.Common.ObjectPointer pointer) : base(pointer static Sample? global::Il2CppInterop.Common.IIl2CppType.ReadFromSpan(global::System.ReadOnlySpan span) { - return global::Il2CppInterop.Runtime.Il2CppType.ReadReference(span); + return global::Il2CppInterop.Common.Il2CppType.ReadReference(span); } static void global::Il2CppInterop.Common.IIl2CppType.WriteToSpan(Sample? value, global::System.Span span) { - global::Il2CppInterop.Runtime.Il2CppType.WriteReference(value, span); + global::Il2CppInterop.Common.Il2CppType.WriteReference(value, span); } static Sample() @@ -53,7 +53,7 @@ file static class Il2CppInternals static Il2CppInternals() { global::Il2CppInterop.Runtime.Injection.TypeInjector.RegisterTypeInIl2Cpp(); - global::Il2CppInterop.Runtime.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer(), ptr => new Sample(ptr)); + global::Il2CppInterop.Common.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Common.Il2CppType.GetClassPointer(), ptr => new Sample(ptr)); } } diff --git a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs index 1f85927a..d44cf8cd 100644 --- a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs +++ b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs @@ -298,7 +298,7 @@ private static void EmitInterfaceMembers(IndentedTextWriter writer, TypeModel mo var typeName = model.TypeName; // ObjectClass - writer.WriteLine($"nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer<{typeName}>();"); + writer.WriteLine($"nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Common.Il2CppType.GetClassPointer<{typeName}>();"); writer.WriteLineNoTabs(); if (model.TypeKind == TypeKind.Struct) @@ -322,7 +322,7 @@ private static void EmitInterfaceMembers(IndentedTextWriter writer, TypeModel mo writer.WriteLine("{"); writer.Indent++; foreach (var member in model.Members.Where(x => !x.IsStatic)) - writer.WriteLine($"{member.Name} = global::Il2CppInterop.Runtime.Il2CppType.ReadFromSpanAtOffset<{member.Type}>(span, Il2CppInternals.FieldOffset_{member.Index}),"); + writer.WriteLine($"{member.Name} = global::Il2CppInterop.Common.Il2CppType.ReadFromSpanAtOffset<{member.Type}>(span, Il2CppInternals.FieldOffset_{member.Index}),"); writer.Indent--; writer.WriteLine("};"); writer.WriteLine("#nullable restore"); @@ -335,7 +335,7 @@ private static void EmitInterfaceMembers(IndentedTextWriter writer, TypeModel mo writer.WriteLine("{"); writer.Indent++; foreach (var member in model.Members.Where(x => !x.IsStatic)) - writer.WriteLine($"global::Il2CppInterop.Runtime.Il2CppType.WriteToSpanAtOffset(value.{member.Name}, span, Il2CppInternals.FieldOffset_{member.Index});"); + writer.WriteLine($"global::Il2CppInterop.Common.Il2CppType.WriteToSpanAtOffset(value.{member.Name}, span, Il2CppInternals.FieldOffset_{member.Index});"); writer.Indent--; writer.WriteLine("}"); writer.WriteLineNoTabs(); @@ -354,7 +354,7 @@ private static void EmitInterfaceMembers(IndentedTextWriter writer, TypeModel mo writer.WriteLine($"static {typeName}? global::Il2CppInterop.Common.IIl2CppType<{typeName}>.ReadFromSpan(global::System.ReadOnlySpan span)"); writer.WriteLine("{"); writer.Indent++; - writer.WriteLine($"return global::Il2CppInterop.Runtime.Il2CppType.ReadReference<{typeName}>(span);"); + writer.WriteLine($"return global::Il2CppInterop.Common.Il2CppType.ReadReference<{typeName}>(span);"); writer.Indent--; writer.WriteLine("}"); writer.WriteLineNoTabs(); @@ -363,7 +363,7 @@ private static void EmitInterfaceMembers(IndentedTextWriter writer, TypeModel mo writer.WriteLine($"static void global::Il2CppInterop.Common.IIl2CppType<{typeName}>.WriteToSpan({typeName}? value, global::System.Span span)"); writer.WriteLine("{"); writer.Indent++; - writer.WriteLine("global::Il2CppInterop.Runtime.Il2CppType.WriteReference(value, span);"); + writer.WriteLine("global::Il2CppInterop.Common.Il2CppType.WriteReference(value, span);"); writer.Indent--; writer.WriteLine("}"); writer.WriteLineNoTabs(); @@ -412,19 +412,19 @@ private static void EmitInternalsClass(IndentedTextWriter writer, TypeModel mode foreach (var member in model.Members) { if (member.IsStatic) - writer.WriteLine($"FieldInfoPtr_{member.Index} = global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer<{model.TypeName}>(), \"{member.Name}\");"); + writer.WriteLine($"FieldInfoPtr_{member.Index} = global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Common.Il2CppType.GetClassPointer<{model.TypeName}>(), \"{member.Name}\");"); else - writer.WriteLine($"FieldOffset_{member.Index} = global::Il2CppInterop.Runtime.FieldAccess.GetFieldOffset(global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer<{model.TypeName}>(), \"{member.Name}\"));"); + writer.WriteLine($"FieldOffset_{member.Index} = global::Il2CppInterop.Runtime.FieldAccess.GetFieldOffset(global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Common.Il2CppType.GetClassPointer<{model.TypeName}>(), \"{member.Name}\"));"); } if (isValueType) { - writer.WriteLine($"Size = global::Il2CppInterop.Common.IL2CPP.il2cpp_class_value_size(global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer<{model.TypeName}>(), out _);"); - writer.WriteLine($"global::Il2CppInterop.Runtime.Il2CppObjectPool.RegisterValueTypeInitializer<{model.TypeName}>();"); + writer.WriteLine($"Size = global::Il2CppInterop.Common.IL2CPP.il2cpp_class_value_size(global::Il2CppInterop.Common.Il2CppType.GetClassPointer<{model.TypeName}>(), out _);"); + writer.WriteLine($"global::Il2CppInterop.Common.Il2CppObjectPool.RegisterValueTypeInitializer<{model.TypeName}>();"); } else if (!model.IsAbstract) { - writer.WriteLine($"global::Il2CppInterop.Runtime.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Runtime.Il2CppType.GetClassPointer<{model.TypeName}>(), ptr => new {model.TypeName}(ptr));"); + writer.WriteLine($"global::Il2CppInterop.Common.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Common.Il2CppType.GetClassPointer<{model.TypeName}>(), ptr => new {model.TypeName}(ptr));"); } writer.Indent--; From c9765c9c9aa215a03aa6a8afea1f16fa0421f163 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 6 May 2026 19:11:15 -0700 Subject: [PATCH 385/486] ObjectPointer.New<>() --- Il2CppInterop.Common/Il2CppType.cs | 6 ------ Il2CppInterop.Common/ObjectPointer.cs | 5 +++++ Il2CppInterop.Generator/MethodInvokerProcessingLayer.cs | 3 ++- .../InteropTypes/Il2CppToMonoDelegateReference.cs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Il2CppInterop.Common/Il2CppType.cs b/Il2CppInterop.Common/Il2CppType.cs index 38c48f50..90483771 100644 --- a/Il2CppInterop.Common/Il2CppType.cs +++ b/Il2CppInterop.Common/Il2CppType.cs @@ -189,10 +189,4 @@ private static class Il2CppClassPointerStore where T : IIl2CppType { public static nint NativeClassPointer; } - - // Temporary location for this method - public static ObjectPointer NewObjectPointer() where T : IIl2CppType - { - return (ObjectPointer)IL2CPP.il2cpp_object_new(GetClassPointer()); - } } diff --git a/Il2CppInterop.Common/ObjectPointer.cs b/Il2CppInterop.Common/ObjectPointer.cs index 03544bbf..35b40150 100644 --- a/Il2CppInterop.Common/ObjectPointer.cs +++ b/Il2CppInterop.Common/ObjectPointer.cs @@ -9,4 +9,9 @@ public readonly record struct ObjectPointer(IntPtr Value) public static unsafe explicit operator void*(ObjectPointer value) => (void*)value.Value; public static ObjectPointer Null => new(IntPtr.Zero); + + public static ObjectPointer New() where T : IIl2CppType + { + return (ObjectPointer)IL2CPP.il2cpp_object_new(Il2CppType.GetClassPointer()); + } } diff --git a/Il2CppInterop.Generator/MethodInvokerProcessingLayer.cs b/Il2CppInterop.Generator/MethodInvokerProcessingLayer.cs index 300d5689..08baf6fd 100644 --- a/Il2CppInterop.Generator/MethodInvokerProcessingLayer.cs +++ b/Il2CppInterop.Generator/MethodInvokerProcessingLayer.cs @@ -27,7 +27,8 @@ public override void Process(ApplicationAnalysisContext appContext, Action()) + public Il2CppToMonoDelegateReference(Delegate referencedDelegate, IntPtr methodInfo) : this(ObjectPointer.New()) { ReferencedDelegate = referencedDelegate; MethodInfo = methodInfo; From 298829b7074ac88a68028f0a2fe04b293e209ff8 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 6 May 2026 19:26:04 -0700 Subject: [PATCH 386/486] Automatic intializer registration --- Il2CppInterop.Common/Il2CppObjectPool.cs | 11 ++-- Il2CppInterop.Common/Il2CppType.cs | 1 + .../InitializationClassProcessingLayer.cs | 54 ------------------- .../InteropTypes/Arrays/Il2CppArrayRank1.cs | 1 - .../InteropTypes/Arrays/Il2CppArrayRank2.cs | 1 - .../InteropTypes/Arrays/Il2CppArrayRank3.cs | 1 - .../InjectedClassTests.cs | 1 - .../Il2CppTypeGenerator.cs | 15 ++---- 8 files changed, 11 insertions(+), 74 deletions(-) diff --git a/Il2CppInterop.Common/Il2CppObjectPool.cs b/Il2CppInterop.Common/Il2CppObjectPool.cs index efc2361e..cec25490 100644 --- a/Il2CppInterop.Common/Il2CppObjectPool.cs +++ b/Il2CppInterop.Common/Il2CppObjectPool.cs @@ -39,7 +39,7 @@ public static void Remove(nint ptr) return newObj; } - public static void RegisterInitializer(nint classPtr, Func initializer) + private static void RegisterInitializer(nint classPtr, Func initializer) { ArgumentOutOfRangeException.ThrowIfZero(classPtr); if (!s_initializers.TryAdd(classPtr, initializer)) @@ -49,14 +49,13 @@ public static void RegisterInitializer(nint classPtr, Func() where T : struct, IIl2CppType + internal static void RegisterInitializer() where T : IIl2CppType { - RegisterInitializer(Il2CppType.GetClassPointer(), ValueTypeInitializer); + RegisterInitializer(Il2CppType.GetClassPointer(), TypeInitializer); } - public static unsafe object ValueTypeInitializer(ObjectPointer obj) where T : struct, IIl2CppType + private static object TypeInitializer(ObjectPointer obj) where T : IIl2CppType { - var unboxed = IL2CPP.il2cpp_object_unbox((nint)obj); - return Il2CppType.ReadFromPointer((void*)unboxed); + return T.UnboxNative(obj)!; } } diff --git a/Il2CppInterop.Common/Il2CppType.cs b/Il2CppInterop.Common/Il2CppType.cs index 90483771..95259f2f 100644 --- a/Il2CppInterop.Common/Il2CppType.cs +++ b/Il2CppInterop.Common/Il2CppType.cs @@ -177,6 +177,7 @@ public static void SetClassPointer(nint classPointer) where T : IIl2CppType.NativeClassPointer == nint.Zero) { Il2CppClassPointerStore.NativeClassPointer = classPointer; + Il2CppObjectPool.RegisterInitializer(); } else { diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index dd34af44..2b112ec7 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -65,15 +65,6 @@ public override void Process(ApplicationAnalysisContext appContext, Action m.Name == nameof(Il2CppType.GetClassPointer) && m.GenericParameters.Count == 1); var il2CppType_SetClassPointer = il2CppType.Methods.Single(m => m.Name == nameof(Il2CppType.SetClassPointer) && m.GenericParameters.Count == 1); - var il2CppObjectPool = appContext.ResolveTypeOrThrow(typeof(Il2CppObjectPool)); - var il2CppObjectPool_RegisterInitializer = il2CppObjectPool.GetMethodByName(nameof(Il2CppObjectPool.RegisterInitializer)); - var il2CppObjectPool_ValueTypeInitializer = il2CppObjectPool.GetMethodByName(nameof(Il2CppObjectPool.ValueTypeInitializer)); - - var funcTypeInstantiated = (GenericInstanceTypeAnalysisContext)il2CppObjectPool_RegisterInitializer.Parameters[1].ParameterType; - var funcType = funcTypeInstantiated.GenericType; - var funcConstructor = funcType.Methods.Single(m => m.IsInstanceConstructor && m.Parameters.Count == 2); - var funcConstructorInstantiated = funcConstructor.MakeConcreteGeneric(funcTypeInstantiated.GenericArguments, []); - var il2CppTypeAttribute = appContext.ResolveTypeOrThrow(typeof(Il2CppTypeAttribute)); var il2CppTypeAttributeConstructor = il2CppTypeAttribute.GetMethodByName(".ctor"); @@ -449,51 +440,6 @@ public override void Process(ApplicationAnalysisContext appContext, Action : Il2CppArrayBase, IIl2CppType, T>(1); - Il2CppObjectPool.RegisterInitializer(Il2CppType.GetClassPointer>(), static (ptr) => new Il2CppArrayRank1(ptr)); } public Il2CppArrayRank1(ObjectPointer pointer) : base(pointer) diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs index 93d82186..7354ecb7 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs @@ -14,7 +14,6 @@ public sealed class Il2CppArrayRank2 : Il2CppArrayBase, IIl2CppType, T>(2); - Il2CppObjectPool.RegisterInitializer(Il2CppType.GetClassPointer>(), static (ptr) => new Il2CppArrayRank2(ptr)); } public Il2CppArrayRank2(ObjectPointer pointer) : base(pointer) diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs index 643bd8be..7d7e800e 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs @@ -14,7 +14,6 @@ public sealed class Il2CppArrayRank3 : Il2CppArrayBase, IIl2CppType, T>(3); - Il2CppObjectPool.RegisterInitializer(Il2CppType.GetClassPointer>(), static (ptr) => new Il2CppArrayRank3(ptr)); } public Il2CppArrayRank3(ObjectPointer pointer) : base(pointer) diff --git a/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs b/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs index 1e1cdc96..44fffbfe 100644 --- a/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs +++ b/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs @@ -53,7 +53,6 @@ file static class Il2CppInternals static Il2CppInternals() { global::Il2CppInterop.Runtime.Injection.TypeInjector.RegisterTypeInIl2Cpp(); - global::Il2CppInterop.Common.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Common.Il2CppType.GetClassPointer(), ptr => new Sample(ptr)); } } diff --git a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs index d44cf8cd..5719dad3 100644 --- a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs +++ b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs @@ -409,6 +409,11 @@ private static void EmitInternalsClass(IndentedTextWriter writer, TypeModel mode writer.WriteLine($"global::Il2CppInterop.Runtime.Injection.TypeInjector.RegisterTypeInIl2Cpp<{model.TypeName}>();"); + if (isValueType) + { + writer.WriteLine($"Size = global::Il2CppInterop.Common.IL2CPP.il2cpp_class_value_size(global::Il2CppInterop.Common.Il2CppType.GetClassPointer<{model.TypeName}>(), out _);"); + } + foreach (var member in model.Members) { if (member.IsStatic) @@ -417,16 +422,6 @@ private static void EmitInternalsClass(IndentedTextWriter writer, TypeModel mode writer.WriteLine($"FieldOffset_{member.Index} = global::Il2CppInterop.Runtime.FieldAccess.GetFieldOffset(global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Common.Il2CppType.GetClassPointer<{model.TypeName}>(), \"{member.Name}\"));"); } - if (isValueType) - { - writer.WriteLine($"Size = global::Il2CppInterop.Common.IL2CPP.il2cpp_class_value_size(global::Il2CppInterop.Common.Il2CppType.GetClassPointer<{model.TypeName}>(), out _);"); - writer.WriteLine($"global::Il2CppInterop.Common.Il2CppObjectPool.RegisterValueTypeInitializer<{model.TypeName}>();"); - } - else if (!model.IsAbstract) - { - writer.WriteLine($"global::Il2CppInterop.Common.Il2CppObjectPool.RegisterInitializer(global::Il2CppInterop.Common.Il2CppType.GetClassPointer<{model.TypeName}>(), ptr => new {model.TypeName}(ptr));"); - } - writer.Indent--; writer.WriteLine("}"); From 71663c63fa83a2eb307c5f9efa04487b11891c4b Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 6 May 2026 19:32:40 -0700 Subject: [PATCH 387/486] Use function pointers instead of delegates in Il2CppObjectPool --- Il2CppInterop.Common/Il2CppObjectPool.cs | 29 ++++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/Il2CppInterop.Common/Il2CppObjectPool.cs b/Il2CppInterop.Common/Il2CppObjectPool.cs index cec25490..9df7b40f 100644 --- a/Il2CppInterop.Common/Il2CppObjectPool.cs +++ b/Il2CppInterop.Common/Il2CppObjectPool.cs @@ -6,7 +6,7 @@ public static class Il2CppObjectPool { private static readonly ConcurrentDictionary> s_cache = new(); - private static readonly ConcurrentDictionary> s_initializers = new(); + private static readonly ConcurrentDictionary s_initializers = new(); public static void Remove(nint ptr) { @@ -30,7 +30,7 @@ public static void Remove(nint ptr) throw new InvalidOperationException($"No initializer found for class {className}"); } - var newObj = initializer((ObjectPointer)ptr); + var newObj = initializer.Invoke((ObjectPointer)ptr); if (!newObj.GetType().IsValueType) { s_cache[ptr] = new WeakReference(newObj); @@ -39,7 +39,7 @@ public static void Remove(nint ptr) return newObj; } - private static void RegisterInitializer(nint classPtr, Func initializer) + private static void RegisterInitializer(nint classPtr, FunctionInitializer initializer) { ArgumentOutOfRangeException.ThrowIfZero(classPtr); if (!s_initializers.TryAdd(classPtr, initializer)) @@ -49,13 +49,28 @@ private static void RegisterInitializer(nint classPtr, Func() where T : IIl2CppType + internal static unsafe void RegisterInitializer() where T : IIl2CppType { - RegisterInitializer(Il2CppType.GetClassPointer(), TypeInitializer); + RegisterInitializer(Il2CppType.GetClassPointer(), new FunctionInitializer(&TypeInitializer)); + + static object TypeInitializer(ObjectPointer obj) + { + return T.UnboxNative(obj)!; + } } - private static object TypeInitializer(ObjectPointer obj) where T : IIl2CppType + private readonly unsafe struct FunctionInitializer { - return T.UnboxNative(obj)!; + private readonly delegate* initializer; + + public FunctionInitializer(delegate* initializer) + { + this.initializer = initializer; + } + + public object Invoke(ObjectPointer obj) + { + return initializer(obj); + } } } From f80ebbdb777f811fb4e3795be88e0c9615948817 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 6 May 2026 19:33:36 -0700 Subject: [PATCH 388/486] Slight name change --- Il2CppInterop.Common/Il2CppObjectPool.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Il2CppInterop.Common/Il2CppObjectPool.cs b/Il2CppInterop.Common/Il2CppObjectPool.cs index 9df7b40f..2f5d8af4 100644 --- a/Il2CppInterop.Common/Il2CppObjectPool.cs +++ b/Il2CppInterop.Common/Il2CppObjectPool.cs @@ -6,7 +6,7 @@ public static class Il2CppObjectPool { private static readonly ConcurrentDictionary> s_cache = new(); - private static readonly ConcurrentDictionary s_initializers = new(); + private static readonly ConcurrentDictionary s_initializers = new(); public static void Remove(nint ptr) { @@ -39,7 +39,7 @@ public static void Remove(nint ptr) return newObj; } - private static void RegisterInitializer(nint classPtr, FunctionInitializer initializer) + private static void RegisterInitializer(nint classPtr, InitializerFunction initializer) { ArgumentOutOfRangeException.ThrowIfZero(classPtr); if (!s_initializers.TryAdd(classPtr, initializer)) @@ -51,7 +51,7 @@ private static void RegisterInitializer(nint classPtr, FunctionInitializer initi internal static unsafe void RegisterInitializer() where T : IIl2CppType { - RegisterInitializer(Il2CppType.GetClassPointer(), new FunctionInitializer(&TypeInitializer)); + RegisterInitializer(Il2CppType.GetClassPointer(), new InitializerFunction(&TypeInitializer)); static object TypeInitializer(ObjectPointer obj) { @@ -59,11 +59,11 @@ static object TypeInitializer(ObjectPointer obj) } } - private readonly unsafe struct FunctionInitializer + private readonly unsafe struct InitializerFunction { private readonly delegate* initializer; - public FunctionInitializer(delegate* initializer) + public InitializerFunction(delegate* initializer) { this.initializer = initializer; } From 6561b05a471ede2958841c753feaf5807e7bdd16 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 6 May 2026 22:00:41 -0700 Subject: [PATCH 389/486] Unstrip TypedReference op codes --- .../TranslatedMethodBody.cs | 30 +++++++++++++++---- Il2CppInterop.Runtime/GenerationInternals.cs | 25 ++++++++++++++++ Il2Cppmscorlib/TypedReference.cs | 22 ++++++++++++++ 3 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 Il2Cppmscorlib/TypedReference.cs diff --git a/Il2CppInterop.Generator/TranslatedMethodBody.cs b/Il2CppInterop.Generator/TranslatedMethodBody.cs index ff0ffc93..88790dd3 100644 --- a/Il2CppInterop.Generator/TranslatedMethodBody.cs +++ b/Il2CppInterop.Generator/TranslatedMethodBody.cs @@ -326,8 +326,13 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo goto default; case CilCode.Refanytype: - // Not implemented yet - return false; + { + translatedInstruction.Code = CilOpCodes.Call; + translatedInstruction.Operand = appContext + .ResolveTypeOrThrow(typeof(GenerationInternals)) + .GetMethodByName(nameof(GenerationInternals.RefAnyType)); + } + break; case CilCode.Throw: { @@ -674,9 +679,24 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, getElementAddress.ReturnType); } break; - case CilCode.Mkrefany or CilCode.Refanyval: - // Not implemented yet - return false; + case CilCode.Mkrefany: + { + translatedInstruction.Code = CilOpCodes.Call; + translatedInstruction.Operand = appContext + .ResolveTypeOrThrow(typeof(GenerationInternals)) + .GetMethodByName(nameof(GenerationInternals.MakeRefAny)) + .MakeGenericInstanceMethod(translatedType); + } + break; + case CilCode.Refanyval: + { + translatedInstruction.Code = CilOpCodes.Call; + translatedInstruction.Operand = appContext + .ResolveTypeOrThrow(typeof(GenerationInternals)) + .GetMethodByName(nameof(GenerationInternals.RefAnyValue)) + .MakeGenericInstanceMethod(translatedType); + } + break; default: Debug.Fail($"Unexpected CIL code: {originalCode}"); return false; diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index 9b982699..e134ece6 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -53,6 +53,31 @@ public static Il2CppSystem.Type ManagedTypeToIl2CppType(Type type) return Il2CppSystem.Type.FromClassPointer(classPointer); } + public static unsafe Il2CppSystem.TypedReference MakeRefAny(void* value) where T : IIl2CppType + { + Il2CppSystem.TypedReference result = default; + result.Value = (IntPtr)value; + result.Type = Il2CppTypePointerStore.NativeTypePointer; + result.type = Il2CppSystem.Type.FromTypePointer(result.Type).TypeHandle; + return result; + } + + public static unsafe T? RefAnyValue(Il2CppSystem.TypedReference typedReference) where T : IIl2CppType + { + return Il2CppType.ReadFromPointer((void*)(nint)typedReference.Value); + } + + public static Il2CppSystem.RuntimeTypeHandle RefAnyType(Il2CppSystem.TypedReference typedReference) + { + if (typedReference.type.value != nint.Zero) + return typedReference.type; + + if (typedReference.Type != nint.Zero) + return Il2CppSystem.Type.FromTypePointer(typedReference.Type).TypeHandle; + + throw new InvalidOperationException("TypedReference does not have a type"); + } + // For unstripping the box instruction public static object? Box(T? value) where T : IIl2CppType { diff --git a/Il2Cppmscorlib/TypedReference.cs b/Il2Cppmscorlib/TypedReference.cs new file mode 100644 index 00000000..2ffa208b --- /dev/null +++ b/Il2Cppmscorlib/TypedReference.cs @@ -0,0 +1,22 @@ +namespace Il2CppSystem; + +public struct TypedReference +{ + /// + /// A field that Unity has, but is not present in .NET Framework nor .NET Core. + /// + /// + /// This field was added in + /// + public RuntimeTypeHandle type; + + /// + /// A pointer to the data + /// + public IntPtr Value; + + /// + /// The type handle + /// + public IntPtr Type; +} From a17400ae98a8b7487373a01eddce086630a5712d Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 6 May 2026 22:27:04 -0700 Subject: [PATCH 390/486] Fix method translation logging incorrect statistics --- .../MethodBodyTranslationProcessingLayer.cs | 4 ++-- Il2CppInterop.Generator/MethodInvokerProcessingLayer.cs | 6 ++++++ Il2CppInterop.Generator/NativeMethodBodyProcessingLayer.cs | 7 +++++++ Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs b/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs index d80c3983..fa49364f 100644 --- a/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs +++ b/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs @@ -10,6 +10,7 @@ public class MethodBodyTranslationProcessingLayer : Cpp2IlProcessingLayer public override string Name => "Method Body Translation"; public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { + Logger.InfoNewline("Translating method bodies...", nameof(MethodBodyTranslationProcessingLayer)); var successfulCount = 0; var totalCount = 0; foreach (var method in appContext.AllTypes.SelectMany(t => t.Methods)) @@ -26,8 +27,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action Date: Wed, 6 May 2026 23:01:38 -0700 Subject: [PATCH 391/486] Support using multidimensional arrays in unstripped method bodies --- .../TranslatedMethodBody.cs | 56 ++++++++++++++++++- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/Il2CppInterop.Generator/TranslatedMethodBody.cs b/Il2CppInterop.Generator/TranslatedMethodBody.cs index 88790dd3..4008cdf8 100644 --- a/Il2CppInterop.Generator/TranslatedMethodBody.cs +++ b/Il2CppInterop.Generator/TranslatedMethodBody.cs @@ -1033,10 +1033,60 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo return false; } } - else if (originalOperand is MultiDimensionalArrayMethod) + else if (originalOperand is MultiDimensionalArrayMethod multiDimensionalArrayMethod) { - // Not implemented yet - return false; + var arrayType = multiDimensionalArrayMethod.Rank switch + { + 2 => appContext.ResolveTypeOrThrow(typeof(Il2CppArrayRank2<>)), + 3 => appContext.ResolveTypeOrThrow(typeof(Il2CppArrayRank3<>)), + _ => null, + }; + if (arrayType is null) + return false; + + switch (multiDimensionalArrayMethod.MethodType) + { + case MultiDimensionalArrayMethodType.Get: + { + var genericMethod = arrayType.Methods.Single(m => m.Name == "get_Item" && m.Parameters.Count == multiDimensionalArrayMethod.Rank); + translatedInstruction.Code = CilOpCodes.Callvirt; + translatedInstruction.Operand = genericMethod.MakeConcreteGeneric([multiDimensionalArrayMethod.ArrayType.ElementType], []); + MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, genericMethod.ReturnType); + } + break; + case MultiDimensionalArrayMethodType.Set: + { + var genericMethod = arrayType.Methods.Single(m => m.Name == "set_Item" && m.Parameters.Count == multiDimensionalArrayMethod.Rank + 1); + translatedInstruction.Code = CilOpCodes.Callvirt; + translatedInstruction.Operand = genericMethod.MakeConcreteGeneric([multiDimensionalArrayMethod.ArrayType.ElementType], []); + MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, genericMethod.Parameters[^1].ParameterType); + } + break; + case MultiDimensionalArrayMethodType.Address: + { + var genericMethod = arrayType.Methods.Single(m => m.Name == nameof(Il2CppArrayRank2<>.GetElementAddress) && m.Parameters.Count == multiDimensionalArrayMethod.Rank); + translatedInstruction.Code = CilOpCodes.Callvirt; + translatedInstruction.Operand = genericMethod.MakeConcreteGeneric([multiDimensionalArrayMethod.ArrayType.ElementType], []); + MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, genericMethod.ReturnType); + } + break; + case MultiDimensionalArrayMethodType.Constructor: + { + var genericMethod = arrayType.Methods.Single(m => + { + return m.IsInstanceConstructor + && m.Parameters.Count == multiDimensionalArrayMethod.Rank + && m.Parameters.All(p => p.ParameterType == appContext.SystemTypes.SystemInt32Type); + }); + translatedInstruction.Code = CilOpCodes.Newobj; + translatedInstruction.Operand = genericMethod.MakeConcreteGeneric([multiDimensionalArrayMethod.ArrayType.ElementType], []); + MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, genericMethod.ReturnType); + } + break; + default: + Debug.Fail("Unexpected multidimensional array method type"); + return false; + } } else { From 11b802a7ab56c2f281b6fa2993bb371928862802 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 6 May 2026 23:34:03 -0700 Subject: [PATCH 392/486] Unstrip ldelem_ref and stelem_ref --- .../TranslatedMethodBody.cs | 20 +++++++++++++++---- .../InteropTypes/Arrays/Il2CppArrayBase.cs | 16 +++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Il2CppInterop.Generator/TranslatedMethodBody.cs b/Il2CppInterop.Generator/TranslatedMethodBody.cs index 4008cdf8..16e1d4e1 100644 --- a/Il2CppInterop.Generator/TranslatedMethodBody.cs +++ b/Il2CppInterop.Generator/TranslatedMethodBody.cs @@ -302,12 +302,24 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo break; case CilCode.Ldelem_Ref: - // This is Il2CppReferenceArray.get_Item but the T is not known because the operand is null. - return false; + // This is Il2CppArrayBase.LoadReferenceElementUnsafe + { + translatedInstruction.Code = CilOpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.LoadReferenceElementUnsafe)); + } + break; case CilCode.Stelem_Ref: - // This is Il2CppReferenceArray.set_Item but the T is not known because the operand is null. - return false; + // This is Il2CppArrayBase.StoreReferenceElementUnsafe + { + translatedInstruction.Code = CilOpCodes.Callvirt; + translatedInstruction.Operand = methodContext.AppContext + .ResolveTypeOrThrow(typeof(Il2CppArrayBase)) + .GetMethodByName(nameof(Il2CppArrayBase.StoreReferenceElementUnsafe)); + } + break; case >= CilCode.Ldind_I1 and < CilCode.Ldind_Ref: // This is for by ref and pointers diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs index 3f89deea..0474720b 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs @@ -44,6 +44,22 @@ public void StoreElementUnsafe(int index, T value) where T : unmanaged element = value; } + public IIl2CppType? LoadReferenceElementUnsafe(int index) + { + ThrowIfIndexOutOfRange(index); + var span = GetUnsafeSpanForElement(index); + var ptr = Il2CppType.ReadPointer(span); + return (IIl2CppType?)Il2CppObjectPool.Get(ptr); + } + + public void StoreReferenceElementUnsafe(int index, IIl2CppType? value) + { + ThrowIfIndexOutOfRange(index); + var span = GetUnsafeSpanForElement(index); + var ptr = (nint)NativeBoxing.Box(value); + Il2CppType.WritePointer(ptr, span); + } + private protected virtual Span GetUnsafeSpanForElement(int index) { throw new NotSupportedException("Only rank 1 arrays support unsafe element access"); From 2ae5774fcf47a1582dde657ea4867fc2dfdd835d Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 7 May 2026 09:30:57 -0700 Subject: [PATCH 393/486] Support ldind.ref and stind.ref in unstripping --- Il2CppInterop.Generator/TranslatedMethodBody.cs | 16 ++++++++++++++-- Il2CppInterop.Runtime/GenerationInternals.cs | 16 +++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/Il2CppInterop.Generator/TranslatedMethodBody.cs b/Il2CppInterop.Generator/TranslatedMethodBody.cs index 16e1d4e1..206c00e2 100644 --- a/Il2CppInterop.Generator/TranslatedMethodBody.cs +++ b/Il2CppInterop.Generator/TranslatedMethodBody.cs @@ -327,11 +327,23 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo case CilCode.Ldind_Ref: // This is for by ref and pointers - return false; + { + translatedInstruction.Code = CilOpCodes.Call; + translatedInstruction.Operand = appContext + .ResolveTypeOrThrow(typeof(GenerationInternals)) + .GetMethodByName(nameof(GenerationInternals.LoadIndirectReference)); + } + break; case CilCode.Stind_Ref: // This is for by ref and pointers - return false; + { + translatedInstruction.Code = CilOpCodes.Call; + translatedInstruction.Operand = appContext + .ResolveTypeOrThrow(typeof(GenerationInternals)) + .GetMethodByName(nameof(GenerationInternals.StoreIndirectReference)); + } + break; case > CilCode.Stind_Ref and <= CilCode.Stind_R8: // This is for by ref and pointers diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index e134ece6..d6ffa4c8 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -78,10 +78,24 @@ public static Il2CppSystem.RuntimeTypeHandle RefAnyType(Il2CppSystem.TypedRefere throw new InvalidOperationException("TypedReference does not have a type"); } + public static unsafe IIl2CppType? LoadIndirectReference(void* address) + { + ArgumentNullException.ThrowIfNull(address); + var objectPointer = *(nint*)address; + return (IIl2CppType?)Il2CppObjectPool.Get(objectPointer); + } + + public static unsafe void StoreIndirectReference(void* address, IIl2CppType? obj) + { + ArgumentNullException.ThrowIfNull(address); + var objectPointer = obj?.BoxNative() ?? ObjectPointer.Null; + *(nint*)address = (nint)objectPointer; + } + // For unstripping the box instruction public static object? Box(T? value) where T : IIl2CppType { - return value?.Box() ?? null; + return value?.Box(); } // For unstripping the unbox.any instruction From 958d4e344e2b6b9af343fdede7673434f3824299 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 7 May 2026 10:41:31 -0700 Subject: [PATCH 394/486] Avoid unnecessary nop instructions when unstripping method calls --- .../TranslatedMethodBody.cs | 84 +++++++++++-------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/Il2CppInterop.Generator/TranslatedMethodBody.cs b/Il2CppInterop.Generator/TranslatedMethodBody.cs index 206c00e2..3aeeba87 100644 --- a/Il2CppInterop.Generator/TranslatedMethodBody.cs +++ b/Il2CppInterop.Generator/TranslatedMethodBody.cs @@ -779,65 +779,81 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo } if (originalCode.Code is CilCode.Call && baseMethod.UnsafeInvokeMethod is not null) { - translatedInstruction.Code = CilOpCodes.Nop; - var targetMethod = baseMethod.UnsafeInvokeMethod?.MaybeMakeConcreteGeneric(typeGenericArguments, methodGenericArguments); Debug.Assert(targetMethod is not null); Debug.Assert(targetMethod.IsStatic); Debug.Assert(method.Parameters.Count == targetMethod.Parameters.Count - 1); - var temporaryVariables = new LocalVariable[targetMethod.Parameters.Count]; - for (var i = targetMethod.Parameters.Count - 1; i >= 0; i--) // Order matters + if (targetMethod.Parameters.Count > 0) { - var methodParameter = targetMethod.Parameters[i]; - MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, methodParameter.ParameterType); - var temporaryVariable = new LocalVariable + translatedInstruction.Code = CilOpCodes.Nop; + + var temporaryVariables = new LocalVariable[targetMethod.Parameters.Count]; + for (var i = targetMethod.Parameters.Count - 1; i >= 0; i--) // Order matters { - Type = methodParameter.ParameterType, - }; - translatedInstructions.Add(CilOpCodes.Stloc, temporaryVariable); + var methodParameter = targetMethod.Parameters[i]; + MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, methodParameter.ParameterType); + var temporaryVariable = new LocalVariable + { + Type = methodParameter.ParameterType, + }; + translatedInstructions.Add(CilOpCodes.Stloc, temporaryVariable); - temporaryVariables[i] = temporaryVariable; - localVariableList.Add(temporaryVariable); - } + temporaryVariables[i] = temporaryVariable; + localVariableList.Add(temporaryVariable); + } - foreach (var temporaryVariable in temporaryVariables) + foreach (var temporaryVariable in temporaryVariables) + { + translatedInstructions.Add(CilOpCodes.Ldloc, temporaryVariable); + } + + translatedInstructions.Add(CilOpCodes.Call, targetMethod); + } + else { - translatedInstructions.Add(CilOpCodes.Ldloc, temporaryVariable); + translatedInstruction.Code = CilOpCodes.Call; + translatedInstruction.Operand = targetMethod; } - - translatedInstructions.Add(originalCode, targetMethod); MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, targetMethod.ReturnType); } else if (originalCode.Code is CilCode.Call or CilCode.Callvirt or CilCode.Newobj) { - translatedInstruction.Code = CilOpCodes.Nop; - var targetMethod = baseMethod.MaybeMakeConcreteGeneric(typeGenericArguments, methodGenericArguments); - var temporaryVariables = new LocalVariable[targetMethod.Parameters.Count]; - for (var i = targetMethod.Parameters.Count - 1; i >= 0; i--) // Order matters + if (targetMethod.Parameters.Count > 0) { - var methodParameter = targetMethod.Parameters[i]; - MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, methodParameter.ParameterType); - var temporaryVariable = new LocalVariable + translatedInstruction.Code = CilOpCodes.Nop; + + var temporaryVariables = new LocalVariable[targetMethod.Parameters.Count]; + for (var i = targetMethod.Parameters.Count - 1; i >= 0; i--) // Order matters { - Type = methodParameter.ParameterType, - }; - translatedInstructions.Add(CilOpCodes.Stloc, temporaryVariable); + var methodParameter = targetMethod.Parameters[i]; + MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, methodParameter.ParameterType); + var temporaryVariable = new LocalVariable + { + Type = methodParameter.ParameterType, + }; + translatedInstructions.Add(CilOpCodes.Stloc, temporaryVariable); - temporaryVariables[i] = temporaryVariable; - localVariableList.Add(temporaryVariable); - } + temporaryVariables[i] = temporaryVariable; + localVariableList.Add(temporaryVariable); + } - foreach (var temporaryVariable in temporaryVariables) + foreach (var temporaryVariable in temporaryVariables) + { + translatedInstructions.Add(CilOpCodes.Ldloc, temporaryVariable); + } + + translatedInstructions.Add(originalCode, targetMethod); + } + else { - translatedInstructions.Add(CilOpCodes.Ldloc, temporaryVariable); + translatedInstruction.Code = originalCode; + translatedInstruction.Operand = targetMethod; } - translatedInstructions.Add(originalCode, targetMethod); - var returnType = originalCode == CilOpCodes.Newobj ? targetMethod.DeclaringType! : targetMethod.ReturnType; MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, returnType); } From c02ce7756750f2aaa23cfbd315e6abdbcb2b3b2b Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 7 May 2026 11:40:46 -0700 Subject: [PATCH 395/486] Free original method body after translation --- .../MethodBodyTranslationProcessingLayer.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs b/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs index fa49364f..43225b13 100644 --- a/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs +++ b/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs @@ -15,15 +15,15 @@ public override void Process(ApplicationAnalysisContext appContext, Action t.Methods)) { - var successful = TranslatedMethodBody.TryTranslateOriginalMethodBody(method); - if (successful) - { - successfulCount++; - } if (method.HasExtraData()) { totalCount++; } + method.RemoveExtraData(); + if (TranslatedMethodBody.TryTranslateOriginalMethodBody(method)) + { + successfulCount++; + } } // Report how many method bodies were successfully translated. From dcb7bfa4ec3fab1bce98d13b6163b56a3605132f Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 7 May 2026 12:03:54 -0700 Subject: [PATCH 396/486] Fix bug in previous commit --- Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs b/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs index 43225b13..b4d14542 100644 --- a/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs +++ b/Il2CppInterop.Generator/MethodBodyTranslationProcessingLayer.cs @@ -19,11 +19,11 @@ public override void Process(ApplicationAnalysisContext appContext, Action(); if (TranslatedMethodBody.TryTranslateOriginalMethodBody(method)) { successfulCount++; } + method.RemoveExtraData(); } // Report how many method bodies were successfully translated. From 6ab43d251e1d800f6498061c5550ccebeefa1a79 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 7 May 2026 12:42:02 -0700 Subject: [PATCH 397/486] Improve unstripping of calls to IObject, IValueType, and IEnum methods --- .../MethodAnalysisContextExtensions.cs | 1 + .../ObjectInterfaceProcessingLayer.cs | 21 ++++- .../TranslatedMethodBody.cs | 86 ++++++++----------- 3 files changed, 57 insertions(+), 51 deletions(-) diff --git a/Il2CppInterop.Generator/Extensions/MethodAnalysisContextExtensions.cs b/Il2CppInterop.Generator/Extensions/MethodAnalysisContextExtensions.cs index 1cbd217a..76042245 100644 --- a/Il2CppInterop.Generator/Extensions/MethodAnalysisContextExtensions.cs +++ b/Il2CppInterop.Generator/Extensions/MethodAnalysisContextExtensions.cs @@ -71,6 +71,7 @@ public int InitializationClassIndex public bool IsConstructor => method.IsInstanceConstructor || method.IsStaticConstructor; public bool IsPublic => (method.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public; public bool IsSpecialName => (method.Attributes & MethodAttributes.SpecialName) != default; + public bool IsFinal => (method.Attributes & MethodAttributes.Final) != default; public bool ImplementsAnInterfaceMethod => method.Overrides.Count > 0; diff --git a/Il2CppInterop.Generator/ObjectInterfaceProcessingLayer.cs b/Il2CppInterop.Generator/ObjectInterfaceProcessingLayer.cs index 721d1db3..ec16173b 100644 --- a/Il2CppInterop.Generator/ObjectInterfaceProcessingLayer.cs +++ b/Il2CppInterop.Generator/ObjectInterfaceProcessingLayer.cs @@ -48,21 +48,21 @@ public override void Process(ApplicationAnalysisContext appContext, Action 0) - { - translatedInstruction.Code = CilOpCodes.Nop; - - var temporaryVariables = new LocalVariable[targetMethod.Parameters.Count]; - for (var i = targetMethod.Parameters.Count - 1; i >= 0; i--) // Order matters + if (baseMethod.IsFinal) { - var methodParameter = targetMethod.Parameters[i]; - MonoIl2CppConversion.AddMonoToIl2CppConversion(translatedInstructions, methodParameter.ParameterType); - var temporaryVariable = new LocalVariable - { - Type = methodParameter.ParameterType, - }; - translatedInstructions.Add(CilOpCodes.Stloc, temporaryVariable); - - temporaryVariables[i] = temporaryVariable; - localVariableList.Add(temporaryVariable); + targetMethod = baseMethod.InterfaceRedirectMethod!; + targetOpCode = CilOpCodes.Callvirt; } - - foreach (var temporaryVariable in temporaryVariables) + else if (baseMethod.UnsafeInvokeMethod is not null) { - translatedInstructions.Add(CilOpCodes.Ldloc, temporaryVariable); + targetMethod = baseMethod.UnsafeInvokeMethod!.MaybeMakeConcreteGeneric(typeGenericArguments, methodGenericArguments); + Debug.Assert(targetMethod.IsStatic); + Debug.Assert(method.Parameters.Count == targetMethod.Parameters.Count - 1); + Debug.Assert(baseMethod.InterfaceRedirectMethod!.DeclaringType == targetMethod.Parameters[0].ParameterType); + targetOpCode = CilOpCodes.Call; + } + else + { + // This should not happen + return false; } - - translatedInstructions.Add(CilOpCodes.Call, targetMethod); + } + else if (originalCode.Code is CilCode.Call && baseMethod.UnsafeInvokeMethod is not null) + { + targetMethod = baseMethod.UnsafeInvokeMethod!.MaybeMakeConcreteGeneric(typeGenericArguments, methodGenericArguments); + Debug.Assert(targetMethod.IsStatic); + Debug.Assert(method.Parameters.Count == targetMethod.Parameters.Count - 1); + targetOpCode = CilOpCodes.Call; } else { - translatedInstruction.Code = CilOpCodes.Call; - translatedInstruction.Operand = targetMethod; + if (originalCode.Code is CilCode.Callvirt && baseMethod.InterfaceRedirectMethod is not null) + { + // Interface redirects are only used for IObject, IValueType, and IEnum + // Which have no generic methods + targetMethod = baseMethod.InterfaceRedirectMethod!; + } + else + { + targetMethod = baseMethod.MaybeMakeConcreteGeneric(typeGenericArguments, methodGenericArguments); + } + targetOpCode = originalCode; } - MonoIl2CppConversion.AddIl2CppToMonoConversion(translatedInstructions, targetMethod.ReturnType); - } - else if (originalCode.Code is CilCode.Call or CilCode.Callvirt or CilCode.Newobj) - { - var targetMethod = baseMethod.MaybeMakeConcreteGeneric(typeGenericArguments, methodGenericArguments); if (targetMethod.Parameters.Count > 0) { @@ -846,11 +836,11 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo translatedInstructions.Add(CilOpCodes.Ldloc, temporaryVariable); } - translatedInstructions.Add(originalCode, targetMethod); + translatedInstructions.Add(targetOpCode, targetMethod); } else { - translatedInstruction.Code = originalCode; + translatedInstruction.Code = targetOpCode; translatedInstruction.Operand = targetMethod; } From ac5979b368b1b1fd37625844c6d776c97fd1c542 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 7 May 2026 13:38:09 -0700 Subject: [PATCH 398/486] Fix signature for interface implementation in Nullable --- Il2CppInterop.Generator/BoxingProcessingLayer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Il2CppInterop.Generator/BoxingProcessingLayer.cs b/Il2CppInterop.Generator/BoxingProcessingLayer.cs index cfe6d74a..88859b57 100644 --- a/Il2CppInterop.Generator/BoxingProcessingLayer.cs +++ b/Il2CppInterop.Generator/BoxingProcessingLayer.cs @@ -68,7 +68,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action Date: Thu, 7 May 2026 15:01:43 -0700 Subject: [PATCH 399/486] Don't register initializers for abstract classes and interfaces --- Il2CppInterop.Common/Il2CppType.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Il2CppInterop.Common/Il2CppType.cs b/Il2CppInterop.Common/Il2CppType.cs index 95259f2f..1ec546fd 100644 --- a/Il2CppInterop.Common/Il2CppType.cs +++ b/Il2CppInterop.Common/Il2CppType.cs @@ -177,7 +177,10 @@ public static void SetClassPointer(nint classPointer) where T : IIl2CppType.NativeClassPointer == nint.Zero) { Il2CppClassPointerStore.NativeClassPointer = classPointer; - Il2CppObjectPool.RegisterInitializer(); + if (!typeof(T).IsAbstract && !typeof(T).IsInterface) + { + Il2CppObjectPool.RegisterInitializer(); + } } else { From 6efc3eb43c136394990d58c0202f7408b8180a79 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 7 May 2026 20:26:04 -0700 Subject: [PATCH 400/486] Enable operation without assemblies for unstripping --- .../Il2CppInterop.Generator.csproj | 1 + ...scorlibAssemblyInjectionProcessingLayer.cs | 85 +++++++++++++------ Il2CppInterop.Generator/SystemTypeResolver.cs | 27 +++++- 3 files changed, 84 insertions(+), 29 deletions(-) diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index 50fefc2b..e2baeb85 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -14,6 +14,7 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs b/Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs index 6057d98b..5da6d3a5 100644 --- a/Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs +++ b/Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs @@ -10,45 +10,76 @@ public class MscorlibAssemblyInjectionProcessingLayer : UnstripBaseProcessingLay public override string Id => "mscorlib_injector"; + private static readonly string[] injectedAssemblies = + [ + "mscorlib", + "System.Collections", + ]; + internal static ReadOnlySpan InjectedAssemblies => injectedAssemblies; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { - var assemblyList = appContext.GetExtraData>(AssembliesKey); - if (assemblyList is null) - { - var directoryPath = appContext.GetExtraData(DirectoryKey); - if (directoryPath is null) - { - Logger.WarnNewline($"No assemblies specified - processor will not run. You need to provide the {DirectoryKey}, either by programmatically adding it as extra data in the app context, or by specifying it in the --processor-config command line option.", nameof(UnstripProcessingLayer)); - return; - } - - assemblyList = Directory.GetFiles(directoryPath, "*.dll", SearchOption.AllDirectories) - .Where(x => x.Contains("mscorlib", StringComparison.OrdinalIgnoreCase)) - .Select(path => AssemblyDefinition.FromFile(path)) - .ToList(); - } + Logger.InfoNewline($"Injecting new mscorlib...", nameof(MscorlibAssemblyInjectionProcessingLayer)); - var mscorlib = assemblyList.FirstOrDefault(x => x.Name == "mscorlib"); + var mscorlib = LoadSystemRuntime(); + var runtimeContext = new RuntimeContext(DotNetRuntimeInfo.NetCoreApp(10, 0), new AssemblyResolver(), mscorlib); + runtimeContext.AddAssembly(mscorlib); - if (mscorlib is null) + var assembliesToInject = new AssemblyDefinition[injectedAssemblies.Length]; + assembliesToInject[0] = mscorlib; + for (var i = 1; i < injectedAssemblies.Length; i++) { - Logger.WarnNewline("mscorlib not provided - processor will not run.", nameof(UnstripProcessingLayer)); - return; + var assemblyName = injectedAssemblies[i]; + assembliesToInject[i] = LoadAssembly(assemblyName, runtimeContext); } - if (appContext.AssembliesByName.ContainsKey("mscorlib")) + InjectAssemblies(appContext, assembliesToInject, false, true); + + // Need to reset the system types context to use the new corlib + appContext.SystemTypes = new SystemTypesContext(appContext); + + foreach (var assemblyName in injectedAssemblies) { - Logger.WarnNewline("mscorlib already injected - processor will not run.", nameof(MscorlibAssemblyInjectionProcessingLayer)); - return; + appContext.AssembliesByName[assemblyName].IsReferenceAssembly = true; } + } - Logger.InfoNewline($"Injecting new mscorlib...", nameof(MscorlibAssemblyInjectionProcessingLayer)); + private static AssemblyDefinition LoadSystemRuntime() + { + AssemblyDefinition assembly = AssemblyDefinition.FromBytes(Basic.Reference.Assemblies.Net100.ReferenceInfos.SystemRuntime.ImageBytes, createRuntimeContext: false); + assembly.Name = "mscorlib"; + assembly.ManifestModule!.Name = "mscorlib.dll"; + return assembly; + } - InjectAssemblies(appContext, [mscorlib], false, true); + private static AssemblyDefinition LoadAssembly(string assemblyName, RuntimeContext runtimeContext) + { + var assembly = AssemblyDefinition.FromBytes(GetAssemblyBytes($"{assemblyName}.dll"), createRuntimeContext: false); + foreach (var module in assembly.Modules) + { + foreach (var assemblyReference in module.AssemblyReferences) + { + if (assemblyReference.Name == "System.Runtime") + { + assemblyReference.Name = "mscorlib"; + } + } + } + runtimeContext.AddAssembly(assembly); + return assembly; + } - // Need to reset the system types context to use the new corlib - appContext.SystemTypes = new SystemTypesContext(appContext); + private static byte[] GetAssemblyBytes(string fileName) + { + return Basic.Reference.Assemblies.Net100.ReferenceInfos.All.First(x => x.FileName == fileName).ImageBytes; + } - appContext.AssembliesByName["mscorlib"].IsReferenceAssembly = true; + private sealed class AssemblyResolver : IAssemblyResolver + { + public ResolutionStatus Resolve(AssemblyDescriptor assembly, ModuleDefinition? originModule, out AssemblyDefinition? result) + { + result = null; + return ResolutionStatus.AssemblyNotFound; + } } } diff --git a/Il2CppInterop.Generator/SystemTypeResolver.cs b/Il2CppInterop.Generator/SystemTypeResolver.cs index 50929e85..0160dd1a 100644 --- a/Il2CppInterop.Generator/SystemTypeResolver.cs +++ b/Il2CppInterop.Generator/SystemTypeResolver.cs @@ -82,10 +82,33 @@ public TypeAnalysisContext ResolveOrThrow(Type? type, bool allowGenericInstance // Custom modifiers might be possible to support, but probably not necessary var assemblyName = type.Assembly.GetName().Name!; + var fullName = type.FullName!; if (assemblyName == "System.Private.CoreLib") - assemblyName = "mscorlib"; + { + return ResolveSystemType(fullName); + } + else + { + return ResolveSimpleType(assemblyName, fullName); + } + } + + private TypeAnalysisContext? ResolveSystemType(string fullName) + { + TypeAnalysisContext? type = null; + foreach (var assemblyName in MscorlibAssemblyInjectionProcessingLayer.InjectedAssemblies) + { + type = ResolveSimpleType(assemblyName, fullName); + if (type is not null) + break; + } + return type; + } + + private TypeAnalysisContext? ResolveSimpleType(string assemblyName, string fullName) + { var assembly = referencedFrom.AppContext.GetAssemblyByName(assemblyName); - return assembly?.GetTypeByFullName(type.FullName!); + return assembly?.GetTypeByFullName(fullName); } private static GenericParameterTypeAnalysisContext? TryGetGenericParameter(List? genericParameters, int index) From 2efc186b18263ef973a15989f93f6d638c22fdda Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 7 May 2026 20:51:11 -0700 Subject: [PATCH 401/486] Remove temporary fix for interface base types It is no longer necessary --- .../AsmResolverDllOutputFormatBinding.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Il2CppInterop.Generator/AsmResolverDllOutputFormatBinding.cs b/Il2CppInterop.Generator/AsmResolverDllOutputFormatBinding.cs index 2411e89e..56d7b6f7 100644 --- a/Il2CppInterop.Generator/AsmResolverDllOutputFormatBinding.cs +++ b/Il2CppInterop.Generator/AsmResolverDllOutputFormatBinding.cs @@ -61,15 +61,6 @@ public override List BuildAssemblies(ApplicationAnalysisCont reference.Culture = dotNetCorLib.Culture; } } - - // Temporary fix - foreach (var type in module.GetAllTypes()) - { - if (type.IsInterface) - { - type.BaseType = null; - } - } } } From 70fc661d8d3a78c2b2d2b02ce18c7b0b8da303b1 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 7 May 2026 21:13:51 -0700 Subject: [PATCH 402/486] Remove ExpandMacros backport implementation --- .../CilInstructionCollectionBackport.cs | 139 ------------------ Il2CppInterop.Generator/OriginalMethodBody.cs | 2 +- 2 files changed, 1 insertion(+), 140 deletions(-) delete mode 100644 Il2CppInterop.Generator/Extensions/CilInstructionCollectionBackport.cs diff --git a/Il2CppInterop.Generator/Extensions/CilInstructionCollectionBackport.cs b/Il2CppInterop.Generator/Extensions/CilInstructionCollectionBackport.cs deleted file mode 100644 index 79a3cd38..00000000 --- a/Il2CppInterop.Generator/Extensions/CilInstructionCollectionBackport.cs +++ /dev/null @@ -1,139 +0,0 @@ -using AsmResolver.DotNet.Code.Cil; - -namespace Il2CppInterop.Generator.Extensions; - -// https://github.com/Washi1337/AsmResolver/issues/678 -// https://github.com/Washi1337/AsmResolver/pull/679 -internal static class CilInstructionCollectionBackport -{ - extension(CilInstructionCollection instructions) - { - public void ExpandMacrosBackport() - { - int currentOffset = 0; - foreach (var instruction in instructions) - { - instruction.Offset = currentOffset; - instructions.ExpandMacroBackport(instruction); - currentOffset += instruction.Size; - } - } - private void ExpandMacroBackport(CilInstruction instruction) - { - // operand changes must come before opcode changes to not overwrite needed data - switch (instruction.OpCode.Code) - { - case CilCode.Ldc_I4_0: - case CilCode.Ldc_I4_1: - case CilCode.Ldc_I4_2: - case CilCode.Ldc_I4_3: - case CilCode.Ldc_I4_4: - case CilCode.Ldc_I4_5: - case CilCode.Ldc_I4_6: - case CilCode.Ldc_I4_7: - case CilCode.Ldc_I4_8: - case CilCode.Ldc_I4_M1: - case CilCode.Ldc_I4_S: - instruction.Operand = instruction.GetLdcI4Constant(); - instruction.OpCode = CilOpCodes.Ldc_I4; - break; - - case CilCode.Ldarg_0: - case CilCode.Ldarg_1: - case CilCode.Ldarg_2: - case CilCode.Ldarg_3: - case CilCode.Ldarg_S: - instruction.Operand = instructions.Owner.Owner?.Parameters is { } parameters - ? instruction.GetParameter(parameters) - : (ushort)instruction.GetParameterIndex(); - instruction.OpCode = CilOpCodes.Ldarg; - break; - - case CilCode.Ldarga_S: - { - if (instruction.Operand is byte index) - instruction.Operand = (ushort)index; - instruction.OpCode = CilOpCodes.Ldarga; - break; - } - - case CilCode.Starg_S: - { - if (instruction.Operand is byte index) - instruction.Operand = (ushort)index; - instruction.OpCode = CilOpCodes.Starg; - break; - } - - case CilCode.Ldloc_0: - case CilCode.Ldloc_1: - case CilCode.Ldloc_2: - case CilCode.Ldloc_3: - case CilCode.Ldloc_S: - instruction.Operand = instruction.GetLocalVariable(instructions.Owner.LocalVariables); - instruction.OpCode = CilOpCodes.Ldloc; - break; - - case CilCode.Ldloca_S: - { - if (instruction.Operand is byte index) - instruction.Operand = (ushort)index; - instruction.OpCode = CilOpCodes.Ldloca; - break; - } - - case CilCode.Stloc_0: - case CilCode.Stloc_1: - case CilCode.Stloc_2: - case CilCode.Stloc_3: - case CilCode.Stloc_S: - instruction.Operand = instruction.GetLocalVariable(instructions.Owner.LocalVariables); - instruction.OpCode = CilOpCodes.Stloc; - break; - - case CilCode.Beq_S: - instruction.OpCode = CilOpCodes.Beq; - break; - case CilCode.Bge_S: - instruction.OpCode = CilOpCodes.Bge; - break; - case CilCode.Bgt_S: - instruction.OpCode = CilOpCodes.Bgt; - break; - case CilCode.Ble_S: - instruction.OpCode = CilOpCodes.Ble; - break; - case CilCode.Blt_S: - instruction.OpCode = CilOpCodes.Blt; - break; - case CilCode.Br_S: - instruction.OpCode = CilOpCodes.Br; - break; - case CilCode.Brfalse_S: - instruction.OpCode = CilOpCodes.Brfalse; - break; - case CilCode.Brtrue_S: - instruction.OpCode = CilOpCodes.Brtrue; - break; - case CilCode.Bge_Un_S: - instruction.OpCode = CilOpCodes.Bge_Un; - break; - case CilCode.Bgt_Un_S: - instruction.OpCode = CilOpCodes.Bgt_Un; - break; - case CilCode.Ble_Un_S: - instruction.OpCode = CilOpCodes.Ble_Un; - break; - case CilCode.Blt_Un_S: - instruction.OpCode = CilOpCodes.Blt_Un; - break; - case CilCode.Bne_Un_S: - instruction.OpCode = CilOpCodes.Bne_Un; - break; - case CilCode.Leave_S: - instruction.OpCode = CilOpCodes.Leave; - break; - } - } - } -} diff --git a/Il2CppInterop.Generator/OriginalMethodBody.cs b/Il2CppInterop.Generator/OriginalMethodBody.cs index cdce37bc..1d0c026d 100644 --- a/Il2CppInterop.Generator/OriginalMethodBody.cs +++ b/Il2CppInterop.Generator/OriginalMethodBody.cs @@ -34,7 +34,7 @@ private static bool TryResolveOriginalMethodBody(MethodDefinition method, Method var resolver = new ContextResolver(methodContext, runtimeContext); var originalInstructions = body.Instructions; - originalInstructions.ExpandMacrosBackport(); + originalInstructions.ExpandMacros(); var newInstructions = new Instruction[originalInstructions.Count]; for (var i = 0; i < newInstructions.Length; i++) From 7219f096300d52c7b31ee667694254ef31d0a659 Mon Sep 17 00:00:00 2001 From: Atmudia <44307026+Atmudia@users.noreply.github.com> Date: Fri, 8 May 2026 23:57:41 +0200 Subject: [PATCH 403/486] Add multiple diagnostic analyzers for Il2CppInterop injected types (#11) * add multiple diagnostic analyzers for Il2CppInterop injected types and refine existing field/struct validation rules * Improved Injected Type Analyzer * improve diagnostic reporting logic in InjectedTypePartialAnalyzer --- Il2CppInterop.SourceGenerator/Extensions.cs | 7 + .../InjectedTypePartialAnalyzer.cs | 238 ++++++++++++++---- 2 files changed, 202 insertions(+), 43 deletions(-) diff --git a/Il2CppInterop.SourceGenerator/Extensions.cs b/Il2CppInterop.SourceGenerator/Extensions.cs index 52123868..6736951d 100644 --- a/Il2CppInterop.SourceGenerator/Extensions.cs +++ b/Il2CppInterop.SourceGenerator/Extensions.cs @@ -34,6 +34,12 @@ symbol is not null && symbol.Name == name && MatchesNamespace(symbol.ContainingNamespace, namespaceParts); + public bool HasAttribute(string name, ReadOnlySpan namespaceParts) => + ((ISymbol?)symbol).HasAttribute(name, namespaceParts); + } + + extension(ISymbol? symbol) + { public bool HasAttribute(string name, ReadOnlySpan namespaceParts) { if (symbol is null) @@ -62,6 +68,7 @@ private static bool MatchesNamespace(INamespaceSymbol? ns, ReadOnlySpan // Make sure we've consumed all namespaces up to global return ns is null or { IsGlobalNamespace: true }; } + internal static void WriteLineNoTabs(this IndentedTextWriter writer) => writer.WriteLineNoTabs(null); } diff --git a/Il2CppInterop.SourceGenerator/InjectedTypePartialAnalyzer.cs b/Il2CppInterop.SourceGenerator/InjectedTypePartialAnalyzer.cs index 31fd78ba..68f6ce78 100644 --- a/Il2CppInterop.SourceGenerator/InjectedTypePartialAnalyzer.cs +++ b/Il2CppInterop.SourceGenerator/InjectedTypePartialAnalyzer.cs @@ -55,10 +55,10 @@ public sealed class InjectedTypePartialAnalyzer : DiagnosticAnalyzer defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); - public static DiagnosticDescriptor CannotHaveIl2CppFieldOnStruct { get; } = new( + public static DiagnosticDescriptor CannotHaveIl2CppFieldOnStructOrInterface { get; } = new( id: "IL2CPP0006", - title: "Structs cannot have instance properties marked with [Il2CppField]", - messageFormat: "Type '{0}' is a struct and cannot have instance properties marked with [Il2CppField]", + title: "Structs and interfaces cannot have instance properties marked with [Il2CppField]", + messageFormat: "Type '{0}' is a {1} and cannot have instance properties marked with [Il2CppField]", category: "Il2CppInterop", defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); @@ -79,14 +79,54 @@ public sealed class InjectedTypePartialAnalyzer : DiagnosticAnalyzer defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); - public static DiagnosticDescriptor ShouldNotHaveUninjectedInstanceMembers { get; } = new( + public static DiagnosticDescriptor ShouldNotHaveUninjectedInstanceFields { get; } = new( id: "IL2CPP0009", - title: "Injected types should not have uninjected instance members", - messageFormat: "Type '{0}' has instance member '{1}' which is not managed by Il2CppInterop. Use [ManagedField] or [Il2CppField] properties instead.", + title: "Injected types should not have uninjected instance fields", + messageFormat: "Type '{0}' has instance field '{1}' which is not managed by Il2CppInterop. Use [ManagedField] or [Il2CppField] properties instead.", category: "Il2CppInterop", defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true); + public static DiagnosticDescriptor Il2CppFinalizerMustHaveNoParameters { get; } = new( + id: "IL2CPP0010", + title: "Methods annotated with [Il2CppFinalizer] should have no parameters", + messageFormat: "Method '{0}' is annotated with [Il2CppFinalizer] but has parameters. The finalizer must be parameterless.", + category: "Il2CppInterop", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static DiagnosticDescriptor Il2CppFinalizerShouldReturnVoid { get; } = new( + id: "IL2CPP0011", + title: "Methods annotated with [Il2CppFinalizer] should return nothing", + messageFormat: "Method '{0}' is annotated with [Il2CppFinalizer] but does not return void.", + category: "Il2CppInterop", + defaultSeverity: DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public static DiagnosticDescriptor OnlyObjectPointerConstructorCanCallBase { get; } = new( + id: "IL2CPP0012", + title: "Only the ObjectPointer constructor can call a base constructor", + messageFormat: "Constructor in type '{0}' calls a base constructor, but only the ObjectPointer constructor is allowed to do so.", + category: "Il2CppInterop", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static DiagnosticDescriptor Il2CppFieldCannotBeStatic { get; } = new( + id: "IL2CPP0013", + title: "Static fields cannot be annotated with [Il2CppField]", + messageFormat: "Field '{0}' is static and cannot be annotated with [Il2CppField].", + category: "Il2CppInterop", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public static DiagnosticDescriptor InstanceFieldsInClassesCannotBeInjected { get; } = new( + id: "IL2CPP0014", + title: "Instance fields in classes cannot be annotated with [Il2CppField]", + messageFormat: "Field '{0}' in class '{1}' is an instance member annotated with [Il2CppField]. [Il2CppField] is only valid on properties in classes.", + category: "Il2CppInterop", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + public override ImmutableArray SupportedDiagnostics => [ MustBePartial, @@ -94,10 +134,15 @@ public sealed class InjectedTypePartialAnalyzer : DiagnosticAnalyzer CannotHaveStaticConstructor, CannotOverrideIl2CppFinalize, CannotHaveManagedFieldOnStructOrInterface, - CannotHaveIl2CppFieldOnStruct, + CannotHaveIl2CppFieldOnStructOrInterface, ManagedFieldMustBeInstance, FieldPropertyMustBePartial, - ShouldNotHaveUninjectedInstanceMembers, + ShouldNotHaveUninjectedInstanceFields, + Il2CppFinalizerMustHaveNoParameters, + Il2CppFinalizerShouldReturnVoid, + OnlyObjectPointerConstructorCanCallBase, + Il2CppFieldCannotBeStatic, + InstanceFieldsInClassesCannotBeInjected, ]; #endregion @@ -137,20 +182,29 @@ private static void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context) CheckNoStaticConstructor(context, tds, symbol); CheckNoIl2CppFinalizeOverride(context, tds, symbol); CheckNoManagedFieldOnStructOrInterface(context, tds, symbol); - CheckNoIl2CppFieldOnStruct(context, tds, symbol); + CheckNoIl2CppFieldOnStructOrInterface(context, tds, symbol); CheckManagedFieldMustBeInstance(context, tds); CheckFieldPropertiesMustBePartial(context, tds); CheckNoUninjectedInstanceMembers(context, tds, symbol); + CheckIl2CppFinalizerMethods(context, tds); + CheckConstructorsDoNotCallBase(context, tds, symbol); + CheckIl2CppFieldOnStaticProperties(context, tds); + CheckIl2CppFieldOnInstanceFieldsInClass(context, tds, symbol); } #endregion - #region Syntax Helpers + #region Helpers - private static bool HasAttribute(PropertyDeclarationSyntax prop, params string[] names) => - prop.AttributeLists - .SelectMany(al => al.Attributes) - .Any(a => names.Contains(a.Name.ToString())); + private static bool HasAttribute( + SyntaxNodeAnalysisContext context, + PropertyDeclarationSyntax prop, + string attributeName, + ReadOnlySpan attributeNamespace) + { + var symbol = context.SemanticModel.GetDeclaredSymbol(prop, context.CancellationToken); + return symbol?.HasAttribute(attributeName, attributeNamespace) ?? false; + } #endregion @@ -246,7 +300,7 @@ private static void CheckNoManagedFieldOnStructOrInterface( var offending = tds.Members .OfType() - .Where(p => HasAttribute(p, "ManagedField", "ManagedFieldAttribute")); + .Where(p => HasAttribute(context, p, "ManagedFieldAttribute", ["Il2CppInterop", "Common", "Attributes"])); foreach (var prop in offending) { @@ -259,24 +313,25 @@ private static void CheckNoManagedFieldOnStructOrInterface( } // IL2CPP0006 - private static void CheckNoIl2CppFieldOnStruct( + private static void CheckNoIl2CppFieldOnStructOrInterface( SyntaxNodeAnalysisContext context, TypeDeclarationSyntax tds, INamedTypeSymbol symbol) { - if (tds is not StructDeclarationSyntax) + if (tds is not (StructDeclarationSyntax or InterfaceDeclarationSyntax)) return; var offending = tds.Members .OfType() .Where(p => !p.Modifiers.Any(SyntaxKind.StaticKeyword) && - HasAttribute(p, "Il2CppField", "Il2CppFieldAttribute")); + HasAttribute(context, p, "Il2CppFieldAttribute", ["Il2CppInterop", "Common", "Attributes"])); foreach (var prop in offending) { context.ReportDiagnostic(Diagnostic.Create( - CannotHaveIl2CppFieldOnStruct, + CannotHaveIl2CppFieldOnStructOrInterface, prop.Identifier.GetLocation(), - symbol.Name)); + symbol.Name, + symbol.TypeKind == TypeKind.Struct ? "struct" : "interface")); } } @@ -288,7 +343,7 @@ private static void CheckManagedFieldMustBeInstance( .OfType() .Where(p => p.Modifiers.Any(SyntaxKind.StaticKeyword) && - HasAttribute(p, "ManagedField", "ManagedFieldAttribute")); + HasAttribute(context, p, "ManagedFieldAttribute", ["Il2CppInterop", "Common", "Attributes"])); foreach (var prop in offending) { @@ -309,22 +364,29 @@ private static void CheckFieldPropertiesMustBePartial( foreach (var prop in offending) { - var matchingAttr = prop.AttributeLists - .SelectMany(al => al.Attributes) - .FirstOrDefault(a => a.Name.ToString() is - "ManagedField" or "ManagedFieldAttribute" or - "Il2CppField" or "Il2CppFieldAttribute"); + var hasManagedField = HasAttribute(context, prop, "ManagedFieldAttribute", ["Il2CppInterop", "Common", "Attributes"]); + var hasIl2CppField = HasAttribute(context, prop, "Il2CppFieldAttribute", ["Il2CppInterop", "Common", "Attributes"]); - if (matchingAttr is null) + if (!hasManagedField && !hasIl2CppField) continue; - var attrName = matchingAttr.Name.ToString().Replace("Attribute", ""); + if (hasManagedField) + { + context.ReportDiagnostic(Diagnostic.Create( + FieldPropertyMustBePartial, + prop.Identifier.GetLocation(), + prop.Identifier.Text, + "ManagedField")); + } - context.ReportDiagnostic(Diagnostic.Create( - FieldPropertyMustBePartial, - prop.Identifier.GetLocation(), - prop.Identifier.Text, - attrName)); + if (hasIl2CppField) + { + context.ReportDiagnostic(Diagnostic.Create( + FieldPropertyMustBePartial, + prop.Identifier.GetLocation(), + prop.Identifier.Text, + "Il2CppField")); + } } } @@ -332,34 +394,124 @@ private static void CheckFieldPropertiesMustBePartial( private static void CheckNoUninjectedInstanceMembers( SyntaxNodeAnalysisContext context, TypeDeclarationSyntax tds, INamedTypeSymbol symbol) { - // Plain instance fields foreach (var field in tds.Members.OfType() .Where(f => !f.Modifiers.Any(SyntaxKind.StaticKeyword))) { foreach (var variable in field.Declaration.Variables) { context.ReportDiagnostic(Diagnostic.Create( - ShouldNotHaveUninjectedInstanceMembers, + ShouldNotHaveUninjectedInstanceFields, variable.Identifier.GetLocation(), symbol.Name, variable.Identifier.Text)); } } + } - // Instance properties without [ManagedField] or [Il2CppField] - foreach (var prop in tds.Members.OfType() - .Where(p => - !p.Modifiers.Any(SyntaxKind.StaticKeyword) && - !HasAttribute(p, "ManagedField", "ManagedFieldAttribute") && - !HasAttribute(p, "Il2CppField", "Il2CppFieldAttribute"))) + // IL2CPP0010 + IL2CPP0011 + private static void CheckIl2CppFinalizerMethods( + SyntaxNodeAnalysisContext context, TypeDeclarationSyntax tds) + { + var finalizerMethods = tds.Members + .OfType() + .Where(m => + { + var sym = context.SemanticModel.GetDeclaredSymbol(m, context.CancellationToken); + return sym?.HasAttribute("Il2CppFinalizerAttribute", ["Il2CppInterop", "Common", "Attributes"]) ?? false; + }); + + foreach (var method in finalizerMethods) + { + if (method.ParameterList.Parameters.Count > 0) + { + context.ReportDiagnostic(Diagnostic.Create( + Il2CppFinalizerMustHaveNoParameters, + method.Identifier.GetLocation(), + method.Identifier.Text)); + } + var methodSymbol = context.SemanticModel.GetDeclaredSymbol(method, context.CancellationToken); + if (methodSymbol?.ReturnType.SpecialType != SpecialType.System_Void) + { + context.ReportDiagnostic(Diagnostic.Create( + Il2CppFinalizerShouldReturnVoid, + method.ReturnType.GetLocation(), + method.Identifier.Text)); + } + } + } + + // IL2CPP0012 + private static void CheckConstructorsDoNotCallBase( + SyntaxNodeAnalysisContext context, TypeDeclarationSyntax tds, INamedTypeSymbol symbol) + { + var offending = tds.Members + .OfType() + .Where(c => + c.Initializer is { ThisOrBaseKeyword.RawKind: (int)SyntaxKind.BaseKeyword } && + !IsObjectPointerConstructor(context, c)); + + foreach (var ctor in offending) { context.ReportDiagnostic(Diagnostic.Create( - ShouldNotHaveUninjectedInstanceMembers, + OnlyObjectPointerConstructorCanCallBase, + ctor.Initializer!.GetLocation(), + symbol.Name)); + } + } + + private static bool IsObjectPointerConstructor(SyntaxNodeAnalysisContext context, ConstructorDeclarationSyntax ctor) + { + if (ctor.ParameterList.Parameters.Count != 1) + return false; + + var paramSyntax = ctor.ParameterList.Parameters[0]; + var paramSymbol = context.SemanticModel.GetDeclaredSymbol(paramSyntax, context.CancellationToken); + return (paramSymbol?.Type as INamedTypeSymbol).IsType("ObjectPointer", ["Il2CppInterop", "Common"]); + } + + // IL2CPP0013 + private static void CheckIl2CppFieldOnStaticProperties( + SyntaxNodeAnalysisContext context, TypeDeclarationSyntax tds) + { + var offending = tds.Members + .OfType() + .Where(p => + p.Modifiers.Any(SyntaxKind.StaticKeyword) && + HasAttribute(context, p, "Il2CppFieldAttribute", ["Il2CppInterop", "Common", "Attributes"])); + + foreach (var prop in offending) + { + context.ReportDiagnostic(Diagnostic.Create( + Il2CppFieldCannotBeStatic, prop.Identifier.GetLocation(), - symbol.Name, prop.Identifier.Text)); } } + // IL2CPP0014 + private static void CheckIl2CppFieldOnInstanceFieldsInClass( + SyntaxNodeAnalysisContext context, TypeDeclarationSyntax tds, INamedTypeSymbol symbol) + { + if (tds is not ClassDeclarationSyntax || symbol.TypeKind != TypeKind.Class) + return; + + foreach (var field in tds.Members.OfType() + .Where(f => !f.Modifiers.Any(SyntaxKind.StaticKeyword))) + { + foreach (var variable in field.Declaration.Variables) + { + var fieldSymbol = context.SemanticModel.GetDeclaredSymbol(variable, context.CancellationToken); + if (fieldSymbol?.HasAttribute("Il2CppFieldAttribute", ["Il2CppInterop", "Common", "Attributes"]) != true) + continue; + + context.ReportDiagnostic(Diagnostic.Create( + InstanceFieldsInClassesCannotBeInjected, + variable.Identifier.GetLocation(), + variable.Identifier.Text, + symbol.Name)); + } + } + } + #endregion } From 836c7f3e8d91e851a63ec1b8a51adf73b194031c Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Fri, 8 May 2026 16:11:17 -0700 Subject: [PATCH 404/486] Update AssetRipper.Cpp2IL.Core to version 1.0.3 Upgraded the AssetRipper.Cpp2IL.Core NuGet package from version 1.0.2 to 1.0.3 to incorporate the latest improvements and fixes. No other project changes were made. --- Il2CppInterop.Generator/Il2CppInterop.Generator.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index e2baeb85..1b47be71 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -13,7 +13,7 @@ - + all From 8066b080cd917ae76578952b5ab9ded16ae1a7e3 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Fri, 8 May 2026 16:23:55 -0700 Subject: [PATCH 405/486] Formatting --- Il2CppInterop.SourceGenerator/InjectedTypePartialAnalyzer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Il2CppInterop.SourceGenerator/InjectedTypePartialAnalyzer.cs b/Il2CppInterop.SourceGenerator/InjectedTypePartialAnalyzer.cs index 68f6ce78..bfc1d150 100644 --- a/Il2CppInterop.SourceGenerator/InjectedTypePartialAnalyzer.cs +++ b/Il2CppInterop.SourceGenerator/InjectedTypePartialAnalyzer.cs @@ -200,7 +200,7 @@ private static bool HasAttribute( SyntaxNodeAnalysisContext context, PropertyDeclarationSyntax prop, string attributeName, - ReadOnlySpan attributeNamespace) + ReadOnlySpan attributeNamespace) { var symbol = context.SemanticModel.GetDeclaredSymbol(prop, context.CancellationToken); return symbol?.HasAttribute(attributeName, attributeNamespace) ?? false; From 915fd77889fdae58af7685628656ba75b449d8e4 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Fri, 8 May 2026 21:54:15 -0700 Subject: [PATCH 406/486] Add empty processing layer for system interfaces --- Il2CppInterop.CLI/Program.cs | 3 +-- .../SystemInterfaceProcessingLayer.cs | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs diff --git a/Il2CppInterop.CLI/Program.cs b/Il2CppInterop.CLI/Program.cs index e0362eb7..b1b9f3b2 100644 --- a/Il2CppInterop.CLI/Program.cs +++ b/Il2CppInterop.CLI/Program.cs @@ -51,7 +51,7 @@ new DelegateConversionProcessingLayer(), new ByRefParameterOverloadProcessingLayer(), new UserFriendlyOverloadProcessingLayer(), - // new SystemInterfaceRecoveryProcessingLayer(), // Should handle INotifyCompletion, IEnumerable, IEquatable, etc + new SystemInterfaceProcessingLayer(), new ConstantInitializationProcessingLayer(), new StaticConstructorProcessingLayer(), ], @@ -62,6 +62,5 @@ Todo - System interfaces - overloads with delegates, primitives -- Source generation for user-injected types - Add attributes to "Unsafe" methods so that users cannot see them */ diff --git a/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs b/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs new file mode 100644 index 00000000..65e7c217 --- /dev/null +++ b/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs @@ -0,0 +1,14 @@ +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +public sealed class SystemInterfaceProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "System Interface Implementations"; + public override string Id => "system_interface_implementations"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + // Should handle INotifyCompletion, IEnumerable, IEquatable, etc + } +} From bfb41b0097b5ce2dba36107edcf08fe47e5c6f01 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Fri, 8 May 2026 22:38:38 -0700 Subject: [PATCH 407/486] Replace comments with Debug.Fail calls --- .../MscorlibAssemblyInjectionProcessingLayer.cs | 4 +++- Il2CppInterop.Generator/TranslatedMethodBody.cs | 10 ++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs b/Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs index 5da6d3a5..b0eae145 100644 --- a/Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs +++ b/Il2CppInterop.Generator/MscorlibAssemblyInjectionProcessingLayer.cs @@ -1,4 +1,5 @@ -using AsmResolver.DotNet; +using System.Diagnostics; +using AsmResolver.DotNet; using Cpp2IL.Core.Logging; using Cpp2IL.Core.Model.Contexts; @@ -78,6 +79,7 @@ private sealed class AssemblyResolver : IAssemblyResolver { public ResolutionStatus Resolve(AssemblyDescriptor assembly, ModuleDefinition? originModule, out AssemblyDefinition? result) { + Debug.Fail("Resolution of external assemblies should not be necessary."); result = null; return ResolutionStatus.AssemblyNotFound; } diff --git a/Il2CppInterop.Generator/TranslatedMethodBody.cs b/Il2CppInterop.Generator/TranslatedMethodBody.cs index 1e11ba6b..1feaab72 100644 --- a/Il2CppInterop.Generator/TranslatedMethodBody.cs +++ b/Il2CppInterop.Generator/TranslatedMethodBody.cs @@ -786,7 +786,7 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo } else { - // This should not happen + Debug.Fail("This should not happen"); return false; } } @@ -942,6 +942,7 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo if (!operandIsReferenceType) { + Debug.Fail("Operand was unexpectedly not a reference type."); return false; } @@ -969,7 +970,7 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo } else { - // This should not occur. + Debug.Fail("This should not occur."); return false; } @@ -1002,7 +1003,7 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo Debug.Assert(!baseField.IsStatic, "There should be no static fields."); Debug.Assert(baseField.FieldType.DeclaringAssembly == appContext.Mscorlib); - // This should not occur because the primitive fields are readonly. + Debug.Fail("Unexpected store to a primitive field because the primitive fields are readonly."); return false; } else if (baseField.DeclaringType.Fields.Contains(baseField)) @@ -1025,7 +1026,7 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo } else { - // This should not occur. + Debug.Fail("This should not occur."); return false; } } @@ -1120,6 +1121,7 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo } else { + Debug.Fail($"Unexpected operand type: {originalInstruction.Operand?.GetType().Name}"); return false; } } From 543fb90e7d10869d80da107ee34b786b942150c4 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Fri, 8 May 2026 23:45:35 -0700 Subject: [PATCH 408/486] Move GetFullyQualifiedName to TypeInjector --- Il2CppInterop.Common/Il2CppType.cs | 5 ----- Il2CppInterop.Runtime/Injection/TypeInjector.cs | 8 +++++++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Il2CppInterop.Common/Il2CppType.cs b/Il2CppInterop.Common/Il2CppType.cs index 1ec546fd..057d39f6 100644 --- a/Il2CppInterop.Common/Il2CppType.cs +++ b/Il2CppInterop.Common/Il2CppType.cs @@ -64,11 +64,6 @@ public static string GetName() where T : IIl2CppType return T.Name; } - public static (string AssemblyName, string Namespace, string Name) GetFullyQualifiedName() where T : IIl2CppType - { - return (T.AssemblyName, T.Namespace, T.Name); - } - public static void WriteToSpan(this T? value, Span span) where T : IIl2CppType { T.WriteToSpan(value, span); diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 31c4d576..a2448acd 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -1402,11 +1402,17 @@ private static TNative ConvertManagedToNative(TManaged? value private static (string AssemblyName, string Namespace, string Name) GetFullyQualifiedName(Type type) { - return typeof(Il2CppType).GetMethod(nameof(Il2CppType.GetFullyQualifiedName))!.MakeGenericMethod(type).Invoke(null, null) is ValueTuple result + var methodInfo = typeof(TypeInjector).GetMethod(nameof(GetFullyQualifiedNameGeneric), BindingFlags.NonPublic | BindingFlags.Static)!.MakeGenericMethod(type); + return methodInfo.Invoke(null, null) is ValueTuple result ? result : throw new InvalidOperationException("GetFullyQualifiedName should return a ValueTuple"); } + private static (string AssemblyName, string Namespace, string Name) GetFullyQualifiedNameGeneric() where T : IIl2CppType + { + return (T.AssemblyName, T.Namespace, T.Name); + } + private static Il2CppClassAttributes TypeAttributesToClassAttributes(TypeAttributes typeAttributes) { Il2CppClassAttributes result = default; From 5f3acdedb268483ad916b1da1a1ac0cfe46fe017 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 9 May 2026 10:38:21 -0700 Subject: [PATCH 409/486] Performance improvements for ContextResolver --- Il2CppInterop.Generator/ContextResolver.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Il2CppInterop.Generator/ContextResolver.cs b/Il2CppInterop.Generator/ContextResolver.cs index 37abd641..9d72f8e9 100644 --- a/Il2CppInterop.Generator/ContextResolver.cs +++ b/Il2CppInterop.Generator/ContextResolver.cs @@ -125,8 +125,7 @@ public bool TryResolve(TypeSignature? type, [NotNullWhen(true)] out TypeAnalysis if (assemblyName == null) return null; - var targetAssembly = referencedFrom.AppContext.Assemblies.FirstOrDefault(a => a.Name == assemblyName); - if (targetAssembly == null) + if (!referencedFrom.AppContext.AssembliesByName.TryGetValue(assemblyName, out var targetAssembly)) return null; return targetAssembly.GetTypeByFullName(typeDefOrRef.FullName); @@ -277,9 +276,6 @@ public bool TryResolve(IMethodDescriptor methodDescriptor, [NotNullWhen(true)] o foreach (var methodContext in referencingType.Methods) { - if (methodContext.Name != methodDefOrRef.Name) - continue; - if (methodContext.Parameters.Count != methodDefOrRef.Signature.ParameterTypes.Count) continue; @@ -292,6 +288,9 @@ public bool TryResolve(IMethodDescriptor methodDescriptor, [NotNullWhen(true)] o if (methodContext.IsVoid == methodDefOrRef.Signature.ReturnsValue) continue; + if (methodContext.Name != (string?)methodDefOrRef.Name) + continue; + // We need to use a resolver for the method context to resolve potential method generic parameters correctly. var methodResolver = new ContextResolver(methodContext, runtimeContext); From fb6e736e970919dc6cca47a829b60afebffa6589 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 9 May 2026 10:41:56 -0700 Subject: [PATCH 410/486] Rename Il2CppInteropUtils -> Il2CppInternalsAccess --- .../{Il2CppInteropUtils.cs => Il2CppInternalsAccess.cs} | 2 +- Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs | 2 +- Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs | 4 ++-- Il2CppInterop.Runtime/Injection/InjectorHelpers.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename Il2CppInterop.Common/{Il2CppInteropUtils.cs => Il2CppInternalsAccess.cs} (97%) diff --git a/Il2CppInterop.Common/Il2CppInteropUtils.cs b/Il2CppInterop.Common/Il2CppInternalsAccess.cs similarity index 97% rename from Il2CppInterop.Common/Il2CppInteropUtils.cs rename to Il2CppInterop.Common/Il2CppInternalsAccess.cs index 956373d4..e50f367b 100644 --- a/Il2CppInterop.Common/Il2CppInteropUtils.cs +++ b/Il2CppInterop.Common/Il2CppInternalsAccess.cs @@ -3,7 +3,7 @@ namespace Il2CppInterop.Common; -public static class Il2CppInteropUtils +public static class Il2CppInternalsAccess { private static FieldInfo? GetFieldInfo(Type declaringType, string prefix, int index) { diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs index 4ed6d674..a8b4c082 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs @@ -126,7 +126,7 @@ private MethodInfo ProcessPointerPatchedLeaf(MethodReference leafRef) cursor.Goto(0) .GotoNext(x => - x.MatchLdsfld(Il2CppInteropUtils + x.MatchLdsfld(Il2CppInternalsAccess .GetIl2CppMethodInfoPointerFieldForGeneratedMethod(Source)!)) .Remove(); diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs index 75263cb8..6c5f539b 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs @@ -34,11 +34,11 @@ private static bool TryCreateDetour(CreateDetourRequest request, [NotNullWhen(tr throw new InvalidOperationException("IDetourFactory consumer has to support CreateSourceCloneIfNotILClone"); } - var methodField = Il2CppInteropUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(request.Source); + var methodField = Il2CppInternalsAccess.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(request.Source); if (methodField == null) { - var fieldInfoField = Il2CppInteropUtils.GetIl2CppFieldInfoPointerFieldForGeneratedFieldAccessor(request.Source); + var fieldInfoField = Il2CppInternalsAccess.GetIl2CppFieldInfoPointerFieldForGeneratedFieldAccessor(request.Source); if (fieldInfoField != null) { diff --git a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs index 6513ffbf..e9ede516 100644 --- a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs +++ b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs @@ -68,7 +68,7 @@ internal static IntPtr GetIl2CppMethodPointer(MethodBase? proxyMethod) { if (proxyMethod == null) return IntPtr.Zero; - var methodInfoPointerField = Il2CppInteropUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(proxyMethod) + var methodInfoPointerField = Il2CppInternalsAccess.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(proxyMethod) ?? throw new ArgumentException($"Couldn't find the generated method info pointer for {proxyMethod.Name}"); // Il2CppClassPointerStore calls the static constructor for the type From 4310a38b957836928c8895b1c7d46eb162f1bd6a Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 9 May 2026 10:43:28 -0700 Subject: [PATCH 411/486] Rename source generator types --- Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs | 2 +- Il2CppInterop.SourceGenerator.Tests/SimpleAnalyzerTests.cs | 2 +- Il2CppInterop.SourceGenerator.Tests/SourceGenerationTests.cs | 4 ++-- ...InjectedTypePartialAnalyzer.cs => InjectedTypeAnalyzer.cs} | 2 +- .../{Il2CppTypeGenerator.cs => InjectedTypeGenerator.cs} | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) rename Il2CppInterop.SourceGenerator/{InjectedTypePartialAnalyzer.cs => InjectedTypeAnalyzer.cs} (99%) rename Il2CppInterop.SourceGenerator/{Il2CppTypeGenerator.cs => InjectedTypeGenerator.cs} (99%) diff --git a/Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs b/Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs index 87d111f2..bb437a67 100644 --- a/Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs +++ b/Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs @@ -7,7 +7,7 @@ namespace Il2CppInterop.SourceGenerator.Tests; public abstract class AnalyzerTests { - protected CSharpAnalyzerTest Context { get; private set; } + protected CSharpAnalyzerTest Context { get; private set; } [SetUp] public void Setup() diff --git a/Il2CppInterop.SourceGenerator.Tests/SimpleAnalyzerTests.cs b/Il2CppInterop.SourceGenerator.Tests/SimpleAnalyzerTests.cs index a8a65c5e..e1f78a72 100644 --- a/Il2CppInterop.SourceGenerator.Tests/SimpleAnalyzerTests.cs +++ b/Il2CppInterop.SourceGenerator.Tests/SimpleAnalyzerTests.cs @@ -16,7 +16,7 @@ public class Sample : Il2CppSystem.Object } """; - var expectedDiagnostic = new DiagnosticResult(InjectedTypePartialAnalyzer.MustBePartial) + var expectedDiagnostic = new DiagnosticResult(InjectedTypeAnalyzer.MustBePartial) .WithSpan(LinePositionSpan.FindInSource(testCode, "Sample")) .WithArguments("Sample"); diff --git a/Il2CppInterop.SourceGenerator.Tests/SourceGenerationTests.cs b/Il2CppInterop.SourceGenerator.Tests/SourceGenerationTests.cs index 08df653b..b7dc796a 100644 --- a/Il2CppInterop.SourceGenerator.Tests/SourceGenerationTests.cs +++ b/Il2CppInterop.SourceGenerator.Tests/SourceGenerationTests.cs @@ -9,7 +9,7 @@ namespace Il2CppInterop.SourceGenerator.Tests; public abstract class SourceGenerationTests { - protected CSharpSourceGeneratorTest Context { get; private set; } + protected CSharpSourceGeneratorTest Context { get; private set; } [SetUp] public void Setup() @@ -26,7 +26,7 @@ public void Setup() protected async Task TestGeneration(string testCode, string expectedFileName, string expectedGeneratedCode) { Context.TestCode = testCode; - Context.TestState.GeneratedSources.Add((typeof(Il2CppTypeGenerator), expectedFileName, SourceText.From(expectedGeneratedCode.Replace("\r", null), Encoding.UTF8, SourceHashAlgorithm.Sha256))); + Context.TestState.GeneratedSources.Add((typeof(InjectedTypeGenerator), expectedFileName, SourceText.From(expectedGeneratedCode.Replace("\r", null), Encoding.UTF8, SourceHashAlgorithm.Sha256))); await Context.RunAsync(TestContext.CurrentContext.CancellationToken); } } diff --git a/Il2CppInterop.SourceGenerator/InjectedTypePartialAnalyzer.cs b/Il2CppInterop.SourceGenerator/InjectedTypeAnalyzer.cs similarity index 99% rename from Il2CppInterop.SourceGenerator/InjectedTypePartialAnalyzer.cs rename to Il2CppInterop.SourceGenerator/InjectedTypeAnalyzer.cs index bfc1d150..604b83c5 100644 --- a/Il2CppInterop.SourceGenerator/InjectedTypePartialAnalyzer.cs +++ b/Il2CppInterop.SourceGenerator/InjectedTypeAnalyzer.cs @@ -7,7 +7,7 @@ namespace Il2CppInterop.SourceGenerator; [DiagnosticAnalyzer(LanguageNames.CSharp)] -public sealed class InjectedTypePartialAnalyzer : DiagnosticAnalyzer +public sealed class InjectedTypeAnalyzer : DiagnosticAnalyzer { #region Diagnostic Descriptors diff --git a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs b/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs similarity index 99% rename from Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs rename to Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs index 5719dad3..fdd061a3 100644 --- a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs +++ b/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs @@ -6,7 +6,7 @@ namespace Il2CppInterop.SourceGenerator; [Generator] -public sealed class Il2CppTypeGenerator : IIncrementalGenerator +public sealed class InjectedTypeGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { From d35b61cee5c5e543436d5670f78bb55d884c9272 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 9 May 2026 11:24:50 -0700 Subject: [PATCH 412/486] Add static Null property to ByReference and Pointer Introduced a static Null property for both ByReference and Pointer structs. This provides a convenient way to create null instances of these types, improving code clarity and safety when handling null references. --- Il2CppInterop.Runtime/InteropTypes/ByReference.cs | 1 + Il2CppInterop.Runtime/InteropTypes/Pointer.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/Il2CppInterop.Runtime/InteropTypes/ByReference.cs b/Il2CppInterop.Runtime/InteropTypes/ByReference.cs index 979d4f7a..b344900b 100644 --- a/Il2CppInterop.Runtime/InteropTypes/ByReference.cs +++ b/Il2CppInterop.Runtime/InteropTypes/ByReference.cs @@ -36,6 +36,7 @@ public readonly unsafe struct ByReference(void* pointer) : IIl2CppType Null => new(null); public readonly bool IsNull => _pointer is null; public readonly T? GetValue() diff --git a/Il2CppInterop.Runtime/InteropTypes/Pointer.cs b/Il2CppInterop.Runtime/InteropTypes/Pointer.cs index 96a01727..18cae2a8 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Pointer.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Pointer.cs @@ -9,6 +9,7 @@ public readonly unsafe struct Pointer(void* pointer) : IIl2CppType { private readonly void* _pointer = pointer; + public static Pointer Null => new(null); public readonly bool IsNull => _pointer is null; public readonly T? this[int index] From 16b63da3588aee01f02321cd7166b06001c48d26 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 9 May 2026 15:17:11 -0700 Subject: [PATCH 413/486] Minor comments and changes --- Il2CppInterop.Runtime/FieldAccess.cs | 3 +++ Il2CppInterop.Runtime/GenerationInternals.cs | 1 - Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs | 2 ++ .../Runtime/ApplicableToUnityVersionsSinceAttribute.cs | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Il2CppInterop.Runtime/FieldAccess.cs b/Il2CppInterop.Runtime/FieldAccess.cs index d206152c..821cd598 100644 --- a/Il2CppInterop.Runtime/FieldAccess.cs +++ b/Il2CppInterop.Runtime/FieldAccess.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using System.Runtime.InteropServices; using Il2CppInterop.Common; using Microsoft.Extensions.Logging; @@ -42,6 +43,7 @@ public static void SetInstanceFieldValue(Object instance, int fieldOffset, T? FunctionPointerCache.SetInstanceFieldValue(instance, fieldOffset, value); } + [EditorBrowsable(EditorBrowsableState.Never)] public static void SetInstanceFieldValue_WriteBarrier(Object instance, int fieldOffset, T? value) where T : IIl2CppType { ArgumentOutOfRangeException.ThrowIfNegative(fieldOffset); @@ -56,6 +58,7 @@ public static void SetInstanceFieldValue_WriteBarrier(Object instance, int fi } } + [EditorBrowsable(EditorBrowsableState.Never)] public static void SetInstanceFieldValue_Pointer(Object instance, int fieldOffset, T? value) where T : IIl2CppType { ArgumentOutOfRangeException.ThrowIfNegative(fieldOffset); diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index d6ffa4c8..c0a8e839 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -1,6 +1,5 @@ using System; using System.ComponentModel; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using Il2CppInterop.Common; diff --git a/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs b/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs index 64d84ac8..0907325a 100644 --- a/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs +++ b/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs @@ -14,6 +14,8 @@ internal static nint InflateGenericType(nint genericClassPointer, nint[] generic private static nint InflateGenericType(INativeClassStruct genericClassPointer, nint[] genericArgClassPtrs) { + // This is an extremely naive implementation of generic type inflation and likely breaks the moment someone touches an inflated type. + var inflatedClassPointer = UnityVersionHandler.NewClass(genericClassPointer.VTableCount); CopyFrom(inflatedClassPointer.ByValArg, genericClassPointer.ByValArg); diff --git a/Il2CppInterop.Runtime/Runtime/ApplicableToUnityVersionsSinceAttribute.cs b/Il2CppInterop.Runtime/Runtime/ApplicableToUnityVersionsSinceAttribute.cs index 22fde8ba..9b2ab056 100644 --- a/Il2CppInterop.Runtime/Runtime/ApplicableToUnityVersionsSinceAttribute.cs +++ b/Il2CppInterop.Runtime/Runtime/ApplicableToUnityVersionsSinceAttribute.cs @@ -3,7 +3,7 @@ namespace Il2CppInterop.Runtime.Runtime; [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] -internal class ApplicableToUnityVersionsSinceAttribute : Attribute +internal sealed class ApplicableToUnityVersionsSinceAttribute : Attribute { public ApplicableToUnityVersionsSinceAttribute(string startVersion) { From 627a63d130ba9b5ce9d64bcbba31886e34f31c74 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 9 May 2026 15:29:50 -0700 Subject: [PATCH 414/486] Make INativeStructHandler::Size a property --- .../Runtime/INativeStructHandler.cs | 2 +- .../Runtime/UnityVersionHandler.cs | 24 +++++++++---------- .../Assembly/Assembly_104_0.cs | 4 ++-- .../VersionSpecific/Assembly/Assembly_16_0.cs | 4 ++-- .../VersionSpecific/Assembly/Assembly_20_0.cs | 4 ++-- .../VersionSpecific/Assembly/Assembly_24_0.cs | 4 ++-- .../VersionSpecific/Assembly/Assembly_24_1.cs | 4 ++-- .../VersionSpecific/Assembly/Assembly_24_2.cs | 4 ++-- .../AssemblyName/AssemblyName_16_0.cs | 4 ++-- .../AssemblyName/AssemblyName_24_0.cs | 4 ++-- .../AssemblyName/AssemblyName_24_1.cs | 4 ++-- .../VersionSpecific/Class/Class_104_0.cs | 4 ++-- .../VersionSpecific/Class/Class_105_0.cs | 4 ++-- .../VersionSpecific/Class/Class_16_0.cs | 4 ++-- .../VersionSpecific/Class/Class_19_0.cs | 4 ++-- .../VersionSpecific/Class/Class_20_0.cs | 4 ++-- .../VersionSpecific/Class/Class_21_0.cs | 4 ++-- .../VersionSpecific/Class/Class_21_1.cs | 4 ++-- .../VersionSpecific/Class/Class_21_2.cs | 4 ++-- .../VersionSpecific/Class/Class_22_0.cs | 4 ++-- .../VersionSpecific/Class/Class_22_1.cs | 4 ++-- .../VersionSpecific/Class/Class_23_0.cs | 4 ++-- .../VersionSpecific/Class/Class_23_1.cs | 4 ++-- .../VersionSpecific/Class/Class_24_0.cs | 4 ++-- .../VersionSpecific/Class/Class_24_1.cs | 4 ++-- .../VersionSpecific/Class/Class_24_2.cs | 4 ++-- .../VersionSpecific/Class/Class_24_3.cs | 4 ++-- .../VersionSpecific/Class/Class_24_4.cs | 4 ++-- .../VersionSpecific/Class/Class_24_5.cs | 4 ++-- .../VersionSpecific/Class/Class_24_6.cs | 4 ++-- .../VersionSpecific/Class/Class_24_7.cs | 4 ++-- .../VersionSpecific/Class/Class_27_0.cs | 4 ++-- .../VersionSpecific/Class/Class_27_1.cs | 4 ++-- .../VersionSpecific/Class/Class_27_2.cs | 4 ++-- .../VersionSpecific/Class/Class_27_3.cs | 4 ++-- .../VersionSpecific/Class/Class_27_4.cs | 4 ++-- .../VersionSpecific/Class/Class_27_5.cs | 4 ++-- .../VersionSpecific/Class/Class_29_0.cs | 4 ++-- .../VersionSpecific/Class/Class_29_1.cs | 4 ++-- .../VersionSpecific/Class/Class_29_2.cs | 4 ++-- .../VersionSpecific/Class/Class_39_0.cs | 4 ++-- .../EventInfo/EventInfo_16_0.cs | 4 ++-- .../EventInfo/EventInfo_19_0.cs | 4 ++-- .../EventInfo/EventInfo_24_0.cs | 4 ++-- .../Exception/Exception_16_0.cs | 4 ++-- .../Exception/Exception_20_0.cs | 4 ++-- .../Exception/Exception_21_0.cs | 4 ++-- .../Exception/Exception_22_0.cs | 4 ++-- .../Exception/Exception_23_0.cs | 4 ++-- .../Exception/Exception_23_1.cs | 4 ++-- .../Exception/Exception_27_0.cs | 4 ++-- .../FieldInfo/FieldInfo_16_0.cs | 4 ++-- .../FieldInfo/FieldInfo_19_0.cs | 4 ++-- .../FieldInfo/FieldInfo_24_0.cs | 4 ++-- .../VersionSpecific/Image/Image_16_0.cs | 4 ++-- .../VersionSpecific/Image/Image_19_0.cs | 4 ++-- .../VersionSpecific/Image/Image_24_0.cs | 4 ++-- .../VersionSpecific/Image/Image_24_1.cs | 4 ++-- .../VersionSpecific/Image/Image_24_2.cs | 4 ++-- .../VersionSpecific/Image/Image_24_3.cs | 4 ++-- .../VersionSpecific/Image/Image_24_4.cs | 4 ++-- .../VersionSpecific/Image/Image_24_5.cs | 4 ++-- .../VersionSpecific/Image/Image_24_6.cs | 4 ++-- .../MethodInfo/MethodInfo_16_0.cs | 4 ++-- .../MethodInfo/MethodInfo_21_0.cs | 4 ++-- .../MethodInfo/MethodInfo_24_0.cs | 4 ++-- .../MethodInfo/MethodInfo_24_1.cs | 4 ++-- .../MethodInfo/MethodInfo_24_2.cs | 4 ++-- .../MethodInfo/MethodInfo_27_0.cs | 4 ++-- .../MethodInfo/MethodInfo_28_0.cs | 4 ++-- .../MethodInfo/MethodInfo_29_0.cs | 4 ++-- .../MethodInfo/MethodInfo_29_1.cs | 4 ++-- .../MethodInfo/MethodInfo_29_2.cs | 4 ++-- .../ParameterInfo/ParameterInfo_16_0.cs | 4 ++-- .../ParameterInfo/ParameterInfo_24_0.cs | 4 ++-- .../ParameterInfo/ParameterInfo_27_0.cs | 4 ++-- .../PropertyInfo/PropertyInfo_16_0.cs | 4 ++-- .../PropertyInfo/PropertyInfo_19_0.cs | 4 ++-- .../PropertyInfo/PropertyInfo_24_0.cs | 4 ++-- .../Runtime/VersionSpecific/Type/Type_16_0.cs | 4 ++-- .../Runtime/VersionSpecific/Type/Type_27_0.cs | 4 ++-- .../StructHandlerGenerator.cs | 6 ++--- .../TypeGenerators/Il2CppClassGenerator.cs | 2 +- 83 files changed, 175 insertions(+), 175 deletions(-) diff --git a/Il2CppInterop.Runtime/Runtime/INativeStructHandler.cs b/Il2CppInterop.Runtime/Runtime/INativeStructHandler.cs index bb32ce3a..38b9e28f 100644 --- a/Il2CppInterop.Runtime/Runtime/INativeStructHandler.cs +++ b/Il2CppInterop.Runtime/Runtime/INativeStructHandler.cs @@ -2,5 +2,5 @@ public interface INativeStructHandler { - public int Size(); + public int Size { get; } } diff --git a/Il2CppInterop.Runtime/Runtime/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Runtime/UnityVersionHandler.cs index c3256fee..56228cd1 100644 --- a/Il2CppInterop.Runtime/Runtime/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Runtime/UnityVersionHandler.cs @@ -128,7 +128,7 @@ public static unsafe INativeAssemblyStruct Wrap(Il2CppAssembly* assemblyPointer) public static int AssemblySize() { - return assemblyStructHandler.Size(); + return assemblyStructHandler.Size; } //Assembly Names @@ -144,7 +144,7 @@ public static unsafe INativeAssemblyNameStruct Wrap(Il2CppAssemblyName* assembly public static int AssemblyNameSize() { - return assemblyNameStructHandler.Size(); + return assemblyNameStructHandler.Size; } //Classes @@ -160,7 +160,7 @@ public static unsafe INativeClassStruct Wrap(Il2CppClass* classPointer) public static int ClassSize() { - return classStructHandler.Size(); + return classStructHandler.Size; } //Events @@ -176,7 +176,7 @@ public static unsafe INativeEventInfoStruct Wrap(Il2CppEventInfo* eventInfoPoint public static int EventSize() { - return eventInfoStructHandler.Size(); + return eventInfoStructHandler.Size; } //Exceptions @@ -192,7 +192,7 @@ public static unsafe INativeExceptionStruct Wrap(Il2CppException* exceptionPoint public static int ExceptionSize() { - return exceptionStructHandler.Size(); + return exceptionStructHandler.Size; } //Fields @@ -208,7 +208,7 @@ public static unsafe INativeFieldInfoStruct Wrap(Il2CppFieldInfo* fieldInfoPoint public static int FieldInfoSize() { - return fieldInfoStructHandler.Size(); + return fieldInfoStructHandler.Size; } //Images @@ -224,7 +224,7 @@ public static unsafe INativeImageStruct Wrap(Il2CppImage* imagePointer) public static int ImageSize() { - return imageStructHandler.Size(); + return imageStructHandler.Size; } //Methods @@ -240,7 +240,7 @@ public static unsafe INativeMethodInfoStruct Wrap(Il2CppMethodInfo* methodPointe public static int MethodSize() { - return methodInfoStructHandler.Size(); + return methodInfoStructHandler.Size; } //Parameters @@ -249,7 +249,7 @@ public static int MethodSize() if (count == 0) return []; - var elementSize = parameterInfoStructHandler.Size(); + var elementSize = parameterInfoStructHandler.Size; var totalSize = elementSize * count; var startPointer = Marshal.AllocHGlobal(totalSize); new Span(startPointer.ToPointer(), totalSize).Clear(); @@ -268,7 +268,7 @@ public static unsafe INativeParameterInfoStruct Wrap(Il2CppParameterInfo* parame public static unsafe INativeParameterInfoStruct Wrap(Il2CppParameterInfo* parameterInfo, int index) { - var address = (nint)parameterInfo + index * parameterInfoStructHandler.Size(); + var address = (nint)parameterInfo + index * parameterInfoStructHandler.Size; return parameterInfoStructHandler.Wrap((Il2CppParameterInfo*)address); } @@ -285,7 +285,7 @@ public static unsafe INativePropertyInfoStruct Wrap(Il2CppPropertyInfo* property public static int ParameterInfoSize() { - return parameterInfoStructHandler.Size(); + return parameterInfoStructHandler.Size; } //Types @@ -301,6 +301,6 @@ public static unsafe INativeTypeStruct Wrap(Il2CppTypeStruct* typePointer) public static int TypeSize() { - return typeStructHandler.Size(); + return typeStructHandler.Size; } } diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_104_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_104_0.cs index ca109c73..45309b36 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_104_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_104_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly [ApplicableToUnityVersionsSince("6000.5.0")] public unsafe class NativeAssemblyStructHandler_104_0 : INativeAssemblyStructHandler { - public int Size() => sizeof(Il2CppAssembly_104_0); public INativeAssemblyStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppAssembly_104_0* _ = (Il2CppAssembly_104_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeAssemblyStruct Wrap(Il2CppAssembly* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppAssembly_104_0); internal unsafe struct Il2CppAssembly_104_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_16_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_16_0.cs index a57d78e9..a00853b6 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_16_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_16_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeAssemblyStructHandler_16_0 : INativeAssemblyStructHandler { - public int Size() => sizeof(Il2CppAssembly_16_0); public INativeAssemblyStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppAssembly_16_0* _ = (Il2CppAssembly_16_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeAssemblyStruct Wrap(Il2CppAssembly* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppAssembly_16_0); internal unsafe struct Il2CppAssembly_16_0 { public int imageIndex; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_20_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_20_0.cs index 91c7d673..666174ca 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_20_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_20_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly [ApplicableToUnityVersionsSince("5.3.2p1")] public unsafe class NativeAssemblyStructHandler_20_0 : INativeAssemblyStructHandler { - public int Size() => sizeof(Il2CppAssembly_20_0); public INativeAssemblyStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppAssembly_20_0* _ = (Il2CppAssembly_20_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeAssemblyStruct Wrap(Il2CppAssembly* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppAssembly_20_0); internal unsafe struct Il2CppAssembly_20_0 { public int imageIndex; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_0.cs index 28e6c5a2..3f414bed 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeAssemblyStructHandler_24_0 : INativeAssemblyStructHandler { - public int Size() => sizeof(Il2CppAssembly_24_0); public INativeAssemblyStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppAssembly_24_0* _ = (Il2CppAssembly_24_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeAssemblyStruct Wrap(Il2CppAssembly* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppAssembly_24_0); internal unsafe struct Il2CppAssembly_24_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_1.cs index f480124d..cd802be4 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_1.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeAssemblyStructHandler_24_1 : INativeAssemblyStructHandler { - public int Size() => sizeof(Il2CppAssembly_24_1); public INativeAssemblyStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppAssembly_24_1* _ = (Il2CppAssembly_24_1*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeAssemblyStruct Wrap(Il2CppAssembly* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppAssembly_24_1); internal unsafe struct Il2CppAssembly_24_1 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_2.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_2.cs index 3b750592..ccc54b09 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_2.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_2.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly [ApplicableToUnityVersionsSince("2018.4.34")] public unsafe class NativeAssemblyStructHandler_24_2 : INativeAssemblyStructHandler { - public int Size() => sizeof(Il2CppAssembly_24_2); public INativeAssemblyStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppAssembly_24_2* _ = (Il2CppAssembly_24_2*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeAssemblyStruct Wrap(Il2CppAssembly* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppAssembly_24_2); internal unsafe struct Il2CppAssembly_24_2 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_16_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_16_0.cs index e785a1ff..c09158e0 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_16_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_16_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeAssemblyNameStructHandler_16_0 : INativeAssemblyNameStructHandler { - public int Size() => sizeof(Il2CppAssemblyName_16_0); public INativeAssemblyNameStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppAssemblyName_16_0* _ = (Il2CppAssemblyName_16_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeAssemblyNameStruct Wrap(Il2CppAssemblyName* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppAssemblyName_16_0); internal unsafe struct Il2CppAssemblyName_16_0 { public int nameIndex; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_0.cs index 105b14fd..04206b4d 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeAssemblyNameStructHandler_24_0 : INativeAssemblyNameStructHandler { - public int Size() => sizeof(Il2CppAssemblyName_24_0); public INativeAssemblyNameStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppAssemblyName_24_0* _ = (Il2CppAssemblyName_24_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeAssemblyNameStruct Wrap(Il2CppAssemblyName* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppAssemblyName_24_0); internal unsafe struct Il2CppAssemblyName_24_0 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_1.cs index 7a421498..eb68332b 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_1.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName [ApplicableToUnityVersionsSince("2018.4.34")] public unsafe class NativeAssemblyNameStructHandler_24_1 : INativeAssemblyNameStructHandler { - public int Size() => sizeof(Il2CppAssemblyName_24_1); public INativeAssemblyNameStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppAssemblyName_24_1* _ = (Il2CppAssemblyName_24_1*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeAssemblyNameStruct Wrap(Il2CppAssemblyName* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppAssemblyName_24_1); internal unsafe struct Il2CppAssemblyName_24_1 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_104_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_104_0.cs index 07aa1b07..b37d2d1c 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_104_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_104_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("6000.5.0")] public unsafe class NativeClassStructHandler_104_0 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_104_0); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_104_0* _ = (Il2CppClass_104_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_104_0); internal unsafe struct Il2CppClass_104_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_105_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_105_0.cs index 5c20ed4a..027b27af 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_105_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_105_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("6000.5.0a5")] public unsafe class NativeClassStructHandler_105_0 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_105_0); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_105_0* _ = (Il2CppClass_105_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_105_0); internal unsafe struct Il2CppClass_105_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_16_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_16_0.cs index 1e351cf6..68f13eb4 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_16_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_16_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeClassStructHandler_16_0 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_16_0); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_16_0* _ = (Il2CppClass_16_0*)ptr; *_ = default; Marshal.FreeHGlobal(ptr); @@ -20,6 +19,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_16_0); internal unsafe struct Il2CppClass_16_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_19_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_19_0.cs index d7e1b251..6071ae64 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_19_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_19_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.3.1p3")] public unsafe class NativeClassStructHandler_19_0 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_19_0); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_19_0* _ = (Il2CppClass_19_0*)ptr; *_ = default; Marshal.FreeHGlobal(ptr); @@ -20,6 +19,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_19_0); internal unsafe struct Il2CppClass_19_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_20_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_20_0.cs index 014d173e..4478f19a 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_20_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_20_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.3.2p2")] public unsafe class NativeClassStructHandler_20_0 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_20_0); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_20_0* _ = (Il2CppClass_20_0*)ptr; *_ = default; Marshal.FreeHGlobal(ptr); @@ -20,6 +19,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_20_0); internal unsafe struct Il2CppClass_20_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_0.cs index f6d518dc..9f19703d 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.3.5p1")] public unsafe class NativeClassStructHandler_21_0 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_21_0); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_21_0* _ = (Il2CppClass_21_0*)ptr; *_ = default; Marshal.FreeHGlobal(ptr); @@ -20,6 +19,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_21_0); internal unsafe struct Il2CppClass_21_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_1.cs index 5a9e8096..d6101f0f 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_1.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.3.5p3")] public unsafe class NativeClassStructHandler_21_1 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_21_1); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_21_1* _ = (Il2CppClass_21_1*)ptr; *_ = default; Marshal.FreeHGlobal(ptr); @@ -20,6 +19,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_21_1); internal unsafe struct Il2CppClass_21_1 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_2.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_2.cs index 09719850..079f4780 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_2.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_2.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.4.3p4")] public unsafe class NativeClassStructHandler_21_2 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_21_2); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_21_2* _ = (Il2CppClass_21_2*)ptr; *_ = default; Marshal.FreeHGlobal(ptr); @@ -20,6 +19,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_21_2); internal unsafe struct Il2CppClass_21_2 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_0.cs index c24b21ee..8c0e9ea2 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.5.0")] public unsafe class NativeClassStructHandler_22_0 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_22_0); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_22_0* _ = (Il2CppClass_22_0*)ptr; *_ = default; _->byval_arg = UnityVersionHandler.NewType().TypePointer; @@ -20,6 +19,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_22_0); internal unsafe struct Il2CppClass_22_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_1.cs index df6abdca..87822f1b 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_1.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.5.0p2")] public unsafe class NativeClassStructHandler_22_1 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_22_1); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_22_1* _ = (Il2CppClass_22_1*)ptr; *_ = default; _->byval_arg = UnityVersionHandler.NewType().TypePointer; @@ -20,6 +19,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_22_1); internal unsafe struct Il2CppClass_22_1 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_0.cs index 45265ec5..98e6160d 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.6.0")] public unsafe class NativeClassStructHandler_23_0 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_23_0); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_23_0* _ = (Il2CppClass_23_0*)ptr; *_ = default; _->byval_arg = UnityVersionHandler.NewType().TypePointer; @@ -20,6 +19,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_23_0); internal unsafe struct Il2CppClass_23_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_1.cs index 3c579080..6ba3336a 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_1.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.6.0b3")] public unsafe class NativeClassStructHandler_23_1 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_23_1); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_23_1* _ = (Il2CppClass_23_1*)ptr; *_ = default; _->byval_arg = UnityVersionHandler.NewType().TypePointer; @@ -20,6 +19,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_23_1); internal unsafe struct Il2CppClass_23_1 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_0.cs index 8329b808..a5d848df 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeClassStructHandler_24_0 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_24_0); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_24_0* _ = (Il2CppClass_24_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_24_0); internal unsafe struct Il2CppClass_24_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_1.cs index aba76495..196c0625 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_1.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2018.2.0")] public unsafe class NativeClassStructHandler_24_1 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_24_1); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_24_1* _ = (Il2CppClass_24_1*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_24_1); internal unsafe struct Il2CppClass_24_1 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_2.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_2.cs index 3faea67d..147262b9 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_2.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_2.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeClassStructHandler_24_2 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_24_2); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_24_2* _ = (Il2CppClass_24_2*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_24_2); internal unsafe struct Il2CppClass_24_2 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_3.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_3.cs index a6179610..ac486ef6 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_3.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_3.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2018.3.0b11")] public unsafe class NativeClassStructHandler_24_3 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_24_3); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_24_3* _ = (Il2CppClass_24_3*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_24_3); internal unsafe struct Il2CppClass_24_3 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_4.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_4.cs index 4044f6ae..7a4e2fef 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_4.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_4.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2018.3.8")] public unsafe class NativeClassStructHandler_24_4 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_24_4); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_24_4* _ = (Il2CppClass_24_4*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_24_4); internal unsafe struct Il2CppClass_24_4 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_5.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_5.cs index c62bbcfb..78bfb743 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_5.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_5.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2019.1.0a11")] public unsafe class NativeClassStructHandler_24_5 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_24_5); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_24_5* _ = (Il2CppClass_24_5*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_24_5); internal unsafe struct Il2CppClass_24_5 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_6.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_6.cs index 27843a4a..c0d2f148 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_6.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_6.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2019.1.0b5")] public unsafe class NativeClassStructHandler_24_6 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_24_6); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_24_6* _ = (Il2CppClass_24_6*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_24_6); internal unsafe struct Il2CppClass_24_6 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_7.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_7.cs index 6e2da927..fd566426 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_7.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_7.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2020.2.0")] public unsafe class NativeClassStructHandler_24_7 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_24_7); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_24_7* _ = (Il2CppClass_24_7*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_24_7); internal unsafe struct Il2CppClass_24_7 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_0.cs index 67b2889c..e8baa2dd 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2020.3.20")] public unsafe class NativeClassStructHandler_27_0 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_27_0); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_27_0* _ = (Il2CppClass_27_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_27_0); internal unsafe struct Il2CppClass_27_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_1.cs index df69f53b..2a43e0f9 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_1.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2021.1.0")] public unsafe class NativeClassStructHandler_27_1 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_27_1); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_27_1* _ = (Il2CppClass_27_1*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_27_1); internal unsafe struct Il2CppClass_27_1 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_2.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_2.cs index 579ae943..102fcd34 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_2.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_2.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2021.1.24")] public unsafe class NativeClassStructHandler_27_2 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_27_2); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_27_2* _ = (Il2CppClass_27_2*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_27_2); internal unsafe struct Il2CppClass_27_2 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_3.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_3.cs index da727a74..029e2ae0 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_3.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_3.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2021.2.0")] public unsafe class NativeClassStructHandler_27_3 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_27_3); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_27_3* _ = (Il2CppClass_27_3*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_27_3); internal unsafe struct Il2CppClass_27_3 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_4.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_4.cs index 9b5e1043..8913cafd 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_4.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_4.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2021.2.0a12")] public unsafe class NativeClassStructHandler_27_4 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_27_4); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_27_4* _ = (Il2CppClass_27_4*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_27_4); internal unsafe struct Il2CppClass_27_4 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_5.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_5.cs index 1ef9bade..7c09b57d 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_5.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_5.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2021.2.0a21")] public unsafe class NativeClassStructHandler_27_5 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_27_5); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_27_5* _ = (Il2CppClass_27_5*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_27_5); internal unsafe struct Il2CppClass_27_5 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_0.cs index 37fd387f..441ad720 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2021.2.0b13")] public unsafe class NativeClassStructHandler_29_0 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_29_0); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_29_0* _ = (Il2CppClass_29_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_29_0); internal unsafe struct Il2CppClass_29_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_1.cs index 4b05ed4a..cc58c530 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_1.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2022.2.0")] public unsafe class NativeClassStructHandler_29_1 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_29_1); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_29_1* _ = (Il2CppClass_29_1*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_29_1); internal unsafe struct Il2CppClass_29_1 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_2.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_2.cs index fbabc678..1418569c 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_2.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_2.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("2023.1.0a15")] public unsafe class NativeClassStructHandler_29_2 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_29_2); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_29_2* _ = (Il2CppClass_29_2*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_29_2); internal unsafe struct Il2CppClass_29_2 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_39_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_39_0.cs index bd8063a5..36a090a2 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_39_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_39_0.cs @@ -5,10 +5,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class [ApplicableToUnityVersionsSince("6000.3.3")] public unsafe class NativeClassStructHandler_39_0 : INativeClassStructHandler { - public int Size() => sizeof(Il2CppClass_39_0); public INativeClassStruct CreateNewStruct(int vTableSlots) { - nint ptr = Marshal.AllocHGlobal(Size() + sizeof(VirtualInvokeData) * vTableSlots); + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); Il2CppClass_39_0* _ = (Il2CppClass_39_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -18,6 +17,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppClass_39_0); internal unsafe struct Il2CppClass_39_0 { public Il2CppImage* image; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_16_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_16_0.cs index 2fe25683..a2fa20c3 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_16_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.EventInfo [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeEventInfoStructHandler_16_0 : INativeEventInfoStructHandler { - public int Size() => sizeof(Il2CppEventInfo_16_0); public INativeEventInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppEventInfo_16_0* _ = (Il2CppEventInfo_16_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeEventInfoStruct Wrap(Il2CppEventInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppEventInfo_16_0); internal unsafe struct Il2CppEventInfo_16_0 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_19_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_19_0.cs index c0b8ed73..fd25d684 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_19_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_19_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.EventInfo [ApplicableToUnityVersionsSince("5.3.1p3")] public unsafe class NativeEventInfoStructHandler_19_0 : INativeEventInfoStructHandler { - public int Size() => sizeof(Il2CppEventInfo_19_0); public INativeEventInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppEventInfo_19_0* _ = (Il2CppEventInfo_19_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeEventInfoStruct Wrap(Il2CppEventInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppEventInfo_19_0); internal unsafe struct Il2CppEventInfo_19_0 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_24_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_24_0.cs index 859510a9..9439d3ea 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_24_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.EventInfo [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeEventInfoStructHandler_24_0 : INativeEventInfoStructHandler { - public int Size() => sizeof(Il2CppEventInfo_24_0); public INativeEventInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppEventInfo_24_0* _ = (Il2CppEventInfo_24_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeEventInfoStruct Wrap(Il2CppEventInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppEventInfo_24_0); internal unsafe struct Il2CppEventInfo_24_0 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_16_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_16_0.cs index 155f0fc5..e71cf465 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_16_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_16_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeExceptionStructHandler_16_0 : INativeExceptionStructHandler { - public int Size() => sizeof(Il2CppException_16_0); public INativeExceptionStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppException_16_0* _ = (Il2CppException_16_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppException_16_0); internal unsafe struct Il2CppException_16_0 { public Il2CppObject _object; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_20_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_20_0.cs index 94ad77bb..80ea0f98 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_20_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_20_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception [ApplicableToUnityVersionsSince("5.3.2p2")] public unsafe class NativeExceptionStructHandler_20_0 : INativeExceptionStructHandler { - public int Size() => sizeof(Il2CppException_20_0); public INativeExceptionStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppException_20_0* _ = (Il2CppException_20_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppException_20_0); internal unsafe struct Il2CppException_20_0 { public Il2CppObject _object; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_21_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_21_0.cs index 2d7f31f6..2a521c15 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_21_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_21_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception [ApplicableToUnityVersionsSince("5.3.4p3")] public unsafe class NativeExceptionStructHandler_21_0 : INativeExceptionStructHandler { - public int Size() => sizeof(Il2CppException_21_0); public INativeExceptionStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppException_21_0* _ = (Il2CppException_21_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppException_21_0); internal unsafe struct Il2CppException_21_0 { public Il2CppObject _object; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_22_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_22_0.cs index 6417c039..b91d2028 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_22_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_22_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception [ApplicableToUnityVersionsSince("5.5.0")] public unsafe class NativeExceptionStructHandler_22_0 : INativeExceptionStructHandler { - public int Size() => sizeof(Il2CppException_22_0); public INativeExceptionStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppException_22_0* _ = (Il2CppException_22_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppException_22_0); internal unsafe struct Il2CppException_22_0 { public Il2CppObject _object; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_0.cs index 888297e0..ef52979e 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception [ApplicableToUnityVersionsSince("5.6.0b3")] public unsafe class NativeExceptionStructHandler_23_0 : INativeExceptionStructHandler { - public int Size() => sizeof(Il2CppException_23_0); public INativeExceptionStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppException_23_0* _ = (Il2CppException_23_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppException_23_0); internal unsafe struct Il2CppException_23_0 { public Il2CppObject _object; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_1.cs index 23aa7ab2..ba4e2fc4 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_1.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception [ApplicableToUnityVersionsSince("5.6.0b6")] public unsafe class NativeExceptionStructHandler_23_1 : INativeExceptionStructHandler { - public int Size() => sizeof(Il2CppException_23_1); public INativeExceptionStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppException_23_1* _ = (Il2CppException_23_1*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppException_23_1); internal unsafe struct Il2CppException_23_1 { public Il2CppObject Object; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_27_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_27_0.cs index 7f386251..06eea88a 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_27_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_27_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception [ApplicableToUnityVersionsSince("2021.2.0a19")] public unsafe class NativeExceptionStructHandler_27_0 : INativeExceptionStructHandler { - public int Size() => sizeof(Il2CppException_27_0); public INativeExceptionStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppException_27_0* _ = (Il2CppException_27_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppException_27_0); internal unsafe struct Il2CppException_27_0 { public Il2CppObject _object; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_16_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_16_0.cs index be5ef660..dd4fd841 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_16_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.FieldInfo [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeFieldInfoStructHandler_16_0 : INativeFieldInfoStructHandler { - public int Size() => sizeof(Il2CppFieldInfo_16_0); public INativeFieldInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppFieldInfo_16_0* _ = (Il2CppFieldInfo_16_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeFieldInfoStruct Wrap(Il2CppFieldInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppFieldInfo_16_0); internal unsafe struct Il2CppFieldInfo_16_0 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_19_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_19_0.cs index d75ad208..8e206db2 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_19_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_19_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.FieldInfo [ApplicableToUnityVersionsSince("5.3.1p3")] public unsafe class NativeFieldInfoStructHandler_19_0 : INativeFieldInfoStructHandler { - public int Size() => sizeof(Il2CppFieldInfo_19_0); public INativeFieldInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppFieldInfo_19_0* _ = (Il2CppFieldInfo_19_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeFieldInfoStruct Wrap(Il2CppFieldInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppFieldInfo_19_0); internal unsafe struct Il2CppFieldInfo_19_0 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_24_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_24_0.cs index 6399c135..92c897ab 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_24_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.FieldInfo [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeFieldInfoStructHandler_24_0 : INativeFieldInfoStructHandler { - public int Size() => sizeof(Il2CppFieldInfo_24_0); public INativeFieldInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppFieldInfo_24_0* _ = (Il2CppFieldInfo_24_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeFieldInfoStruct Wrap(Il2CppFieldInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppFieldInfo_24_0); internal unsafe struct Il2CppFieldInfo_24_0 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_16_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_16_0.cs index 1878e284..4832b775 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_16_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_16_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeImageStructHandler_16_0 : INativeImageStructHandler { - public int Size() => sizeof(Il2CppImage_16_0); public INativeImageStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppImage_16_0* _ = (Il2CppImage_16_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppImage_16_0); internal unsafe struct Il2CppImage_16_0 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_19_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_19_0.cs index 886b2f9e..cdc8d11c 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_19_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_19_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image [ApplicableToUnityVersionsSince("5.3.1p3")] public unsafe class NativeImageStructHandler_19_0 : INativeImageStructHandler { - public int Size() => sizeof(Il2CppImage_19_0); public INativeImageStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppImage_19_0* _ = (Il2CppImage_19_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppImage_19_0); internal unsafe struct Il2CppImage_19_0 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_0.cs index 078eb1bb..1325e6ff 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image [ApplicableToUnityVersionsSince("2017.1.0")] public unsafe class NativeImageStructHandler_24_0 : INativeImageStructHandler { - public int Size() => sizeof(Il2CppImage_24_0); public INativeImageStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppImage_24_0* _ = (Il2CppImage_24_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppImage_24_0); internal unsafe struct Il2CppImage_24_0 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_1.cs index 8ccd689a..f0059dc4 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_1.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image [ApplicableToUnityVersionsSince("2017.1.2p1")] public unsafe class NativeImageStructHandler_24_1 : INativeImageStructHandler { - public int Size() => sizeof(Il2CppImage_24_1); public INativeImageStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppImage_24_1* _ = (Il2CppImage_24_1*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppImage_24_1); internal unsafe struct Il2CppImage_24_1 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_2.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_2.cs index eaab898e..7b7610d5 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_2.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_2.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image [ApplicableToUnityVersionsSince("2018.1.0")] public unsafe class NativeImageStructHandler_24_2 : INativeImageStructHandler { - public int Size() => sizeof(Il2CppImage_24_2); public INativeImageStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppImage_24_2* _ = (Il2CppImage_24_2*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppImage_24_2); internal unsafe struct Il2CppImage_24_2 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_3.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_3.cs index 0f5218cc..cdb8165f 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_3.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_3.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeImageStructHandler_24_3 : INativeImageStructHandler { - public int Size() => sizeof(Il2CppImage_24_3); public INativeImageStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppImage_24_3* _ = (Il2CppImage_24_3*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppImage_24_3); internal unsafe struct Il2CppImage_24_3 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_4.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_4.cs index ffbe16d1..a6ecd041 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_4.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_4.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeImageStructHandler_24_4 : INativeImageStructHandler { - public int Size() => sizeof(Il2CppImage_24_4); public INativeImageStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppImage_24_4* _ = (Il2CppImage_24_4*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppImage_24_4); internal unsafe struct Il2CppImage_24_4 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_5.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_5.cs index 6870247c..7522b3c7 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_5.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_5.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image [ApplicableToUnityVersionsSince("2019.1.0a12")] public unsafe class NativeImageStructHandler_24_5 : INativeImageStructHandler { - public int Size() => sizeof(Il2CppImage_24_5); public INativeImageStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppImage_24_5* _ = (Il2CppImage_24_5*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppImage_24_5); internal unsafe struct Il2CppImage_24_5 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_6.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_6.cs index 4f2bd1b2..f3806c75 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_6.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_6.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image [ApplicableToUnityVersionsSince("2020.2.0")] public unsafe class NativeImageStructHandler_24_6 : INativeImageStructHandler { - public int Size() => sizeof(Il2CppImage_24_6); public INativeImageStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppImage_24_6* _ = (Il2CppImage_24_6*)ptr; *_ = default; Il2CppImageGlobalMetadata* metadata = (Il2CppImageGlobalMetadata*)Marshal.AllocHGlobal(sizeof(Il2CppImageGlobalMetadata)); @@ -20,6 +19,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppImage_24_6); internal unsafe struct Il2CppImage_24_6 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_16_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_16_0.cs index 82906fc1..17bde1d0 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_16_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeMethodInfoStructHandler_16_0 : INativeMethodInfoStructHandler { - public int Size() => sizeof(Il2CppMethodInfo_16_0); public INativeMethodInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppMethodInfo_16_0* _ = (Il2CppMethodInfo_16_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppMethodInfo_16_0); internal unsafe struct Il2CppMethodInfo_16_0 { public void* method; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_21_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_21_0.cs index e02d3d08..8a138a12 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_21_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_21_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("5.3.5p3")] public unsafe class NativeMethodInfoStructHandler_21_0 : INativeMethodInfoStructHandler { - public int Size() => sizeof(Il2CppMethodInfo_21_0); public INativeMethodInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppMethodInfo_21_0* _ = (Il2CppMethodInfo_21_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppMethodInfo_21_0); internal unsafe struct Il2CppMethodInfo_21_0 { public void* methodPointer; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_0.cs index 2a9814a7..51c25eec 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeMethodInfoStructHandler_24_0 : INativeMethodInfoStructHandler { - public int Size() => sizeof(Il2CppMethodInfo_24_0); public INativeMethodInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppMethodInfo_24_0* _ = (Il2CppMethodInfo_24_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppMethodInfo_24_0); internal unsafe struct Il2CppMethodInfo_24_0 { public void* methodPointer; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_1.cs index 9ce38ba3..a37758ae 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_1.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2018.1.0f1")] public unsafe class NativeMethodInfoStructHandler_24_1 : INativeMethodInfoStructHandler { - public int Size() => sizeof(Il2CppMethodInfo_24_1); public INativeMethodInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppMethodInfo_24_1* _ = (Il2CppMethodInfo_24_1*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppMethodInfo_24_1); internal unsafe struct Il2CppMethodInfo_24_1 { public void* methodPointer; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_2.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_2.cs index b192a0fc..197b0a7b 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_2.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_2.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeMethodInfoStructHandler_24_2 : INativeMethodInfoStructHandler { - public int Size() => sizeof(Il2CppMethodInfo_24_2); public INativeMethodInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppMethodInfo_24_2* _ = (Il2CppMethodInfo_24_2*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppMethodInfo_24_2); internal unsafe struct Il2CppMethodInfo_24_2 { public void* methodPointer; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_27_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_27_0.cs index 690efa45..91896fe3 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_27_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_27_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2021.2.0")] public unsafe class NativeMethodInfoStructHandler_27_0 : INativeMethodInfoStructHandler { - public int Size() => sizeof(Il2CppMethodInfo_27_0); public INativeMethodInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppMethodInfo_27_0* _ = (Il2CppMethodInfo_27_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppMethodInfo_27_0); internal unsafe struct Il2CppMethodInfo_27_0 { public void* methodPointer; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_28_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_28_0.cs index 99999e1b..0eb01fa8 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_28_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_28_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2021.2.0b7")] public unsafe class NativeMethodInfoStructHandler_28_0 : INativeMethodInfoStructHandler { - public int Size() => sizeof(Il2CppMethodInfo_28_0); public INativeMethodInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppMethodInfo_28_0* _ = (Il2CppMethodInfo_28_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppMethodInfo_28_0); internal unsafe struct Il2CppMethodInfo_28_0 { public void* methodPointer; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_0.cs index 78c78695..562229de 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2021.2.0b8")] public unsafe class NativeMethodInfoStructHandler_29_0 : INativeMethodInfoStructHandler { - public int Size() => sizeof(Il2CppMethodInfo_29_0); public INativeMethodInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppMethodInfo_29_0* _ = (Il2CppMethodInfo_29_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppMethodInfo_29_0); internal unsafe struct Il2CppMethodInfo_29_0 { public void* methodPointer; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_1.cs index 84899536..53becf7d 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_1.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2021.2.0b13")] public unsafe class NativeMethodInfoStructHandler_29_1 : INativeMethodInfoStructHandler { - public int Size() => sizeof(Il2CppMethodInfo_29_1); public INativeMethodInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppMethodInfo_29_1* _ = (Il2CppMethodInfo_29_1*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppMethodInfo_29_1); internal unsafe struct Il2CppMethodInfo_29_1 { public void* methodPointer; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_2.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_2.cs index a2981bc3..c7e77119 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_2.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_2.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2023.2.0a22")] public unsafe class NativeMethodInfoStructHandler_29_2 : INativeMethodInfoStructHandler { - public int Size() => sizeof(Il2CppMethodInfo_29_2); public INativeMethodInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppMethodInfo_29_2* _ = (Il2CppMethodInfo_29_2*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppMethodInfo_29_2); internal unsafe struct Il2CppMethodInfo_29_2 { public void* methodPointer; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs index 94d03344..ec3ad76e 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.ParameterInfo [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeParameterInfoStructHandler_16_0 : INativeParameterInfoStructHandler { - public int Size() => sizeof(Il2CppParameterInfo_16_0); public INativeParameterInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppParameterInfo_16_0* _ = (Il2CppParameterInfo_16_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeParameterInfoStruct Wrap(Il2CppParameterInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppParameterInfo_16_0); internal unsafe struct Il2CppParameterInfo_16_0 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs index 2741bd86..fbcbc387 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.ParameterInfo [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeParameterInfoStructHandler_24_0 : INativeParameterInfoStructHandler { - public int Size() => sizeof(Il2CppParameterInfo_24_0); public INativeParameterInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppParameterInfo_24_0* _ = (Il2CppParameterInfo_24_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeParameterInfoStruct Wrap(Il2CppParameterInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppParameterInfo_24_0); internal unsafe struct Il2CppParameterInfo_24_0 { public byte* name; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs index d1886b65..198dad47 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.ParameterInfo [ApplicableToUnityVersionsSince("2021.2.0")] public unsafe class NativeParameterInfoStructHandler_27_0 : INativeParameterInfoStructHandler { - public int Size() => sizeof(Il2CppParameterInfo_27_0); public INativeParameterInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppParameterInfo_27_0* _ = (Il2CppParameterInfo_27_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeParameterInfoStruct Wrap(Il2CppParameterInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppParameterInfo_27_0); internal unsafe struct Il2CppParameterInfo_27_0 { public Il2CppTypeStruct* parameter_type; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs index bd81d3a4..94556f50 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.PropertyInfo [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativePropertyInfoStructHandler_16_0 : INativePropertyInfoStructHandler { - public int Size() => sizeof(Il2CppPropertyInfo_16_0); public INativePropertyInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppPropertyInfo_16_0* _ = (Il2CppPropertyInfo_16_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativePropertyInfoStruct Wrap(Il2CppPropertyInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppPropertyInfo_16_0); internal unsafe struct Il2CppPropertyInfo_16_0 { public Il2CppClass* parent; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs index b5ba6ca2..7096763a 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.PropertyInfo [ApplicableToUnityVersionsSince("5.3.1p3")] public unsafe class NativePropertyInfoStructHandler_19_0 : INativePropertyInfoStructHandler { - public int Size() => sizeof(Il2CppPropertyInfo_19_0); public INativePropertyInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppPropertyInfo_19_0* _ = (Il2CppPropertyInfo_19_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativePropertyInfoStruct Wrap(Il2CppPropertyInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppPropertyInfo_19_0); internal unsafe struct Il2CppPropertyInfo_19_0 { public Il2CppClass* parent; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs index 4dc6f451..df112482 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.PropertyInfo [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativePropertyInfoStructHandler_24_0 : INativePropertyInfoStructHandler { - public int Size() => sizeof(Il2CppPropertyInfo_24_0); public INativePropertyInfoStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppPropertyInfo_24_0* _ = (Il2CppPropertyInfo_24_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativePropertyInfoStruct Wrap(Il2CppPropertyInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppPropertyInfo_24_0); internal unsafe struct Il2CppPropertyInfo_24_0 { public Il2CppClass* parent; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_16_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_16_0.cs index 2d5310b2..a6a991b9 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_16_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_16_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Type [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeTypeStructHandler_16_0 : INativeTypeStructHandler { - public int Size() => sizeof(Il2CppType_16_0); public INativeTypeStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppType_16_0* _ = (Il2CppType_16_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeTypeStruct Wrap(Il2CppTypeStruct* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppType_16_0); internal unsafe struct Il2CppType_16_0 { public void* data; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_27_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_27_0.cs index 53e5a306..c3397fe1 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_27_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_27_0.cs @@ -4,10 +4,9 @@ namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Type [ApplicableToUnityVersionsSince("2021.1.0")] public unsafe class NativeTypeStructHandler_27_0 : INativeTypeStructHandler { - public int Size() => sizeof(Il2CppType_27_0); public INativeTypeStruct CreateNewStruct() { - nint ptr = Marshal.AllocHGlobal(Size()); + nint ptr = Marshal.AllocHGlobal(Size); Il2CppType_27_0* _ = (Il2CppType_27_0*)ptr; *_ = default; return new NativeStructWrapper(ptr); @@ -17,6 +16,7 @@ public INativeTypeStruct Wrap(Il2CppTypeStruct* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public int Size => sizeof(Il2CppType_27_0); internal unsafe struct Il2CppType_27_0 { public void* data; diff --git a/Il2CppInterop.StructGenerator/StructHandlerGenerator.cs b/Il2CppInterop.StructGenerator/StructHandlerGenerator.cs index 4893087a..091478e6 100644 --- a/Il2CppInterop.StructGenerator/StructHandlerGenerator.cs +++ b/Il2CppInterop.StructGenerator/StructHandlerGenerator.cs @@ -15,9 +15,9 @@ public StructHandlerGenerator(string name, string handlerInterface, string nativ IsUnsafe = true, InterfaceNames = { handlerInterface } }; - HandlerClass.Methods.Add(new CodeGenMethod("int", ElementProtection.Public, "Size") + HandlerClass.Properties.Add(new CodeGenProperty("int", ElementProtection.Public, "Size") { - ImmediateReturn = $"sizeof({nativeStructGen.NativeStruct.Name})" + ImmediateGet = $"sizeof({nativeStructGen.NativeStruct.Name})" }); CodeGenMethod createNewMethod = new(nativeInterface, ElementProtection.Public, "CreateNewStruct") { @@ -27,7 +27,7 @@ public StructHandlerGenerator(string name, string handlerInterface, string nativ if (SizeProviderOverride != null) writer.WriteLine($"{SizeProviderOverride});"); else - writer.WriteLine("Size());"); + writer.WriteLine("Size);"); writer.WriteLine( $"{nativeStructGen.NativeStruct.Name}* _ = ({nativeStructGen.NativeStruct.Name}*)ptr;"); writer.WriteLine("*_ = default;"); diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs index a90009bc..f5c0816f 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs @@ -22,7 +22,7 @@ public Il2CppClassGenerator(string metadataSuffix, CppClass nativeClass) : base( protected override IEnumerable? CreateNewParameters => [new CodeGenParameter("int", "vTableSlots")]; - protected override string? SizeOverride => "Size() + sizeof(VirtualInvokeData) * vTableSlots"; + protected override string? SizeOverride => "Size + sizeof(VirtualInvokeData) * vTableSlots"; private bool ByValArgIsPointer => GetNativeField("byval_arg")?.FieldType.EndsWith('*') ?? false; private bool ThisArgIsPointer => GetNativeField("this_arg")?.FieldType.EndsWith('*') ?? false; From f90325207b2a9ab53afcdbb0d482c135bfa7a68b Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 9 May 2026 15:47:50 -0700 Subject: [PATCH 415/486] Update Il2CppArrayRank3 indexer to support 3 indices Refactored the indexer in Il2CppArrayRank3 to accept three indices, aligning with its role as a 3D array wrapper. The getter and setter now use a three-element index array for element access. --- .../InteropTypes/Arrays/Il2CppArrayRank3.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs index 7d7e800e..352f29f3 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs @@ -42,10 +42,10 @@ public Il2CppArrayRank3(T[,,] values) : this(values.GetLength(0), values.GetLeng } } - public T this[int index0, int index1] + public T this[int index0, int index1, int index2] { - get => this[[index0, index1]]; - set => this[[index0, index1]] = value; + get => this[[index0, index1, index2]]; + set => this[[index0, index1, index2]] = value; } public ByReference GetElementAddress(int index0, int index1, int index2) => GetElementAddress([index0, index1, index2]); From f24f4758ccabfa5609d3efd3fa1f7ceb72f5aaf5 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 9 May 2026 15:49:52 -0700 Subject: [PATCH 416/486] Support 4D and 5D arrays --- ...ferenceAssemblyInjectionProcessingLayer.cs | 2 + .../TranslatedMethodBody.cs | 2 + .../Visitors/TypeConversionVisitor.cs | 9 +- .../InteropTypes/Arrays/Il2CppArrayRank4.cs | 89 +++++++++++++++++ .../InteropTypes/Arrays/Il2CppArrayRank5.cs | 97 +++++++++++++++++++ 5 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank4.cs create mode 100644 Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank5.cs diff --git a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs index 2c3d9e77..4492d8a7 100644 --- a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs +++ b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs @@ -43,6 +43,8 @@ public override void Process(ApplicationAnalysisContext appContext, Action), typeof(Il2CppArrayRank2<>), typeof(Il2CppArrayRank3<>), + typeof(Il2CppArrayRank4<>), + typeof(Il2CppArrayRank5<>), typeof(Il2CppException), typeof(TypeInjector), diff --git a/Il2CppInterop.Generator/TranslatedMethodBody.cs b/Il2CppInterop.Generator/TranslatedMethodBody.cs index 1feaab72..7fc9c1ee 100644 --- a/Il2CppInterop.Generator/TranslatedMethodBody.cs +++ b/Il2CppInterop.Generator/TranslatedMethodBody.cs @@ -1070,6 +1070,8 @@ public static bool TryTranslateOriginalMethodBody(MethodAnalysisContext methodCo { 2 => appContext.ResolveTypeOrThrow(typeof(Il2CppArrayRank2<>)), 3 => appContext.ResolveTypeOrThrow(typeof(Il2CppArrayRank3<>)), + 4 => appContext.ResolveTypeOrThrow(typeof(Il2CppArrayRank4<>)), + 5 => appContext.ResolveTypeOrThrow(typeof(Il2CppArrayRank5<>)), _ => null, }; if (arrayType is null) diff --git a/Il2CppInterop.Generator/Visitors/TypeConversionVisitor.cs b/Il2CppInterop.Generator/Visitors/TypeConversionVisitor.cs index 905779ac..fd61bce9 100644 --- a/Il2CppInterop.Generator/Visitors/TypeConversionVisitor.cs +++ b/Il2CppInterop.Generator/Visitors/TypeConversionVisitor.cs @@ -1,5 +1,4 @@ using Cpp2IL.Core.Model.Contexts; -using Il2CppInterop.Generator; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; @@ -16,6 +15,8 @@ private TypeConversionVisitor(Dictionary)); var arrayRank2 = il2CppInteropRuntime.GetTypeByFullNameOrThrow(typeof(Il2CppArrayRank2<>)); var arrayRank3 = il2CppInteropRuntime.GetTypeByFullNameOrThrow(typeof(Il2CppArrayRank3<>)); + var arrayRank4 = il2CppInteropRuntime.GetTypeByFullNameOrThrow(typeof(Il2CppArrayRank4<>)); + var arrayRank5 = il2CppInteropRuntime.GetTypeByFullNameOrThrow(typeof(Il2CppArrayRank5<>)); (string, string)[] replacements = [ @@ -45,6 +48,8 @@ public static TypeConversionVisitor Create(ApplicationAnalysisContext appContext ArrayRank1 = arrayRank1, ArrayRank2 = arrayRank2, ArrayRank3 = arrayRank3, + ArrayRank4 = arrayRank4, + ArrayRank5 = arrayRank5, }; } @@ -55,6 +60,8 @@ protected override TypeAnalysisContext CombineResults(ArrayTypeAnalysisContext t 1 => ArrayRank1.MakeGenericInstanceType([elementResult]), 2 => ArrayRank2.MakeGenericInstanceType([elementResult]), 3 => ArrayRank3.MakeGenericInstanceType([elementResult]), + 4 => ArrayRank4.MakeGenericInstanceType([elementResult]), + 5 => ArrayRank5.MakeGenericInstanceType([elementResult]), _ => throw new NotImplementedException($"Support for arrays with rank {type.Rank} has not been implemented."), }; } diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank4.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank4.cs new file mode 100644 index 00000000..48df612e --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank4.cs @@ -0,0 +1,89 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using Il2CppInterop.Common; + +namespace Il2CppInterop.Runtime.InteropTypes.Arrays; + +public sealed class Il2CppArrayRank4 : Il2CppArrayBase, IIl2CppType> + where T : IIl2CppType +{ + static int IIl2CppType>.Size => IntPtr.Size; + + nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); + + static Il2CppArrayRank4() + { + SetClassPointer, T>(4); + } + + public Il2CppArrayRank4(ObjectPointer pointer) : base(pointer) + { + } + + public Il2CppArrayRank4(int length0, int length1, int length2, int length3) : base([length0, length1, length2, length3], Il2CppType.GetClassPointer>()) + { + } + + public Il2CppArrayRank4(T[,,,] values) : this(values.GetLength(0), values.GetLength(1), values.GetLength(2), values.GetLength(3)) + { + var length_0 = values.GetLength(0); + var length_1 = values.GetLength(1); + var length_2 = values.GetLength(2); + var length_3 = values.GetLength(3); + + for (var i_0 = 0; i_0 < length_0; i_0++) + { + for (var i_1 = 0; i_1 < length_1; i_1++) + { + for (var i_2 = 0; i_2 < length_2; i_2++) + { + for (var i_3 = 0; i_3 < length_3; i_3++) + { + this[i_0, i_1, i_2, i_3] = values[i_0, i_1, i_2, i_3]; + } + } + } + } + } + + public T this[int index0, int index1, int index2, int index3] + { + get => this[[index0, index1, index2, index3]]; + set => this[[index0, index1, index2, index3]] = value; + } + + public ByReference GetElementAddress(int index0, int index1, int index2, int index3) => GetElementAddress([index0, index1, index2, index3]); + + static void IIl2CppType>.WriteToSpan(Il2CppArrayRank4? value, Span span) => Il2CppType.WriteReference(value, span); + static Il2CppArrayRank4? IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => Il2CppType.ReadReference>(span); + + [return: NotNullIfNotNull(nameof(array))] + public static explicit operator Il2CppArrayRank4?(T[,,,]? array) => array is null ? null : new(array); + + [return: NotNullIfNotNull(nameof(array))] + public static explicit operator T[,,,]?(Il2CppArrayRank4? array) + { + if (array is null) + return null; + + var length_0 = array.GetLength(0); + var length_1 = array.GetLength(1); + var length_2 = array.GetLength(2); + var length_3 = array.GetLength(3); + var result = new T[length_0, length_1, length_2, length_3]; + for (var i_0 = 0; i_0 < length_0; i_0++) + { + for (var i_1 = 0; i_1 < length_1; i_1++) + { + for (var i_2 = 0; i_2 < length_2; i_2++) + { + for (var i_3 = 0; i_3 < length_3; i_3++) + { + result[i_0, i_1, i_2, i_3] = array[i_0, i_1, i_2, i_3]; + } + } + } + } + return result; + } +} diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank5.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank5.cs new file mode 100644 index 00000000..31ecff41 --- /dev/null +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank5.cs @@ -0,0 +1,97 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using Il2CppInterop.Common; + +namespace Il2CppInterop.Runtime.InteropTypes.Arrays; + +public sealed class Il2CppArrayRank5 : Il2CppArrayBase, IIl2CppType> + where T : IIl2CppType +{ + static int IIl2CppType>.Size => IntPtr.Size; + + nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); + + static Il2CppArrayRank5() + { + SetClassPointer, T>(5); + } + + public Il2CppArrayRank5(ObjectPointer pointer) : base(pointer) + { + } + + public Il2CppArrayRank5(int length0, int length1, int length2, int length3, int length4) : base([length0, length1, length2, length3, length4], Il2CppType.GetClassPointer>()) + { + } + + public Il2CppArrayRank5(T[,,,,] values) : this(values.GetLength(0), values.GetLength(1), values.GetLength(2), values.GetLength(3), values.GetLength(4)) + { + var length_0 = values.GetLength(0); + var length_1 = values.GetLength(1); + var length_2 = values.GetLength(2); + var length_3 = values.GetLength(3); + var length_4 = values.GetLength(4); + + for (var i_0 = 0; i_0 < length_0; i_0++) + { + for (var i_1 = 0; i_1 < length_1; i_1++) + { + for (var i_2 = 0; i_2 < length_2; i_2++) + { + for (var i_3 = 0; i_3 < length_3; i_3++) + { + for (var i_4 = 0; i_4 < length_4; i_4++) + { + this[i_0, i_1, i_2, i_3, i_4] = values[i_0, i_1, i_2, i_3, i_4]; + } + } + } + } + } + } + + public T this[int index0, int index1, int index2, int index3, int index4] + { + get => this[[index0, index1, index2, index3, index4]]; + set => this[[index0, index1, index2, index3, index4]] = value; + } + + public ByReference GetElementAddress(int index0, int index1, int index2, int index3, int index4) => GetElementAddress([index0, index1, index2, index3, index4]); + + static void IIl2CppType>.WriteToSpan(Il2CppArrayRank5? value, Span span) => Il2CppType.WriteReference(value, span); + static Il2CppArrayRank5? IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => Il2CppType.ReadReference>(span); + + [return: NotNullIfNotNull(nameof(array))] + public static explicit operator Il2CppArrayRank5?(T[,,,,]? array) => array is null ? null : new(array); + + [return: NotNullIfNotNull(nameof(array))] + public static explicit operator T[,,,,]?(Il2CppArrayRank5? array) + { + if (array is null) + return null; + + var length_0 = array.GetLength(0); + var length_1 = array.GetLength(1); + var length_2 = array.GetLength(2); + var length_3 = array.GetLength(3); + var length_4 = array.GetLength(4); + var result = new T[length_0, length_1, length_2, length_3, length_4]; + for (var i_0 = 0; i_0 < length_0; i_0++) + { + for (var i_1 = 0; i_1 < length_1; i_1++) + { + for (var i_2 = 0; i_2 < length_2; i_2++) + { + for (var i_3 = 0; i_3 < length_3; i_3++) + { + for (var i_4 = 0; i_4 < length_4; i_4++) + { + result[i_0, i_1, i_2, i_3, i_4] = array[i_0, i_1, i_2, i_3, i_4]; + } + } + } + } + } + return result; + } +} From 0918175b6148ee1cf8d3ad08fb3e86cf1e975e5c Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 9 May 2026 16:02:53 -0700 Subject: [PATCH 417/486] Change Il2CppInterop.Runtime.Runtime namespace to Il2CppInterop.Runtime.Structs --- .../Il2CppInteropDetour.cs | 4 ++-- .../Il2CppInteropDetourFactory.cs | 4 ++-- Il2CppInterop.Runtime/DelegateSupport.cs | 2 +- Il2CppInterop.Runtime/GenerationInternals.cs | 2 +- .../Il2CppTypePointerStore.cs | 2 +- .../Injection/AssemblyInjector.cs | 4 ++-- .../Injection/GenericTypeInflater.cs | 6 ++--- .../Hooks/Class_FromIl2CppType_Hook.cs | 2 +- .../Injection/Hooks/Class_FromName_Hook.cs | 2 +- .../Hooks/Class_GetFieldDefaultValue_Hook.cs | 6 ++--- ...GetTypeInfoFromTypeDefinitionIndex_Hook.cs | 2 +- .../Injection/InjectorHelpers.cs | 4 ++-- .../Injection/TypeInjector.cs | 6 ++--- .../InteropTypes/Arrays/Il2CppArrayBase.cs | 2 +- .../Startup/Il2CppInteropRuntime.cs | 2 +- ...ApplicableToUnityVersionsSinceAttribute.cs | 2 +- .../{Runtime => Structs}/INativeStruct.cs | 2 +- .../INativeStructHandler.cs | 2 +- .../{Runtime => Structs}/Il2CppStructs.cs | 2 +- .../UnityVersionHandler.cs | 24 +++++++++---------- .../Assembly/Assembly_104_0.cs | 4 ++-- .../VersionSpecific/Assembly/Assembly_16_0.cs | 4 ++-- .../VersionSpecific/Assembly/Assembly_20_0.cs | 4 ++-- .../VersionSpecific/Assembly/Assembly_24_0.cs | 4 ++-- .../VersionSpecific/Assembly/Assembly_24_1.cs | 4 ++-- .../VersionSpecific/Assembly/Assembly_24_2.cs | 4 ++-- .../VersionSpecific/Assembly/Interfaces.cs | 4 ++-- .../AssemblyName/AssemblyName_16_0.cs | 2 +- .../AssemblyName/AssemblyName_24_0.cs | 2 +- .../AssemblyName/AssemblyName_24_1.cs | 2 +- .../AssemblyName/Interfaces.cs | 2 +- .../VersionSpecific/Class/Class_104_0.cs | 4 ++-- .../VersionSpecific/Class/Class_105_0.cs | 4 ++-- .../VersionSpecific/Class/Class_16_0.cs | 4 ++-- .../VersionSpecific/Class/Class_19_0.cs | 4 ++-- .../VersionSpecific/Class/Class_20_0.cs | 4 ++-- .../VersionSpecific/Class/Class_21_0.cs | 4 ++-- .../VersionSpecific/Class/Class_21_1.cs | 4 ++-- .../VersionSpecific/Class/Class_21_2.cs | 4 ++-- .../VersionSpecific/Class/Class_22_0.cs | 4 ++-- .../VersionSpecific/Class/Class_22_1.cs | 4 ++-- .../VersionSpecific/Class/Class_23_0.cs | 4 ++-- .../VersionSpecific/Class/Class_23_1.cs | 4 ++-- .../VersionSpecific/Class/Class_24_0.cs | 4 ++-- .../VersionSpecific/Class/Class_24_1.cs | 4 ++-- .../VersionSpecific/Class/Class_24_2.cs | 4 ++-- .../VersionSpecific/Class/Class_24_3.cs | 4 ++-- .../VersionSpecific/Class/Class_24_4.cs | 4 ++-- .../VersionSpecific/Class/Class_24_5.cs | 4 ++-- .../VersionSpecific/Class/Class_24_6.cs | 4 ++-- .../VersionSpecific/Class/Class_24_7.cs | 4 ++-- .../VersionSpecific/Class/Class_27_0.cs | 4 ++-- .../VersionSpecific/Class/Class_27_1.cs | 4 ++-- .../VersionSpecific/Class/Class_27_2.cs | 4 ++-- .../VersionSpecific/Class/Class_27_3.cs | 4 ++-- .../VersionSpecific/Class/Class_27_4.cs | 4 ++-- .../VersionSpecific/Class/Class_27_5.cs | 4 ++-- .../VersionSpecific/Class/Class_29_0.cs | 4 ++-- .../VersionSpecific/Class/Class_29_1.cs | 4 ++-- .../VersionSpecific/Class/Class_29_2.cs | 4 ++-- .../VersionSpecific/Class/Class_39_0.cs | 4 ++-- .../VersionSpecific/Class/Interfaces.cs | 4 ++-- .../EventInfo/EventInfo_16_0.cs | 2 +- .../EventInfo/EventInfo_19_0.cs | 2 +- .../EventInfo/EventInfo_24_0.cs | 2 +- .../VersionSpecific/EventInfo/Interfaces.cs | 2 +- .../Exception/Exception_16_0.cs | 2 +- .../Exception/Exception_20_0.cs | 2 +- .../Exception/Exception_21_0.cs | 2 +- .../Exception/Exception_22_0.cs | 2 +- .../Exception/Exception_23_0.cs | 2 +- .../Exception/Exception_23_1.cs | 2 +- .../Exception/Exception_27_0.cs | 2 +- .../VersionSpecific/Exception/Interfaces.cs | 2 +- .../FieldInfo/FieldInfo_16_0.cs | 2 +- .../FieldInfo/FieldInfo_19_0.cs | 2 +- .../FieldInfo/FieldInfo_24_0.cs | 2 +- .../VersionSpecific/FieldInfo/Interfaces.cs | 2 +- .../VersionSpecific/Image/Image_16_0.cs | 2 +- .../VersionSpecific/Image/Image_19_0.cs | 2 +- .../VersionSpecific/Image/Image_24_0.cs | 2 +- .../VersionSpecific/Image/Image_24_1.cs | 2 +- .../VersionSpecific/Image/Image_24_2.cs | 2 +- .../VersionSpecific/Image/Image_24_3.cs | 2 +- .../VersionSpecific/Image/Image_24_4.cs | 2 +- .../VersionSpecific/Image/Image_24_5.cs | 2 +- .../VersionSpecific/Image/Image_24_6.cs | 2 +- .../VersionSpecific/Image/Interfaces.cs | 2 +- .../VersionSpecific/MethodInfo/Interfaces.cs | 2 +- .../MethodInfo/MethodInfo_16_0.cs | 2 +- .../MethodInfo/MethodInfo_21_0.cs | 2 +- .../MethodInfo/MethodInfo_24_0.cs | 2 +- .../MethodInfo/MethodInfo_24_1.cs | 2 +- .../MethodInfo/MethodInfo_24_2.cs | 2 +- .../MethodInfo/MethodInfo_27_0.cs | 2 +- .../MethodInfo/MethodInfo_28_0.cs | 2 +- .../MethodInfo/MethodInfo_29_0.cs | 2 +- .../MethodInfo/MethodInfo_29_1.cs | 2 +- .../MethodInfo/MethodInfo_29_2.cs | 2 +- .../ParameterInfo/Interfaces.cs | 2 +- .../ParameterInfo/ParameterInfo_16_0.cs | 2 +- .../ParameterInfo/ParameterInfo_24_0.cs | 2 +- .../ParameterInfo/ParameterInfo_27_0.cs | 2 +- .../PropertyInfo/Interfaces.cs | 2 +- .../PropertyInfo/PropertyInfo_16_0.cs | 2 +- .../PropertyInfo/PropertyInfo_19_0.cs | 2 +- .../PropertyInfo/PropertyInfo_24_0.cs | 2 +- .../VersionSpecific/Type/Interfaces.cs | 2 +- .../VersionSpecific/Type/Type_16_0.cs | 2 +- .../VersionSpecific/Type/Type_27_0.cs | 2 +- .../Il2CppStructWrapperGenerator.cs | 4 ++-- .../TypeGenerators/Il2CppClassGenerator.cs | 2 +- .../VersionSpecificGenerator.cs | 2 +- 113 files changed, 173 insertions(+), 173 deletions(-) rename Il2CppInterop.Runtime/{Runtime => Structs}/ApplicableToUnityVersionsSinceAttribute.cs (89%) rename Il2CppInterop.Runtime/{Runtime => Structs}/INativeStruct.cs (95%) rename Il2CppInterop.Runtime/{Runtime => Structs}/INativeStructHandler.cs (62%) rename Il2CppInterop.Runtime/{Runtime => Structs}/Il2CppStructs.cs (99%) rename Il2CppInterop.Runtime/{Runtime => Structs}/UnityVersionHandler.cs (93%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Assembly/Assembly_104_0.cs (93%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Assembly/Assembly_16_0.cs (92%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Assembly/Assembly_20_0.cs (93%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Assembly/Assembly_24_0.cs (93%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Assembly/Assembly_24_1.cs (93%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Assembly/Assembly_24_2.cs (93%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Assembly/Interfaces.cs (77%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/AssemblyName/AssemblyName_16_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/AssemblyName/AssemblyName_24_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/AssemblyName/AssemblyName_24_1.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/AssemblyName/Interfaces.cs (90%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_104_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_105_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_16_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_19_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_20_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_21_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_21_1.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_21_2.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_22_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_22_1.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_23_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_23_1.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_24_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_24_1.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_24_2.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_24_3.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_24_4.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_24_5.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_24_6.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_24_7.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_27_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_27_1.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_27_2.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_27_3.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_27_4.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_27_5.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_29_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_29_1.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_29_2.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Class_39_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Class/Interfaces.cs (94%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/EventInfo/EventInfo_16_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/EventInfo/EventInfo_19_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/EventInfo/EventInfo_24_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/EventInfo/Interfaces.cs (90%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Exception/Exception_16_0.cs (97%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Exception/Exception_20_0.cs (97%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Exception/Exception_21_0.cs (97%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Exception/Exception_22_0.cs (97%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Exception/Exception_23_0.cs (97%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Exception/Exception_23_1.cs (97%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Exception/Exception_27_0.cs (97%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Exception/Interfaces.cs (91%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/FieldInfo/FieldInfo_16_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/FieldInfo/FieldInfo_19_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/FieldInfo/FieldInfo_24_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/FieldInfo/Interfaces.cs (88%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Image/Image_16_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Image/Image_19_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Image/Image_24_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Image/Image_24_1.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Image/Image_24_2.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Image/Image_24_3.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Image/Image_24_4.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Image/Image_24_5.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Image/Image_24_6.cs (97%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Image/Interfaces.cs (88%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/MethodInfo/Interfaces.cs (93%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/MethodInfo/MethodInfo_16_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/MethodInfo/MethodInfo_21_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/MethodInfo/MethodInfo_24_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/MethodInfo/MethodInfo_24_1.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/MethodInfo/MethodInfo_24_2.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/MethodInfo/MethodInfo_27_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/MethodInfo/MethodInfo_28_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/MethodInfo/MethodInfo_29_0.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/MethodInfo/MethodInfo_29_1.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/MethodInfo/MethodInfo_29_2.cs (98%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/ParameterInfo/Interfaces.cs (89%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/PropertyInfo/Interfaces.cs (90%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs (96%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Type/Interfaces.cs (89%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Type/Type_16_0.cs (97%) rename Il2CppInterop.Runtime/{Runtime => Structs}/VersionSpecific/Type/Type_27_0.cs (97%) diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs index a8b4c082..4615f683 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs @@ -4,8 +4,8 @@ using Il2CppInterop.Common; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Injection; -using Il2CppInterop.Runtime.Runtime; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo; +using Il2CppInterop.Runtime.Structs; +using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; using Microsoft.Extensions.Logging; using Mono.Cecil; using MonoMod.Cil; diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs index 6c5f539b..34e002d5 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs @@ -1,8 +1,8 @@ using System.Diagnostics.CodeAnalysis; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Injection; -using Il2CppInterop.Runtime.Runtime; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo; +using Il2CppInterop.Runtime.Structs; +using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; using MonoMod.Core; namespace Il2CppInterop.HarmonySupport; diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index 8458c204..c0fe162b 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -12,7 +12,7 @@ using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; -using Il2CppInterop.Runtime.Runtime; +using Il2CppInterop.Runtime.Structs; using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime; diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index c0a8e839..cb68c736 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -6,7 +6,7 @@ using Il2CppInterop.Runtime.Exceptions; using Il2CppInterop.Runtime.Extensions; using Il2CppInterop.Runtime.Injection; -using Il2CppInterop.Runtime.Runtime; +using Il2CppInterop.Runtime.Structs; using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime; diff --git a/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs b/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs index 24d6d563..5598fc8f 100644 --- a/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs +++ b/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs @@ -1,6 +1,6 @@ using Il2CppInterop.Common; using Il2CppInterop.Runtime.InteropTypes; -using Il2CppInterop.Runtime.Runtime; +using Il2CppInterop.Runtime.Structs; namespace Il2CppInterop.Runtime; diff --git a/Il2CppInterop.Runtime/Injection/AssemblyInjector.cs b/Il2CppInterop.Runtime/Injection/AssemblyInjector.cs index 673dac70..ca3ca591 100644 --- a/Il2CppInterop.Runtime/Injection/AssemblyInjector.cs +++ b/Il2CppInterop.Runtime/Injection/AssemblyInjector.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Runtime.InteropServices; using Il2CppInterop.Common; -using Il2CppInterop.Runtime.Runtime; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Image; +using Il2CppInterop.Runtime.Structs; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Image; using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime.Injection; diff --git a/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs b/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs index 0907325a..a44e5cb5 100644 --- a/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs +++ b/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs @@ -1,7 +1,7 @@ using System; -using Il2CppInterop.Runtime.Runtime; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; +using Il2CppInterop.Runtime.Structs; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Class; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Injection; diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs index 31a6ece0..ea27a942 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Runtime.InteropServices; using Il2CppInterop.Common; -using Il2CppInterop.Runtime.Runtime; +using Il2CppInterop.Runtime.Structs; using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime.Injection.Hooks diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs index cbe9c8a7..3ce3e808 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Runtime.InteropServices; using Il2CppInterop.Common; -using Il2CppInterop.Runtime.Runtime; +using Il2CppInterop.Runtime.Structs; using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime.Injection.Hooks diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs index dc91fa54..0d4c7054 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs @@ -3,10 +3,10 @@ using System.Runtime.InteropServices; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Extensions; -using Il2CppInterop.Runtime.Runtime; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.FieldInfo; using Il2CppInterop.Runtime.Startup; +using Il2CppInterop.Runtime.Structs; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Class; +using Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo; using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime.Injection.Hooks diff --git a/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs index 4a03efcf..8c1dba0c 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs @@ -2,8 +2,8 @@ using System.Linq; using System.Runtime.InteropServices; using Il2CppInterop.Common; -using Il2CppInterop.Runtime.Runtime; using Il2CppInterop.Runtime.Startup; +using Il2CppInterop.Runtime.Structs; using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime.Injection.Hooks diff --git a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs index e9ede516..8990e030 100644 --- a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs +++ b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs @@ -8,8 +8,8 @@ using System.Threading; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Injection.Hooks; -using Il2CppInterop.Runtime.Runtime; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo; +using Il2CppInterop.Runtime.Structs; +using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime.Injection diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index a2448acd..dda97fd2 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -10,9 +10,9 @@ using Il2CppInterop.Common; using Il2CppInterop.Common.Attributes; using Il2CppInterop.Runtime.Extensions; -using Il2CppInterop.Runtime.Runtime; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo; +using Il2CppInterop.Runtime.Structs; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Class; +using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime.Injection; diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs index 0474720b..ae47fae9 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayBase.cs @@ -2,7 +2,7 @@ using System.Buffers; using System.Runtime.CompilerServices; using Il2CppInterop.Common; -using Il2CppInterop.Runtime.Runtime; +using Il2CppInterop.Runtime.Structs; namespace Il2CppInterop.Runtime.InteropTypes.Arrays; diff --git a/Il2CppInterop.Runtime/Startup/Il2CppInteropRuntime.cs b/Il2CppInterop.Runtime/Startup/Il2CppInteropRuntime.cs index bf1167bd..ad0ec305 100644 --- a/Il2CppInterop.Runtime/Startup/Il2CppInteropRuntime.cs +++ b/Il2CppInterop.Runtime/Startup/Il2CppInteropRuntime.cs @@ -1,7 +1,7 @@ using AssetRipper.Primitives; using Il2CppInterop.Common.Host; using Il2CppInterop.Runtime.Injection; -using Il2CppInterop.Runtime.Runtime; +using Il2CppInterop.Runtime.Structs; namespace Il2CppInterop.Runtime.Startup; diff --git a/Il2CppInterop.Runtime/Runtime/ApplicableToUnityVersionsSinceAttribute.cs b/Il2CppInterop.Runtime/Structs/ApplicableToUnityVersionsSinceAttribute.cs similarity index 89% rename from Il2CppInterop.Runtime/Runtime/ApplicableToUnityVersionsSinceAttribute.cs rename to Il2CppInterop.Runtime/Structs/ApplicableToUnityVersionsSinceAttribute.cs index 9b2ab056..9fc771a8 100644 --- a/Il2CppInterop.Runtime/Runtime/ApplicableToUnityVersionsSinceAttribute.cs +++ b/Il2CppInterop.Runtime/Structs/ApplicableToUnityVersionsSinceAttribute.cs @@ -1,6 +1,6 @@ using System; -namespace Il2CppInterop.Runtime.Runtime; +namespace Il2CppInterop.Runtime.Structs; [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] internal sealed class ApplicableToUnityVersionsSinceAttribute : Attribute diff --git a/Il2CppInterop.Runtime/Runtime/INativeStruct.cs b/Il2CppInterop.Runtime/Structs/INativeStruct.cs similarity index 95% rename from Il2CppInterop.Runtime/Runtime/INativeStruct.cs rename to Il2CppInterop.Runtime/Structs/INativeStruct.cs index c55e8059..0b27a347 100644 --- a/Il2CppInterop.Runtime/Runtime/INativeStruct.cs +++ b/Il2CppInterop.Runtime/Structs/INativeStruct.cs @@ -1,4 +1,4 @@ -namespace Il2CppInterop.Runtime.Runtime; +namespace Il2CppInterop.Runtime.Structs; public interface INativeStruct { diff --git a/Il2CppInterop.Runtime/Runtime/INativeStructHandler.cs b/Il2CppInterop.Runtime/Structs/INativeStructHandler.cs similarity index 62% rename from Il2CppInterop.Runtime/Runtime/INativeStructHandler.cs rename to Il2CppInterop.Runtime/Structs/INativeStructHandler.cs index 38b9e28f..001c22e4 100644 --- a/Il2CppInterop.Runtime/Runtime/INativeStructHandler.cs +++ b/Il2CppInterop.Runtime/Structs/INativeStructHandler.cs @@ -1,4 +1,4 @@ -namespace Il2CppInterop.Runtime.Runtime; +namespace Il2CppInterop.Runtime.Structs; public interface INativeStructHandler { diff --git a/Il2CppInterop.Runtime/Runtime/Il2CppStructs.cs b/Il2CppInterop.Runtime/Structs/Il2CppStructs.cs similarity index 99% rename from Il2CppInterop.Runtime/Runtime/Il2CppStructs.cs rename to Il2CppInterop.Runtime/Structs/Il2CppStructs.cs index c2f48fc0..8deeb873 100644 --- a/Il2CppInterop.Runtime/Runtime/Il2CppStructs.cs +++ b/Il2CppInterop.Runtime/Structs/Il2CppStructs.cs @@ -8,7 +8,7 @@ // ReSharper disable InconsistentNaming // ReSharper disable UnusedMember.Global -namespace Il2CppInterop.Runtime.Runtime; +namespace Il2CppInterop.Runtime.Structs; //Stub structs public struct Il2CppAssembly diff --git a/Il2CppInterop.Runtime/Runtime/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs similarity index 93% rename from Il2CppInterop.Runtime/Runtime/UnityVersionHandler.cs rename to Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs index 56228cd1..1c65a17b 100644 --- a/Il2CppInterop.Runtime/Runtime/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs @@ -6,21 +6,21 @@ using AssetRipper.Primitives; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Extensions; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.EventInfo; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.FieldInfo; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Image; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.ParameterInfo; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.PropertyInfo; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; using Il2CppInterop.Runtime.Startup; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly; +using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Class; +using Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Exception; +using Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Image; +using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; +using Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo; +using Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; using Microsoft.Extensions.Logging; -namespace Il2CppInterop.Runtime.Runtime; +namespace Il2CppInterop.Runtime.Structs; public static class UnityVersionHandler { diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_104_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_104_0.cs similarity index 93% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_104_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_104_0.cs index 45309b36..cc4c0420 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_104_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_104_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly +using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly { [ApplicableToUnityVersionsSince("6000.5.0")] public unsafe class NativeAssemblyStructHandler_104_0 : INativeAssemblyStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_16_0.cs similarity index 92% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_16_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_16_0.cs index a00853b6..142e74b8 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_16_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly +using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly { [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeAssemblyStructHandler_16_0 : INativeAssemblyStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_20_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_20_0.cs similarity index 93% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_20_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_20_0.cs index 666174ca..034e3003 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_20_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_20_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly +using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly { [ApplicableToUnityVersionsSince("5.3.2p1")] public unsafe class NativeAssemblyStructHandler_20_0 : INativeAssemblyStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_0.cs similarity index 93% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_0.cs index 3f414bed..f035e60d 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly +using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly { [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeAssemblyStructHandler_24_0 : INativeAssemblyStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_1.cs similarity index 93% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_1.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_1.cs index cd802be4..6e34789d 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_1.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly +using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly { [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeAssemblyStructHandler_24_1 : INativeAssemblyStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_2.cs similarity index 93% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_2.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_2.cs index ccc54b09..f20fa1e6 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Assembly_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_2.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly +using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly { [ApplicableToUnityVersionsSince("2018.4.34")] public unsafe class NativeAssemblyStructHandler_24_2 : INativeAssemblyStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Interfaces.cs similarity index 77% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Interfaces.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Interfaces.cs index 7fa69ad4..f1c06e7a 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Assembly/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Interfaces.cs @@ -1,5 +1,5 @@ -using Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Assembly +using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly { public interface INativeAssemblyStructHandler : INativeStructHandler { diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_16_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_16_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_16_0.cs index c09158e0..ea63b213 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_16_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName { [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeAssemblyNameStructHandler_16_0 : INativeAssemblyNameStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_0.cs index 04206b4d..f9e97271 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName { [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeAssemblyNameStructHandler_24_0 : INativeAssemblyNameStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_1.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_1.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_1.cs index eb68332b..e47501a1 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/AssemblyName_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_1.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName { [ApplicableToUnityVersionsSince("2018.4.34")] public unsafe class NativeAssemblyNameStructHandler_24_1 : INativeAssemblyNameStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/Interfaces.cs similarity index 90% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/Interfaces.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/Interfaces.cs index f51c60f0..fbe59eb5 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/AssemblyName/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/Interfaces.cs @@ -1,4 +1,4 @@ -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.AssemblyName +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName { public interface INativeAssemblyNameStructHandler : INativeStructHandler { diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_104_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_104_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs index b37d2d1c..3667063e 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_104_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("6000.5.0")] public unsafe class NativeClassStructHandler_104_0 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_105_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_105_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs index 027b27af..05c547bb 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_105_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("6000.5.0a5")] public unsafe class NativeClassStructHandler_105_0 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_16_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs index 68f13eb4..307f7b12 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeClassStructHandler_16_0 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_19_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs index 6071ae64..f2f7399f 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.3.1p3")] public unsafe class NativeClassStructHandler_19_0 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_20_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_20_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs index 4478f19a..4292bae2 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_20_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.3.2p2")] public unsafe class NativeClassStructHandler_20_0 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs index 9f19703d..b1610144 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.3.5p1")] public unsafe class NativeClassStructHandler_21_0 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_1.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs index d6101f0f..16152eaf 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.3.5p3")] public unsafe class NativeClassStructHandler_21_1 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_2.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs index 079f4780..3ecd8615 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.4.3p4")] public unsafe class NativeClassStructHandler_21_2 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs index 8c0e9ea2..c980d232 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.5.0")] public unsafe class NativeClassStructHandler_22_0 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_1.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs index 87822f1b..26f02b89 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.5.0p2")] public unsafe class NativeClassStructHandler_22_1 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs index 98e6160d..a18dd64e 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.6.0")] public unsafe class NativeClassStructHandler_23_0 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_1.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs index 6ba3336a..40fa1791 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.6.0b3")] public unsafe class NativeClassStructHandler_23_1 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs index a5d848df..352db28b 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeClassStructHandler_24_0 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_1.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs index 196c0625..ee39744a 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2018.2.0")] public unsafe class NativeClassStructHandler_24_1 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_2.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs index 147262b9..2296ce31 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeClassStructHandler_24_2 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_3.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_3.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs index ac486ef6..dc2265fe 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_3.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2018.3.0b11")] public unsafe class NativeClassStructHandler_24_3 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_4.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_4.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs index 7a4e2fef..eea04ec1 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_4.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2018.3.8")] public unsafe class NativeClassStructHandler_24_4 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_5.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_5.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs index 78bfb743..a2f762ef 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_5.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2019.1.0a11")] public unsafe class NativeClassStructHandler_24_5 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_6.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_6.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs index c0d2f148..66e1b42a 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_6.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2019.1.0b5")] public unsafe class NativeClassStructHandler_24_6 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_7.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_7.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs index fd566426..df220df5 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_7.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2020.2.0")] public unsafe class NativeClassStructHandler_24_7 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs index e8baa2dd..38dfc36f 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2020.3.20")] public unsafe class NativeClassStructHandler_27_0 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_1.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs index 2a43e0f9..14f1f308 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2021.1.0")] public unsafe class NativeClassStructHandler_27_1 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_2.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs index 102fcd34..67da67cf 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2021.1.24")] public unsafe class NativeClassStructHandler_27_2 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_3.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_3.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs index 029e2ae0..0f3cac60 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_3.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2021.2.0")] public unsafe class NativeClassStructHandler_27_3 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_4.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_4.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs index 8913cafd..767a95dc 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_4.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2021.2.0a12")] public unsafe class NativeClassStructHandler_27_4 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_5.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_5.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs index 7c09b57d..f6c40e9b 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_5.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2021.2.0a21")] public unsafe class NativeClassStructHandler_27_5 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs index 441ad720..867fc5c3 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2021.2.0b13")] public unsafe class NativeClassStructHandler_29_0 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_1.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs index cc58c530..f1287c72 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2022.2.0")] public unsafe class NativeClassStructHandler_29_1 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_2.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs index 1418569c..24c57cf0 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2023.1.0a15")] public unsafe class NativeClassStructHandler_29_2 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_39_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_39_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs index 36a090a2..460c826c 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_39_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("6000.3.3")] public unsafe class NativeClassStructHandler_39_0 : INativeClassStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Interfaces.cs similarity index 94% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Interfaces.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Interfaces.cs index 9e937179..3c4031e3 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Interfaces.cs @@ -1,5 +1,5 @@ -using Il2CppInterop.Runtime.Runtime.VersionSpecific.Type; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Class +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { public interface INativeClassStructHandler : INativeStructHandler { diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_16_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_16_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_16_0.cs index a2fa20c3..f9683e3b 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_16_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.EventInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo { [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeEventInfoStructHandler_16_0 : INativeEventInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_19_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_19_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_19_0.cs index fd25d684..95110105 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_19_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.EventInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo { [ApplicableToUnityVersionsSince("5.3.1p3")] public unsafe class NativeEventInfoStructHandler_19_0 : INativeEventInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_24_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_24_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_24_0.cs index 9439d3ea..3e26dee3 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/EventInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_24_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.EventInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo { [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeEventInfoStructHandler_24_0 : INativeEventInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/Interfaces.cs similarity index 90% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/Interfaces.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/Interfaces.cs index 0b10356b..04c5bf68 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/EventInfo/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/Interfaces.cs @@ -1,4 +1,4 @@ -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.EventInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo { public interface INativeEventInfoStructHandler : INativeStructHandler { diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_16_0.cs similarity index 97% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_16_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_16_0.cs index e71cf465..5fc0fb5d 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_16_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeExceptionStructHandler_16_0 : INativeExceptionStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_20_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_20_0.cs similarity index 97% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_20_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_20_0.cs index 80ea0f98..dd259000 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_20_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_20_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { [ApplicableToUnityVersionsSince("5.3.2p2")] public unsafe class NativeExceptionStructHandler_20_0 : INativeExceptionStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_21_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_21_0.cs similarity index 97% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_21_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_21_0.cs index 2a521c15..e81a6ddd 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_21_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_21_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { [ApplicableToUnityVersionsSince("5.3.4p3")] public unsafe class NativeExceptionStructHandler_21_0 : INativeExceptionStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_22_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_22_0.cs similarity index 97% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_22_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_22_0.cs index b91d2028..5b43ca78 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_22_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_22_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { [ApplicableToUnityVersionsSince("5.5.0")] public unsafe class NativeExceptionStructHandler_22_0 : INativeExceptionStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_0.cs similarity index 97% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_0.cs index ef52979e..f83f6dc7 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { [ApplicableToUnityVersionsSince("5.6.0b3")] public unsafe class NativeExceptionStructHandler_23_0 : INativeExceptionStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_1.cs similarity index 97% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_1.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_1.cs index ba4e2fc4..137a0dd8 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_23_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_1.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { [ApplicableToUnityVersionsSince("5.6.0b6")] public unsafe class NativeExceptionStructHandler_23_1 : INativeExceptionStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_27_0.cs similarity index 97% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_27_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_27_0.cs index 06eea88a..a039590e 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Exception_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_27_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { [ApplicableToUnityVersionsSince("2021.2.0a19")] public unsafe class NativeExceptionStructHandler_27_0 : INativeExceptionStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Interfaces.cs similarity index 91% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Interfaces.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Interfaces.cs index 9e0f66aa..5014269c 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Exception/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Interfaces.cs @@ -1,4 +1,4 @@ -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Exception +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { public interface INativeExceptionStructHandler : INativeStructHandler { diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_16_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_16_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_16_0.cs index dd4fd841..64ef1cb0 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_16_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.FieldInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo { [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeFieldInfoStructHandler_16_0 : INativeFieldInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_19_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_19_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_19_0.cs index 8e206db2..242748b1 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_19_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.FieldInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo { [ApplicableToUnityVersionsSince("5.3.1p3")] public unsafe class NativeFieldInfoStructHandler_19_0 : INativeFieldInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_24_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_24_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_24_0.cs index 92c897ab..86d095ae 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/FieldInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_24_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.FieldInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo { [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeFieldInfoStructHandler_24_0 : INativeFieldInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/Interfaces.cs similarity index 88% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/Interfaces.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/Interfaces.cs index e45ead95..d6d260fa 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/FieldInfo/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/Interfaces.cs @@ -1,4 +1,4 @@ -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.FieldInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo { public interface INativeFieldInfoStructHandler : INativeStructHandler { diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_16_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_16_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_16_0.cs index 4832b775..b984b3cd 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_16_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeImageStructHandler_16_0 : INativeImageStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_19_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_19_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_19_0.cs index cdc8d11c..b283e216 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_19_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("5.3.1p3")] public unsafe class NativeImageStructHandler_19_0 : INativeImageStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_0.cs index 1325e6ff..2ac4d9d4 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("2017.1.0")] public unsafe class NativeImageStructHandler_24_0 : INativeImageStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_1.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_1.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_1.cs index f0059dc4..e6a17008 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_1.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("2017.1.2p1")] public unsafe class NativeImageStructHandler_24_1 : INativeImageStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_2.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_2.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_2.cs index 7b7610d5..9509889d 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_2.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("2018.1.0")] public unsafe class NativeImageStructHandler_24_2 : INativeImageStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_3.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_3.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_3.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_3.cs index cdb8165f..2a2ba102 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_3.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_3.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeImageStructHandler_24_3 : INativeImageStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_4.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_4.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_4.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_4.cs index a6ecd041..6c5f9ebb 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_4.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_4.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeImageStructHandler_24_4 : INativeImageStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_5.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_5.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_5.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_5.cs index 7522b3c7..92dca77b 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_5.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_5.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("2019.1.0a12")] public unsafe class NativeImageStructHandler_24_5 : INativeImageStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_6.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_6.cs similarity index 97% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_6.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_6.cs index f3806c75..d87a8c87 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Image_24_6.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_6.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("2020.2.0")] public unsafe class NativeImageStructHandler_24_6 : INativeImageStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Interfaces.cs similarity index 88% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Interfaces.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Interfaces.cs index 820030c2..a169ef6f 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Image/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Interfaces.cs @@ -1,4 +1,4 @@ -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Image +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { public interface INativeImageStructHandler : INativeStructHandler { diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/Interfaces.cs similarity index 93% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/Interfaces.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/Interfaces.cs index 2f413f60..287e1c58 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/Interfaces.cs @@ -1,4 +1,4 @@ -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { public interface INativeMethodInfoStructHandler : INativeStructHandler { diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_16_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_16_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_16_0.cs index 17bde1d0..60764aa8 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_16_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeMethodInfoStructHandler_16_0 : INativeMethodInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_21_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_21_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_21_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_21_0.cs index 8a138a12..a4762e66 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_21_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_21_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("5.3.5p3")] public unsafe class NativeMethodInfoStructHandler_21_0 : INativeMethodInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_0.cs index 51c25eec..234a98eb 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeMethodInfoStructHandler_24_0 : INativeMethodInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_1.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_1.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_1.cs index a37758ae..4dba8b6e 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_1.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("2018.1.0f1")] public unsafe class NativeMethodInfoStructHandler_24_1 : INativeMethodInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_2.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_2.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_2.cs index 197b0a7b..754b5262 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_2.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeMethodInfoStructHandler_24_2 : INativeMethodInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_27_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_27_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_27_0.cs index 91896fe3..e0c97989 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_27_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("2021.2.0")] public unsafe class NativeMethodInfoStructHandler_27_0 : INativeMethodInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_28_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_28_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_28_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_28_0.cs index 0eb01fa8..f2d701bd 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_28_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_28_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("2021.2.0b7")] public unsafe class NativeMethodInfoStructHandler_28_0 : INativeMethodInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_0.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_0.cs index 562229de..4132722f 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("2021.2.0b8")] public unsafe class NativeMethodInfoStructHandler_29_0 : INativeMethodInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_1.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_1.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_1.cs index 53becf7d..0f183e02 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_1.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("2021.2.0b13")] public unsafe class NativeMethodInfoStructHandler_29_1 : INativeMethodInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_2.cs similarity index 98% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_2.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_2.cs index c7e77119..2ccc618f 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/MethodInfo/MethodInfo_29_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_2.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("2023.2.0a22")] public unsafe class NativeMethodInfoStructHandler_29_2 : INativeMethodInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/Interfaces.cs similarity index 89% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/Interfaces.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/Interfaces.cs index 90866137..064762cc 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/Interfaces.cs @@ -1,4 +1,4 @@ -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.ParameterInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo { public interface INativeParameterInfoStructHandler : INativeStructHandler { diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs index ec3ad76e..88ad165b 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.ParameterInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo { [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeParameterInfoStructHandler_16_0 : INativeParameterInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs index fbcbc387..88ccfd54 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.ParameterInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo { [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeParameterInfoStructHandler_24_0 : INativeParameterInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs index 198dad47..9da6a7e7 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.ParameterInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo { [ApplicableToUnityVersionsSince("2021.2.0")] public unsafe class NativeParameterInfoStructHandler_27_0 : INativeParameterInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/Interfaces.cs similarity index 90% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/Interfaces.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/Interfaces.cs index f986b03b..cfa8dbef 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/Interfaces.cs @@ -1,4 +1,4 @@ -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.PropertyInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo { public interface INativePropertyInfoStructHandler : INativeStructHandler { diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs index 94556f50..8a34356d 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.PropertyInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo { [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativePropertyInfoStructHandler_16_0 : INativePropertyInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs index 7096763a..5b744191 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.PropertyInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo { [ApplicableToUnityVersionsSince("5.3.1p3")] public unsafe class NativePropertyInfoStructHandler_19_0 : INativePropertyInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs similarity index 96% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs index df112482..6e059a63 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.PropertyInfo +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo { [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativePropertyInfoStructHandler_24_0 : INativePropertyInfoStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Interfaces.cs similarity index 89% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Interfaces.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Interfaces.cs index 0e19d488..6d9c8119 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Interfaces.cs @@ -1,4 +1,4 @@ -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Type +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Type { public interface INativeTypeStructHandler : INativeStructHandler { diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_16_0.cs similarity index 97% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_16_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_16_0.cs index a6a991b9..9671ed86 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_16_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Type +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Type { [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeTypeStructHandler_16_0 : INativeTypeStructHandler diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_27_0.cs similarity index 97% rename from Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_27_0.cs rename to Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_27_0.cs index c3397fe1..528418fd 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Type/Type_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_27_0.cs @@ -1,5 +1,5 @@ using System.Runtime.InteropServices; -namespace Il2CppInterop.Runtime.Runtime.VersionSpecific.Type +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Type { [ApplicableToUnityVersionsSince("2021.1.0")] public unsafe class NativeTypeStructHandler_27_0 : INativeTypeStructHandler diff --git a/Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs b/Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs index bb81cd7a..7b05bd71 100644 --- a/Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs +++ b/Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs @@ -40,7 +40,7 @@ public static partial class Il2CppStructWrapperGenerator generator.NativeStructGenerator.FieldsToImport.Remove(field); if (Config.ClassNames.Contains(gen.NativeStructGenerator.CppClass.Name)) generator.ExtraUsings.Add( - $"Il2CppInterop.Runtime.Runtime.VersionSpecific.{gen.NativeStructGenerator.CppClass.Name.Replace("Il2Cpp", null)}"); + $"Il2CppInterop.Runtime.Structs.VersionSpecific.{gen.NativeStructGenerator.CppClass.Name.Replace("Il2Cpp", null)}"); } } generator.SetupElements(); @@ -142,7 +142,7 @@ public static void Generate(Il2CppStructWrapperGeneratorOptions options) Directory.CreateDirectory(generatorOutputDirectory); CodeGenFile file = new() { - Namespace = $"Il2CppInterop.Runtime.Runtime.VersionSpecific.{generator.NativeStructGenerator.CppClass.Name.Replace("Il2Cpp", null)}", + Namespace = $"Il2CppInterop.Runtime.Structs.VersionSpecific.{generator.NativeStructGenerator.CppClass.Name.Replace("Il2Cpp", null)}", Usings = { "System.Runtime.InteropServices" diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs index f5c0816f..f7b8e039 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs @@ -11,7 +11,7 @@ public Il2CppClassGenerator(string metadataSuffix, CppClass nativeClass) : base( var lastField = NativeStructGenerator.NativeStruct.Fields[^1]; if (lastField.Name == "vtable") NativeStructGenerator.NativeStruct.Fields.RemoveAt(NativeStructGenerator.NativeStruct.Fields.Count - 1); - ExtraUsings.Add("Il2CppInterop.Runtime.Runtime.VersionSpecific.Type"); + ExtraUsings.Add("Il2CppInterop.Runtime.Structs.VersionSpecific.Type"); } public override string CppClassName => "Il2CppClass"; diff --git a/Il2CppInterop.StructGenerator/VersionSpecificGenerator.cs b/Il2CppInterop.StructGenerator/VersionSpecificGenerator.cs index ed1ad56f..15eeded7 100644 --- a/Il2CppInterop.StructGenerator/VersionSpecificGenerator.cs +++ b/Il2CppInterop.StructGenerator/VersionSpecificGenerator.cs @@ -249,7 +249,7 @@ public CodeGenFile GenerateInterfacesFile() } var file = new CodeGenFile() { - Namespace = $"Il2CppInterop.Runtime.Runtime.VersionSpecific.{NativeStructGenerator.CppClass.Name.Replace("Il2Cpp", null)}", + Namespace = $"Il2CppInterop.Runtime.Structs.VersionSpecific.{NativeStructGenerator.CppClass.Name.Replace("Il2Cpp", null)}", Elements = { handlerInterface, From b3eff30edab70103a139a2c90bff7d6bcc34b55a Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 10:10:01 -0700 Subject: [PATCH 418/486] Change namespace for SignatureDefinition --- .../Injection/{ => Hooks}/SignatureDefinition.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Il2CppInterop.Runtime/Injection/{ => Hooks}/SignatureDefinition.cs (98%) diff --git a/Il2CppInterop.Runtime/Injection/SignatureDefinition.cs b/Il2CppInterop.Runtime/Injection/Hooks/SignatureDefinition.cs similarity index 98% rename from Il2CppInterop.Runtime/Injection/SignatureDefinition.cs rename to Il2CppInterop.Runtime/Injection/Hooks/SignatureDefinition.cs index 5c4a384d..2b33fdd2 100644 --- a/Il2CppInterop.Runtime/Injection/SignatureDefinition.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/SignatureDefinition.cs @@ -5,7 +5,7 @@ using System.Runtime.Versioning; using TerraFX.Interop.Windows; -namespace Il2CppInterop.Runtime.Injection; +namespace Il2CppInterop.Runtime.Injection.Hooks; internal struct SignatureDefinition { From eb279fdfd350e8d559186c21de668370671bf6aa Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 10:16:05 -0700 Subject: [PATCH 419/486] Move signature hashing logic from TypeInjector to separate files --- .../INativeMethodInfoStructExtensions.cs | 23 ++++ .../Extensions/XxHash128Extensions.cs | 52 +++++++++ .../Injection/NamedSignatureHash.cs | 54 +++++++++ .../Injection/SignatureHash.cs | 50 ++++++++ .../Injection/TypeInjector.cs | 108 +++--------------- 5 files changed, 194 insertions(+), 93 deletions(-) create mode 100644 Il2CppInterop.Runtime/Extensions/INativeMethodInfoStructExtensions.cs create mode 100644 Il2CppInterop.Runtime/Extensions/XxHash128Extensions.cs create mode 100644 Il2CppInterop.Runtime/Injection/NamedSignatureHash.cs create mode 100644 Il2CppInterop.Runtime/Injection/SignatureHash.cs diff --git a/Il2CppInterop.Runtime/Extensions/INativeMethodInfoStructExtensions.cs b/Il2CppInterop.Runtime/Extensions/INativeMethodInfoStructExtensions.cs new file mode 100644 index 00000000..b8d2962d --- /dev/null +++ b/Il2CppInterop.Runtime/Extensions/INativeMethodInfoStructExtensions.cs @@ -0,0 +1,23 @@ +using System; +using System.Runtime.InteropServices; +using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; + +namespace Il2CppInterop.Runtime.Extensions; + +internal static class INativeMethodInfoStructExtensions +{ + public static unsafe ReadOnlySpan GetNameSpan(this INativeMethodInfoStruct methodInfo) + { + var namePtr = methodInfo.Name; + if (namePtr == IntPtr.Zero) + return default; + + // Find null terminator + var length = 0; + while (Marshal.ReadByte(namePtr, length) > 0) + { + length++; + } + return new ReadOnlySpan((void*)namePtr, length); + } +} diff --git a/Il2CppInterop.Runtime/Extensions/XxHash128Extensions.cs b/Il2CppInterop.Runtime/Extensions/XxHash128Extensions.cs new file mode 100644 index 00000000..cc0c90f9 --- /dev/null +++ b/Il2CppInterop.Runtime/Extensions/XxHash128Extensions.cs @@ -0,0 +1,52 @@ +using System; +using System.Buffers; +using System.IO.Hashing; +using System.Runtime.InteropServices; +using System.Text; +using Il2CppInterop.Common; + +namespace Il2CppInterop.Runtime.Extensions; + +internal static class XxHash128Extensions +{ + public static void Append(this XxHash128 hash, byte value) + { + ReadOnlySpan data = [value]; + hash.Append(data); + } + + public static void Append(this XxHash128 hash, bool value) + { + hash.Append((byte)(value ? 1 : 0)); + } + + public static void Append(this XxHash128 hash, ReadOnlySpan characters) + { + var data = MemoryMarshal.AsBytes(characters); + hash.Append(data); + } + + public static void AppendUtf8(this XxHash128 hash, ReadOnlySpan characters) + { + var buffer = ArrayPool.Shared.Rent(Encoding.UTF8.GetMaxByteCount(characters.Length)); + var bytesWritten = Encoding.UTF8.GetBytes(characters, buffer); + hash.Append(buffer.AsSpan(0, bytesWritten)); + ArrayPool.Shared.Return(buffer); + } + + public static void Append(this XxHash128 hash, Il2CppSystem.String? str) + { + hash.Append(GetSpan(str)); + } + + private static unsafe ReadOnlySpan GetSpan(Il2CppSystem.String? str) + { + if (str is null) + return default; + + var pointer = str.Pointer; + var length = IL2CPP.il2cpp_string_length(pointer); + var characters = IL2CPP.il2cpp_string_chars(pointer); + return new ReadOnlySpan(characters, length); + } +} diff --git a/Il2CppInterop.Runtime/Injection/NamedSignatureHash.cs b/Il2CppInterop.Runtime/Injection/NamedSignatureHash.cs new file mode 100644 index 00000000..9ddad994 --- /dev/null +++ b/Il2CppInterop.Runtime/Injection/NamedSignatureHash.cs @@ -0,0 +1,54 @@ +using System; +using System.IO.Hashing; +using System.Reflection; +using Il2CppInterop.Common.Attributes; +using Il2CppInterop.Runtime.Extensions; +using Il2CppInterop.Runtime.Structs; +using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; + +namespace Il2CppInterop.Runtime.Injection; + +internal readonly record struct NamedSignatureHash +{ + private readonly UInt128 _hash; + + public unsafe NamedSignatureHash(INativeMethodInfoStruct methodInfo) + { + XxHash128 hash = new(); + hash.Append(methodInfo.GetNameSpan()); + hash.Append((methodInfo.Flags & Il2CppMethodFlags.METHOD_ATTRIBUTE_STATIC) != 0); + hash.Append(GetFullName(methodInfo.ReturnType)); + for (var i = 0; i < methodInfo.ParametersCount; i++) + { + var parameter = UnityVersionHandler.Wrap(methodInfo.Parameters, i); + hash.Append(GetFullName(parameter.ParameterType)); + } + _hash = hash.GetCurrentHashAsUInt128(); + } + + public NamedSignatureHash(MethodInfo methodInfo) + { + XxHash128 hash = new(); + var name = methodInfo.GetCustomAttribute()?.Name ?? methodInfo.Name; + hash.AppendUtf8(name); + hash.Append(methodInfo.IsStatic); + hash.Append(GetFullName(methodInfo.ReturnType)); + foreach (var parameter in methodInfo.GetParameters()) + { + hash.Append(GetFullName(parameter.ParameterType)); + } + _hash = hash.GetCurrentHashAsUInt128(); + } + + private static unsafe Il2CppSystem.String GetFullName(Type type) + { + return GetFullName((Il2CppTypeStruct*)Il2CppTypePointerStore.GetNativeTypePointer(type)); + } + + private static unsafe Il2CppSystem.String GetFullName(Il2CppTypeStruct* type) + { + return Il2CppSystem.Type.FromTypePointer((nint)type).FullName; + } + + public override string ToString() => _hash.ToString(); +} diff --git a/Il2CppInterop.Runtime/Injection/SignatureHash.cs b/Il2CppInterop.Runtime/Injection/SignatureHash.cs new file mode 100644 index 00000000..7a5f7ea7 --- /dev/null +++ b/Il2CppInterop.Runtime/Injection/SignatureHash.cs @@ -0,0 +1,50 @@ +using System; +using System.IO.Hashing; +using System.Reflection; +using Il2CppInterop.Runtime.Extensions; +using Il2CppInterop.Runtime.Structs; +using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; + +namespace Il2CppInterop.Runtime.Injection; + +internal readonly record struct SignatureHash +{ + private readonly UInt128 _hash; + + public unsafe SignatureHash(INativeMethodInfoStruct methodInfo) + { + XxHash128 hash = new(); + hash.Append((methodInfo.Flags & Il2CppMethodFlags.METHOD_ATTRIBUTE_STATIC) != 0); + hash.Append(GetFullName(methodInfo.ReturnType)); + for (var i = 0; i < methodInfo.ParametersCount; i++) + { + var parameter = UnityVersionHandler.Wrap(methodInfo.Parameters, i); + hash.Append(GetFullName(parameter.ParameterType)); + } + _hash = hash.GetCurrentHashAsUInt128(); + } + + public SignatureHash(MethodInfo methodInfo) + { + XxHash128 hash = new(); + hash.Append(methodInfo.IsStatic); + hash.Append(GetFullName(methodInfo.ReturnType)); + foreach (var parameter in methodInfo.GetParameters()) + { + hash.Append(GetFullName(parameter.ParameterType)); + } + _hash = hash.GetCurrentHashAsUInt128(); + } + + private static unsafe Il2CppSystem.String GetFullName(Type type) + { + return GetFullName((Il2CppTypeStruct*)Il2CppTypePointerStore.GetNativeTypePointer(type)); + } + + private static unsafe Il2CppSystem.String GetFullName(Il2CppTypeStruct* type) + { + return Il2CppSystem.Type.FromTypePointer((nint)type).FullName; + } + + public override string ToString() => _hash.ToString(); +} diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index dda97fd2..3498e8ad 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -29,7 +29,7 @@ public static unsafe class TypeInjector private static readonly HashSet NeedsInitialized = new(); private static readonly Dictionary NeedsVTableSet = new(); private static readonly HashSet NeedsFieldsSet = new(); - private static readonly ConcurrentDictionary InvokerCache = new(); + private static readonly ConcurrentDictionary InvokerCache = new(); /// /// If true, this type is part of the game and not something we are trying to inject nor something that has already been injected by us. @@ -546,26 +546,26 @@ private static int LowestInterfaceOffset(INativeClassStruct classPointer) return result; } - private static Dictionary CreateHashToMethodInfoDictionary(Type type) + private static Dictionary CreateHashToMethodInfoDictionary(Type type) { - return GetAllIl2CppMethods(type).ToDictionary(HashSignature); + return GetAllIl2CppMethods(type).ToDictionary(m => new NamedSignatureHash(m)); } - private static Dictionary CreateMethodInfoToHashDictionary(Type type) + private static Dictionary CreateMethodInfoToHashDictionary(Type type) { - return GetAllIl2CppMethods(type).ToDictionary(m => m, HashSignature); + return GetAllIl2CppMethods(type).ToDictionary(m => m, m => new NamedSignatureHash(m)); } - private static Dictionary CreateHashToNativeMethodInfoDictionary(INativeClassStruct classPointer) + private static Dictionary CreateHashToNativeMethodInfoDictionary(INativeClassStruct classPointer) { - var dict = new Dictionary(classPointer.MethodCount); + var dict = new Dictionary(classPointer.MethodCount); var currentClassPointer = classPointer; while (true) { for (var i = 0; i < currentClassPointer.MethodCount; i++) { var methodInfo = UnityVersionHandler.Wrap(currentClassPointer.Methods[i]); - dict.TryAdd(HashSignature(methodInfo), methodInfo); + dict.TryAdd(new NamedSignatureHash(methodInfo), methodInfo); } if (currentClassPointer.Parent is null) break; @@ -574,16 +574,16 @@ private static Dictionary CreateHashToNativeMe return dict; } - private static Dictionary CreateNativeMethodInfoToHashDictionary(INativeClassStruct classPointer) + private static Dictionary CreateNativeMethodInfoToHashDictionary(INativeClassStruct classPointer) { - var dict = new Dictionary(classPointer.MethodCount); + var dict = new Dictionary(classPointer.MethodCount); var currentClassPointer = classPointer; while (true) { for (var i = 0; i < currentClassPointer.MethodCount; i++) { var methodInfo = UnityVersionHandler.Wrap(currentClassPointer.Methods[i]); - dict.Add(methodInfo.Pointer, HashSignature(methodInfo)); + dict.Add(methodInfo.Pointer, new NamedSignatureHash(methodInfo)); } if (currentClassPointer.Parent is null) break; @@ -592,84 +592,6 @@ private static Dictionary CreateNativeMethodInfoToHashDictionar return dict; } - private static UInt128 HashSignature(INativeMethodInfoStruct methodInfo) - { - // The probability of a hash collision is infinitesimal. - XxHash128 hash = new(); - hash.Append(GetName(methodInfo)); - hash.Append((byte)((methodInfo.Flags & Il2CppMethodFlags.METHOD_ATTRIBUTE_STATIC) != 0 ? 1 : 0)); - hash.Append(GetFullName(methodInfo.ReturnType)); - for (var i = 0; i < methodInfo.ParametersCount; i++) - { - var parameter = UnityVersionHandler.Wrap(methodInfo.Parameters, i); - hash.Append(GetFullName(parameter.ParameterType)); - } - return hash.GetCurrentHashAsUInt128(); - } - - private static UInt128 HashSignature(MethodInfo methodInfo) - { - // The probability of a hash collision is infinitesimal. - XxHash128 hash = new(); - var name = methodInfo.GetCustomAttribute()?.Name ?? methodInfo.Name; - hash.Append(System.Text.Encoding.UTF8.GetBytes(name)); - hash.Append((byte)(methodInfo.IsStatic ? 1 : 0)); - hash.Append(GetFullName(methodInfo.ReturnType)); - foreach (var parameter in methodInfo.GetParameters()) - { - hash.Append(GetFullName(parameter.ParameterType)); - } - return hash.GetCurrentHashAsUInt128(); - } - - private static void Append(this XxHash128 hash, byte b) - { - ReadOnlySpan data = [b]; - hash.Append(data); - } - - private static void Append(this XxHash128 hash, Il2CppSystem.String? str) - { - var data = MemoryMarshal.AsBytes(GetSpan(str)); - hash.Append(data); - } - - private static ReadOnlySpan GetName(INativeMethodInfoStruct methodInfo) - { - var namePtr = methodInfo.Name; - if (namePtr == IntPtr.Zero) - return default; - - // Find null terminator - int length = 0; - while (Marshal.ReadByte(namePtr, length) != 0) - { - length++; - } - return new ReadOnlySpan((void*)namePtr, length); - } - - private static Il2CppSystem.String GetFullName(Type type) - { - return GetFullName((Il2CppTypeStruct*)Il2CppTypePointerStore.GetNativeTypePointer(type)); - } - - private static Il2CppSystem.String GetFullName(Il2CppTypeStruct* type) - { - return Il2CppSystem.Type.FromTypePointer((nint)type).FullName; - } - - private static ReadOnlySpan GetSpan(Il2CppSystem.String? str) - { - if (str is null) - return default; - - var pointer = str.Pointer; - var length = IL2CPP.il2cpp_string_length(pointer); - var characters = IL2CPP.il2cpp_string_chars(pointer); - return new ReadOnlySpan(characters, length); - } - private static IEnumerable GetAllIl2CppMethods(Type type) => type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static).Where(IsIl2CppMethod); private static IEnumerable GetIl2CppMethods(Type type) => type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(IsIl2CppMethod); private static IEnumerable GetIl2CppProperties(Type type) => type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(IsIl2CppProperty); @@ -1134,7 +1056,7 @@ static void Method(IntPtr obj, Il2CppMethodInfo* methodInfo) private static Delegate GetOrCreateInvoker(MethodInfo monoMethod) { - return InvokerCache.GetOrAdd(HashSignature(monoMethod), + return InvokerCache.GetOrAdd(new NamedSignatureHash(monoMethod), static (_, monoMethodInner) => CreateInvoker(monoMethodInner), monoMethod); } @@ -1152,7 +1074,7 @@ private static Delegate CreateInvoker(MethodInfo monoMethod) // arguments pointer // return value pointer (if not void) - method = new DynamicMethod($"Invoker_{HashSignature(monoMethod)}", + method = new DynamicMethod($"Invoker_{new NamedSignatureHash(monoMethod)}", MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(void), parameterTypes, typeof(TypeInjector), true); } @@ -1164,7 +1086,7 @@ private static Delegate CreateInvoker(MethodInfo monoMethod) // this pointer // arguments pointer - method = new DynamicMethod($"Invoker_{HashSignature(monoMethod)}", + method = new DynamicMethod($"Invoker_{new NamedSignatureHash(monoMethod)}", MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(IntPtr), parameterTypes, typeof(TypeInjector), true); } @@ -1261,7 +1183,7 @@ private static Delegate CreateTrampoline(MethodInfo monoMethod, bool callVirt) ]; var method = new DynamicMethod( - $"Trampoline_{monoMethod.DeclaringType}_{monoMethod.Name}_{HashSignature(monoMethod)}{(callVirt ? "_Virtual" : "")}", + $"Trampoline_{monoMethod.DeclaringType}_{monoMethod.Name}_{new NamedSignatureHash(monoMethod)}{(callVirt ? "_Virtual" : "")}", MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, nativeReturnType, nativeParameterTypes, typeof(TypeInjector), true); From cc89576b0a4f1a18700d8d2d6a764fee2dcca693 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 10:21:26 -0700 Subject: [PATCH 420/486] Don't create useless maps in TypeInjector --- Il2CppInterop.Runtime/Injection/TypeInjector.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 3498e8ad..1b603cad 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -280,8 +280,6 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i var interfaceOffsets = new List(); var map1 = CreateMethodInfoToHashDictionary(type); - var map2 = CreateHashToMethodInfoDictionary(type); - var map3 = CreateNativeMethodInfoToHashDictionary(classPointer); var map4 = CreateHashToNativeMethodInfoDictionary(classPointer); var index = 0; @@ -291,10 +289,8 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i var baseMethodToMethodMap = GetIl2CppMethods(type).ToDictionary(m => m.GetBaseDefinition(), m => m); - var baseMap1 = CreateMethodInfoToHashDictionary(baseType); var baseMap2 = CreateHashToMethodInfoDictionary(baseType); var baseMap3 = CreateNativeMethodInfoToHashDictionary(baseClassPointer); - var baseMap4 = CreateHashToNativeMethodInfoDictionary(baseClassPointer); var lowestedInterfaceOffset = LowestInterfaceOffset(baseClassPointer); for (; index < lowestedInterfaceOffset; index++) @@ -363,10 +359,8 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i } } - var interfaceMap1 = CreateMethodInfoToHashDictionary(interfaceType); var interfaceMap2 = CreateHashToMethodInfoDictionary(interfaceType); var interfaceMap3 = CreateNativeMethodInfoToHashDictionary(interfaceClassPointer); - var interfaceMap4 = CreateHashToNativeMethodInfoDictionary(interfaceClassPointer); for (var i = 0; i < interfaceVtableCount; i++) { @@ -416,10 +410,8 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i } } - var interfaceMap1 = CreateMethodInfoToHashDictionary(interfaceType); var interfaceMap2 = CreateHashToMethodInfoDictionary(interfaceType); var interfaceMap3 = CreateNativeMethodInfoToHashDictionary(interfaceClassPointer); - var interfaceMap4 = CreateHashToNativeMethodInfoDictionary(interfaceClassPointer); for (var i = 0; i < interfaceVtableCount; i++) { From f40afcac4ae5dbba400af07571c9fcf51b71da6b Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 10:30:42 -0700 Subject: [PATCH 421/486] Use SignatureHash for invokers instead of NamedSignatureHash --- Il2CppInterop.Runtime/Injection/TypeInjector.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 1b603cad..533f4ce6 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -29,7 +29,7 @@ public static unsafe class TypeInjector private static readonly HashSet NeedsInitialized = new(); private static readonly Dictionary NeedsVTableSet = new(); private static readonly HashSet NeedsFieldsSet = new(); - private static readonly ConcurrentDictionary InvokerCache = new(); + private static readonly ConcurrentDictionary InvokerCache = new(); /// /// If true, this type is part of the game and not something we are trying to inject nor something that has already been injected by us. @@ -1048,11 +1048,11 @@ static void Method(IntPtr obj, Il2CppMethodInfo* methodInfo) private static Delegate GetOrCreateInvoker(MethodInfo monoMethod) { - return InvokerCache.GetOrAdd(new NamedSignatureHash(monoMethod), - static (_, monoMethodInner) => CreateInvoker(monoMethodInner), monoMethod); + return InvokerCache.GetOrAdd(new SignatureHash(monoMethod), + static (signatureHash, monoMethodInner) => CreateInvoker(signatureHash, monoMethodInner), monoMethod); } - private static Delegate CreateInvoker(MethodInfo monoMethod) + private static Delegate CreateInvoker(SignatureHash signatureHash, MethodInfo monoMethod) { Debug.Assert(monoMethod.DeclaringType is not null); @@ -1066,7 +1066,7 @@ private static Delegate CreateInvoker(MethodInfo monoMethod) // arguments pointer // return value pointer (if not void) - method = new DynamicMethod($"Invoker_{new NamedSignatureHash(monoMethod)}", + method = new DynamicMethod($"Invoker_{signatureHash}", MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(void), parameterTypes, typeof(TypeInjector), true); } @@ -1078,7 +1078,7 @@ private static Delegate CreateInvoker(MethodInfo monoMethod) // this pointer // arguments pointer - method = new DynamicMethod($"Invoker_{new NamedSignatureHash(monoMethod)}", + method = new DynamicMethod($"Invoker_{signatureHash}", MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(IntPtr), parameterTypes, typeof(TypeInjector), true); } From a6b7b9da04c33b744f6e8090a372128bb1a0854e Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 10:32:56 -0700 Subject: [PATCH 422/486] Update XxHash128Extensions byte Append method Refactored the Append method for byte values to use new ReadOnlySpan(ref value) instead of a collection expression, improving clarity and consistency in span initialization. --- Il2CppInterop.Runtime/Extensions/XxHash128Extensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Il2CppInterop.Runtime/Extensions/XxHash128Extensions.cs b/Il2CppInterop.Runtime/Extensions/XxHash128Extensions.cs index cc0c90f9..3069b44f 100644 --- a/Il2CppInterop.Runtime/Extensions/XxHash128Extensions.cs +++ b/Il2CppInterop.Runtime/Extensions/XxHash128Extensions.cs @@ -11,7 +11,7 @@ internal static class XxHash128Extensions { public static void Append(this XxHash128 hash, byte value) { - ReadOnlySpan data = [value]; + ReadOnlySpan data = new ReadOnlySpan(ref value); hash.Append(data); } From a1b13c9ef69a6cd19651d10f864b97fbeada5a50 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 10:50:54 -0700 Subject: [PATCH 423/486] Refactor Il2Cppmscorlib access and remove static field Refactored Class_GetFieldDefaultValue_Hook.cs to directly retrieve Il2Cppmscorlib via typeof(Il2CppSystem.Type).Assembly, removing reliance on InjectorHelpers.Il2CppMscorlib. Deleted the now-unused static field from InjectorHelpers.cs. --- .../Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs | 3 ++- Il2CppInterop.Runtime/Injection/InjectorHelpers.cs | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs index 0d4c7054..d6bfbd5a 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs @@ -86,7 +86,8 @@ private static nint FindClassGetFieldDefaultValueXref(bool forceICallMethod = fa if (forceICallMethod) { // MonoField isn't present on 2021.2.0+ - var monoFieldType = InjectorHelpers.Il2CppMscorlib.GetTypesSafe().SingleOrDefault((x) => x.Name is nameof(Il2CppSystem.Reflection.MonoField)); + var il2Cppmscorlib = typeof(Il2CppSystem.Type).Assembly; + var monoFieldType = il2Cppmscorlib.GetTypesSafe().SingleOrDefault((x) => x.Name is nameof(Il2CppSystem.Reflection.MonoField)); if (monoFieldType == null) throw new Exception($"Unity {Il2CppInteropRuntime.Instance.UnityVersion} is not supported at the moment: MonoField isn't present in Il2Cppmscorlib.dll for unity version, unable to fetch icall"); diff --git a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs index 8990e030..9f6f047b 100644 --- a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs +++ b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs @@ -16,7 +16,6 @@ namespace Il2CppInterop.Runtime.Injection { internal static unsafe class InjectorHelpers { - internal static Assembly Il2CppMscorlib = typeof(Il2CppSystem.Type).Assembly; internal static ProcessModule Il2CppModule = Process.GetCurrentProcess() .Modules.OfType() .Single((x) => x.ModuleName is "GameAssembly.dll" or "GameAssembly.dylib" or "GameAssembly.so" or "UserAssembly.dll" || string.Equals(x.ModuleName, "GameAssembly.dll", StringComparison.OrdinalIgnoreCase)); From b6d7c2c5184499fa53ee9766c93ed3be731c988d Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 10:52:27 -0700 Subject: [PATCH 424/486] File scoped namespace for hooking classes --- Il2CppInterop.Runtime/Injection/Hook.cs | 59 +++-- .../Hooks/Class_FromIl2CppType_Hook.cs | 61 +++-- .../Injection/Hooks/Class_FromName_Hook.cs | 49 ++-- .../Hooks/Class_GetFieldDefaultValue_Hook.cs | 238 +++++++++--------- ...GetTypeInfoFromTypeDefinitionIndex_Hook.cs | 171 +++++++------ 5 files changed, 287 insertions(+), 291 deletions(-) diff --git a/Il2CppInterop.Runtime/Injection/Hook.cs b/Il2CppInterop.Runtime/Injection/Hook.cs index 24bb7bd1..502b2e39 100644 --- a/Il2CppInterop.Runtime/Injection/Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hook.cs @@ -3,44 +3,43 @@ using Il2CppInterop.Common; using Microsoft.Extensions.Logging; -namespace Il2CppInterop.Runtime.Injection +namespace Il2CppInterop.Runtime.Injection; + +internal abstract class Hook where T : Delegate { - internal abstract class Hook where T : Delegate - { - private bool _isApplied; - private T _detour; - private T _method; - private T _original; + private bool _isApplied; + private T _detour; + private T _method; + private T _original; - public T Original => _original; + public T Original => _original; - public abstract string TargetMethodName { get; } - public abstract T GetDetour(); - public abstract IntPtr FindTargetMethod(); + public abstract string TargetMethodName { get; } + public abstract T GetDetour(); + public abstract IntPtr FindTargetMethod(); - public virtual void TargetMethodNotFound() - { - throw new Exception($"Required target method {TargetMethodName} not found"); - } + public virtual void TargetMethodNotFound() + { + throw new Exception($"Required target method {TargetMethodName} not found"); + } - public void ApplyHook() - { - if (_isApplied) return; + public void ApplyHook() + { + if (_isApplied) return; - var methodPtr = FindTargetMethod(); + var methodPtr = FindTargetMethod(); - if (methodPtr == IntPtr.Zero) - { - TargetMethodNotFound(); - return; - } + if (methodPtr == IntPtr.Zero) + { + TargetMethodNotFound(); + return; + } - Logger.Instance.LogTrace("{MethodName} found: 0x{MethodPtr}", TargetMethodName, methodPtr.ToInt64().ToString("X2")); + Logger.Instance.LogTrace("{MethodName} found: 0x{MethodPtr}", TargetMethodName, methodPtr.ToInt64().ToString("X2")); - _detour = GetDetour(); - Detour.Apply(methodPtr, _detour, out _original); - _method = Marshal.GetDelegateForFunctionPointer(methodPtr); - _isApplied = true; - } + _detour = GetDetour(); + Detour.Apply(methodPtr, _detour, out _original); + _method = Marshal.GetDelegateForFunctionPointer(methodPtr); + _isApplied = true; } } diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs index ea27a942..a6b75074 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs @@ -5,45 +5,44 @@ using Il2CppInterop.Runtime.Structs; using Microsoft.Extensions.Logging; -namespace Il2CppInterop.Runtime.Injection.Hooks +namespace Il2CppInterop.Runtime.Injection.Hooks; + +internal unsafe class Class_FromIl2CppType_Hook : Hook { - internal unsafe class Class_FromIl2CppType_Hook : Hook + public override string TargetMethodName => "Class::FromIl2CppType"; + public override MethodDelegate GetDetour() => Hook; + + /// Common version of the Il2CppType, the only thing that changed between unity version are the bitfields values that we don't use + internal readonly struct Il2CppType { - public override string TargetMethodName => "Class::FromIl2CppType"; - public override MethodDelegate GetDetour() => Hook; + public readonly void* data; + public readonly ushort attrs; + public readonly Il2CppTypeEnum type; + private readonly byte _bitfield; + } - /// Common version of the Il2CppType, the only thing that changed between unity version are the bitfields values that we don't use - internal readonly struct Il2CppType - { - public readonly void* data; - public readonly ushort attrs; - public readonly Il2CppTypeEnum type; - private readonly byte _bitfield; - } + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate Il2CppClass* MethodDelegate(Il2CppType* type, bool throwOnError); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate Il2CppClass* MethodDelegate(Il2CppType* type, bool throwOnError); + private Il2CppClass* Hook(Il2CppType* type, bool throwOnError) + { + if (type == null) + return Original(type, throwOnError); - private Il2CppClass* Hook(Il2CppType* type, bool throwOnError) + if ((nint)type->data < 0 && (type->type is Il2CppTypeEnum.IL2CPP_TYPE_CLASS or Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)) { - if (type == null) - return Original(type, throwOnError); - - if ((nint)type->data < 0 && (type->type is Il2CppTypeEnum.IL2CPP_TYPE_CLASS or Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)) - { - InjectorHelpers.s_InjectedClasses.TryGetValue((nint)type->data, out var classPointer); - return (Il2CppClass*)classPointer; - } - - return Original(type, throwOnError); + InjectorHelpers.s_InjectedClasses.TryGetValue((nint)type->data, out var classPointer); + return (Il2CppClass*)classPointer; } - public override IntPtr FindTargetMethod() - { - var classFromTypeAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_class_from_il2cpp_type)); - Logger.Instance.LogTrace("il2cpp_class_from_il2cpp_type: 0x{ClassFromTypeApiAddress}", classFromTypeAPI.ToInt64().ToString("X2")); + return Original(type, throwOnError); + } - return XrefScanner.JumpTargets(classFromTypeAPI).Single(); - } + public override IntPtr FindTargetMethod() + { + var classFromTypeAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_class_from_il2cpp_type)); + Logger.Instance.LogTrace("il2cpp_class_from_il2cpp_type: 0x{ClassFromTypeApiAddress}", classFromTypeAPI.ToInt64().ToString("X2")); + + return XrefScanner.JumpTargets(classFromTypeAPI).Single(); } } diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs index 3ce3e808..3d9650ee 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs @@ -5,37 +5,36 @@ using Il2CppInterop.Runtime.Structs; using Microsoft.Extensions.Logging; -namespace Il2CppInterop.Runtime.Injection.Hooks -{ - internal unsafe class Class_FromName_Hook : Hook - { - public override string TargetMethodName => "Class::FromName"; - public override MethodDelegate GetDetour() => Hook; +namespace Il2CppInterop.Runtime.Injection.Hooks; - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate Il2CppClass* MethodDelegate(Il2CppImage* image, IntPtr _namespace, IntPtr name); +internal unsafe class Class_FromName_Hook : Hook +{ + public override string TargetMethodName => "Class::FromName"; + public override MethodDelegate GetDetour() => Hook; - private Il2CppClass* Hook(Il2CppImage* image, IntPtr _namespace, IntPtr name) - { - Il2CppClass* classPtr = Original(image, _namespace, name); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate Il2CppClass* MethodDelegate(Il2CppImage* image, IntPtr _namespace, IntPtr name); - if (classPtr == null) - { - var namespaze = Marshal.PtrToStringUTF8(_namespace) ?? ""; - var className = Marshal.PtrToStringUTF8(name) ?? ""; - InjectorHelpers.s_ClassNameLookup.TryGetValue((namespaze, className, (IntPtr)image), out IntPtr injectedClass); - classPtr = (Il2CppClass*)injectedClass; - } + private Il2CppClass* Hook(Il2CppImage* image, IntPtr _namespace, IntPtr name) + { + Il2CppClass* classPtr = Original(image, _namespace, name); - return classPtr; + if (classPtr == null) + { + var namespaze = Marshal.PtrToStringUTF8(_namespace) ?? ""; + var className = Marshal.PtrToStringUTF8(name) ?? ""; + InjectorHelpers.s_ClassNameLookup.TryGetValue((namespaze, className, (IntPtr)image), out IntPtr injectedClass); + classPtr = (Il2CppClass*)injectedClass; } - public override IntPtr FindTargetMethod() - { - var classFromNameAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_class_from_name)); - Logger.Instance.LogTrace("il2cpp_class_from_name: 0x{ClassFromNameApiAddress}", classFromNameAPI.ToInt64().ToString("X2")); + return classPtr; + } - return XrefScanner.JumpTargets(classFromNameAPI).Single(); - } + public override IntPtr FindTargetMethod() + { + var classFromNameAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_class_from_name)); + Logger.Instance.LogTrace("il2cpp_class_from_name: 0x{ClassFromNameApiAddress}", classFromNameAPI.ToInt64().ToString("X2")); + + return XrefScanner.JumpTargets(classFromNameAPI).Single(); } } diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs index d6bfbd5a..195c97e2 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs @@ -9,148 +9,148 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo; using Microsoft.Extensions.Logging; -namespace Il2CppInterop.Runtime.Injection.Hooks +namespace Il2CppInterop.Runtime.Injection.Hooks; + +internal unsafe class Class_GetFieldDefaultValue_Hook : Hook { - internal unsafe class Class_GetFieldDefaultValue_Hook : Hook + public override string TargetMethodName => "Class::GetDefaultFieldValue"; + public override MethodDelegate GetDetour() => Hook; + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate byte* MethodDelegate(Il2CppFieldInfo* field, out Il2CppTypeStruct* type); + + private byte* Hook(Il2CppFieldInfo* field, out Il2CppTypeStruct* type) { - public override string TargetMethodName => "Class::GetDefaultFieldValue"; - public override MethodDelegate GetDetour() => Hook; + if (TypeInjector.GetFieldDefaultValueOverride(field, out IntPtr newDefaultPtr)) + { + INativeFieldInfoStruct wrappedField = UnityVersionHandler.Wrap(field); + INativeClassStruct wrappedParent = UnityVersionHandler.Wrap(wrappedField.Parent); + INativeClassStruct wrappedElementClass = UnityVersionHandler.Wrap(wrappedParent.ElementClass); + type = wrappedElementClass.ByValArg.TypePointer; + return (byte*)newDefaultPtr; + } + return Original(field, out type); + } - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate byte* MethodDelegate(Il2CppFieldInfo* field, out Il2CppTypeStruct* type); + private static readonly SignatureDefinition[] s_Signatures = + [ + // Test Game - Unity 2021.3.4 (x64) + new SignatureDefinition + { + pattern = "\x48\x89\x5C\x24\x08\x48\x89\x74\x24\x10\x57\x48\x83\xEC\x20\x48\x8B\x79\x10\x48\x8B\xD9\x48\x8B\xF2\x48\x2B\x9F", + mask = "xxxxxxxxxxxxxx?xxxxxxxxxxxxx", + xref = false + }, - private byte* Hook(Il2CppFieldInfo* field, out Il2CppTypeStruct* type) + // V Rising - Unity 2022.3.23 (x64) + new SignatureDefinition + { + pattern = "\x48\x89\x5C\x24\x08\x48\x89\x74\x24\x10\x57\x48\x83\xEC\x40\x48\x8B\x41\x10", + mask = "xxxxxxxxxxxxxxxxxxx", + xref = false + }, + // GTFO - Unity 2019.4.21 (x64) + // DigitalCraft Dolce 3.1.2 - Unity 2022.3.55 (x64) + new SignatureDefinition + { + pattern = "\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x20\x48\x8B\x41\x10\x48\x8B\xD9\x48\x8B", + // mask the stack allocation length + mask = "xxxxxxxxx?xxxxxxxxx", + xref = false + }, + // Idle Slayer - Unity 2021.3.17 (x64) + new SignatureDefinition { - if (TypeInjector.GetFieldDefaultValueOverride(field, out IntPtr newDefaultPtr)) - { - INativeFieldInfoStruct wrappedField = UnityVersionHandler.Wrap(field); - INativeClassStruct wrappedParent = UnityVersionHandler.Wrap(wrappedField.Parent); - INativeClassStruct wrappedElementClass = UnityVersionHandler.Wrap(wrappedParent.ElementClass); - type = wrappedElementClass.ByValArg.TypePointer; - return (byte*)newDefaultPtr; - } - return Original(field, out type); + pattern = "\x40\x53\x48\x83\xEC\x20\x48\x8B\xDA\xE8\x00\x00\x00\x00\x4C\x8B\xC8\x48\x85\xC0", + mask = "xxxxxxxxxx????xxxxxx", + xref = false + }, + // Evony - Unity 2018.4.0 (x86) + new SignatureDefinition + { + pattern = "\x55\x8B\xEC\x56\xFF\x75\x08\xE8\x00\x00\x00\x00\x8B\xF0\x83\xC4\x04\x85\xF6", + mask = "xxxxxxxx????xxxxxxx", + xref = false + }, + // Idle Slayer - Unity 2021.3.23 (x64) + new SignatureDefinition + { + pattern = "\x40\x53\x48\x83\xEC\x20\x48\x8B\xDA\xE8\xCC\xCC\xCC\xCC\x4C", + mask = "xxxxxxxxxx????x", + xref = false } + ]; - private static readonly SignatureDefinition[] s_Signatures = - [ - // Test Game - Unity 2021.3.4 (x64) - new SignatureDefinition - { - pattern = "\x48\x89\x5C\x24\x08\x48\x89\x74\x24\x10\x57\x48\x83\xEC\x20\x48\x8B\x79\x10\x48\x8B\xD9\x48\x8B\xF2\x48\x2B\x9F", - mask = "xxxxxxxxxxxxxx?xxxxxxxxxxxxx", - xref = false - }, - // V Rising - Unity 2022.3.23 (x64) - new SignatureDefinition - { - pattern = "\x48\x89\x5C\x24\x08\x48\x89\x74\x24\x10\x57\x48\x83\xEC\x40\x48\x8B\x41\x10", - mask = "xxxxxxxxxxxxxxxxxxx", - xref = false - }, - // GTFO - Unity 2019.4.21 (x64) - // DigitalCraft Dolce 3.1.2 - Unity 2022.3.55 (x64) - new SignatureDefinition - { - pattern = "\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x20\x48\x8B\x41\x10\x48\x8B\xD9\x48\x8B", - // mask the stack allocation length - mask = "xxxxxxxxx?xxxxxxxxx", - xref = false - }, - // Idle Slayer - Unity 2021.3.17 (x64) - new SignatureDefinition - { - pattern = "\x40\x53\x48\x83\xEC\x20\x48\x8B\xDA\xE8\x00\x00\x00\x00\x4C\x8B\xC8\x48\x85\xC0", - mask = "xxxxxxxxxx????xxxxxx", - xref = false - }, - // Evony - Unity 2018.4.0 (x86) - new SignatureDefinition - { - pattern = "\x55\x8B\xEC\x56\xFF\x75\x08\xE8\x00\x00\x00\x00\x8B\xF0\x83\xC4\x04\x85\xF6", - mask = "xxxxxxxx????xxxxxxx", - xref = false - }, - // Idle Slayer - Unity 2021.3.23 (x64) - new SignatureDefinition - { - pattern = "\x40\x53\x48\x83\xEC\x20\x48\x8B\xDA\xE8\xCC\xCC\xCC\xCC\x4C", - mask = "xxxxxxxxxx????x", - xref = false - } - ]; - - private static nint FindClassGetFieldDefaultValueXref(bool forceICallMethod = false) + private static nint FindClassGetFieldDefaultValueXref(bool forceICallMethod = false) + { + nint classGetDefaultFieldValue = 0; + if (forceICallMethod) { - nint classGetDefaultFieldValue = 0; - if (forceICallMethod) - { - // MonoField isn't present on 2021.2.0+ - var il2Cppmscorlib = typeof(Il2CppSystem.Type).Assembly; - var monoFieldType = il2Cppmscorlib.GetTypesSafe().SingleOrDefault((x) => x.Name is nameof(Il2CppSystem.Reflection.MonoField)); - if (monoFieldType == null) - throw new Exception($"Unity {Il2CppInteropRuntime.Instance.UnityVersion} is not supported at the moment: MonoField isn't present in Il2Cppmscorlib.dll for unity version, unable to fetch icall"); + // MonoField isn't present on 2021.2.0+ + var il2Cppmscorlib = typeof(Il2CppSystem.Type).Assembly; + var monoFieldType = il2Cppmscorlib.GetTypesSafe().SingleOrDefault((x) => x.Name is nameof(Il2CppSystem.Reflection.MonoField)); + if (monoFieldType == null) + throw new Exception($"Unity {Il2CppInteropRuntime.Instance.UnityVersion} is not supported at the moment: MonoField isn't present in Il2Cppmscorlib.dll for unity version, unable to fetch icall"); - var monoFieldGetValueInternalThunk = InjectorHelpers.GetIl2CppMethodPointer(monoFieldType.GetMethod(nameof(Il2CppSystem.Reflection.MonoField.GetValueInternal))); - Logger.Instance.LogTrace("Il2CppSystem.Reflection.MonoField::thunk_GetValueInternal: 0x{MonoFieldGetValueInternalThunkAddress}", monoFieldGetValueInternalThunk.ToInt64().ToString("X2")); + var monoFieldGetValueInternalThunk = InjectorHelpers.GetIl2CppMethodPointer(monoFieldType.GetMethod(nameof(Il2CppSystem.Reflection.MonoField.GetValueInternal))); + Logger.Instance.LogTrace("Il2CppSystem.Reflection.MonoField::thunk_GetValueInternal: 0x{MonoFieldGetValueInternalThunkAddress}", monoFieldGetValueInternalThunk.ToInt64().ToString("X2")); - var monoFieldGetValueInternal = XrefScanner.JumpTargets(monoFieldGetValueInternalThunk).Single(); - Logger.Instance.LogTrace("Il2CppSystem.Reflection.MonoField::GetValueInternal: 0x{MonoFieldGetValueInternalAddress}", monoFieldGetValueInternal.ToInt64().ToString("X2")); + var monoFieldGetValueInternal = XrefScanner.JumpTargets(monoFieldGetValueInternalThunk).Single(); + Logger.Instance.LogTrace("Il2CppSystem.Reflection.MonoField::GetValueInternal: 0x{MonoFieldGetValueInternalAddress}", monoFieldGetValueInternal.ToInt64().ToString("X2")); - // Field::GetValueObject could be inlined with Field::GetValueObjectForThread - var fieldGetValueObject = XrefScanner.JumpTargets(monoFieldGetValueInternal).Single(); - Logger.Instance.LogTrace("Field::GetValueObject: 0x{FieldGetValueObjectAddress}", fieldGetValueObject.ToInt64().ToString("X2")); + // Field::GetValueObject could be inlined with Field::GetValueObjectForThread + var fieldGetValueObject = XrefScanner.JumpTargets(monoFieldGetValueInternal).Single(); + Logger.Instance.LogTrace("Field::GetValueObject: 0x{FieldGetValueObjectAddress}", fieldGetValueObject.ToInt64().ToString("X2")); - var fieldGetValueObjectForThread = XrefScanner.JumpTargets(fieldGetValueObject).Last(); - Logger.Instance.LogTrace("Field::GetValueObjectForThread: 0x{FieldGetValueObjectForThreadAddress}", fieldGetValueObjectForThread.ToInt64().ToString("X2")); + var fieldGetValueObjectForThread = XrefScanner.JumpTargets(fieldGetValueObject).Last(); + Logger.Instance.LogTrace("Field::GetValueObjectForThread: 0x{FieldGetValueObjectForThreadAddress}", fieldGetValueObjectForThread.ToInt64().ToString("X2")); - classGetDefaultFieldValue = XrefScanner.JumpTargets(fieldGetValueObjectForThread).ElementAt(2); - } - else - { - var getStaticFieldValueAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_field_static_get_value)); - Logger.Instance.LogTrace("il2cpp_field_static_get_value: 0x{GetStaticFieldValueApiAddress}", getStaticFieldValueAPI.ToInt64().ToString("X2")); + classGetDefaultFieldValue = XrefScanner.JumpTargets(fieldGetValueObjectForThread).ElementAt(2); + } + else + { + var getStaticFieldValueAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_field_static_get_value)); + Logger.Instance.LogTrace("il2cpp_field_static_get_value: 0x{GetStaticFieldValueApiAddress}", getStaticFieldValueAPI.ToInt64().ToString("X2")); - var getStaticFieldValue = XrefScanner.JumpTargets(getStaticFieldValueAPI).Single(); - Logger.Instance.LogTrace("Field::StaticGetValue: 0x{GetStaticFieldValueAddress}", getStaticFieldValue.ToInt64().ToString("X2")); + var getStaticFieldValue = XrefScanner.JumpTargets(getStaticFieldValueAPI).Single(); + Logger.Instance.LogTrace("Field::StaticGetValue: 0x{GetStaticFieldValueAddress}", getStaticFieldValue.ToInt64().ToString("X2")); - var getStaticFieldValueTargets = XrefScanner.JumpTargets(getStaticFieldValue).ToList(); + var getStaticFieldValueTargets = XrefScanner.JumpTargets(getStaticFieldValue).ToList(); - // Sometimes the compiler can do an optimization and omit 'retn' instruction, - // which then causes code following to grab wrong function pointer. A correct match should not contain more than 4 jumps - // This optimization also causes Field::StaticGetValueInternal method to be located right under Field::StaticGetValue method - // Example: https://discord.com/channels/623153565053222947/754333645199900723/1104817647171932283 - if (getStaticFieldValueTargets.Count > 4) - return getStaticFieldValueTargets[^2]; + // Sometimes the compiler can do an optimization and omit 'retn' instruction, + // which then causes code following to grab wrong function pointer. A correct match should not contain more than 4 jumps + // This optimization also causes Field::StaticGetValueInternal method to be located right under Field::StaticGetValue method + // Example: https://discord.com/channels/623153565053222947/754333645199900723/1104817647171932283 + if (getStaticFieldValueTargets.Count > 4) + return getStaticFieldValueTargets[^2]; - var getStaticFieldValueInternal = getStaticFieldValueTargets[^1]; - Logger.Instance.LogTrace("Field::StaticGetValueInternal: 0x{GetStaticFieldValueInternalAddress}", getStaticFieldValueInternal.ToInt64().ToString("X2")); + var getStaticFieldValueInternal = getStaticFieldValueTargets[^1]; + Logger.Instance.LogTrace("Field::StaticGetValueInternal: 0x{GetStaticFieldValueInternalAddress}", getStaticFieldValueInternal.ToInt64().ToString("X2")); - var getStaticFieldValueInternalTargets = XrefScanner.JumpTargets(getStaticFieldValueInternal).ToArray(); + var getStaticFieldValueInternalTargets = XrefScanner.JumpTargets(getStaticFieldValueInternal).ToArray(); - if (getStaticFieldValueInternalTargets.Length == 0) return FindClassGetFieldDefaultValueXref(true); + if (getStaticFieldValueInternalTargets.Length == 0) return FindClassGetFieldDefaultValueXref(true); - classGetDefaultFieldValue = getStaticFieldValueInternalTargets.Length == 3 ? getStaticFieldValueInternalTargets.Last() : getStaticFieldValueInternalTargets.First(); - } - return classGetDefaultFieldValue; + classGetDefaultFieldValue = getStaticFieldValueInternalTargets.Length == 3 ? getStaticFieldValueInternalTargets.Last() : getStaticFieldValueInternalTargets.First(); } + return classGetDefaultFieldValue; + } - public override IntPtr FindTargetMethod() + public override IntPtr FindTargetMethod() + { + // NOTE: In some cases this pointer will be MetadataCache::GetFieldDefaultValueForField due to Field::GetDefaultFieldValue being + // inlined but we'll treat it the same even though it doesn't receive the type parameter the RDX register + // doesn't get cleared so we still get the same parameters + var classGetDefaultFieldValue = s_Signatures + .Select(s => SignatureDefinition.FindSignatureInModule(InjectorHelpers.Il2CppModule, s)) + .FirstOrDefault(p => p != 0); + + if (classGetDefaultFieldValue == 0) { - // NOTE: In some cases this pointer will be MetadataCache::GetFieldDefaultValueForField due to Field::GetDefaultFieldValue being - // inlined but we'll treat it the same even though it doesn't receive the type parameter the RDX register - // doesn't get cleared so we still get the same parameters - var classGetDefaultFieldValue = s_Signatures - .Select(s => SignatureDefinition.FindSignatureInModule(InjectorHelpers.Il2CppModule, s)) - .FirstOrDefault(p => p != 0); - - if (classGetDefaultFieldValue == 0) - { - Logger.Instance.LogTrace("Couldn't fetch Class::GetDefaultFieldValue with signatures, using method traversal"); - classGetDefaultFieldValue = FindClassGetFieldDefaultValueXref(); - } - - return classGetDefaultFieldValue; + Logger.Instance.LogTrace("Couldn't fetch Class::GetDefaultFieldValue with signatures, using method traversal"); + classGetDefaultFieldValue = FindClassGetFieldDefaultValueXref(); } + + return classGetDefaultFieldValue; } } diff --git a/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs index 8c1dba0c..db8cbb60 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs @@ -6,116 +6,115 @@ using Il2CppInterop.Runtime.Structs; using Microsoft.Extensions.Logging; -namespace Il2CppInterop.Runtime.Injection.Hooks +namespace Il2CppInterop.Runtime.Injection.Hooks; + +internal unsafe class MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook : + Hook { - internal unsafe class MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook : - Hook + public override string TargetMethodName => "MetadataCache::GetTypeInfoFromTypeDefinitionIndex"; + public override MethodDelegate GetDetour() => Hook; + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + internal delegate Il2CppClass* MethodDelegate(int index); + + private Il2CppClass* Hook(int index) { - public override string TargetMethodName => "MetadataCache::GetTypeInfoFromTypeDefinitionIndex"; - public override MethodDelegate GetDetour() => Hook; + if (InjectorHelpers.s_InjectedClasses.TryGetValue(index, out IntPtr classPtr)) + return (Il2CppClass*)classPtr; - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate Il2CppClass* MethodDelegate(int index); + return Original(index); + } - private Il2CppClass* Hook(int index) + private IntPtr FindGetTypeInfoFromTypeDefinitionIndex(bool forceICallMethod = false) + { + IntPtr getTypeInfoFromTypeDefinitionIndex = IntPtr.Zero; + + // il2cpp_image_get_class is added in 2018.3.0f1 + if (Il2CppInteropRuntime.Instance.UnityVersion.LessThan(2018, 3, 0) || forceICallMethod) { - if (InjectorHelpers.s_InjectedClasses.TryGetValue(index, out IntPtr classPtr)) - return (Il2CppClass*)classPtr; + // (Kasuromi): RuntimeHelpers.InitializeArray calls an il2cpp icall, proxy function does some magic before it invokes it + // https://github.com/Unity-Technologies/mono/blob/unity-2018.2/mcs/class/corlib/System.Runtime.CompilerServices/RuntimeHelpers.cs#L53-L54 + IntPtr runtimeHelpersInitializeArray = InjectorHelpers.GetIl2CppMethodPointer( + typeof(Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers) + .GetMethod(nameof(Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers.InitializeArray), new Type[] { typeof(Il2CppSystem.Array), typeof(IntPtr) }) + ); + Logger.Instance.LogTrace("Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers::InitializeArray: 0x{RuntimeHelpersInitializeArrayAddress}", runtimeHelpersInitializeArray.ToInt64().ToString("X2")); + + var runtimeHelpersInitializeArrayICall = XrefScanner.JumpTargets(runtimeHelpersInitializeArray).Last(); + if (XrefScanner.JumpTargets(runtimeHelpersInitializeArrayICall).Count() == 1) + { + // is a thunk function + Logger.Instance.LogTrace("RuntimeHelpers::thunk_InitializeArray: 0x{RuntimeHelpersInitializeArrayICallAddress}", runtimeHelpersInitializeArrayICall.ToInt64().ToString("X2")); + runtimeHelpersInitializeArrayICall = XrefScanner.JumpTargets(runtimeHelpersInitializeArrayICall).Single(); + } - return Original(index); - } + Logger.Instance.LogTrace("RuntimeHelpers::InitializeArray: 0x{RuntimeHelpersInitializeArrayICallAddress}", runtimeHelpersInitializeArrayICall.ToInt64().ToString("X2")); - private IntPtr FindGetTypeInfoFromTypeDefinitionIndex(bool forceICallMethod = false) - { - IntPtr getTypeInfoFromTypeDefinitionIndex = IntPtr.Zero; + var typeGetUnderlyingType = XrefScanner.JumpTargets(runtimeHelpersInitializeArrayICall).ElementAt(1); + Logger.Instance.LogTrace("Type::GetUnderlyingType: 0x{TypeGetUnderlyingTypeAddress}", typeGetUnderlyingType.ToInt64().ToString("X2")); - // il2cpp_image_get_class is added in 2018.3.0f1 - if (Il2CppInteropRuntime.Instance.UnityVersion.LessThan(2018, 3, 0) || forceICallMethod) - { - // (Kasuromi): RuntimeHelpers.InitializeArray calls an il2cpp icall, proxy function does some magic before it invokes it - // https://github.com/Unity-Technologies/mono/blob/unity-2018.2/mcs/class/corlib/System.Runtime.CompilerServices/RuntimeHelpers.cs#L53-L54 - IntPtr runtimeHelpersInitializeArray = InjectorHelpers.GetIl2CppMethodPointer( - typeof(Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers) - .GetMethod(nameof(Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers.InitializeArray), new Type[] { typeof(Il2CppSystem.Array), typeof(IntPtr) }) - ); - Logger.Instance.LogTrace("Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers::InitializeArray: 0x{RuntimeHelpersInitializeArrayAddress}", runtimeHelpersInitializeArray.ToInt64().ToString("X2")); - - var runtimeHelpersInitializeArrayICall = XrefScanner.JumpTargets(runtimeHelpersInitializeArray).Last(); - if (XrefScanner.JumpTargets(runtimeHelpersInitializeArrayICall).Count() == 1) - { - // is a thunk function - Logger.Instance.LogTrace("RuntimeHelpers::thunk_InitializeArray: 0x{RuntimeHelpersInitializeArrayICallAddress}", runtimeHelpersInitializeArrayICall.ToInt64().ToString("X2")); - runtimeHelpersInitializeArrayICall = XrefScanner.JumpTargets(runtimeHelpersInitializeArrayICall).Single(); - } + getTypeInfoFromTypeDefinitionIndex = XrefScanner.JumpTargets(typeGetUnderlyingType).First(); + } + else + { + var imageGetClassAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_image_get_class)); + Logger.Instance.LogTrace("il2cpp_image_get_class: 0x{ImageGetClassApiAddress}", imageGetClassAPI.ToInt64().ToString("X2")); - Logger.Instance.LogTrace("RuntimeHelpers::InitializeArray: 0x{RuntimeHelpersInitializeArrayICallAddress}", runtimeHelpersInitializeArrayICall.ToInt64().ToString("X2")); + var imageGetType = XrefScanner.JumpTargets(imageGetClassAPI).First(); + Logger.Instance.LogTrace("Image::GetType: 0x{ImageGetTypeAddress}", imageGetType.ToInt64().ToString("X2")); - var typeGetUnderlyingType = XrefScanner.JumpTargets(runtimeHelpersInitializeArrayICall).ElementAt(1); - Logger.Instance.LogTrace("Type::GetUnderlyingType: 0x{TypeGetUnderlyingTypeAddress}", typeGetUnderlyingType.ToInt64().ToString("X2")); + var imageGetTypeXrefs = XrefScanner.JumpTargets(imageGetType).ToArray(); - getTypeInfoFromTypeDefinitionIndex = XrefScanner.JumpTargets(typeGetUnderlyingType).First(); + if (imageGetTypeXrefs.Length == 0) + { + // (Kasuromi): Image::GetType appears to be inlined in il2cpp_image_get_class on some occasions, + // if the unconditional xrefs are 0 then we are in the correct method (seen on unity 2019.3.15) + getTypeInfoFromTypeDefinitionIndex = imageGetType; + } + else getTypeInfoFromTypeDefinitionIndex = imageGetTypeXrefs[0]; + if ((getTypeInfoFromTypeDefinitionIndex.ToInt64() & 0xF) != 0) + { + Logger.Instance.LogTrace("Image::GetType xref wasn't aligned, attempting to resolve from icall"); + return FindGetTypeInfoFromTypeDefinitionIndex(true); } - else + if (imageGetTypeXrefs.Count() > 1 && UnityVersionHandler.IsMetadataV29OrHigher) { - var imageGetClassAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_image_get_class)); - Logger.Instance.LogTrace("il2cpp_image_get_class: 0x{ImageGetClassApiAddress}", imageGetClassAPI.ToInt64().ToString("X2")); + // (Kasuromi): metadata v29 introduces handles and adds extra calls, a check for unity versions might be necessary in the future - var imageGetType = XrefScanner.JumpTargets(imageGetClassAPI).First(); - Logger.Instance.LogTrace("Image::GetType: 0x{ImageGetTypeAddress}", imageGetType.ToInt64().ToString("X2")); + Logger.Instance.LogTrace($"imageGetTypeXrefs.Length: {imageGetTypeXrefs.Length}"); - var imageGetTypeXrefs = XrefScanner.JumpTargets(imageGetType).ToArray(); + // If the game is built as IL2CPP Master, GetAssemblyTypeHandle is inlined, xrefs length is 3 and it's the first function call, + // if not, it's the last call. + var getTypeInfoFromHandle = imageGetTypeXrefs.Length == 2 ? imageGetTypeXrefs.Last() : imageGetTypeXrefs.First(); - if (imageGetTypeXrefs.Length == 0) - { - // (Kasuromi): Image::GetType appears to be inlined in il2cpp_image_get_class on some occasions, - // if the unconditional xrefs are 0 then we are in the correct method (seen on unity 2019.3.15) - getTypeInfoFromTypeDefinitionIndex = imageGetType; - } - else getTypeInfoFromTypeDefinitionIndex = imageGetTypeXrefs[0]; - if ((getTypeInfoFromTypeDefinitionIndex.ToInt64() & 0xF) != 0) + Logger.Instance.LogTrace($"getTypeInfoFromHandle: {getTypeInfoFromHandle:X2}"); + + var getTypeInfoFromHandleXrefs = XrefScanner.JumpTargets(getTypeInfoFromHandle).ToArray(); + + // If getTypeInfoFromHandle xrefs is not a single call, it's the function we want, if not, we keep xrefing until we find it + if (getTypeInfoFromHandleXrefs.Length != 1) { - Logger.Instance.LogTrace("Image::GetType xref wasn't aligned, attempting to resolve from icall"); - return FindGetTypeInfoFromTypeDefinitionIndex(true); + getTypeInfoFromTypeDefinitionIndex = getTypeInfoFromHandle; + Logger.Instance.LogTrace($"Xrefs length was not 1, getTypeInfoFromTypeDefinitionIndex: {getTypeInfoFromTypeDefinitionIndex:X2}"); } - if (imageGetTypeXrefs.Count() > 1 && UnityVersionHandler.IsMetadataV29OrHigher) + else { - // (Kasuromi): metadata v29 introduces handles and adds extra calls, a check for unity versions might be necessary in the future - - Logger.Instance.LogTrace($"imageGetTypeXrefs.Length: {imageGetTypeXrefs.Length}"); - - // If the game is built as IL2CPP Master, GetAssemblyTypeHandle is inlined, xrefs length is 3 and it's the first function call, - // if not, it's the last call. - var getTypeInfoFromHandle = imageGetTypeXrefs.Length == 2 ? imageGetTypeXrefs.Last() : imageGetTypeXrefs.First(); - - Logger.Instance.LogTrace($"getTypeInfoFromHandle: {getTypeInfoFromHandle:X2}"); - - var getTypeInfoFromHandleXrefs = XrefScanner.JumpTargets(getTypeInfoFromHandle).ToArray(); - - // If getTypeInfoFromHandle xrefs is not a single call, it's the function we want, if not, we keep xrefing until we find it - if (getTypeInfoFromHandleXrefs.Length != 1) + // Two calls, second one (GetIndexForTypeDefinitionInternal) is inlined + getTypeInfoFromTypeDefinitionIndex = getTypeInfoFromHandleXrefs.Single(); + // Xref scanner is sometimes confused about getTypeInfoFromHandle so we walk all the thunks until we hit the big method we need + while (XrefScanner.JumpTargets(getTypeInfoFromTypeDefinitionIndex).ToArray().Length == 1) { - getTypeInfoFromTypeDefinitionIndex = getTypeInfoFromHandle; - Logger.Instance.LogTrace($"Xrefs length was not 1, getTypeInfoFromTypeDefinitionIndex: {getTypeInfoFromTypeDefinitionIndex:X2}"); - } - else - { - // Two calls, second one (GetIndexForTypeDefinitionInternal) is inlined - getTypeInfoFromTypeDefinitionIndex = getTypeInfoFromHandleXrefs.Single(); - // Xref scanner is sometimes confused about getTypeInfoFromHandle so we walk all the thunks until we hit the big method we need - while (XrefScanner.JumpTargets(getTypeInfoFromTypeDefinitionIndex).ToArray().Length == 1) - { - getTypeInfoFromTypeDefinitionIndex = XrefScanner.JumpTargets(getTypeInfoFromTypeDefinitionIndex).Single(); - } + getTypeInfoFromTypeDefinitionIndex = XrefScanner.JumpTargets(getTypeInfoFromTypeDefinitionIndex).Single(); } } } - - return getTypeInfoFromTypeDefinitionIndex; } - public override IntPtr FindTargetMethod() - { - return FindGetTypeInfoFromTypeDefinitionIndex(); - } + return getTypeInfoFromTypeDefinitionIndex; + } + + public override IntPtr FindTargetMethod() + { + return FindGetTypeInfoFromTypeDefinitionIndex(); } } From e633341885159f353d9f46d8acefca59a2401fcb Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 10:54:23 -0700 Subject: [PATCH 425/486] Refactor detour logic into Hook class Removed Detour class and moved detour application logic to a new static Hook class via ApplyDetour. Updated Hook to use the new method. --- Il2CppInterop.Runtime/Injection/Detour.cs | 12 ------------ Il2CppInterop.Runtime/Injection/Hook.cs | 10 +++++++++- 2 files changed, 9 insertions(+), 13 deletions(-) delete mode 100644 Il2CppInterop.Runtime/Injection/Detour.cs diff --git a/Il2CppInterop.Runtime/Injection/Detour.cs b/Il2CppInterop.Runtime/Injection/Detour.cs deleted file mode 100644 index 0b8592e7..00000000 --- a/Il2CppInterop.Runtime/Injection/Detour.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using Il2CppInterop.Runtime.Startup; - -namespace Il2CppInterop.Runtime.Injection; - -internal static class Detour -{ - public static IDisposable Apply(nint original, T target, out T trampoline) where T : Delegate - { - return Il2CppInteropRuntime.Instance.DetourProvider.Create(original, target, out trampoline); - } -} diff --git a/Il2CppInterop.Runtime/Injection/Hook.cs b/Il2CppInterop.Runtime/Injection/Hook.cs index 502b2e39..dc42de2b 100644 --- a/Il2CppInterop.Runtime/Injection/Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hook.cs @@ -1,10 +1,18 @@ using System; using System.Runtime.InteropServices; using Il2CppInterop.Common; +using Il2CppInterop.Runtime.Startup; using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime.Injection; +internal static class Hook +{ + public static IDisposable ApplyDetour(nint original, T target, out T trampoline) where T : Delegate + { + return Il2CppInteropRuntime.Instance.DetourProvider.Create(original, target, out trampoline); + } +} internal abstract class Hook where T : Delegate { private bool _isApplied; @@ -38,7 +46,7 @@ public void ApplyHook() Logger.Instance.LogTrace("{MethodName} found: 0x{MethodPtr}", TargetMethodName, methodPtr.ToInt64().ToString("X2")); _detour = GetDetour(); - Detour.Apply(methodPtr, _detour, out _original); + Hook.ApplyDetour(methodPtr, _detour, out _original); _method = Marshal.GetDelegateForFunctionPointer(methodPtr); _isApplied = true; } From 2c33ec9ed52a59e378f4d91ccdf19396a70744b4 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 11:56:31 -0700 Subject: [PATCH 426/486] Remove InjectorHelpers and move its functionality to other classes --- .../INativeMethodInfoStructExtensions.cs | 44 ++++-- .../Injection/ClassInitializer.cs | 74 +++++++++ Il2CppInterop.Runtime/Injection/Hook.cs | 16 ++ .../Hooks/Class_FromIl2CppType_Hook.cs | 4 +- .../Injection/Hooks/Class_FromName_Hook.cs | 13 +- .../Hooks/Class_GetFieldDefaultValue_Hook.cs | 7 +- ...GetTypeInfoFromTypeDefinitionIndex_Hook.cs | 10 +- .../Injection/Il2CppModule.cs | 30 ++++ .../Injection/InjectorHelpers.cs | 148 ------------------ .../Injection/TokenAllocator.cs | 23 +++ .../Injection/TypeInjector.cs | 21 ++- 11 files changed, 211 insertions(+), 179 deletions(-) create mode 100644 Il2CppInterop.Runtime/Injection/ClassInitializer.cs create mode 100644 Il2CppInterop.Runtime/Injection/Il2CppModule.cs delete mode 100644 Il2CppInterop.Runtime/Injection/InjectorHelpers.cs create mode 100644 Il2CppInterop.Runtime/Injection/TokenAllocator.cs diff --git a/Il2CppInterop.Runtime/Extensions/INativeMethodInfoStructExtensions.cs b/Il2CppInterop.Runtime/Extensions/INativeMethodInfoStructExtensions.cs index b8d2962d..3f3e79aa 100644 --- a/Il2CppInterop.Runtime/Extensions/INativeMethodInfoStructExtensions.cs +++ b/Il2CppInterop.Runtime/Extensions/INativeMethodInfoStructExtensions.cs @@ -1,23 +1,49 @@ using System; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; using System.Runtime.InteropServices; +using Il2CppInterop.Common; +using Il2CppInterop.Runtime.Structs; using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; namespace Il2CppInterop.Runtime.Extensions; internal static class INativeMethodInfoStructExtensions { - public static unsafe ReadOnlySpan GetNameSpan(this INativeMethodInfoStruct methodInfo) + extension(INativeMethodInfoStruct methodInfo) { - var namePtr = methodInfo.Name; - if (namePtr == IntPtr.Zero) - return default; + public unsafe ReadOnlySpan GetNameSpan() + { + var namePtr = methodInfo.Name; + if (namePtr == IntPtr.Zero) + return default; + + // Find null terminator + var length = 0; + while (Marshal.ReadByte(namePtr, length) > 0) + { + length++; + } + return new ReadOnlySpan((void*)namePtr, length); + } - // Find null terminator - var length = 0; - while (Marshal.ReadByte(namePtr, length) > 0) + [return: NotNullIfNotNull(nameof(generatedMethod))] + public static unsafe INativeMethodInfoStruct? FromGeneratedMethod(MethodBase? generatedMethod) { - length++; + if (generatedMethod is null) + return null; + + var methodInfoPointerField = Il2CppInternalsAccess.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(generatedMethod) + ?? throw new ArgumentException($"Couldn't find the generated method info pointer for {generatedMethod.Name}"); + + // Il2CppClassPointerStore calls the static constructor for the type + Il2CppType.GetClassPointer(generatedMethod.DeclaringType!); + + var methodInfoPointer = (IntPtr)methodInfoPointerField.GetValue(null)!; + if (methodInfoPointer == IntPtr.Zero) + throw new ArgumentException($"Generated method info pointer for {generatedMethod.Name} doesn't point to any il2cpp method info"); + + return UnityVersionHandler.Wrap((Il2CppMethodInfo*)methodInfoPointer); } - return new ReadOnlySpan((void*)namePtr, length); } } diff --git a/Il2CppInterop.Runtime/Injection/ClassInitializer.cs b/Il2CppInterop.Runtime/Injection/ClassInitializer.cs new file mode 100644 index 00000000..d5a10c59 --- /dev/null +++ b/Il2CppInterop.Runtime/Injection/ClassInitializer.cs @@ -0,0 +1,74 @@ +using System; +using System.Linq; +using System.Runtime.InteropServices; +using Il2CppInterop.Common; +using Il2CppInterop.Runtime.Injection.Hooks; +using Il2CppInterop.Runtime.Structs; +using Microsoft.Extensions.Logging; + +namespace Il2CppInterop.Runtime.Injection; + +internal static unsafe class ClassInitializer +{ + private delegate void d_ClassInit(Il2CppClass* klass); + private static readonly d_ClassInit ClassInit = FindClassInit(); + + public static void Invoke(Il2CppClass* klass) + { + ClassInit.Invoke(klass); + } + + private static readonly SignatureDefinition[] s_ClassInitSignatures = + [ + new SignatureDefinition + { + pattern = "\xE8\x00\x00\x00\x00\x0F\xB7\x47\x28\x83", + mask = "x????xxxxx", + xref = true + }, + new SignatureDefinition + { + pattern = "\xE8\x00\x00\x00\x00\x0F\xB7\x47\x48\x48", + mask = "x????xxxxx", + xref = true + } + ]; + + private static d_ClassInit FindClassInit() + { + static nint GetClassInitSubstitute() + { + if (Il2CppModule.TryGetExport("mono_class_instance_size", out var classInit)) + { + Logger.Instance.LogTrace("Picked mono_class_instance_size as a Class::Init substitute"); + return classInit; + } + if (Il2CppModule.TryGetExport("mono_class_setup_vtable", out classInit)) + { + Logger.Instance.LogTrace("Picked mono_class_setup_vtable as a Class::Init substitute"); + return classInit; + } + if (Il2CppModule.TryGetExport(nameof(IL2CPP.il2cpp_class_has_references), out classInit)) + { + Logger.Instance.LogTrace("Picked il2cpp_class_has_references as a Class::Init substitute"); + return classInit; + } + + Logger.Instance.LogTrace("GameAssembly.dll: 0x{Il2CppModuleAddress}", Il2CppModule.Module.BaseAddress.ToInt64().ToString("X2")); + throw new NotSupportedException("Failed to use signature for Class::Init and a substitute cannot be found, please create an issue and report your unity version & game"); + } + var pClassInit = s_ClassInitSignatures + .Select(s => SignatureDefinition.FindSignatureInModule(Il2CppModule.Module, s)) + .FirstOrDefault(p => p != 0); + + if (pClassInit == 0) + { + Logger.Instance.LogWarning("Class::Init signatures have been exhausted, using a substitute!"); + pClassInit = GetClassInitSubstitute(); + } + + Logger.Instance.LogTrace("Class::Init: 0x{PClassInitAddress}", pClassInit.ToString("X2")); + + return Marshal.GetDelegateForFunctionPointer(pClassInit); + } +} diff --git a/Il2CppInterop.Runtime/Injection/Hook.cs b/Il2CppInterop.Runtime/Injection/Hook.cs index dc42de2b..7168586f 100644 --- a/Il2CppInterop.Runtime/Injection/Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hook.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.InteropServices; using Il2CppInterop.Common; +using Il2CppInterop.Runtime.Injection.Hooks; using Il2CppInterop.Runtime.Startup; using Microsoft.Extensions.Logging; @@ -8,6 +9,19 @@ namespace Il2CppInterop.Runtime.Injection; internal static class Hook { + private static readonly MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook GetTypeInfoFromTypeDefinitionIndexHook = new(); + private static readonly Class_GetFieldDefaultValue_Hook GetFieldDefaultValueHook = new(); + private static readonly Class_FromIl2CppType_Hook FromIl2CppTypeHook = new(); + private static readonly Class_FromName_Hook FromNameHook = new(); + + internal static void ApplyInjectionHooks() + { + GetTypeInfoFromTypeDefinitionIndexHook.ApplyHook(); + GetFieldDefaultValueHook.ApplyHook(); + FromIl2CppTypeHook.ApplyHook(); + FromNameHook.ApplyHook(); + } + public static IDisposable ApplyDetour(nint original, T target, out T trampoline) where T : Delegate { return Il2CppInteropRuntime.Instance.DetourProvider.Create(original, target, out trampoline); @@ -15,10 +29,12 @@ public static IDisposable ApplyDetour(nint original, T target, out T trampoli } internal abstract class Hook where T : Delegate { +#nullable disable private bool _isApplied; private T _detour; private T _method; private T _original; +#nullable restore public T Original => _original; diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs index a6b75074..ad5a899f 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs @@ -31,7 +31,7 @@ internal readonly struct Il2CppType if ((nint)type->data < 0 && (type->type is Il2CppTypeEnum.IL2CPP_TYPE_CLASS or Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)) { - InjectorHelpers.s_InjectedClasses.TryGetValue((nint)type->data, out var classPointer); + TokenAllocator.TryGetClassPointer((nint)type->data, out var classPointer); return (Il2CppClass*)classPointer; } @@ -40,7 +40,7 @@ internal readonly struct Il2CppType public override IntPtr FindTargetMethod() { - var classFromTypeAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_class_from_il2cpp_type)); + var classFromTypeAPI = Il2CppModule.GetExport(nameof(IL2CPP.il2cpp_class_from_il2cpp_type)); Logger.Instance.LogTrace("il2cpp_class_from_il2cpp_type: 0x{ClassFromTypeApiAddress}", classFromTypeAPI.ToInt64().ToString("X2")); return XrefScanner.JumpTargets(classFromTypeAPI).Single(); diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs index 3d9650ee..02f68ade 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using Il2CppInterop.Common; @@ -9,6 +10,8 @@ namespace Il2CppInterop.Runtime.Injection.Hooks; internal unsafe class Class_FromName_Hook : Hook { + private static readonly Dictionary<(IntPtr ImagePointer, string Namespace, string Class), IntPtr> s_ClassNameLookup = new(); + public override string TargetMethodName => "Class::FromName"; public override MethodDelegate GetDetour() => Hook; @@ -23,7 +26,7 @@ internal unsafe class Class_FromName_Hook : Hook SignatureDefinition.FindSignatureInModule(InjectorHelpers.Il2CppModule, s)) + .Select(s => SignatureDefinition.FindSignatureInModule(Il2CppModule.Module, s)) .FirstOrDefault(p => p != 0); if (classGetDefaultFieldValue == 0) diff --git a/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs index db8cbb60..c486a9be 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs @@ -2,8 +2,10 @@ using System.Linq; using System.Runtime.InteropServices; using Il2CppInterop.Common; +using Il2CppInterop.Runtime.Extensions; using Il2CppInterop.Runtime.Startup; using Il2CppInterop.Runtime.Structs; +using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime.Injection.Hooks; @@ -19,7 +21,7 @@ internal unsafe class MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook : private Il2CppClass* Hook(int index) { - if (InjectorHelpers.s_InjectedClasses.TryGetValue(index, out IntPtr classPtr)) + if (TokenAllocator.TryGetClassPointer(index, out var classPtr)) return (Il2CppClass*)classPtr; return Original(index); @@ -34,10 +36,10 @@ private IntPtr FindGetTypeInfoFromTypeDefinitionIndex(bool forceICallMethod = fa { // (Kasuromi): RuntimeHelpers.InitializeArray calls an il2cpp icall, proxy function does some magic before it invokes it // https://github.com/Unity-Technologies/mono/blob/unity-2018.2/mcs/class/corlib/System.Runtime.CompilerServices/RuntimeHelpers.cs#L53-L54 - IntPtr runtimeHelpersInitializeArray = InjectorHelpers.GetIl2CppMethodPointer( + IntPtr runtimeHelpersInitializeArray = INativeMethodInfoStruct.FromGeneratedMethod( typeof(Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers) .GetMethod(nameof(Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers.InitializeArray), new Type[] { typeof(Il2CppSystem.Array), typeof(IntPtr) }) - ); + )!.MethodPointer; Logger.Instance.LogTrace("Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers::InitializeArray: 0x{RuntimeHelpersInitializeArrayAddress}", runtimeHelpersInitializeArray.ToInt64().ToString("X2")); var runtimeHelpersInitializeArrayICall = XrefScanner.JumpTargets(runtimeHelpersInitializeArray).Last(); @@ -57,7 +59,7 @@ private IntPtr FindGetTypeInfoFromTypeDefinitionIndex(bool forceICallMethod = fa } else { - var imageGetClassAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_image_get_class)); + var imageGetClassAPI = Il2CppModule.GetExport(nameof(IL2CPP.il2cpp_image_get_class)); Logger.Instance.LogTrace("il2cpp_image_get_class: 0x{ImageGetClassApiAddress}", imageGetClassAPI.ToInt64().ToString("X2")); var imageGetType = XrefScanner.JumpTargets(imageGetClassAPI).First(); diff --git a/Il2CppInterop.Runtime/Injection/Il2CppModule.cs b/Il2CppInterop.Runtime/Injection/Il2CppModule.cs new file mode 100644 index 00000000..a7c8bd3a --- /dev/null +++ b/Il2CppInterop.Runtime/Injection/Il2CppModule.cs @@ -0,0 +1,30 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; + +namespace Il2CppInterop.Runtime.Injection; + +internal static class Il2CppModule +{ + internal static readonly ProcessModule Module = Process.GetCurrentProcess() + .Modules.OfType() + .Single((x) => x.ModuleName is "GameAssembly.dll" or "GameAssembly.dylib" or "GameAssembly.so" or "UserAssembly.dll" || string.Equals(x.ModuleName, "GameAssembly.dll", StringComparison.OrdinalIgnoreCase)); + + private static readonly IntPtr Handle = NativeLibrary.Load("GameAssembly", typeof(Il2CppModule).Assembly, null); + + internal static IntPtr GetExport(string name) + { + if (!TryGetExport(name, out var address)) + { + throw new NotSupportedException($"Couldn't find {name} in {Module.ModuleName}'s exports"); + } + + return address; + } + + internal static bool TryGetExport(string name, out IntPtr address) + { + return NativeLibrary.TryGetExport(Handle, name, out address); + } +} diff --git a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs deleted file mode 100644 index 9f6f047b..00000000 --- a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs +++ /dev/null @@ -1,148 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Threading; -using Il2CppInterop.Common; -using Il2CppInterop.Runtime.Injection.Hooks; -using Il2CppInterop.Runtime.Structs; -using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; -using Microsoft.Extensions.Logging; - -namespace Il2CppInterop.Runtime.Injection -{ - internal static unsafe class InjectorHelpers - { - internal static ProcessModule Il2CppModule = Process.GetCurrentProcess() - .Modules.OfType() - .Single((x) => x.ModuleName is "GameAssembly.dll" or "GameAssembly.dylib" or "GameAssembly.so" or "UserAssembly.dll" || string.Equals(x.ModuleName, "GameAssembly.dll", StringComparison.OrdinalIgnoreCase)); - - internal static IntPtr Il2CppHandle = NativeLibrary.Load("GameAssembly", typeof(InjectorHelpers).Assembly, null); - - private static readonly MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook GetTypeInfoFromTypeDefinitionIndexHook = new(); - private static readonly Class_GetFieldDefaultValue_Hook GetFieldDefaultValueHook = new(); - private static readonly Class_FromIl2CppType_Hook FromIl2CppTypeHook = new(); - private static readonly Class_FromName_Hook FromNameHook = new(); - internal static void Setup() - { - GetTypeInfoFromTypeDefinitionIndexHook.ApplyHook(); - GetFieldDefaultValueHook.ApplyHook(); - ClassInit ??= FindClassInit(); - FromIl2CppTypeHook.ApplyHook(); - FromNameHook.ApplyHook(); - } - - internal static long CreateClassToken(IntPtr classPointer) - { - long newToken = Interlocked.Decrement(ref s_LastInjectedToken); - s_InjectedClasses[newToken] = classPointer; - return newToken; - } - - internal static void AddTypeToLookup(string assemblyName, string namespaze, string klass, IntPtr typePointer) - { - var image = AssemblyInjector.GetOrCreateImage(assemblyName).ImagePointer; - s_ClassNameLookup.Add((namespaze, klass, (IntPtr)image), typePointer); - } - - internal static IntPtr GetIl2CppExport(string name) - { - if (!TryGetIl2CppExport(name, out var address)) - { - throw new NotSupportedException($"Couldn't find {name} in {Il2CppModule.ModuleName}'s exports"); - } - - return address; - } - - internal static bool TryGetIl2CppExport(string name, out IntPtr address) - { - return NativeLibrary.TryGetExport(Il2CppHandle, name, out address); - } - - internal static IntPtr GetIl2CppMethodPointer(MethodBase? proxyMethod) - { - if (proxyMethod == null) return IntPtr.Zero; - - var methodInfoPointerField = Il2CppInternalsAccess.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(proxyMethod) - ?? throw new ArgumentException($"Couldn't find the generated method info pointer for {proxyMethod.Name}"); - - // Il2CppClassPointerStore calls the static constructor for the type - Il2CppType.GetClassPointer(proxyMethod.DeclaringType); - - var methodInfoPointer = (IntPtr)methodInfoPointerField.GetValue(null)!; - if (methodInfoPointer == IntPtr.Zero) - throw new ArgumentException($"Generated method info pointer for {proxyMethod.Name} doesn't point to any il2cpp method info"); - INativeMethodInfoStruct methodInfo = UnityVersionHandler.Wrap((Il2CppMethodInfo*)methodInfoPointer); - return methodInfo.MethodPointer; - } - - private static long s_LastInjectedToken = -2; - internal static readonly ConcurrentDictionary s_InjectedClasses = new(); - /// (namespace, class, image) : class - internal static readonly Dictionary<(string _namespace, string _class, IntPtr imagePtr), IntPtr> s_ClassNameLookup = new(); - - #region Class::Init - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate void d_ClassInit(Il2CppClass* klass); - internal static d_ClassInit ClassInit; - - private static readonly SignatureDefinition[] s_ClassInitSignatures = - { - new SignatureDefinition - { - pattern = "\xE8\x00\x00\x00\x00\x0F\xB7\x47\x28\x83", - mask = "x????xxxxx", - xref = true - }, - new SignatureDefinition - { - pattern = "\xE8\x00\x00\x00\x00\x0F\xB7\x47\x48\x48", - mask = "x????xxxxx", - xref = true - } - }; - - private static d_ClassInit FindClassInit() - { - static nint GetClassInitSubstitute() - { - if (TryGetIl2CppExport("mono_class_instance_size", out nint classInit)) - { - Logger.Instance.LogTrace("Picked mono_class_instance_size as a Class::Init substitute"); - return classInit; - } - if (TryGetIl2CppExport("mono_class_setup_vtable", out classInit)) - { - Logger.Instance.LogTrace("Picked mono_class_setup_vtable as a Class::Init substitute"); - return classInit; - } - if (TryGetIl2CppExport(nameof(IL2CPP.il2cpp_class_has_references), out classInit)) - { - Logger.Instance.LogTrace("Picked il2cpp_class_has_references as a Class::Init substitute"); - return classInit; - } - - Logger.Instance.LogTrace("GameAssembly.dll: 0x{Il2CppModuleAddress}", Il2CppModule.BaseAddress.ToInt64().ToString("X2")); - throw new NotSupportedException("Failed to use signature for Class::Init and a substitute cannot be found, please create an issue and report your unity version & game"); - } - nint pClassInit = s_ClassInitSignatures - .Select(s => SignatureDefinition.FindSignatureInModule(Il2CppModule, s)) - .FirstOrDefault(p => p != 0); - - if (pClassInit == 0) - { - Logger.Instance.LogWarning("Class::Init signatures have been exhausted, using a substitute!"); - pClassInit = GetClassInitSubstitute(); - } - - Logger.Instance.LogTrace("Class::Init: 0x{PClassInitAddress}", pClassInit.ToString("X2")); - - return Marshal.GetDelegateForFunctionPointer(pClassInit); - } - #endregion - } -} diff --git a/Il2CppInterop.Runtime/Injection/TokenAllocator.cs b/Il2CppInterop.Runtime/Injection/TokenAllocator.cs new file mode 100644 index 00000000..26db4a82 --- /dev/null +++ b/Il2CppInterop.Runtime/Injection/TokenAllocator.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace Il2CppInterop.Runtime.Injection; + +internal static class TokenAllocator +{ + private static long s_LastInjectedToken = -2; + private static readonly ConcurrentDictionary s_InjectedClasses = new(); + + public static long Assign(IntPtr classPointer) + { + var newToken = Interlocked.Decrement(ref s_LastInjectedToken); + s_InjectedClasses[newToken] = classPointer; + return newToken; + } + + public static bool TryGetClassPointer(long token, out IntPtr classPointer) + { + return s_InjectedClasses.TryGetValue(token, out classPointer); + } +} diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 533f4ce6..9c100b24 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -2,7 +2,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; -using System.IO.Hashing; using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -10,6 +9,7 @@ using Il2CppInterop.Common; using Il2CppInterop.Common.Attributes; using Il2CppInterop.Runtime.Extensions; +using Il2CppInterop.Runtime.Injection.Hooks; using Il2CppInterop.Runtime.Structs; using Il2CppInterop.Runtime.Structs.VersionSpecific.Class; using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; @@ -58,7 +58,7 @@ private static void RegisterTypeInIl2Cpp(Type type) // * the static constructor is malformed and does not call this method. ValidateTypeUsingReflection(type); - InjectorHelpers.Setup(); + Hook.ApplyInjectionHooks(); if (typeof(Il2CppSystem.IEnum).IsAssignableFrom(type)) { RegisterEnumInIl2Cpp(type); @@ -85,7 +85,7 @@ private static void RegisterTypeInIl2Cpp(Type type) classPointer.ValueType = type.IsValueType; classPointer.ThisArg.Type = classPointer.ByValArg.Type = type.IsValueType ? Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE : Il2CppTypeEnum.IL2CPP_TYPE_CLASS; - classPointer.ThisArg.Data = classPointer.ByValArg.Data = (nint)InjectorHelpers.CreateClassToken(classPointer.Pointer); + classPointer.ThisArg.Data = classPointer.ByValArg.Data = (nint)TokenAllocator.Assign(classPointer.Pointer); classPointer.ThisArg.ValueType = classPointer.ByValArg.ValueType = type.IsValueType; classPointer.ThisArg.ByRef = true; @@ -98,7 +98,7 @@ private static void RegisterTypeInIl2Cpp(Type type) NeedsVTableSet.Add(type, vtableUpperBound); NeedsFieldsSet.Add(type); Il2CppType.SetClassPointer(type, (nint)classPointer.ClassPointer); - InjectorHelpers.AddTypeToLookup(assemblyName, @namespace, name, (nint)classPointer.ClassPointer); + Class_FromName_Hook.AddTypeToLookup(assemblyName, @namespace, name, (nint)classPointer.ClassPointer); // Ensure that all other types that this type depends on are at least registered { @@ -163,7 +163,7 @@ static nint GetClassPointerNotNull(Type type) else if (!RegisteredTypes.Contains(type)) { // Ensure that the vtable is initialized for this preexisting type - InjectorHelpers.ClassInit((Il2CppClass*)classPointer); + ClassInitializer.Invoke((Il2CppClass*)classPointer); } return classPointer; } @@ -740,9 +740,9 @@ public static void InjectEnumValues(Type type, Dictionary values if (enumPtr == IntPtr.Zero) throw new ArgumentException("Type needs to be an Il2Cpp enum", nameof(type)); - InjectorHelpers.Setup(); + Hook.ApplyInjectionHooks(); - InjectorHelpers.ClassInit((Il2CppClass*)enumPtr); + ClassInitializer.Invoke((Il2CppClass*)enumPtr); var il2cppEnum = UnityVersionHandler.Wrap((Il2CppClass*)enumPtr); var newFieldCount = il2cppEnum.FieldCount + valuesToAdd.Count; @@ -809,7 +809,7 @@ private static void RegisterEnumInIl2Cpp(Type type) { var baseEnum = UnityVersionHandler.Wrap((Il2CppClass*)Il2CppType.GetClassPointer()); - InjectorHelpers.ClassInit(baseEnum.ClassPointer); + ClassInitializer.Invoke(baseEnum.ClassPointer); var il2cppEnum = UnityVersionHandler.NewClass(baseEnum.VTableCount); var elementClass = @@ -835,8 +835,7 @@ private static void RegisterEnumInIl2Cpp(Type type) il2cppEnum.Name = Marshal.StringToCoTaskMemUTF8(name); il2cppEnum.Namespace = Marshal.StringToCoTaskMemUTF8(@namespace); - var token = InjectorHelpers.CreateClassToken(il2cppEnum.Pointer); - il2cppEnum.ThisArg.Data = il2cppEnum.ByValArg.Data = (IntPtr)token; + il2cppEnum.ThisArg.Data = il2cppEnum.ByValArg.Data = (nint)TokenAllocator.Assign(il2cppEnum.Pointer); // Has to be IL2CPP_TYPE_VALUETYPE because IL2CPP_TYPE_ENUM isn't used il2cppEnum.ThisArg.Type = il2cppEnum.ByValArg.Type = Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE; @@ -898,7 +897,7 @@ private static void RegisterEnumInIl2Cpp(Type type) il2cppEnum.TypeHierarchy[il2cppEnum.TypeHierarchyDepth - 1] = il2cppEnum.ClassPointer; Il2CppType.SetClassPointer(type, il2cppEnum.Pointer); - InjectorHelpers.AddTypeToLookup(assemblyName, @namespace, name, il2cppEnum.Pointer); + Class_FromName_Hook.AddTypeToLookup(assemblyName, @namespace, name, il2cppEnum.Pointer); } private static bool IsIl2CppInterface(Type type) From ec3ae2fc7302c92befd3ecf95c45999529df949c Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 12:50:00 -0700 Subject: [PATCH 427/486] Rename TrampolineHelper to TrampolineBuilder and make public --- .../Il2CppInteropDetour.cs | 4 ++-- Il2CppInterop.Runtime/DelegateSupport.cs | 16 ++++++++-------- ...TrampolineHelpers.cs => TrampolineBuilder.cs} | 4 ++-- Il2CppInterop.Runtime/Injection/TypeInjector.cs | 10 +++++----- Il2CppInterop.Runtime/RuntimeInvoke.cs | 4 ++-- 5 files changed, 19 insertions(+), 19 deletions(-) rename Il2CppInterop.Runtime/Injection/{TrampolineHelpers.cs => TrampolineBuilder.cs} (96%) diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs index 4615f683..3f2561ff 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs @@ -216,7 +216,7 @@ private DynamicMethodDefinition GenerateNativeToManagedThunk() var paramStartIndex = 0; var managedReturnType = GetReturnType(Source); - var unmanagedReturnType = managedReturnType.NativeType(); + var unmanagedReturnType = TrampolineBuilder.GetNativeType(managedReturnType); var returnSize = IntPtr.Size; @@ -258,7 +258,7 @@ private DynamicMethodDefinition GenerateNativeToManagedThunk() } unmanagedParams[^1] = typeof(Il2CppMethodInfo*); - Array.Copy(managedParams.Select(TrampolineHelpers.NativeType).ToArray(), 0, + Array.Copy(managedParams.Select(TrampolineBuilder.GetNativeType).ToArray(), 0, unmanagedParams, paramStartIndex, managedParams.Length); var dmd = new DynamicMethodDefinition("(il2cpp -> managed) " + Source.Name, diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index c0fe162b..77b9fa47 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -57,12 +57,12 @@ private static Type CreateDelegateType(MethodSignature signature, MethodInfo man parameterTypes[parameterTypes.Length - 1] = typeof(Il2CppMethodInfo*); for (var i = 0; i < managedParameters.Length; i++) - parameterTypes[i + parameterOffset] = managedParameters[i].ParameterType.NativeType(); + parameterTypes[i + parameterOffset] = TrampolineBuilder.GetNativeType(managedParameters[i].ParameterType); newType.DefineMethod("Invoke", MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Public, CallingConventions.HasThis, - managedMethodInner.ReturnType.NativeType(), + TrampolineBuilder.GetNativeType(managedMethodInner.ReturnType), parameterTypes).SetImplementationFlags(MethodImplAttributes.CodeTypeMask); newType.DefineMethod("BeginInvoke", @@ -75,7 +75,7 @@ private static Type CreateDelegateType(MethodSignature signature, MethodInfo man newType.DefineMethod("EndInvoke", MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Public, CallingConventions.HasThis, - managedMethodInner.ReturnType.NativeType(), + TrampolineBuilder.GetNativeType(managedMethodInner.ReturnType), new[] { typeof(IAsyncResult) }).SetImplementationFlags(MethodImplAttributes.CodeTypeMask); return newType.CreateType(); @@ -106,14 +106,14 @@ private static Delegate GetOrCreateNativeToManagedTrampoline(MethodSignature sig private static Delegate GenerateNativeToManagedTrampoline(MethodInfo managedMethod, MethodSignature signature) { - var returnType = managedMethod.ReturnType.NativeType(); + var returnType = TrampolineBuilder.GetNativeType(managedMethod.ReturnType); var managedParameters = managedMethod.GetParameters(); var parameterTypes = new Type[managedParameters.Length + 1 + 1]; // thisptr for target, methodInfo last arg parameterTypes[0] = typeof(IntPtr); parameterTypes[managedParameters.Length + 1] = typeof(Il2CppMethodInfo*); for (var i = 0; i < managedParameters.Length; i++) - parameterTypes[i + 1] = managedParameters[i].ParameterType.NativeType(); + parameterTypes[i + 1] = TrampolineBuilder.GetNativeType(managedParameters[i].ParameterType); var trampoline = new DynamicMethod("(il2cpp delegate trampoline) " + ExtractSignature(managedMethod), MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, parameterTypes, @@ -286,11 +286,11 @@ public MethodSignature(MethodInfo methodInfo, bool hasThis) var hashCode = new HashCode(); - hashCode.Add(methodInfo.ReturnType.NativeType()); - if (hasThis) hashCode.Add(methodInfo.DeclaringType!.NativeType()); + hashCode.Add(TrampolineBuilder.GetNativeType(methodInfo.ReturnType)); + if (hasThis) hashCode.Add(TrampolineBuilder.GetNativeType(methodInfo.DeclaringType!)); foreach (var parameterInfo in methodInfo.GetParameters()) { - hashCode.Add(parameterInfo.ParameterType.NativeType()); + hashCode.Add(TrampolineBuilder.GetNativeType(parameterInfo.ParameterType)); } _hashCode = hashCode.ToHashCode(); diff --git a/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs b/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs similarity index 96% rename from Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs rename to Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs index e6d0923b..c35622a3 100644 --- a/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs +++ b/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs @@ -9,7 +9,7 @@ namespace Il2CppInterop.Runtime.Injection; -internal static class TrampolineHelpers +public static class TrampolineBuilder { private static AssemblyBuilder? _fixedStructAssembly; private static ModuleBuilder? _fixedStructModuleBuilder; @@ -38,7 +38,7 @@ private static Type GetFixedSizeStructType(int size) return _fixedStructCache[size] = type; } - internal static Type NativeType(this Type managedType) + public static Type GetNativeType(Type managedType) { if (managedType == typeof(void)) { diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 9c100b24..d6f8651a 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -1092,7 +1092,7 @@ private static Delegate CreateInvoker(SignatureHash signatureHash, MethodInfo mo body.Emit(OpCodes.Ldarg_3); body.Emit(OpCodes.Ldc_I4, i * IntPtr.Size); body.Emit(OpCodes.Add_Ovf_Un); - var nativeType = parameterInfo.ParameterType.NativeType(); + var nativeType = TrampolineBuilder.GetNativeType(parameterInfo.ParameterType); body.Emit(OpCodes.Ldobj, typeof(IntPtr)); if (nativeType != typeof(IntPtr)) body.Emit(OpCodes.Ldobj, nativeType); @@ -1101,11 +1101,11 @@ private static Delegate CreateInvoker(SignatureHash signatureHash, MethodInfo mo body.Emit(OpCodes.Ldarg_1); // methodMetadata body.Emit(OpCodes.Ldarg_0); // methodPointer - var nativeReturnType = monoMethod.ReturnType.NativeType(); + var nativeReturnType = TrampolineBuilder.GetNativeType(monoMethod.ReturnType); Type[] nativeParameterTypes = [ ..(ReadOnlySpan)(monoMethod.IsStatic ? [] : [typeof(IntPtr)]), - ..monoMethod.GetParameters().Select(it => it.ParameterType.NativeType()), + ..monoMethod.GetParameters().Select(it => TrampolineBuilder.GetNativeType(it.ParameterType)), typeof(Il2CppMethodInfo*), ]; body.EmitCalli(OpCodes.Calli, CallingConventions.Standard, nativeReturnType, nativeParameterTypes, null); @@ -1159,11 +1159,11 @@ private static Delegate CreateTrampoline(MethodInfo monoMethod, bool callVirt) { Debug.Assert(monoMethod.DeclaringType is not null); - var nativeReturnType = monoMethod.ReturnType.NativeType(); + var nativeReturnType = TrampolineBuilder.GetNativeType(monoMethod.ReturnType); Type[] nativeParameterTypes = [ ..(ReadOnlySpan)(monoMethod.IsStatic ? [] : [typeof(IntPtr)]), - ..monoMethod.GetParameters().Select(it => it.ParameterType.NativeType()), + ..monoMethod.GetParameters().Select(it => TrampolineBuilder.GetNativeType(it.ParameterType)), typeof(Il2CppMethodInfo*), ]; diff --git a/Il2CppInterop.Runtime/RuntimeInvoke.cs b/Il2CppInterop.Runtime/RuntimeInvoke.cs index 769ae416..d4a2430e 100644 --- a/Il2CppInterop.Runtime/RuntimeInvoke.cs +++ b/Il2CppInterop.Runtime/RuntimeInvoke.cs @@ -147,7 +147,7 @@ private static T GenerateDelegateForICall(nint icallPtr) where T : Delegate // Parameter is a ByReference, and we need to get the underlying type T var elementType = parameterType.GenericTypeArguments[0]; - var nativeStruct = TrampolineHelpers.NativeType(elementType); + var nativeStruct = TrampolineBuilder.GetNativeType(elementType); parameterTypes[i] = nativeStruct; var nativeLocal = bodyBuilder.DeclareLocal(nativeStruct); @@ -173,7 +173,7 @@ private static T GenerateDelegateForICall(nint icallPtr) where T : Delegate else { var returnType = invoke.ReturnType; - var nativeStruct = TrampolineHelpers.NativeType(returnType); + var nativeStruct = TrampolineBuilder.GetNativeType(returnType); bodyBuilder.EmitCalli(OpCodes.Calli, CallingConventions.Standard, nativeStruct, parameterTypes, null); From 57d0f9e29fb9aceba8d89d24f93a1bd222b46a33 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 13:05:43 -0700 Subject: [PATCH 428/486] Rename SignatureHash to InvokerSignatureHash --- .../{SignatureHash.cs => InvokerSignatureHash.cs} | 9 ++++++--- Il2CppInterop.Runtime/Injection/TypeInjector.cs | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) rename Il2CppInterop.Runtime/Injection/{SignatureHash.cs => InvokerSignatureHash.cs} (84%) diff --git a/Il2CppInterop.Runtime/Injection/SignatureHash.cs b/Il2CppInterop.Runtime/Injection/InvokerSignatureHash.cs similarity index 84% rename from Il2CppInterop.Runtime/Injection/SignatureHash.cs rename to Il2CppInterop.Runtime/Injection/InvokerSignatureHash.cs index 7a5f7ea7..e9e028cb 100644 --- a/Il2CppInterop.Runtime/Injection/SignatureHash.cs +++ b/Il2CppInterop.Runtime/Injection/InvokerSignatureHash.cs @@ -7,11 +7,14 @@ namespace Il2CppInterop.Runtime.Injection; -internal readonly record struct SignatureHash +/// +/// A hash representing the signature of a generated invoker method +/// +internal readonly record struct InvokerSignatureHash { private readonly UInt128 _hash; - public unsafe SignatureHash(INativeMethodInfoStruct methodInfo) + public unsafe InvokerSignatureHash(INativeMethodInfoStruct methodInfo) { XxHash128 hash = new(); hash.Append((methodInfo.Flags & Il2CppMethodFlags.METHOD_ATTRIBUTE_STATIC) != 0); @@ -24,7 +27,7 @@ public unsafe SignatureHash(INativeMethodInfoStruct methodInfo) _hash = hash.GetCurrentHashAsUInt128(); } - public SignatureHash(MethodInfo methodInfo) + public InvokerSignatureHash(MethodInfo methodInfo) { XxHash128 hash = new(); hash.Append(methodInfo.IsStatic); diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index d6f8651a..86a4b902 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -29,7 +29,7 @@ public static unsafe class TypeInjector private static readonly HashSet NeedsInitialized = new(); private static readonly Dictionary NeedsVTableSet = new(); private static readonly HashSet NeedsFieldsSet = new(); - private static readonly ConcurrentDictionary InvokerCache = new(); + private static readonly ConcurrentDictionary InvokerCache = new(); /// /// If true, this type is part of the game and not something we are trying to inject nor something that has already been injected by us. @@ -1047,11 +1047,11 @@ static void Method(IntPtr obj, Il2CppMethodInfo* methodInfo) private static Delegate GetOrCreateInvoker(MethodInfo monoMethod) { - return InvokerCache.GetOrAdd(new SignatureHash(monoMethod), + return InvokerCache.GetOrAdd(new InvokerSignatureHash(monoMethod), static (signatureHash, monoMethodInner) => CreateInvoker(signatureHash, monoMethodInner), monoMethod); } - private static Delegate CreateInvoker(SignatureHash signatureHash, MethodInfo monoMethod) + private static Delegate CreateInvoker(InvokerSignatureHash signatureHash, MethodInfo monoMethod) { Debug.Assert(monoMethod.DeclaringType is not null); From c2a6b002a6266acf4f8070b5be497c1648891132 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 13:24:23 -0700 Subject: [PATCH 429/486] Move GetOrCreateDelegateType to TrampolineBuilder --- .../Il2CppInteropDetour.cs | 3 +- Il2CppInterop.Runtime/DelegateSupport.cs | 140 +----------------- .../Il2CppInterop.Runtime.csproj | 6 - .../Injection/TrampolineBuilder.cs | 64 +++++++- .../Injection/TrampolineSignatureHash.cs | 25 ++++ .../Injection/TypeInjector.cs | 3 +- 6 files changed, 91 insertions(+), 150 deletions(-) create mode 100644 Il2CppInterop.Runtime/Injection/TrampolineSignatureHash.cs diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs index 3f2561ff..bb92843a 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs @@ -2,7 +2,6 @@ using System.Reflection.Emit; using System.Runtime.InteropServices; using Il2CppInterop.Common; -using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.Structs; using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; @@ -52,7 +51,7 @@ public Il2CppInteropDetour(MethodBase source, INativeMethodInfoStruct nativeSour try { var thunk = GenerateNativeToManagedThunk().Generate(); - var thunkDelegateType = DelegateSupport.GetOrCreateDelegateType(new DelegateSupport.MethodSignature((MethodInfo)source, !source.IsStatic), (MethodInfo)source); + var thunkDelegateType = TrampolineBuilder.GetOrCreateDelegateType((MethodInfo)source); _thunkDelegate = thunk.CreateDelegate(thunkDelegateType); } catch (Exception e) diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index 77b9fa47..accf930f 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; @@ -19,68 +18,8 @@ namespace Il2CppInterop.Runtime; public static class DelegateSupport { - private static readonly ConcurrentDictionary ourDelegateTypes = new(); - - private static readonly AssemblyBuilder AssemblyBuilder = - AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Il2CppTrampolineDelegates"), AssemblyBuilderAccess.Run); - - private static readonly ModuleBuilder ModuleBuilder = - AssemblyBuilder.DefineDynamicModule("Il2CppTrampolineDelegates"); - private static readonly ConcurrentDictionary NativeToManagedTrampolines = new(); - internal static Type GetOrCreateDelegateType(MethodSignature signature, MethodInfo managedMethod) - { - return ourDelegateTypes.GetOrAdd(signature, CreateDelegateType, managedMethod); - } - - private static Type CreateDelegateType(MethodSignature signature, MethodInfo managedMethodInner) - { - var typeName = "Il2CppToManagedDelegate_" + managedMethodInner.DeclaringType + "_" + signature.GetHashCode() + - (signature.HasThis ? "HasThis" : "") + - (signature.ConstructedFromNative ? "FromNative" : ""); - - var newType = ModuleBuilder.DefineType(typeName, TypeAttributes.Sealed | TypeAttributes.Public, - typeof(MulticastDelegate)); - - var ctor = newType.DefineConstructor( - MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | - MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(object), typeof(IntPtr) }); - ctor.SetImplementationFlags(MethodImplAttributes.CodeTypeMask); - - var parameterOffset = signature.HasThis ? 1 : 0; - var managedParameters = managedMethodInner.GetParameters(); - var parameterTypes = new Type[managedParameters.Length + 1 + parameterOffset]; - - if (signature.HasThis) - parameterTypes[0] = typeof(IntPtr); - - parameterTypes[parameterTypes.Length - 1] = typeof(Il2CppMethodInfo*); - for (var i = 0; i < managedParameters.Length; i++) - parameterTypes[i + parameterOffset] = TrampolineBuilder.GetNativeType(managedParameters[i].ParameterType); - - newType.DefineMethod("Invoke", - MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Public, - CallingConventions.HasThis, - TrampolineBuilder.GetNativeType(managedMethodInner.ReturnType), - parameterTypes).SetImplementationFlags(MethodImplAttributes.CodeTypeMask); - - newType.DefineMethod("BeginInvoke", - MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | - MethodAttributes.Public, - CallingConventions.HasThis, typeof(IAsyncResult), - parameterTypes.Concat(new[] { typeof(AsyncCallback), typeof(object) }).ToArray()) - .SetImplementationFlags(MethodImplAttributes.CodeTypeMask); - - newType.DefineMethod("EndInvoke", - MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Public, - CallingConventions.HasThis, - TrampolineBuilder.GetNativeType(managedMethodInner.ReturnType), - new[] { typeof(IAsyncResult) }).SetImplementationFlags(MethodImplAttributes.CodeTypeMask); - - return newType.CreateType(); - } - private static string ExtractSignature(MethodInfo methodInfo) { var builder = new StringBuilder(); @@ -99,12 +38,12 @@ private static string ExtractSignature(MethodInfo methodInfo) return builder.ToString(); } - private static Delegate GetOrCreateNativeToManagedTrampoline(MethodSignature signature, MethodInfo managedMethod) + private static Delegate GetOrCreateNativeToManagedTrampoline(MethodInfo managedMethod) { - return NativeToManagedTrampolines.GetOrAdd(managedMethod, GenerateNativeToManagedTrampoline, signature); + return NativeToManagedTrampolines.GetOrAdd(managedMethod, GenerateNativeToManagedTrampoline); } - private static Delegate GenerateNativeToManagedTrampoline(MethodInfo managedMethod, MethodSignature signature) + private static Delegate GenerateNativeToManagedTrampoline(MethodInfo managedMethod) { var returnType = TrampolineBuilder.GetNativeType(managedMethod.ReturnType); @@ -152,7 +91,7 @@ private static Delegate GenerateNativeToManagedTrampoline(MethodInfo managedMeth bodyBuilder.Emit(OpCodes.Ldloc, returnLocal); bodyBuilder.Emit(OpCodes.Ret); - return trampoline.CreateDelegate(GetOrCreateDelegateType(signature, managedMethod)); + return trampoline.CreateDelegate(TrampolineBuilder.GetOrCreateDelegateType(managedMethod)); } private static void LogError(Exception exception) @@ -219,8 +158,7 @@ private static unsafe TNative ConvertReturnValue(TManaged? va $"Parameter type at {i} has mismatched native type pointers; types: {nativeType.FullName} != {managedType.FullName}"); } - var signature = new MethodSignature(nativeDelegateInvokeMethod, true); - var managedTrampoline = GetOrCreateNativeToManagedTrampoline(signature, managedInvokeMethod); + var managedTrampoline = GetOrCreateNativeToManagedTrampoline(managedInvokeMethod); var methodInfo = UnityVersionHandler.NewMethod(); methodInfo.MethodPointer = Marshal.GetFunctionPointerForDelegate(managedTrampoline); @@ -255,72 +193,4 @@ private static unsafe TNative ConvertReturnValue(TManaged? va { return (IReadOnlyList)GetParametersInternal(method); } - - internal sealed class MethodSignature : IEquatable - { - public readonly bool ConstructedFromNative; - public readonly bool HasThis; - private readonly int _hashCode; - - public MethodSignature(Il2CppSystem.Reflection.MethodInfo methodInfo, bool hasThis) - { - HasThis = hasThis; - ConstructedFromNative = true; - - var hashCode = new HashCode(); - - hashCode.Add(methodInfo.ReturnType.GetHashCode()); - if (hasThis) hashCode.Add(methodInfo.DeclaringType.GetHashCode()); - foreach (var parameterInfo in methodInfo.GetParameters()) - { - hashCode.Add(parameterInfo.ParameterType.GetHashCode()); - } - - _hashCode = hashCode.ToHashCode(); - } - - public MethodSignature(MethodInfo methodInfo, bool hasThis) - { - HasThis = hasThis; - ConstructedFromNative = false; - - var hashCode = new HashCode(); - - hashCode.Add(TrampolineBuilder.GetNativeType(methodInfo.ReturnType)); - if (hasThis) hashCode.Add(TrampolineBuilder.GetNativeType(methodInfo.DeclaringType!)); - foreach (var parameterInfo in methodInfo.GetParameters()) - { - hashCode.Add(TrampolineBuilder.GetNativeType(parameterInfo.ParameterType)); - } - - _hashCode = hashCode.ToHashCode(); - } - - public override int GetHashCode() - { - return _hashCode; - } - - public bool Equals(MethodSignature? other) - { - if (other is null) return false; - if (ReferenceEquals(this, other)) return true; - return _hashCode.GetHashCode() == other.GetHashCode(); - } - - public override bool Equals(object? obj) - { - return Equals(obj as MethodSignature); - } - - public static bool operator ==(MethodSignature? left, MethodSignature? right) - { - return Equals(left, right); - } - - public static bool operator !=(MethodSignature? left, MethodSignature? right) - { - return !Equals(left, right); - } - } } diff --git a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj index 82a2002f..07f28972 100644 --- a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj +++ b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj @@ -14,12 +14,6 @@ true - - - <_Parameter1>Il2CppInterop.HarmonySupport - - - diff --git a/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs b/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs index c35622a3..2d9ba3eb 100644 --- a/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs +++ b/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs @@ -1,20 +1,27 @@ using System; using System.Buffers.Binary; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using Il2CppInterop.Common; using Il2CppInterop.Runtime.InteropTypes; +using Il2CppInterop.Runtime.Structs; namespace Il2CppInterop.Runtime.Injection; public static class TrampolineBuilder { - private static AssemblyBuilder? _fixedStructAssembly; - private static ModuleBuilder? _fixedStructModuleBuilder; + private static readonly AssemblyBuilder _fixedStructAssembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("FixedSizeStructAssembly"), AssemblyBuilderAccess.Run); + private static readonly ModuleBuilder _fixedStructModuleBuilder = _fixedStructAssembly.DefineDynamicModule("FixedSizeStructAssembly"); private static readonly Dictionary _fixedStructCache = new(); + private static readonly AssemblyBuilder _delegateAssembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Il2CppTrampolineDelegates"), AssemblyBuilderAccess.Run); + private static readonly ModuleBuilder _delegateModule = _delegateAssembly.DefineDynamicModule("Il2CppTrampolineDelegates"); + private static readonly ConcurrentDictionary ourDelegateTypes = new(); + private static Type GetFixedSizeStructType(int size) { if (_fixedStructCache.TryGetValue(size, out var result)) @@ -22,9 +29,6 @@ private static Type GetFixedSizeStructType(int size) return result; } - _fixedStructAssembly ??= AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("FixedSizeStructAssembly"), AssemblyBuilderAccess.Run); - _fixedStructModuleBuilder ??= _fixedStructAssembly.DefineDynamicModule("FixedSizeStructAssembly"); - var tb = _fixedStructModuleBuilder.DefineType($"IL2CPPDetour_FixedSizeStruct_{size}b", TypeAttributes.SequentialLayout | TypeAttributes.BeforeFieldInit | TypeAttributes.Sealed, typeof(ValueType)); tb.DefineField("_element0", typeof(byte), FieldAttributes.Private); @@ -86,4 +90,54 @@ public static Type GetNativeType(Type managedType) return GetFixedSizeStructType(fixedSize); } } + + public static Type GetOrCreateDelegateType(MethodInfo monoMethod) + { + return ourDelegateTypes.GetOrAdd(new TrampolineSignatureHash(monoMethod), CreateDelegateType, monoMethod); + } + + private static Type CreateDelegateType(TrampolineSignatureHash signatureHash, MethodInfo monoMethod) + { + var typeName = $"Il2CppToManagedDelegate_{signatureHash}"; + + var newType = _delegateModule.DefineType(typeName, TypeAttributes.Sealed | TypeAttributes.Public, + typeof(MulticastDelegate)); + + var ctor = newType.DefineConstructor( + MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | + MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(object), typeof(IntPtr) }); + ctor.SetImplementationFlags(MethodImplAttributes.CodeTypeMask); + + var parameterTypes = GetNativeParameters(monoMethod); + + newType.DefineMethod("Invoke", + MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Public, + CallingConventions.HasThis, + GetNativeType(monoMethod.ReturnType), + parameterTypes) + .SetImplementationFlags(MethodImplAttributes.CodeTypeMask); + + newType.DefineMethod("BeginInvoke", + MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | + MethodAttributes.Public, + CallingConventions.HasThis, typeof(IAsyncResult), + parameterTypes.Concat([typeof(AsyncCallback), typeof(object)]).ToArray()) + .SetImplementationFlags(MethodImplAttributes.CodeTypeMask); + + newType.DefineMethod("EndInvoke", + MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | MethodAttributes.Public, + CallingConventions.HasThis, + GetNativeType(monoMethod.ReturnType), + [typeof(IAsyncResult)]) + .SetImplementationFlags(MethodImplAttributes.CodeTypeMask); + + return newType.CreateType(); + } + + private static Type[] GetNativeParameters(MethodInfo monoMethod) => + [ + ..(ReadOnlySpan)(monoMethod.IsStatic ? [] : [typeof(IntPtr)]), + ..monoMethod.GetParameters().Select(it => GetNativeType(it.ParameterType)), + typeof(Il2CppMethodInfo*), + ]; } diff --git a/Il2CppInterop.Runtime/Injection/TrampolineSignatureHash.cs b/Il2CppInterop.Runtime/Injection/TrampolineSignatureHash.cs new file mode 100644 index 00000000..2831f711 --- /dev/null +++ b/Il2CppInterop.Runtime/Injection/TrampolineSignatureHash.cs @@ -0,0 +1,25 @@ +using System; +using System.IO.Hashing; +using System.Reflection; +using Il2CppInterop.Runtime.Extensions; + +namespace Il2CppInterop.Runtime.Injection; + +internal readonly record struct TrampolineSignatureHash +{ + private readonly UInt128 _hash; + + public TrampolineSignatureHash(MethodInfo methodInfo) + { + XxHash128 hash = new(); + hash.Append(methodInfo.IsStatic); + hash.Append(TrampolineBuilder.GetNativeType(methodInfo.ReturnType).FullName); + foreach (var parameter in methodInfo.GetParameters()) + { + hash.Append(TrampolineBuilder.GetNativeType(parameter.ParameterType).FullName); + } + _hash = hash.GetCurrentHashAsUInt128(); + } + + public override string ToString() => _hash.ToString(); +} diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 86a4b902..95444afd 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -1179,8 +1179,7 @@ private static Delegate CreateTrampoline(MethodInfo monoMethod, bool callVirt) nativeReturnType, nativeParameterTypes, typeof(TypeInjector), true); - var signature = new DelegateSupport.MethodSignature(monoMethod, !monoMethod.IsStatic); - var delegateType = DelegateSupport.GetOrCreateDelegateType(signature, monoMethod); + var delegateType = TrampolineBuilder.GetOrCreateDelegateType(monoMethod); var body = method.GetILGenerator(); From 7cf092ec2b1e1d89bf21446cc810303e7327669b Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 22:07:27 -0700 Subject: [PATCH 430/486] Clean up TrampolineBuilder --- .../Injection/TrampolineBuilder.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs b/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs index 2d9ba3eb..400e5ed3 100644 --- a/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs +++ b/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs @@ -103,10 +103,10 @@ private static Type CreateDelegateType(TrampolineSignatureHash signatureHash, Me var newType = _delegateModule.DefineType(typeName, TypeAttributes.Sealed | TypeAttributes.Public, typeof(MulticastDelegate)); - var ctor = newType.DefineConstructor( + newType.DefineConstructor( MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName | - MethodAttributes.Public, CallingConventions.HasThis, new[] { typeof(object), typeof(IntPtr) }); - ctor.SetImplementationFlags(MethodImplAttributes.CodeTypeMask); + MethodAttributes.Public, CallingConventions.HasThis, [typeof(object), typeof(IntPtr)]) + .SetImplementationFlags(MethodImplAttributes.CodeTypeMask); var parameterTypes = GetNativeParameters(monoMethod); @@ -118,10 +118,10 @@ private static Type CreateDelegateType(TrampolineSignatureHash signatureHash, Me .SetImplementationFlags(MethodImplAttributes.CodeTypeMask); newType.DefineMethod("BeginInvoke", - MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | - MethodAttributes.Public, - CallingConventions.HasThis, typeof(IAsyncResult), - parameterTypes.Concat([typeof(AsyncCallback), typeof(object)]).ToArray()) + MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot | + MethodAttributes.Public, + CallingConventions.HasThis, typeof(IAsyncResult), + parameterTypes.Concat([typeof(AsyncCallback), typeof(object)]).ToArray()) .SetImplementationFlags(MethodImplAttributes.CodeTypeMask); newType.DefineMethod("EndInvoke", From b2e6c0ff9a9ca023c64ddd92fa1a65f01aabc9a2 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 23:12:37 -0700 Subject: [PATCH 431/486] Unify trampoline creation --- Il2CppInterop.Runtime/DelegateSupport.cs | 104 +----------- .../Injection/TrampolineBuilder.cs | 152 ++++++++++++++++++ .../Injection/TypeInjector.cs | 152 +----------------- .../Il2CppToMonoDelegateReference.cs | 54 +++++++ 4 files changed, 214 insertions(+), 248 deletions(-) diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index accf930f..934774c0 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -1,120 +1,30 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Reflection; -using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Text; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Extensions; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppInterop.Runtime.Structs; -using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime; public static class DelegateSupport { - private static readonly ConcurrentDictionary NativeToManagedTrampolines = new(); + private static readonly ConcurrentDictionary NativeToManagedTrampolines = new(); - private static string ExtractSignature(MethodInfo methodInfo) + private static Delegate GetOrCreateNativeToManagedTrampoline(Type delegateType) { - var builder = new StringBuilder(); - builder.Append(methodInfo.ReturnType.FullName); - if (!methodInfo.IsStatic) - { - builder.Append('_'); - builder.Append(methodInfo.DeclaringType!.FullName); - } - foreach (var parameterInfo in methodInfo.GetParameters()) - { - builder.Append('_'); - builder.Append(parameterInfo.ParameterType.FullName); - } - - return builder.ToString(); - } - - private static Delegate GetOrCreateNativeToManagedTrampoline(MethodInfo managedMethod) - { - return NativeToManagedTrampolines.GetOrAdd(managedMethod, GenerateNativeToManagedTrampoline); - } - - private static Delegate GenerateNativeToManagedTrampoline(MethodInfo managedMethod) - { - var returnType = TrampolineBuilder.GetNativeType(managedMethod.ReturnType); - - var managedParameters = managedMethod.GetParameters(); - var parameterTypes = new Type[managedParameters.Length + 1 + 1]; // thisptr for target, methodInfo last arg - parameterTypes[0] = typeof(IntPtr); - parameterTypes[managedParameters.Length + 1] = typeof(Il2CppMethodInfo*); - for (var i = 0; i < managedParameters.Length; i++) - parameterTypes[i + 1] = TrampolineBuilder.GetNativeType(managedParameters[i].ParameterType); - - var trampoline = new DynamicMethod("(il2cpp delegate trampoline) " + ExtractSignature(managedMethod), - MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, returnType, parameterTypes, - typeof(DelegateSupport), true); - var bodyBuilder = trampoline.GetILGenerator(); - - var tryLabel = bodyBuilder.BeginExceptionBlock(); - - bodyBuilder.Emit(OpCodes.Ldarg_0); - bodyBuilder.Emit(OpCodes.Call, typeof(Il2CppObjectPool).GetMethod(nameof(Il2CppObjectPool.Get))!); - bodyBuilder.Emit(OpCodes.Castclass, typeof(Il2CppToMonoDelegateReference)); - bodyBuilder.Emit(OpCodes.Callvirt, typeof(Il2CppToMonoDelegateReference).GetProperty(nameof(Il2CppToMonoDelegateReference.ReferencedDelegate))!.GetMethod!); - - for (var i = 0; i < managedParameters.Length; i++) - { - bodyBuilder.Emit(OpCodes.Ldarg, i + 1); - bodyBuilder.Emit(OpCodes.Call, typeof(DelegateSupport).GetMethod(nameof(ConvertNativeArgument), BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(parameterTypes[i + 1], managedParameters[i].ParameterType)); - } - - bodyBuilder.Emit(OpCodes.Call, managedMethod); - - LocalBuilder? returnLocal = null; - if (returnType != typeof(void)) - { - returnLocal = bodyBuilder.DeclareLocal(returnType); - bodyBuilder.Emit(OpCodes.Call, typeof(DelegateSupport).GetMethod(nameof(ConvertReturnValue), BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(managedMethod.ReturnType, returnType)); - bodyBuilder.Emit(OpCodes.Stloc, returnLocal); - } - - bodyBuilder.BeginCatchBlock(typeof(Exception)); - bodyBuilder.Emit(OpCodes.Call, typeof(DelegateSupport).GetMethod(nameof(LogError), BindingFlags.Static | BindingFlags.NonPublic)!); - - bodyBuilder.EndExceptionBlock(); - - if (returnLocal != null) - bodyBuilder.Emit(OpCodes.Ldloc, returnLocal); - bodyBuilder.Emit(OpCodes.Ret); - - return trampoline.CreateDelegate(TrampolineBuilder.GetOrCreateDelegateType(managedMethod)); - } - - private static void LogError(Exception exception) - { - Logger.Instance.LogError("Exception in IL2CPP-to-Managed trampoline, not passing it to il2cpp: {Exception}", exception); - } - - private static unsafe TManaged? ConvertNativeArgument(TNative value) - where TNative : unmanaged - where TManaged : IIl2CppType - { - var span = new ReadOnlySpan(&value, sizeof(TNative)); - return TManaged.ReadFromSpan(span); + return NativeToManagedTrampolines.GetOrAdd(delegateType, CreateNativeToManagedTrampoline); } - private static unsafe TNative ConvertReturnValue(TManaged? value) - where TNative : unmanaged - where TManaged : IIl2CppType + private static Delegate CreateNativeToManagedTrampoline(Type delegateType) { - TNative result = default; - var span = new Span(&result, sizeof(TNative)); - TManaged.WriteToSpan(value, span); - return result; + var invokeMethod = Il2CppToMonoDelegateReference.GetOrCreateInvokeMethod(delegateType); + return TrampolineBuilder.CreateTrampoline(invokeMethod, false); } public static TIl2Cpp? ConvertDelegate(Delegate @delegate) where TIl2Cpp : Il2CppSystem.Delegate, IIl2CppType @@ -158,7 +68,7 @@ private static unsafe TNative ConvertReturnValue(TManaged? va $"Parameter type at {i} has mismatched native type pointers; types: {nativeType.FullName} != {managedType.FullName}"); } - var managedTrampoline = GetOrCreateNativeToManagedTrampoline(managedInvokeMethod); + var managedTrampoline = GetOrCreateNativeToManagedTrampoline(@delegate.GetType()); var methodInfo = UnityVersionHandler.NewMethod(); methodInfo.MethodPointer = Marshal.GetFunctionPointerForDelegate(managedTrampoline); diff --git a/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs b/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs index 400e5ed3..fdce2543 100644 --- a/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs +++ b/Il2CppInterop.Runtime/Injection/TrampolineBuilder.cs @@ -2,6 +2,7 @@ using System.Buffers.Binary; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -9,6 +10,7 @@ using Il2CppInterop.Common; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.Structs; +using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime.Injection; @@ -140,4 +142,154 @@ private static Type[] GetNativeParameters(MethodInfo monoMethod) => ..monoMethod.GetParameters().Select(it => GetNativeType(it.ParameterType)), typeof(Il2CppMethodInfo*), ]; + + internal static Delegate CreateTrampoline(MethodInfo monoMethod, bool callVirt) + { + Debug.Assert(monoMethod.DeclaringType is not null); + + var nativeReturnType = GetNativeType(monoMethod.ReturnType); + var nativeParameterTypes = GetNativeParameters(monoMethod); + + Type[] managedParameters = + [ + ..(ReadOnlySpan)(monoMethod.IsStatic ? [] : [monoMethod.DeclaringType!]), + ..monoMethod.GetParameters().Select(it => it.ParameterType), + ]; + + var trampoline = new DynamicMethod( + $"Trampoline_{monoMethod.DeclaringType}_{monoMethod.Name}_{new NamedSignatureHash(monoMethod)}{(callVirt ? "_Virtual" : "")}", + MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, + nativeReturnType, nativeParameterTypes, + typeof(TypeInjector), true); + + var delegateType = GetOrCreateDelegateType(monoMethod); + + var body = trampoline.GetILGenerator(); + + body.BeginExceptionBlock(); + + // Value types boxed as interfaces can be modified during the execution of the method. + List<(LocalBuilder Local, int ArgumentIndex)> interfaceArguments = []; + + LocalBuilder? thisVariable = null; + if (!monoMethod.IsStatic) + { + body.Emit(OpCodes.Ldarg_0); + if (monoMethod.DeclaringType.IsValueType) + { + // Need to store the value in a local variable so that we can pass a reference to the managed method + thisVariable = body.DeclareLocal(monoMethod.DeclaringType); + body.Emit(OpCodes.Conv_U); + body.Emit(OpCodes.Call, typeof(Il2CppType).GetMethod(nameof(Il2CppType.ReadFromPointer), BindingFlags.Public | BindingFlags.Static)!.MakeGenericMethod(monoMethod.DeclaringType)); + body.Emit(OpCodes.Stloc, thisVariable); + body.Emit(OpCodes.Ldloca, thisVariable); + } + else + { + body.Emit(OpCodes.Call, typeof(Il2CppObjectPool).GetMethod(nameof(Il2CppObjectPool.Get))!); + body.Emit(OpCodes.Castclass, monoMethod.DeclaringType); + + if (monoMethod.DeclaringType.IsInterface) + { + var local = body.DeclareLocal(monoMethod.DeclaringType); + body.Emit(OpCodes.Stloc, local); + body.Emit(OpCodes.Ldloc, local); + interfaceArguments.Add((local, 0)); + } + } + } + + var argOffset = monoMethod.IsStatic ? 0 : 1; + + for (var i = argOffset; i < managedParameters.Length; i++) + { + body.Emit(OpCodes.Ldarg, i); + body.Emit(OpCodes.Call, typeof(TypeInjector).GetMethod(nameof(ConvertNativeToManaged), BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(nativeParameterTypes[i], managedParameters[i])); + if (managedParameters[i].IsInterface) + { + var local = body.DeclareLocal(managedParameters[i]); + body.Emit(OpCodes.Stloc, local); + body.Emit(OpCodes.Ldloc, local); + interfaceArguments.Add((local, i)); + } + } + + body.Emit(callVirt ? OpCodes.Callvirt : OpCodes.Call, monoMethod); + LocalBuilder? nativeReturnVariable = null; + if (monoMethod.ReturnType != typeof(void)) + { + nativeReturnVariable = body.DeclareLocal(nativeReturnType); + body.Emit(OpCodes.Call, typeof(TypeInjector).GetMethod(nameof(ConvertManagedToNative), BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(monoMethod.ReturnType, nativeReturnType)); + body.Emit(OpCodes.Stloc, nativeReturnVariable); + } + + if (thisVariable != null) + { + // Copy any changes to the value type back to the pointer passed by il2cpp + Debug.Assert(monoMethod.DeclaringType.IsValueType); + body.Emit(OpCodes.Ldloc, thisVariable); + body.Emit(OpCodes.Ldarg_0); + body.Emit(OpCodes.Conv_U); + body.Emit(OpCodes.Call, typeof(Il2CppType).GetMethod(nameof(Il2CppType.WriteToPointer), BindingFlags.Public | BindingFlags.Static)!.MakeGenericMethod(monoMethod.DeclaringType)); + } + + // Update boxed value types passed as interfaces + foreach ((var local, var argumentIndex) in interfaceArguments) + { + body.Emit(OpCodes.Ldarg, argumentIndex); + body.Emit(OpCodes.Ldloc, local); + body.Emit(OpCodes.Call, typeof(TypeInjector).GetMethod(nameof(UpdateBoxedValue), BindingFlags.Static | BindingFlags.NonPublic)!); + } + + body.BeginCatchBlock(typeof(Exception)); + body.Emit(OpCodes.Call, typeof(TypeInjector).GetMethod(nameof(LogError), BindingFlags.Static | BindingFlags.NonPublic)!); + + body.EndExceptionBlock(); + + if (nativeReturnVariable != null) + { + body.Emit(OpCodes.Ldloc, nativeReturnVariable); + } + + body.Emit(OpCodes.Ret); + + return trampoline.CreateDelegate(delegateType); + } + + private static void LogError(Exception exception) + { + Logger.Instance.LogError("Exception in IL2CPP-to-Managed trampoline, not passing it to il2cpp: {Exception}", exception); + } + + private static unsafe void UpdateBoxedValue(IntPtr objectPointer, IIl2CppType? @object) + { + if (objectPointer == IntPtr.Zero || @object == null) + return; + + if (!@object.GetType().IsValueType) + return; + + var size = IL2CPP.il2cpp_class_value_size(@object.ObjectClass, out _); + var sourceSpan = new ReadOnlySpan((void*)IL2CPP.il2cpp_object_unbox((nint)@object.BoxNative()), size); + var destinationSpan = new Span((void*)IL2CPP.il2cpp_object_unbox(objectPointer), size); + sourceSpan.CopyTo(destinationSpan); + } + + private static unsafe TManaged? ConvertNativeToManaged(TNative value) + where TNative : unmanaged + where TManaged : IIl2CppType + { + var span = new ReadOnlySpan(&value, sizeof(TNative)); + return TManaged.ReadFromSpan(span); + } + + private static unsafe TNative ConvertManagedToNative(TManaged? value) + where TNative : unmanaged + where TManaged : IIl2CppType + { + TNative result = default; + var span = new Span(&result, sizeof(TNative)); + TManaged.WriteToSpan(value, span); + return result; + } } diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 95444afd..6d6e6db4 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -1157,161 +1157,11 @@ private static Delegate CreateInvoker(InvokerSignatureHash signatureHash, Method private static Delegate CreateTrampoline(MethodInfo monoMethod, bool callVirt) { - Debug.Assert(monoMethod.DeclaringType is not null); - - var nativeReturnType = TrampolineBuilder.GetNativeType(monoMethod.ReturnType); - Type[] nativeParameterTypes = - [ - ..(ReadOnlySpan)(monoMethod.IsStatic ? [] : [typeof(IntPtr)]), - ..monoMethod.GetParameters().Select(it => TrampolineBuilder.GetNativeType(it.ParameterType)), - typeof(Il2CppMethodInfo*), - ]; - - Type[] managedParameters = - [ - ..(ReadOnlySpan)(monoMethod.IsStatic ? [] : [monoMethod.DeclaringType!]), - ..monoMethod.GetParameters().Select(it => it.ParameterType), - ]; - - var method = new DynamicMethod( - $"Trampoline_{monoMethod.DeclaringType}_{monoMethod.Name}_{new NamedSignatureHash(monoMethod)}{(callVirt ? "_Virtual" : "")}", - MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, - nativeReturnType, nativeParameterTypes, - typeof(TypeInjector), true); - - var delegateType = TrampolineBuilder.GetOrCreateDelegateType(monoMethod); - - var body = method.GetILGenerator(); - - body.BeginExceptionBlock(); - - // Value types boxed as interfaces can be modified during the execution of the method. - List<(LocalBuilder Local, int ArgumentIndex)> interfaceArguments = []; - - LocalBuilder? thisVariable = null; - if (!monoMethod.IsStatic) - { - body.Emit(OpCodes.Ldarg_0); - if (monoMethod.DeclaringType.IsValueType) - { - // Need to store the value in a local variable so that we can pass a reference to the managed method - thisVariable = body.DeclareLocal(monoMethod.DeclaringType); - body.Emit(OpCodes.Conv_U); - body.Emit(OpCodes.Call, typeof(Il2CppType).GetMethod(nameof(Il2CppType.ReadFromPointer), BindingFlags.Public | BindingFlags.Static)!.MakeGenericMethod(monoMethod.DeclaringType)); - body.Emit(OpCodes.Stloc, thisVariable); - body.Emit(OpCodes.Ldloca, thisVariable); - } - else - { - body.Emit(OpCodes.Call, typeof(Il2CppObjectPool).GetMethod(nameof(Il2CppObjectPool.Get))!); - body.Emit(OpCodes.Castclass, monoMethod.DeclaringType); - - if (monoMethod.DeclaringType.IsInterface) - { - var local = body.DeclareLocal(monoMethod.DeclaringType); - body.Emit(OpCodes.Stloc, local); - body.Emit(OpCodes.Ldloc, local); - interfaceArguments.Add((local, 0)); - } - } - } - - var argOffset = method.IsStatic ? 0 : 1; - - for (var i = argOffset; i < managedParameters.Length; i++) - { - body.Emit(OpCodes.Ldarg, i); - body.Emit(OpCodes.Call, typeof(TypeInjector).GetMethod(nameof(ConvertNativeToManaged), BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(nativeParameterTypes[i], managedParameters[i])); - if (managedParameters[i].IsInterface) - { - var local = body.DeclareLocal(managedParameters[i]); - body.Emit(OpCodes.Stloc, local); - body.Emit(OpCodes.Ldloc, local); - interfaceArguments.Add((local, i)); - } - } - - body.Emit(callVirt ? OpCodes.Callvirt : OpCodes.Call, monoMethod); - LocalBuilder? nativeReturnVariable = null; - if (monoMethod.ReturnType != typeof(void)) - { - nativeReturnVariable = body.DeclareLocal(nativeReturnType); - body.Emit(OpCodes.Call, typeof(TypeInjector).GetMethod(nameof(ConvertManagedToNative), BindingFlags.Static | BindingFlags.NonPublic)!.MakeGenericMethod(monoMethod.ReturnType, nativeReturnType)); - body.Emit(OpCodes.Stloc, nativeReturnVariable); - } - - if (thisVariable != null) - { - // Copy any changes to the value type back to the pointer passed by il2cpp - Debug.Assert(monoMethod.DeclaringType.IsValueType); - body.Emit(OpCodes.Ldloc, thisVariable); - body.Emit(OpCodes.Ldarg_0); - body.Emit(OpCodes.Conv_U); - body.Emit(OpCodes.Call, typeof(Il2CppType).GetMethod(nameof(Il2CppType.WriteToPointer), BindingFlags.Public | BindingFlags.Static)!.MakeGenericMethod(monoMethod.DeclaringType)); - } - - // Update boxed value types passed as interfaces - foreach ((var local, var argumentIndex) in interfaceArguments) - { - body.Emit(OpCodes.Ldarg, argumentIndex); - body.Emit(OpCodes.Ldloc, local); - body.Emit(OpCodes.Call, typeof(TypeInjector).GetMethod(nameof(UpdateBoxedValue), BindingFlags.Static | BindingFlags.NonPublic)!); - } - - body.BeginCatchBlock(typeof(Exception)); - body.Emit(OpCodes.Call, typeof(TypeInjector).GetMethod(nameof(LogError), BindingFlags.Static | BindingFlags.NonPublic)!); - - body.EndExceptionBlock(); - - if (nativeReturnVariable != null) - { - body.Emit(OpCodes.Ldloc, nativeReturnVariable); - } - - body.Emit(OpCodes.Ret); - - var @delegate = method.CreateDelegate(delegateType); + var @delegate = TrampolineBuilder.CreateTrampoline(monoMethod, callVirt); GCHandle.Alloc(@delegate); // pin it forever return @delegate; } - private static void LogError(Exception exception) - { - Logger.Instance.LogError("Exception in IL2CPP-to-Managed trampoline, not passing it to il2cpp: {Exception}", exception); - } - - private static void UpdateBoxedValue(IntPtr objectPointer, IIl2CppType? @object) - { - if (objectPointer == IntPtr.Zero || @object == null) - return; - - if (!@object.GetType().IsValueType) - return; - - var size = IL2CPP.il2cpp_class_value_size(@object.ObjectClass, out _); - var sourceSpan = new ReadOnlySpan((void*)IL2CPP.il2cpp_object_unbox((nint)@object.BoxNative()), size); - var destinationSpan = new Span((void*)IL2CPP.il2cpp_object_unbox(objectPointer), size); - sourceSpan.CopyTo(destinationSpan); - } - - private static TManaged? ConvertNativeToManaged(TNative value) - where TNative : unmanaged - where TManaged : IIl2CppType - { - var span = new ReadOnlySpan(&value, sizeof(TNative)); - return TManaged.ReadFromSpan(span); - } - - private static TNative ConvertManagedToNative(TManaged? value) - where TNative : unmanaged - where TManaged : IIl2CppType - { - TNative result = default; - var span = new Span(&result, sizeof(TNative)); - TManaged.WriteToSpan(value, span); - return result; - } - private static (string AssemblyName, string Namespace, string Name) GetFullyQualifiedName(Type type) { var methodInfo = typeof(TypeInjector).GetMethod(nameof(GetFullyQualifiedNameGeneric), BindingFlags.NonPublic | BindingFlags.Static)!.MakeGenericMethod(type); diff --git a/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs index 91886a2e..ba0e1228 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs @@ -1,4 +1,8 @@ using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; using System.Runtime.InteropServices; using Il2CppInterop.Common; using Il2CppInterop.Common.Attributes; @@ -31,4 +35,54 @@ partial void LogErrorIl2CppFinalize(Exception exception) { Logger.Instance.LogError($"Exception in {nameof(Il2CppToMonoDelegateReference)}.{nameof(Il2CppFinalize)}: {{Exception}}", exception); } + + private static ConcurrentDictionary _methodInfoCache = new(); + + /// + /// Creates or retrieves a cached dynamic method that will cast + /// to the specified and invoke it with the provided arguments. + /// + /// + /// Due to limitations in dynamic method creation, the dynamic method must be static. + /// As such, the first parameter of the dynamic method is always . + /// The remaining parameters are copied from the Invoke method of . + /// + /// The type of the delegate to cast and invoke. + /// The dynamic method. + internal static MethodInfo GetOrCreateInvokeMethod(Type delegateType) + { + return _methodInfoCache.GetOrAdd(delegateType, CreateInvokeMethod); + } + + private static MethodInfo CreateInvokeMethod(Type delegateType) + { + var delegateInvokeMethod = delegateType.GetMethod("Invoke") + ?? throw new InvalidOperationException($"Delegate type {delegateType.FullName} does not have an Invoke method."); + + var returnType = delegateInvokeMethod.ReturnType; + + // Dynamic methods must be static, so we prepend the declaring type as the first parameter + Type[] parameterTypes = + [ + typeof(Il2CppToMonoDelegateReference), + ..delegateInvokeMethod.GetParameters().Select(p => p.ParameterType) + ]; + + var invokeMethod = new DynamicMethod($"Invoke_{delegateType.FullName}", returnType, parameterTypes, + typeof(Il2CppToMonoDelegateReference), false); + var bodyBuilder = invokeMethod.GetILGenerator(); + + bodyBuilder.Emit(OpCodes.Ldarg_0); + bodyBuilder.Emit(OpCodes.Callvirt, typeof(Il2CppToMonoDelegateReference).GetProperty(nameof(ReferencedDelegate))!.GetMethod!); + bodyBuilder.Emit(OpCodes.Castclass, delegateType); + for (var i = 1; i < parameterTypes.Length; i++) + { + bodyBuilder.Emit(OpCodes.Ldarg, i); + } + + bodyBuilder.Emit(OpCodes.Callvirt, delegateInvokeMethod); + bodyBuilder.Emit(OpCodes.Ret); + + return invokeMethod; + } } From 96ea3e3677df507f80b0dbee00fa58af23fcfa5c Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 23:20:16 -0700 Subject: [PATCH 432/486] Fix issues with DelegateSupport --- Il2CppInterop.Runtime/DelegateSupport.cs | 12 +++++------- Il2Cppmscorlib/Type.cs | 3 +++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index 934774c0..6d9bd144 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -57,15 +57,13 @@ private static Delegate CreateNativeToManagedTrampoline(Type delegateType) for (var i = 0; i < nativeParameters.Count; i++) { var nativeType = nativeParameters[i].ParameterType; - var managedType = parameterInfos[i].ParameterType; - var classPointerFromManagedType = Il2CppType.GetClassPointer(managedType); + var typePointerForManagedType = Il2CppTypePointerStore.GetNativeTypePointer(parameterInfos[i].ParameterType); + var managedType = Il2CppSystem.Type.FromTypePointer(typePointerForManagedType); - var classPointerFromNativeType = IL2CPP.il2cpp_class_from_type(nativeType._impl.value); - - if (classPointerFromManagedType != classPointerFromNativeType) + if (nativeType != managedType) throw new ArgumentException( - $"Parameter type at {i} has mismatched native type pointers; types: {nativeType.FullName} != {managedType.FullName}"); + $"Parameter type at {i} has mismatched native type pointers; types: {nativeType?.FullName} != {managedType?.FullName}"); } var managedTrampoline = GetOrCreateNativeToManagedTrampoline(@delegate.GetType()); @@ -78,7 +76,7 @@ private static Delegate CreateNativeToManagedTrampoline(Type delegateType) var delegateReference = new Il2CppToMonoDelegateReference(@delegate, methodInfo.Pointer); - TIl2Cpp converted = (TIl2Cpp)Activator.CreateInstance(typeof(TIl2Cpp), delegateReference, methodInfo.Pointer)!; + TIl2Cpp converted = (TIl2Cpp)Activator.CreateInstance(typeof(TIl2Cpp), delegateReference, (Il2CppSystem.IntPtr)methodInfo.Pointer)!; converted.method_ptr = methodInfo.MethodPointer; converted.method_info = nativeDelegateInvokeMethod; // todo: is this truly a good hack? diff --git a/Il2Cppmscorlib/Type.cs b/Il2Cppmscorlib/Type.cs index b19c0c57..259d1e81 100644 --- a/Il2Cppmscorlib/Type.cs +++ b/Il2Cppmscorlib/Type.cs @@ -55,4 +55,7 @@ public MethodInfo GetMethod(String name) public Type MakeGenericType(Type[] typeArguments) => throw null; public Type MakePointerType() => throw null; + + public static Boolean operator ==(Type left, Type right) => throw null; + public static Boolean operator !=(Type left, Type right) => throw null; } From 2a1bbc0507551e048b0b80f7910b886d9263b423 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 10 May 2026 23:43:24 -0700 Subject: [PATCH 433/486] Change some static abstract methods to static virtual so that they don't always need generated implementations --- Il2CppInterop.Common/IIl2CppType.cs | 40 ++++++++++++++-- Il2CppInterop.Common/Il2CppType.cs | 4 +- .../MarshallingProcessingLayer.cs | 46 +++++-------------- 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/Il2CppInterop.Common/IIl2CppType.cs b/Il2CppInterop.Common/IIl2CppType.cs index 084a0498..cb6bc49f 100644 --- a/Il2CppInterop.Common/IIl2CppType.cs +++ b/Il2CppInterop.Common/IIl2CppType.cs @@ -27,7 +27,21 @@ public interface IIl2CppType : IIl2CppType where TSelf : notnull, IIl2Cpp /// /// The native size of the type in bytes /// - static abstract int Size { get; } + static virtual int Size + { + get + { + if (typeof(TSelf).IsValueType) + { + throw new NotImplementedException($"{typeof(TSelf).FullName} did not implement this property."); + } + else + { + // All reference types are the size of a pointer in native code + return IntPtr.Size; + } + } + } /// /// The file name of the assembly that the type is defined in /// @@ -60,13 +74,33 @@ static virtual string AssemblyName /// /// The value to write. /// The span to write the value to. - static abstract void WriteToSpan(TSelf? value, Span span); + static virtual void WriteToSpan(TSelf? value, Span span) + { + if (typeof(TSelf).IsValueType) + { + throw new NotImplementedException($"{typeof(TSelf).FullName} did not implement this method."); + } + else + { + Il2CppType.WriteReference(value, span); + } + } /// /// Reads the native representation of the value from the provided span. The span is required to be at least bytes long. /// /// The span to read the value from. /// The value read from the span. - static abstract TSelf? ReadFromSpan(ReadOnlySpan span); + static virtual TSelf? ReadFromSpan(ReadOnlySpan span) + { + if (typeof(TSelf).IsValueType) + { + throw new NotImplementedException($"{typeof(TSelf).FullName} did not implement this method."); + } + else + { + return Il2CppType.ReadReference(span); + } + } /// /// Unboxes the provided native Il2Cpp object to the type /// diff --git a/Il2CppInterop.Common/Il2CppType.cs b/Il2CppInterop.Common/Il2CppType.cs index 057d39f6..d66b8539 100644 --- a/Il2CppInterop.Common/Il2CppType.cs +++ b/Il2CppInterop.Common/Il2CppType.cs @@ -104,12 +104,12 @@ public static unsafe void WriteToPointer(this T? value, void* ptr) where T : return T.ReadFromSpan(new ReadOnlySpan(ptr, T.Size)); } - public static T? ReadReference(ReadOnlySpan span) where T : class, IIl2CppType + public static T? ReadReference(ReadOnlySpan span) where T : IIl2CppType { return T.Unbox(Il2CppObjectPool.Get(ReadPointer(span))); } - public static void WriteReference(T? value, Span span) where T : class, IIl2CppType + public static void WriteReference(T? value, Span span) where T : IIl2CppType { var objectPointer = value?.BoxNative() ?? ObjectPointer.Null; WritePointer((nint)objectPointer, span); diff --git a/Il2CppInterop.Generator/MarshallingProcessingLayer.cs b/Il2CppInterop.Generator/MarshallingProcessingLayer.cs index 5376bdc4..a0f9399c 100644 --- a/Il2CppInterop.Generator/MarshallingProcessingLayer.cs +++ b/Il2CppInterop.Generator/MarshallingProcessingLayer.cs @@ -25,8 +25,6 @@ public override void Process(ApplicationAnalysisContext appContext, Action.WriteToSpan)); var il2CppTypeHelper = appContext.ResolveTypeOrThrow(typeof(Il2CppType)); - var il2CppTypeHelper_ReadReference = il2CppTypeHelper.GetMethodByName(nameof(Il2CppType.ReadReference)); - var il2CppTypeHelper_WriteReference = il2CppTypeHelper.GetMethodByName(nameof(Il2CppType.WriteReference)); var il2CppTypeHelper_ReadFromSpanAtOffset = il2CppTypeHelper.GetMethodByName(nameof(Il2CppType.ReadFromSpanAtOffset)); var il2CppTypeHelper_WriteToSpanAtOffset = il2CppTypeHelper.GetMethodByName(nameof(Il2CppType.WriteToSpanAtOffset)); var il2CppTypeHelper_ReadFromSpanBlittable = il2CppTypeHelper.GetMethodByName(nameof(Il2CppType.ReadFromSpanBlittable)); @@ -34,14 +32,10 @@ public override void Process(ApplicationAnalysisContext appContext, Action m.Name == nameof(Il2CppType.GetClassPointer) && m.GenericParameters.Count == 1); - var intPtr_get_Size = appContext.SystemTypes.SystemIntPtrType.GetMethodByName($"get_{nameof(IntPtr.Size)}"); - var il2CppSystemIObject = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.IObject"); var il2CppSystemIValueType = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.IValueType"); var il2CppSystemIEnum = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.IEnum"); - var il2CppSystemValueType = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.ValueType"); - foreach (var assembly in appContext.Assemblies) { if (assembly.IsReferenceAssembly || assembly.IsInjected) @@ -127,7 +121,14 @@ public override void Process(ApplicationAnalysisContext appContext, Action.Size + if (instantiatedSizeStorage is null) { + // Reference types have a default implementation that returns IntPtr.Size, so we don't need to do anything. + Debug.Assert(!type.IsValueType); + } + else + { + Debug.Assert(type.IsValueType); var instantiated_iil2CppTypeGeneric_get_Size = new ConcreteGenericMethodAnalysisContext(iil2CppTypeGeneric_get_Size, [instantiatedType], []); var methodName = $"{instantiatedIl2CppTypeGeneric.FullName}.get_{nameof(IIl2CppType<>.Size)}"; var method = new InjectedMethodAnalysisContext( @@ -146,7 +147,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action !f.IsStatic); // ReadFromSpan + if (type.IsValueType) { var instantiated_iil2CppTypeGeneric_ReadFromSpan = new ConcreteGenericMethodAnalysisContext(iil2CppTypeGeneric_ReadFromSpan, [instantiatedType], []); var methodName = $"{instantiatedIl2CppTypeGeneric.FullName}.{nameof(IIl2CppType<>.ReadFromSpan)}"; @@ -304,19 +306,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action.WriteToSpan)}"; @@ -396,20 +387,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action Date: Mon, 11 May 2026 00:16:03 -0700 Subject: [PATCH 434/486] Make CI happy --- Il2Cppmscorlib/Type.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Il2Cppmscorlib/Type.cs b/Il2Cppmscorlib/Type.cs index 259d1e81..9871b690 100644 --- a/Il2Cppmscorlib/Type.cs +++ b/Il2Cppmscorlib/Type.cs @@ -58,4 +58,7 @@ public MethodInfo GetMethod(String name) public static Boolean operator ==(Type left, Type right) => throw null; public static Boolean operator !=(Type left, Type right) => throw null; + + public override bool Equals(object obj) => throw new System.NotImplementedException(); + public override int GetHashCode() => throw new System.NotImplementedException(); } From f3a26f9b2a15079dbeaaa71c69d3b87766322a4d Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Mon, 11 May 2026 10:15:19 -0700 Subject: [PATCH 435/486] Support primitives in user friendly overload generation --- Il2CppInterop.Generator/KnownTypeCode.cs | 111 +++++++++++++++++- .../UserFriendlyOverloadProcessingLayer.cs | 68 +++++++++-- 2 files changed, 169 insertions(+), 10 deletions(-) diff --git a/Il2CppInterop.Generator/KnownTypeCode.cs b/Il2CppInterop.Generator/KnownTypeCode.cs index 4402ec36..6845011f 100644 --- a/Il2CppInterop.Generator/KnownTypeCode.cs +++ b/Il2CppInterop.Generator/KnownTypeCode.cs @@ -1,4 +1,6 @@ -namespace Il2CppInterop.Generator; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; public enum KnownTypeCode { @@ -48,3 +50,110 @@ public enum KnownTypeCode Il2CppSystem_IValueType, Il2CppSystem_IEnum, } +internal static class KnownTypeCodeExtensions +{ + extension(KnownTypeCode code) + { + public bool IsSystemType => code >= KnownTypeCode.System_Object && code <= KnownTypeCode.System_Array; + + public bool IsIl2CppSystemType => code >= KnownTypeCode.Il2CppSystem_Object && code <= KnownTypeCode.Il2CppSystem_IEnum; + + /// + /// Boolean, Char, and all the numeric types + /// + public bool IsIl2CppPrimitiveType => code >= KnownTypeCode.Il2CppSystem_Boolean && code <= KnownTypeCode.Il2CppSystem_UIntPtr; + + public string Name => code switch + { + KnownTypeCode.None => "", + KnownTypeCode.System_Object or KnownTypeCode.Il2CppSystem_Object => "Object", + KnownTypeCode.System_ValueType or KnownTypeCode.Il2CppSystem_ValueType => "ValueType", + KnownTypeCode.System_Enum or KnownTypeCode.Il2CppSystem_Enum => "Enum", + KnownTypeCode.System_Attribute or KnownTypeCode.Il2CppSystem_Attribute => "Attribute", + KnownTypeCode.System_String or KnownTypeCode.Il2CppSystem_String => "String", + KnownTypeCode.System_Boolean or KnownTypeCode.Il2CppSystem_Boolean => "Boolean", + KnownTypeCode.System_Byte or KnownTypeCode.Il2CppSystem_Byte => "Byte", + KnownTypeCode.System_SByte or KnownTypeCode.Il2CppSystem_SByte => "SByte", + KnownTypeCode.System_Int16 or KnownTypeCode.Il2CppSystem_Int16 => "Int16", + KnownTypeCode.System_UInt16 or KnownTypeCode.Il2CppSystem_UInt16 => "UInt16", + KnownTypeCode.System_Int32 or KnownTypeCode.Il2CppSystem_Int32 => "Int32", + KnownTypeCode.System_UInt32 or KnownTypeCode.Il2CppSystem_UInt32 => "UInt32", + KnownTypeCode.System_Int64 or KnownTypeCode.Il2CppSystem_Int64 => "Int64", + KnownTypeCode.System_UInt64 or KnownTypeCode.Il2CppSystem_UInt64 => "UInt64", + KnownTypeCode.System_Single or KnownTypeCode.Il2CppSystem_Single => "Single", + KnownTypeCode.System_Double or KnownTypeCode.Il2CppSystem_Double => "Double", + KnownTypeCode.System_Char or KnownTypeCode.Il2CppSystem_Char => "Char", + KnownTypeCode.System_IntPtr or KnownTypeCode.Il2CppSystem_IntPtr => "IntPtr", + KnownTypeCode.System_UIntPtr or KnownTypeCode.Il2CppSystem_UIntPtr => "UIntPtr", + KnownTypeCode.System_Void or KnownTypeCode.Il2CppSystem_Void => "Void", + KnownTypeCode.System_Array => "Array", + KnownTypeCode.Il2CppSystem_IObject => "IObject", + KnownTypeCode.Il2CppSystem_IValueType => "IValueType", + KnownTypeCode.Il2CppSystem_IEnum => "IEnum", + _ => throw new InvalidOperationException($"Unknown KnownTypeCode: {code}") + }; + + public string Namespace + { + get + { + if (code.IsSystemType) + return "System"; + if (code.IsIl2CppSystemType) + return "Il2CppSystem"; + return ""; + } + } + + public string FullName + { + get + { + var @namespace = code.Namespace; + return string.IsNullOrEmpty(@namespace) ? code.Name : $"{@namespace}.{code.Name}"; + } + } + + public KnownTypeCode ToSystemType() => code switch + { + KnownTypeCode.Il2CppSystem_Object => KnownTypeCode.System_Object, + KnownTypeCode.Il2CppSystem_ValueType => KnownTypeCode.System_ValueType, + KnownTypeCode.Il2CppSystem_Enum => KnownTypeCode.System_Enum, + KnownTypeCode.Il2CppSystem_Attribute => KnownTypeCode.System_Attribute, + KnownTypeCode.Il2CppSystem_String => KnownTypeCode.System_String, + KnownTypeCode.Il2CppSystem_Boolean => KnownTypeCode.System_Boolean, + KnownTypeCode.Il2CppSystem_Byte => KnownTypeCode.System_Byte, + KnownTypeCode.Il2CppSystem_SByte => KnownTypeCode.System_SByte, + KnownTypeCode.Il2CppSystem_Int16 => KnownTypeCode.System_Int16, + KnownTypeCode.Il2CppSystem_UInt16 => KnownTypeCode.System_UInt16, + KnownTypeCode.Il2CppSystem_Int32 => KnownTypeCode.System_Int32, + KnownTypeCode.Il2CppSystem_UInt32 => KnownTypeCode.System_UInt32, + KnownTypeCode.Il2CppSystem_Int64 => KnownTypeCode.System_Int64, + KnownTypeCode.Il2CppSystem_UInt64 => KnownTypeCode.System_UInt64, + KnownTypeCode.Il2CppSystem_Single => KnownTypeCode.System_Single, + KnownTypeCode.Il2CppSystem_Double => KnownTypeCode.System_Double, + KnownTypeCode.Il2CppSystem_Char => KnownTypeCode.System_Char, + KnownTypeCode.Il2CppSystem_IntPtr => KnownTypeCode.System_IntPtr, + KnownTypeCode.Il2CppSystem_UIntPtr => KnownTypeCode.System_UIntPtr, + KnownTypeCode.Il2CppSystem_Void => KnownTypeCode.System_Void, + KnownTypeCode.Il2CppSystem_IObject => KnownTypeCode.System_Object, + KnownTypeCode.Il2CppSystem_IValueType => KnownTypeCode.System_ValueType, + KnownTypeCode.Il2CppSystem_IEnum => KnownTypeCode.System_Enum, + _ => code + }; + + public AssemblyAnalysisContext GetAssemblyContext(ApplicationAnalysisContext appContext) + { + if (code.IsSystemType) + return appContext.Mscorlib; + if (code.IsIl2CppSystemType) + return appContext.Il2CppMscorlib; + throw new InvalidOperationException($"KnownTypeCode {code} does not correspond to a known assembly"); + } + + public TypeAnalysisContext ToContext(ApplicationAnalysisContext appContext) + { + return code.GetAssemblyContext(appContext).GetTypeByFullNameOrThrow(code.FullName); + } + } +} diff --git a/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs b/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs index 1346354e..abf035f7 100644 --- a/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs +++ b/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs @@ -1,4 +1,5 @@ -using Cpp2IL.Core.Api; +using System.Runtime.CompilerServices; +using Cpp2IL.Core.Api; using Cpp2IL.Core.Model.Contexts; using Il2CppInterop.Generator.Operands; using Il2CppInterop.Generator.Visitors; @@ -20,6 +21,12 @@ public override void Process(ApplicationAnalysisContext appContext, Action m.Name == "op_Explicit" && m.ReturnType is SzArrayTypeAnalysisContext); var il2CppArrayBase_FromManagedArray = il2CppArrayBase.Methods.Single(m => m.Name == "op_Explicit" && m.Parameters.Count == 1 && m.Parameters[0].ParameterType is SzArrayTypeAnalysisContext); + var unsafeClass = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.Runtime.CompilerServices.Unsafe"); + var unsafeAsMethod = unsafeClass.Methods.Single(m => m.Name == nameof(Unsafe.As) && m.GenericParameters.Count == 2); + + var systemObject = appContext.SystemTypes.SystemObjectType; + var il2CppSystemIObject = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.IObject"); + foreach (var assembly in appContext.Assemblies) { if (assembly.IsReferenceAssembly || assembly.IsInjected) @@ -53,10 +60,11 @@ public override void Process(ApplicationAnalysisContext appContext, Action instructions = new(); + var instructionCount = (newMethod.IsStatic ? 0 : 1) + + newMethod.Parameters.Count + + conversionCount + + 2; + + List instructions = new(instructionCount); if (!newMethod.IsStatic) { - instructions.Add(new Instruction(CilOpCodes.Ldarg, This.Instance)); + instructions.Add(CilOpCodes.Ldarg_0); // Load "this" } for (var i = 0; i < newMethod.Parameters.Count; i++) { - instructions.Add(new Instruction(CilOpCodes.Ldarg, newMethod.Parameters[i])); + instructions.Add(CilOpCodes.Ldarg, newMethod.Parameters[i]); var conversionMethod = conversionMethods[i]; if (conversionMethod is not null) { - instructions.Add(new Instruction(CilOpCodes.Call, conversionMethod)); + instructions.Add(CilOpCodes.Call, conversionMethod); + } + else if (newMethod.Parameters[i].ParameterType == systemObject && method.Parameters[i].ParameterType == il2CppSystemIObject) + { + // Special case for Il2CppSystem.IObject to System.Object conversion, since there's no conversion method for this + instructions.Add(CilOpCodes.Isinst, il2CppSystemIObject); } } - instructions.Add(new Instruction(newMethod.IsStatic || type.IsValueType ? CilOpCodes.Call : CilOpCodes.Callvirt, method.MaybeMakeConcreteGeneric(type.GenericParameters, newMethod.GenericParameters))); + instructions.Add(newMethod.IsStatic || type.IsValueType ? CilOpCodes.Call : CilOpCodes.Callvirt, method.MaybeMakeConcreteGeneric(type.GenericParameters, newMethod.GenericParameters)); - instructions.Add(new Instruction(CilOpCodes.Ret)); + instructions.Add(CilOpCodes.Ret); newMethod.PutExtraData(new NativeMethodBody() { From 6f9c7dfd3d59b2a9f32415c783e6826bb67db45c Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 14 May 2026 21:07:31 -0700 Subject: [PATCH 436/486] Refactor: remove GetCurrentAppContext() helper Replaced all usages of GetCurrentAppContext() with direct access to Cpp2IlApi.CurrentAppContext, simplifying the code and removing an unnecessary wrapper method. Applied the null-forgiving operator where appropriate. --- Il2CppInterop.Generator/Il2CppGame.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Il2CppInterop.Generator/Il2CppGame.cs b/Il2CppInterop.Generator/Il2CppGame.cs index 8cd61519..e3a50fe7 100644 --- a/Il2CppInterop.Generator/Il2CppGame.cs +++ b/Il2CppInterop.Generator/Il2CppGame.cs @@ -2,7 +2,6 @@ using Cpp2IL.Core.Api; using Cpp2IL.Core.InstructionSets; using Cpp2IL.Core.Logging; -using Cpp2IL.Core.Model.Contexts; using Cpp2IL.Plugin.StrippedCodeRegSupport; using LibCpp2IL; @@ -32,7 +31,7 @@ public static void Process(string gameExePath, string outputFolder, Cpp2IlOutput { Process(gameExePath, processingLayers, extraData); - outputFormat.DoOutput(GetCurrentAppContext(), outputFolder); + outputFormat.DoOutput(Cpp2IlApi.CurrentAppContext!, outputFolder); } public static void Process(string gameExePath, List processingLayers, KeyValuePair[] extraData) @@ -58,12 +57,12 @@ public static void Process(string gameExePath, List proce foreach (var cpp2IlProcessingLayer in processingLayers) { - cpp2IlProcessingLayer.PreProcess(GetCurrentAppContext(), processingLayers); + cpp2IlProcessingLayer.PreProcess(Cpp2IlApi.CurrentAppContext, processingLayers); } foreach (var cpp2IlProcessingLayer in processingLayers) { - cpp2IlProcessingLayer.Process(GetCurrentAppContext()); + cpp2IlProcessingLayer.Process(Cpp2IlApi.CurrentAppContext); } } @@ -77,9 +76,4 @@ private static string GetGameAssemblyPath(string gameDirectory) } throw new FileNotFoundException("Could not find GameAssembly binary in game directory."); } - - private static ApplicationAnalysisContext GetCurrentAppContext() - { - return Cpp2IlApi.CurrentAppContext ?? throw new NullReferenceException(); - } } From 3f06452edf7fe5696b7eaedf851b3bb542784340 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 14 May 2026 21:10:16 -0700 Subject: [PATCH 437/486] Fix bug in delegate conversion processing layer --- .../DelegateConversionProcessingLayer.cs | 33 ++++++++++++------- .../TypeAnalysisContextExtensions.cs | 2 ++ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs index 1b96ad77..75ff3c8c 100644 --- a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs +++ b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs @@ -37,7 +37,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action parameterTypes = invokeMethod.Parameters.Select(p => p.ParameterType).ToList(); { var genericParameterDictionary = Enumerable.Range(0, type.GenericParameters.Count) - .ToDictionary(i => type.GenericParameters[i], i => managedDelegateType.GenericParameters[i]); + .ToDictionary(i => type.GenericParameters[i], i => injectedType.GenericParameters[i]); var replacementVisitor = new TypeReplacementVisitor(genericParameterDictionary); replacementVisitor.Modify(parameterTypes); returnType = replacementVisitor.Replace(invokeMethod.ReturnType); @@ -155,8 +155,8 @@ public override void Process(ApplicationAnalysisContext appContext, Action 0) + { + managedDelegateType = injectedType.MakeGenericInstanceType(type.GenericParameters); + } + else + { + managedDelegateType = injectedType; + } } var concreteType = type.HasGenericParameters ? type.MakeGenericInstanceType(type.GenericParameters) : type; diff --git a/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs b/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs index 9b81c6d2..16744fe7 100644 --- a/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs +++ b/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs @@ -43,6 +43,8 @@ public bool IsIl2CppPrimitive } } + public bool IsIl2CppDelegate => type.BaseType is { Namespace: "Il2CppSystem", Name: "MulticastDelegate" }; + /// /// The fields, methods, properties, and events of this type. /// From fee79c25fd88bdf81e43a07cd39ed532adaa910d Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 16 May 2026 11:34:56 -0700 Subject: [PATCH 438/486] Ensure delegate types always have addition and subtraction operators --- .../DelegateConversionProcessingLayer.cs | 90 ++++++++++--------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs index 75ff3c8c..ed6d6e73 100644 --- a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs +++ b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs @@ -1,4 +1,5 @@ -using System.Reflection; +using System.Diagnostics; +using System.Reflection; using Cpp2IL.Core.Api; using Cpp2IL.Core.Model.Contexts; using Il2CppInterop.Generator.Operands; @@ -61,6 +62,46 @@ public override void Process(ApplicationAnalysisContext appContext, Action(new() + { + Instructions = + [ + new Instruction(CilOpCodes.Ldarg_0), + new Instruction(CilOpCodes.Ldarg_1), + new Instruction(CilOpCodes.Call, il2CppSystemDelegateCombine), + new Instruction(CilOpCodes.Castclass, concreteType), + new Instruction(CilOpCodes.Ret), + ] + }); + + var subtraction = new InjectedMethodAnalysisContext( + type, + "op_Subtraction", + concreteType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, + [concreteType, concreteType]); + type.Methods.Add(subtraction); + subtraction.PutExtraData(new() + { + Instructions = + [ + new Instruction(CilOpCodes.Ldarg_0), + new Instruction(CilOpCodes.Ldarg_1), + new Instruction(CilOpCodes.Call, il2CppSystemDelegateRemove), + new Instruction(CilOpCodes.Castclass, concreteType), + new Instruction(CilOpCodes.Ret), + ] + }); + var invokeMethod = type.TryGetMethodByName("Invoke"); if (invokeMethod is null) { @@ -69,11 +110,12 @@ public override void Process(ApplicationAnalysisContext appContext, Action p.ParameterType is not PointerTypeAnalysisContext and not ByRefTypeAnalysisContext), "All pointers and by reference types should be converted to generics"); + TypeAnalysisContext managedDelegateType; - if (invokeMethod.Parameters.Count <= 16 - && invokeMethod.ReturnType is not PointerTypeAnalysisContext and not ByRefTypeAnalysisContext - && invokeMethod.Parameters.All(p => p.ParameterType is not PointerTypeAnalysisContext and not ByRefTypeAnalysisContext)) + if (invokeMethod.Parameters.Count <= 16) { // We can use a System delegate @@ -207,7 +249,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action(new() - { - Instructions = - [ - new Instruction(CilOpCodes.Ldarg_0), - new Instruction(CilOpCodes.Ldarg_1), - new Instruction(CilOpCodes.Call, il2CppSystemDelegateCombine), - new Instruction(CilOpCodes.Castclass, concreteType), - new Instruction(CilOpCodes.Ret), - ] - }); - - var subtraction = new InjectedMethodAnalysisContext( - type, - "op_Subtraction", - concreteType, - MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, - [concreteType, concreteType]); - type.Methods.Add(subtraction); - subtraction.PutExtraData(new() - { - Instructions = - [ - new Instruction(CilOpCodes.Ldarg_0), - new Instruction(CilOpCodes.Ldarg_1), - new Instruction(CilOpCodes.Call, il2CppSystemDelegateRemove), - new Instruction(CilOpCodes.Castclass, concreteType), - new Instruction(CilOpCodes.Ret), - ] - }); } } } From c844bc7ad66c88c48d50a79bcf6005ccd586dcd5 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 16 May 2026 12:40:22 -0700 Subject: [PATCH 439/486] Only use Cpp2IL logger in generator --- Il2CppInterop.Generator/AttributeRemovalProcessingLayer.cs | 1 - Il2CppInterop.Generator/Il2CppGame.cs | 1 - Il2CppInterop.Generator/Il2CppRenamingProcessingLayer.cs | 1 - Il2CppInterop.Generator/InitializationClassProcessingLayer.cs | 3 +-- .../MethodBodyTranslationProcessingLayer.cs | 1 - .../MscorlibAssemblyInjectionProcessingLayer.cs | 1 - Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs | 1 - Il2CppInterop.Generator/UnstripProcessingLayer.cs | 1 - Il2CppInterop.Generator/Usings.cs | 1 + Il2CppInterop.Generator/Visitors/TypeReplacementVisitor.cs | 1 - 10 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Il2CppInterop.Generator/AttributeRemovalProcessingLayer.cs b/Il2CppInterop.Generator/AttributeRemovalProcessingLayer.cs index e9de3683..1ce4806c 100644 --- a/Il2CppInterop.Generator/AttributeRemovalProcessingLayer.cs +++ b/Il2CppInterop.Generator/AttributeRemovalProcessingLayer.cs @@ -1,5 +1,4 @@ using Cpp2IL.Core.Api; -using Cpp2IL.Core.Logging; using Cpp2IL.Core.Model.Contexts; using Cpp2IL.Core.Model.CustomAttributes; diff --git a/Il2CppInterop.Generator/Il2CppGame.cs b/Il2CppInterop.Generator/Il2CppGame.cs index e3a50fe7..f35ec5f3 100644 --- a/Il2CppInterop.Generator/Il2CppGame.cs +++ b/Il2CppInterop.Generator/Il2CppGame.cs @@ -1,7 +1,6 @@ using Cpp2IL.Core; using Cpp2IL.Core.Api; using Cpp2IL.Core.InstructionSets; -using Cpp2IL.Core.Logging; using Cpp2IL.Plugin.StrippedCodeRegSupport; using LibCpp2IL; diff --git a/Il2CppInterop.Generator/Il2CppRenamingProcessingLayer.cs b/Il2CppInterop.Generator/Il2CppRenamingProcessingLayer.cs index ca808274..acc74063 100644 --- a/Il2CppInterop.Generator/Il2CppRenamingProcessingLayer.cs +++ b/Il2CppInterop.Generator/Il2CppRenamingProcessingLayer.cs @@ -1,6 +1,5 @@ using System.Runtime.CompilerServices; using Cpp2IL.Core.Api; -using Cpp2IL.Core.Logging; using Cpp2IL.Core.Model.Contexts; namespace Il2CppInterop.Generator; diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index 2b112ec7..f89c19ed 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -15,7 +15,6 @@ using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; -using Microsoft.Extensions.Logging; namespace Il2CppInterop.Generator; @@ -451,7 +450,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action Date: Sat, 16 May 2026 21:32:54 -0700 Subject: [PATCH 440/486] Support generating overloads for "virtual" methods --- .../ByRefParameterOverloadProcessingLayer.cs | 14 +++++++------- .../TypeAnalysisContextExtensions.cs | 2 +- .../UserFriendlyOverloadProcessingLayer.cs | 18 ++++++++++-------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Il2CppInterop.Generator/ByRefParameterOverloadProcessingLayer.cs b/Il2CppInterop.Generator/ByRefParameterOverloadProcessingLayer.cs index 39737541..92f15bda 100644 --- a/Il2CppInterop.Generator/ByRefParameterOverloadProcessingLayer.cs +++ b/Il2CppInterop.Generator/ByRefParameterOverloadProcessingLayer.cs @@ -34,22 +34,22 @@ public override void Process(ApplicationAnalysisContext appContext, Action p.DefaultParameterType is ByRefTypeAnalysisContext)) continue; - var newMethod = new InjectedMethodAnalysisContext(type, method.Name, appContext.SystemTypes.SystemVoidType, method.Attributes, []) + const MethodAttributes AttributesToRemove = MethodAttributes.Virtual | MethodAttributes.Abstract | MethodAttributes.Final | MethodAttributes.NewSlot; + var newMethod = new InjectedMethodAnalysisContext(type, method.Name, appContext.SystemTypes.SystemVoidType, method.Attributes & ~AttributesToRemove, []) { IsInjected = true, }; diff --git a/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs b/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs index 16744fe7..58f62399 100644 --- a/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs +++ b/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs @@ -43,7 +43,7 @@ public bool IsIl2CppPrimitive } } - public bool IsIl2CppDelegate => type.BaseType is { Namespace: "Il2CppSystem", Name: "MulticastDelegate" }; + public bool IsIl2CppDelegate => type is { BaseType: { Namespace: "Il2CppSystem", Name: "MulticastDelegate" } } or GenericInstanceTypeAnalysisContext { GenericType.BaseType: { Namespace: "Il2CppSystem", Name: "MulticastDelegate" } }; /// /// The fields, methods, properties, and events of this type. diff --git a/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs b/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs index abf035f7..3e038cbd 100644 --- a/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs +++ b/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs @@ -1,4 +1,5 @@ -using System.Runtime.CompilerServices; +using System.Reflection; +using System.Runtime.CompilerServices; using Cpp2IL.Core.Api; using Cpp2IL.Core.Model.Contexts; using Il2CppInterop.Generator.Operands; @@ -36,17 +37,16 @@ public override void Process(ApplicationAnalysisContext appContext, Action Date: Sat, 16 May 2026 21:35:22 -0700 Subject: [PATCH 441/486] Convert Il2Cpp delegates in user friendly overloads --- Il2CppInterop.CLI/Program.cs | 4 ++- .../UserFriendlyOverloadProcessingLayer.cs | 29 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Il2CppInterop.CLI/Program.cs b/Il2CppInterop.CLI/Program.cs index b1b9f3b2..4fc31227 100644 --- a/Il2CppInterop.CLI/Program.cs +++ b/Il2CppInterop.CLI/Program.cs @@ -61,6 +61,8 @@ /* Todo - System interfaces -- overloads with delegates, primitives - Add attributes to "Unsafe" methods so that users cannot see them +- Lazily create field offset accessors +- Reduce number of implementation methods +- Make generic inflation more robust */ diff --git a/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs b/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs index 3e038cbd..ff19d422 100644 --- a/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs +++ b/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs @@ -57,7 +57,12 @@ public override void Process(ApplicationAnalysisContext appContext, Action m.Name == "op_Explicit"); + } // Convert ref Il2CppSystem.Int32 to ref int if (p.ParameterType is ByRefTypeAnalysisContext { ElementType.KnownType.IsIl2CppPrimitiveType: true }) @@ -112,6 +117,28 @@ public override void Process(ApplicationAnalysisContext appContext, Action m.Name == "op_Explicit") + ?.MakeConcreteGeneric(genericInstance.GenericArguments, []); + } + else + { + explicitConversionMethod = parameter.ParameterType.Methods.SingleOrDefault(m => m.Name == "op_Explicit"); + } + if (explicitConversionMethod is not null) + { + parameterTypes[i] = explicitConversionMethod.Parameters[0].ParameterType; + conversionMethods[i] = explicitConversionMethod; + conversionCount++; + continue; + } + } + // Convert Il2Cpp primitive to System primitive { var knownType = parameter.ParameterType.KnownType; From 2f3e75eec2fcee4d56d30cbc9bfc169c27da766e Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 16 May 2026 23:32:38 -0700 Subject: [PATCH 442/486] Initial system interface implementation --- .../SystemInterfaceProcessingLayer.cs | 161 +++++++++++++++++- .../Visitors/TypeReplacementVisitor.cs | 12 +- 2 files changed, 169 insertions(+), 4 deletions(-) diff --git a/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs b/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs index 65e7c217..2cca0755 100644 --- a/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs +++ b/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs @@ -1,5 +1,8 @@ -using Cpp2IL.Core.Api; +using System.Reflection; +using Cpp2IL.Core.Api; using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; +using Il2CppInterop.Generator.Visitors; namespace Il2CppInterop.Generator; @@ -9,6 +12,160 @@ public sealed class SystemInterfaceProcessingLayer : Cpp2IlProcessingLayer public override string Id => "system_interface_implementations"; public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { - // Should handle INotifyCompletion, IEnumerable, IEquatable, etc + // Needs to handle: + // IDisposable + // IEnumerator and IEnumerator + // IEnumerable and IEnumerable + // INotifyCompletion and ICriticalNotifyCompletion + // IEquatable + // IComparable and IComparable + // IReadOnlyCollection and IReadOnlyList + // IReadOnlySet + // IReadOnlyDictionary + // IEqualityComparer + // IComparer and IComparer + + var pairs = FindPairs(appContext); + + foreach (var (il2CppInterface, systemInterface) in pairs) + { + ImplementInterface(il2CppInterface, systemInterface); + } + } + + private static List<(TypeAnalysisContext, TypeAnalysisContext)> FindPairs(ApplicationAnalysisContext appContext) + { + List<(TypeAnalysisContext, TypeAnalysisContext)> pairs = []; + foreach (var type in appContext.Il2CppMscorlib.Types) + { + if (type.IsInterface) + { + var systemType = appContext.Mscorlib.GetTypeByFullName(type.DefaultFullName); + if (systemType != null && IsPublic(systemType)) + { + pairs.Add((type, systemType)); + } + } + } + + return pairs; + + static bool IsPublic(TypeAnalysisContext? type) + { + var current = type; + while (current is not null) + { + if (current.Visibility is not TypeAttributes.Public and not TypeAttributes.NestedPublic) + { + return false; + } + current = current.DeclaringType; + } + return true; + } + } + + private static void ImplementInterface(TypeAnalysisContext il2CppInterface, TypeAnalysisContext systemInterface) + { + il2CppInterface.InterfaceContexts.Add(systemInterface); + + foreach (var systemMethod in systemInterface.Methods) + { + if (systemMethod.IsStatic) + { + continue; + } + + var attributes = (systemMethod.Attributes & ~(MethodAttributes.Abstract | MethodAttributes.MemberAccessMask)) | MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.NewSlot; + var injectedMethod = new InjectedMethodAnalysisContext(il2CppInterface, $"{systemInterface.FullName}.{systemMethod.Name}", systemMethod.ReturnType, attributes, []) + { + IsInjected = true, + }; + injectedMethod.Overrides.Add(systemMethod); + il2CppInterface.Methods.Add(injectedMethod); + + injectedMethod.CopyGenericParameters(systemMethod, true); + + var visitor = TypeReplacementVisitor.CreateForMethodCopying(systemMethod, injectedMethod); + + injectedMethod.SetDefaultReturnType(visitor.Replace(systemMethod.ReturnType)); + + foreach (var parameter in systemMethod.Parameters) + { + injectedMethod.Parameters.Add(new InjectedParameterAnalysisContext(parameter.Name, visitor.Replace(parameter.ParameterType), parameter.Attributes, parameter.ParameterIndex, injectedMethod)); + } + + var il2CppMethod = FindIl2CppMethod(il2CppInterface, systemMethod); + + if (il2CppMethod is null) + { + injectedMethod.PutExtraData(new NativeMethodBody() + { + Instructions = + [ + new Instruction(CilOpCodes.Ldnull), + new Instruction(CilOpCodes.Throw), + ] + }); + continue; + } + + List instructions = []; + instructions.Add(CilOpCodes.Ldarg_0); + foreach (var parameter in injectedMethod.Parameters) + { + instructions.Add(CilOpCodes.Ldarg, parameter); + // Todo: parameter value conversion + } + instructions.Add(CilOpCodes.Call, il2CppMethod); + // Todo: return value conversion + instructions.Add(CilOpCodes.Ret); + + injectedMethod.PutExtraData(new NativeMethodBody() + { + Instructions = instructions + }); + } + } + + private static MethodAnalysisContext? FindIl2CppMethod(TypeAnalysisContext il2CppInterface, MethodAnalysisContext systemMethod) + { + foreach (var il2CppMethod in il2CppInterface.Methods) + { + if (il2CppMethod.Name == systemMethod.Name && !il2CppMethod.IsStatic && il2CppMethod.Parameters.Count == systemMethod.Parameters.Count && il2CppMethod.GenericParameters.Count == systemMethod.GenericParameters.Count) + { + if (!AreTypesEqual(il2CppMethod.ReturnType, systemMethod.ReturnType)) + { + continue; + } + + var parametersMatch = true; + for (var i = 0; i < il2CppMethod.Parameters.Count; i++) + { + var il2CppParameterType = il2CppMethod.Parameters[i].ParameterType; + var systemParameterType = systemMethod.Parameters[i].ParameterType; + if (!AreTypesEqual(il2CppParameterType, systemParameterType)) + { + parametersMatch = false; + break; + } + } + if (parametersMatch) + { + return il2CppMethod; + } + } + } + return null; + + static bool AreTypesEqual(TypeAnalysisContext a, TypeAnalysisContext b) + { + if (a is GenericParameterTypeAnalysisContext aGeneric && b is GenericParameterTypeAnalysisContext bGeneric) + { + // For generic parameters, we consider them equal if they are in the same position + return aGeneric.Type == bGeneric.Type && aGeneric.Index == bGeneric.Index; + } + return TypeAnalysisContextEqualityComparer.Instance.Equals(a, b); + } } } diff --git a/Il2CppInterop.Generator/Visitors/TypeReplacementVisitor.cs b/Il2CppInterop.Generator/Visitors/TypeReplacementVisitor.cs index 74f65ec3..dc16bb67 100644 --- a/Il2CppInterop.Generator/Visitors/TypeReplacementVisitor.cs +++ b/Il2CppInterop.Generator/Visitors/TypeReplacementVisitor.cs @@ -13,8 +13,9 @@ internal class TypeReplacementVisitor(Dictionary(source.GenericParameters.Count); @@ -22,6 +23,13 @@ public static TypeReplacementVisitor CreateForMethodCopying(MethodAnalysisContex { replacements.Add(source.GenericParameters[i], destination.GenericParameters[i]); } + if (source.DeclaringType != destination.DeclaringType) + { + for (var i = source.DeclaringType.GenericParameters.Count - 1; i >= 0; i--) + { + replacements.Add(source.DeclaringType.GenericParameters[i], destination.DeclaringType.GenericParameters[i]); + } + } return new TypeReplacementVisitor(replacements); } From 589ff0dbcb073073a3bae6563f458dc8d703c1ae Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 16 May 2026 23:40:55 -0700 Subject: [PATCH 443/486] Refactor logging and processing layer setup Move Cpp2IL.Core logging setup from Il2CppGame to Program.cs. Extract default processing layers into Il2CppGame.GetDefaultProcessingLayers() and update Program.cs to use this method. Il2CppGame static constructor now only handles instruction set registration. --- Il2CppInterop.CLI/Program.cs | 51 +++++---------------------- Il2CppInterop.Generator/Il2CppGame.cs | 50 +++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/Il2CppInterop.CLI/Program.cs b/Il2CppInterop.CLI/Program.cs index 4fc31227..8c1bf87b 100644 --- a/Il2CppInterop.CLI/Program.cs +++ b/Il2CppInterop.CLI/Program.cs @@ -1,4 +1,4 @@ -using Cpp2IL.Core.ProcessingLayers; +using Cpp2IL.Core.Logging; using Il2CppInterop.Generator; string gameExePath = args[0]; @@ -8,53 +8,18 @@ // Unstrip directory needs to contain all files recursively contained in these directories: // \Editor\Data\MonoBleedingEdge\lib\mono\unityaot-win32 // \Editor\Data\PlaybackEngines\windowsstandalonesupport\Variations\win64_player_nondevelopment_il2cpp\Data\Managed +// For other platforms, the paths will be slightly different. + +Logger.InfoLog += Console.WriteLine; +Logger.WarningLog += Console.WriteLine; +Logger.ErrorLog += Console.WriteLine; +Logger.VerboseLog += Console.WriteLine; Il2CppGame.Process( gameExePath, outputFolder, new AsmResolverDllOutputFormatBinding(), - [ - new AttributeAnalysisProcessingLayer(), // Needed for recovery of unmanaged constraints - //new StableRenamingProcessingLayer(), - new UnstripProcessingLayer(), // Can be disabled for performance during development - new InterfaceOverrideProcessingLayer(), - new InvalidFieldRemovalProcessingLayer(), - new Il2CppRenamingProcessingLayer(), - new CleanRenamingProcessingLayer(), - new ConflictRenamingProcessingLayer(), - new AttributesOverrideProcessingLayer(), - new PublicizerProcessingLayer(), - new MscorlibAssemblyInjectionProcessingLayer(), - new KnownTypeAssignmentProcessingLayer(), - new ReferenceAssemblyInjectionProcessingLayer(), - new InvisibleInterfaceProcessingLayer(), - new ObjectInterfaceProcessingLayer(), - new ReferenceReplacementProcessingLayer(), - new AttributeRemovalProcessingLayer(), - new IndexerAttributeInjectionProcessingLayer(), - new PointerConstructorProcessingLayer(), - new Il2CppTypeConstraintProcessingLayer(), - new InitializationClassProcessingLayer(), - new MarshallingProcessingLayer(), - new BoxingProcessingLayer(), - new PrimitiveImplicitConversionProcessingLayer(), - new EnumProcessingLayer(), - new ObjectOverridesProcessingLayer(), - new ObjectInternalsProcessingLayer(), - new MemberAttributeProcessingLayer(), - new FieldAccessorProcessingLayer(), - new EventProcessingLayer(), - new ExceptionHierarchyProcessingLayer(), - new MethodInvokerProcessingLayer(), - new MethodBodyTranslationProcessingLayer(), - new NativeMethodBodyProcessingLayer(), - new DelegateConversionProcessingLayer(), - new ByRefParameterOverloadProcessingLayer(), - new UserFriendlyOverloadProcessingLayer(), - new SystemInterfaceProcessingLayer(), - new ConstantInitializationProcessingLayer(), - new StaticConstructorProcessingLayer(), - ], + Il2CppGame.GetDefaultProcessingLayers(), [new(UnstripBaseProcessingLayer.DirectoryKey, unstripDirectory)]); Console.WriteLine("Done!"); diff --git a/Il2CppInterop.Generator/Il2CppGame.cs b/Il2CppInterop.Generator/Il2CppGame.cs index f35ec5f3..96b0e4fb 100644 --- a/Il2CppInterop.Generator/Il2CppGame.cs +++ b/Il2CppInterop.Generator/Il2CppGame.cs @@ -1,6 +1,7 @@ using Cpp2IL.Core; using Cpp2IL.Core.Api; using Cpp2IL.Core.InstructionSets; +using Cpp2IL.Core.ProcessingLayers; using Cpp2IL.Plugin.StrippedCodeRegSupport; using LibCpp2IL; @@ -10,11 +11,6 @@ public static class Il2CppGame { static Il2CppGame() { - Logger.InfoLog += Console.WriteLine; - Logger.WarningLog += Console.WriteLine; - Logger.ErrorLog += Console.WriteLine; - Logger.VerboseLog += Console.WriteLine; - InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.X86_32); InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.X86_64); InstructionSetRegistry.RegisterInstructionSet(DefaultInstructionSets.WASM); @@ -75,4 +71,48 @@ private static string GetGameAssemblyPath(string gameDirectory) } throw new FileNotFoundException("Could not find GameAssembly binary in game directory."); } + + public static List GetDefaultProcessingLayers() => + [ + new AttributeAnalysisProcessingLayer(), // Needed for recovery of unmanaged constraints + //new StableRenamingProcessingLayer(), + new UnstripProcessingLayer(), // Can be disabled for performance during development + new InterfaceOverrideProcessingLayer(), + new InvalidFieldRemovalProcessingLayer(), + new Il2CppRenamingProcessingLayer(), + new CleanRenamingProcessingLayer(), + new ConflictRenamingProcessingLayer(), + new AttributesOverrideProcessingLayer(), + new PublicizerProcessingLayer(), + new MscorlibAssemblyInjectionProcessingLayer(), + new KnownTypeAssignmentProcessingLayer(), + new ReferenceAssemblyInjectionProcessingLayer(), + new InvisibleInterfaceProcessingLayer(), + new ObjectInterfaceProcessingLayer(), + new ReferenceReplacementProcessingLayer(), + new AttributeRemovalProcessingLayer(), + new IndexerAttributeInjectionProcessingLayer(), + new PointerConstructorProcessingLayer(), + new Il2CppTypeConstraintProcessingLayer(), + new InitializationClassProcessingLayer(), + new MarshallingProcessingLayer(), + new BoxingProcessingLayer(), + new PrimitiveImplicitConversionProcessingLayer(), + new EnumProcessingLayer(), + new ObjectOverridesProcessingLayer(), + new ObjectInternalsProcessingLayer(), + new MemberAttributeProcessingLayer(), + new FieldAccessorProcessingLayer(), + new EventProcessingLayer(), + new ExceptionHierarchyProcessingLayer(), + new MethodInvokerProcessingLayer(), + new MethodBodyTranslationProcessingLayer(), + new NativeMethodBodyProcessingLayer(), + new DelegateConversionProcessingLayer(), + new ByRefParameterOverloadProcessingLayer(), + new UserFriendlyOverloadProcessingLayer(), + new SystemInterfaceProcessingLayer(), + new ConstantInitializationProcessingLayer(), + new StaticConstructorProcessingLayer(), + ]; } From 4412acb126e2aa2610ac68ba56f757485bed7c92 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 00:16:14 -0700 Subject: [PATCH 444/486] Fix NuGet issues related to Il2Cppmscorlib --- Il2CppInterop.Generator/Il2CppInterop.Generator.csproj | 1 + Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj | 2 +- .../Il2CppInterop.SourceGenerator.Tests.csproj | 1 + Il2Cppmscorlib/Il2Cppmscorlib.csproj | 2 ++ 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index 1b47be71..f0356bad 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -24,5 +24,6 @@ + diff --git a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj index 07f28972..711622c0 100644 --- a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj +++ b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj @@ -22,8 +22,8 @@ - + diff --git a/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj b/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj index 8803fde3..82d552ea 100644 --- a/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj +++ b/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj @@ -24,6 +24,7 @@ + diff --git a/Il2Cppmscorlib/Il2Cppmscorlib.csproj b/Il2Cppmscorlib/Il2Cppmscorlib.csproj index 68233a2b..56b8e1b3 100644 --- a/Il2Cppmscorlib/Il2Cppmscorlib.csproj +++ b/Il2Cppmscorlib/Il2Cppmscorlib.csproj @@ -5,6 +5,8 @@ Il2CppSystem disable disable + false + 0.0.0 From d391a635aa346442cbbd8b80a03a637d92cbf922 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 14:23:47 -0700 Subject: [PATCH 445/486] Make system interfaces more complete and fix some bugs --- Il2CppInterop.CLI/Program.cs | 1 - .../Conversions/CastClassConversion.cs | 12 ++ .../Conversions/Conversion.cs | 8 ++ .../Conversions/IsInstanceConversion.cs | 12 ++ .../Conversions/MethodCallConversion.cs | 12 ++ .../Conversions/NullConversion.cs | 16 +++ .../TypeAnalysisContextExtensions.cs | 54 +++++++- .../SystemInterfaceProcessingLayer.cs | 118 +++++++++++++----- 8 files changed, 193 insertions(+), 40 deletions(-) create mode 100644 Il2CppInterop.Generator/Conversions/CastClassConversion.cs create mode 100644 Il2CppInterop.Generator/Conversions/Conversion.cs create mode 100644 Il2CppInterop.Generator/Conversions/IsInstanceConversion.cs create mode 100644 Il2CppInterop.Generator/Conversions/MethodCallConversion.cs create mode 100644 Il2CppInterop.Generator/Conversions/NullConversion.cs diff --git a/Il2CppInterop.CLI/Program.cs b/Il2CppInterop.CLI/Program.cs index 8c1bf87b..06045404 100644 --- a/Il2CppInterop.CLI/Program.cs +++ b/Il2CppInterop.CLI/Program.cs @@ -25,7 +25,6 @@ /* Todo -- System interfaces - Add attributes to "Unsafe" methods so that users cannot see them - Lazily create field offset accessors - Reduce number of implementation methods diff --git a/Il2CppInterop.Generator/Conversions/CastClassConversion.cs b/Il2CppInterop.Generator/Conversions/CastClassConversion.cs new file mode 100644 index 00000000..34b129cc --- /dev/null +++ b/Il2CppInterop.Generator/Conversions/CastClassConversion.cs @@ -0,0 +1,12 @@ +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator.Conversions; + +internal sealed class CastClassConversion(TypeAnalysisContext targetType) : Conversion +{ + public override void Add(List instructions) + { + instructions.Add(CilOpCodes.Castclass, targetType); + } +} diff --git a/Il2CppInterop.Generator/Conversions/Conversion.cs b/Il2CppInterop.Generator/Conversions/Conversion.cs new file mode 100644 index 00000000..8dc5dc59 --- /dev/null +++ b/Il2CppInterop.Generator/Conversions/Conversion.cs @@ -0,0 +1,8 @@ +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator.Conversions; + +internal abstract class Conversion +{ + public abstract void Add(List instructions); +} diff --git a/Il2CppInterop.Generator/Conversions/IsInstanceConversion.cs b/Il2CppInterop.Generator/Conversions/IsInstanceConversion.cs new file mode 100644 index 00000000..ba6be280 --- /dev/null +++ b/Il2CppInterop.Generator/Conversions/IsInstanceConversion.cs @@ -0,0 +1,12 @@ +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator.Conversions; + +internal sealed class IsInstanceConversion(TypeAnalysisContext targetType) : Conversion +{ + public override void Add(List instructions) + { + instructions.Add(CilOpCodes.Isinst, targetType); + } +} diff --git a/Il2CppInterop.Generator/Conversions/MethodCallConversion.cs b/Il2CppInterop.Generator/Conversions/MethodCallConversion.cs new file mode 100644 index 00000000..982413ad --- /dev/null +++ b/Il2CppInterop.Generator/Conversions/MethodCallConversion.cs @@ -0,0 +1,12 @@ +using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator.Conversions; + +internal sealed class MethodCallConversion(MethodAnalysisContext method) : Conversion +{ + public override void Add(List instructions) + { + instructions.Add(CilOpCodes.Call, method); + } +} diff --git a/Il2CppInterop.Generator/Conversions/NullConversion.cs b/Il2CppInterop.Generator/Conversions/NullConversion.cs new file mode 100644 index 00000000..e7839ee2 --- /dev/null +++ b/Il2CppInterop.Generator/Conversions/NullConversion.cs @@ -0,0 +1,16 @@ +using Il2CppInterop.Generator.Operands; + +namespace Il2CppInterop.Generator.Conversions; + +internal sealed class NullConversion : Conversion +{ + public static NullConversion Instance = new(); + + private NullConversion() + { + } + + public override void Add(List instructions) + { + } +} diff --git a/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs b/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs index 58f62399..5efc4249 100644 --- a/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs +++ b/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs @@ -234,22 +234,64 @@ public bool TryGetMethodInSlot(int slot, [NotNullWhen(true)] out MethodAnalysisC public MethodAnalysisContext GetImplicitConversionFrom(TypeAnalysisContext sourceType) { - return GetConversion("op_Implicit", type, sourceType, type.SelfInstantiateIfGeneric()); + return type.TryGetImplicitConversionFrom(sourceType, out var method) + ? method + : throw new Exception($"No implicit conversion from {sourceType.Name} to {type.Name} found."); } public MethodAnalysisContext GetImplicitConversionTo(TypeAnalysisContext targetType) { - return GetConversion("op_Implicit", type, type.SelfInstantiateIfGeneric(), targetType); + return type.TryGetImplicitConversionTo(targetType, out var method) + ? method + : throw new Exception($"No implicit conversion from {type.Name} to {targetType.Name} found."); } public MethodAnalysisContext GetExplicitConversionFrom(TypeAnalysisContext sourceType) { - return GetConversion("op_Explicit", type, sourceType, type.SelfInstantiateIfGeneric()); + return type.TryGetExplicitConversionFrom(sourceType, out var method) + ? method + : throw new Exception($"No explicit conversion from {sourceType.Name} to {type.Name} found."); } public MethodAnalysisContext GetExplicitConversionTo(TypeAnalysisContext targetType) { - return GetConversion("op_Explicit", type, type.SelfInstantiateIfGeneric(), targetType); + return type.TryGetExplicitConversionTo(targetType, out var method) + ? method + : throw new Exception($"No explicit conversion from {type.Name} to {targetType.Name} found."); + } + + public bool TryGetImplicitConversionFrom(TypeAnalysisContext sourceType, [NotNullWhen(true)] out MethodAnalysisContext? method) + { + method = GetConversion("op_Implicit", type, sourceType, type.SelfInstantiateIfGeneric()); + return method is not null; + } + + public bool TryGetImplicitConversionTo(TypeAnalysisContext targetType, [NotNullWhen(true)] out MethodAnalysisContext? method) + { + method = GetConversion("op_Implicit", type, type.SelfInstantiateIfGeneric(), targetType); + return method is not null; + } + + public bool TryGetExplicitConversionFrom(TypeAnalysisContext sourceType, [NotNullWhen(true)] out MethodAnalysisContext? method) + { + method = GetConversion("op_Explicit", type, sourceType, type.SelfInstantiateIfGeneric()); + return method is not null; + } + + public bool TryGetExplicitConversionTo(TypeAnalysisContext targetType, [NotNullWhen(true)] out MethodAnalysisContext? method) + { + method = GetConversion("op_Explicit", type, type.SelfInstantiateIfGeneric(), targetType); + return method is not null; + } + + public bool TryGetConversionFrom(TypeAnalysisContext sourceType, [NotNullWhen(true)] out MethodAnalysisContext? method) + { + return type.TryGetImplicitConversionFrom(sourceType, out method) || type.TryGetExplicitConversionFrom(sourceType, out method); + } + + public bool TryGetConversionTo(TypeAnalysisContext targetType, [NotNullWhen(true)] out MethodAnalysisContext? method) + { + return type.TryGetImplicitConversionTo(targetType, out method) || type.TryGetExplicitConversionTo(targetType, out method); } public TypeAnalysisContext MaybeMakeGenericInstanceType(IReadOnlyCollection genericArguments) @@ -279,9 +321,9 @@ public bool ImplementsInterface(TypeAnalysisContext interfaceType) } } - private static MethodAnalysisContext GetConversion([ConstantExpected] string name, TypeAnalysisContext declaringType, TypeAnalysisContext sourceType, TypeAnalysisContext targetType) + private static MethodAnalysisContext? GetConversion([ConstantExpected] string name, TypeAnalysisContext declaringType, TypeAnalysisContext sourceType, TypeAnalysisContext targetType) { - return declaringType.Methods.First(m => + return declaringType.Methods.FirstOrDefault(m => { return m.Name == name && m.IsStatic diff --git a/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs b/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs index 2cca0755..93f7c5c4 100644 --- a/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs +++ b/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs @@ -1,30 +1,24 @@ -using System.Reflection; +using System.Diagnostics; +using System.Reflection; using Cpp2IL.Core.Api; using Cpp2IL.Core.Model.Contexts; +using Il2CppInterop.Generator.Conversions; using Il2CppInterop.Generator.Operands; using Il2CppInterop.Generator.Visitors; namespace Il2CppInterop.Generator; +/// +/// This processing layer finds matching interfaces in mscorlib and Il2Cppmscorlib and implements +/// the mscorlib interfaces on the Il2Cppmscorlib interfaces, forwarding calls to the existing Il2Cppmscorlib methods. +/// This allows user code to use the normal .NET interfaces and have them work with the Il2Cpp types. +/// public sealed class SystemInterfaceProcessingLayer : Cpp2IlProcessingLayer { public override string Name => "System Interface Implementations"; public override string Id => "system_interface_implementations"; public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { - // Needs to handle: - // IDisposable - // IEnumerator and IEnumerator - // IEnumerable and IEnumerable - // INotifyCompletion and ICriticalNotifyCompletion - // IEquatable - // IComparable and IComparable - // IReadOnlyCollection and IReadOnlyList - // IReadOnlySet - // IReadOnlyDictionary - // IEqualityComparer - // IComparer and IComparer - var pairs = FindPairs(appContext); foreach (var (il2CppInterface, systemInterface) in pairs) @@ -67,7 +61,7 @@ static bool IsPublic(TypeAnalysisContext? type) private static void ImplementInterface(TypeAnalysisContext il2CppInterface, TypeAnalysisContext systemInterface) { - il2CppInterface.InterfaceContexts.Add(systemInterface); + il2CppInterface.InterfaceContexts.Add(systemInterface.MaybeMakeGenericInstanceType(il2CppInterface.GenericParameters)); foreach (var systemMethod in systemInterface.Methods) { @@ -81,7 +75,6 @@ private static void ImplementInterface(TypeAnalysisContext il2CppInterface, Type { IsInjected = true, }; - injectedMethod.Overrides.Add(systemMethod); il2CppInterface.Methods.Add(injectedMethod); injectedMethod.CopyGenericParameters(systemMethod, true); @@ -95,7 +88,9 @@ private static void ImplementInterface(TypeAnalysisContext il2CppInterface, Type injectedMethod.Parameters.Add(new InjectedParameterAnalysisContext(parameter.Name, visitor.Replace(parameter.ParameterType), parameter.Attributes, parameter.ParameterIndex, injectedMethod)); } - var il2CppMethod = FindIl2CppMethod(il2CppInterface, systemMethod); + injectedMethod.Overrides.Add(systemMethod.MaybeMakeConcreteGeneric(il2CppInterface.GenericParameters, injectedMethod.GenericParameters)); + + var il2CppMethod = FindIl2CppMethod(il2CppInterface, systemMethod.Name, injectedMethod, out var returnConversion, out var parameterConversions); if (il2CppMethod is null) { @@ -112,13 +107,14 @@ private static void ImplementInterface(TypeAnalysisContext il2CppInterface, Type List instructions = []; instructions.Add(CilOpCodes.Ldarg_0); - foreach (var parameter in injectedMethod.Parameters) + for (var i = 0; i < injectedMethod.Parameters.Count; i++) { + var parameter = injectedMethod.Parameters[i]; instructions.Add(CilOpCodes.Ldarg, parameter); - // Todo: parameter value conversion + parameterConversions[i].Add(instructions); } - instructions.Add(CilOpCodes.Call, il2CppMethod); - // Todo: return value conversion + instructions.Add(CilOpCodes.Callvirt, il2CppMethod.MaybeMakeConcreteGeneric(il2CppInterface.GenericParameters, injectedMethod.GenericParameters)); + returnConversion.Add(instructions); instructions.Add(CilOpCodes.Ret); injectedMethod.PutExtraData(new NativeMethodBody() @@ -128,13 +124,24 @@ private static void ImplementInterface(TypeAnalysisContext il2CppInterface, Type } } - private static MethodAnalysisContext? FindIl2CppMethod(TypeAnalysisContext il2CppInterface, MethodAnalysisContext systemMethod) + private static MethodAnalysisContext? FindIl2CppMethod(TypeAnalysisContext il2CppInterface, string methodName, MethodAnalysisContext injectedMethod, out Conversion returnConversion, out Conversion[] parameterConversions) { - foreach (var il2CppMethod in il2CppInterface.Methods) + returnConversion = NullConversion.Instance; + parameterConversions = new Conversion[injectedMethod.Parameters.Count]; + + // Search in reverse order because the most user-friendly overloads will be last (they always get added to the end of the list). + // This ensures correct behavior for array parameters, which have special handling in the user-friendly overload processing layer. + for (var il2CppMethodIndex = il2CppInterface.Methods.Count - 1; il2CppMethodIndex >= 0; il2CppMethodIndex--) { - if (il2CppMethod.Name == systemMethod.Name && !il2CppMethod.IsStatic && il2CppMethod.Parameters.Count == systemMethod.Parameters.Count && il2CppMethod.GenericParameters.Count == systemMethod.GenericParameters.Count) + var il2CppMethod = il2CppInterface.Methods[il2CppMethodIndex]; + if (il2CppMethod.Name == methodName && + !il2CppMethod.IsStatic && + il2CppMethod.Parameters.Count == injectedMethod.Parameters.Count && + il2CppMethod.GenericParameters.Count == injectedMethod.GenericParameters.Count && + il2CppMethod.IsVoid == injectedMethod.IsVoid) { - if (!AreTypesEqual(il2CppMethod.ReturnType, systemMethod.ReturnType)) + var visitor = TypeReplacementVisitor.CreateForMethodCopying(il2CppMethod, injectedMethod); + if (!AreTypesEqual(visitor.Replace(il2CppMethod.ReturnType), injectedMethod.ReturnType, out returnConversion)) { continue; } @@ -142,9 +149,9 @@ private static void ImplementInterface(TypeAnalysisContext il2CppInterface, Type var parametersMatch = true; for (var i = 0; i < il2CppMethod.Parameters.Count; i++) { - var il2CppParameterType = il2CppMethod.Parameters[i].ParameterType; - var systemParameterType = systemMethod.Parameters[i].ParameterType; - if (!AreTypesEqual(il2CppParameterType, systemParameterType)) + var injectedParameterType = injectedMethod.Parameters[i].ParameterType; + var il2CppParameterType = visitor.Replace(il2CppMethod.Parameters[i].ParameterType); + if (!AreTypesEqual(injectedParameterType, il2CppParameterType, out parameterConversions[i])) { parametersMatch = false; break; @@ -158,14 +165,59 @@ private static void ImplementInterface(TypeAnalysisContext il2CppInterface, Type } return null; - static bool AreTypesEqual(TypeAnalysisContext a, TypeAnalysisContext b) + static bool AreTypesEqual(TypeAnalysisContext from, TypeAnalysisContext to, out Conversion conversion) { - if (a is GenericParameterTypeAnalysisContext aGeneric && b is GenericParameterTypeAnalysisContext bGeneric) + if (TypeAnalysisContextEqualityComparer.Instance.Equals(from, to)) + { + conversion = NullConversion.Instance; + return true; + } + else if (from.TryGetConversionTo(to, out var conversionMethod) || to.TryGetConversionFrom(from, out conversionMethod)) + { + // An implicit or explicit conversion exists + conversion = new MethodCallConversion(conversionMethod); + return true; + } + else if (to.KnownType is KnownTypeCode.System_Object && !from.IsValueType) + { + // Any reference type can be converted to System.Object + conversion = NullConversion.Instance; + return true; + } + else if (to.KnownType is KnownTypeCode.Il2CppSystem_IObject && from.KnownType is KnownTypeCode.System_Object) + { + // obj as IObject + conversion = new IsInstanceConversion(to); + return true; + } + else if (to.IsInterface && from.IsInterface && to.DefaultFullName == from.DefaultFullName) + { + if (to.Namespace.StartsWith("Il2Cpp", StringComparison.Ordinal)) + { + // System.IX to Il2CppSystem.IX + // Need to cast + conversion = new CastClassConversion(to); + return true; + } + else if (from.Namespace.StartsWith("Il2Cpp", StringComparison.Ordinal)) + { + // Il2CppSystem.IX to System.IX + // Since the Il2Cpp interface implements the System interface, no conversion is needed. + conversion = NullConversion.Instance; + return true; + } + else + { + Debug.Fail($"Unexpected case where two reference types have the same full name but are not considered equal: {from.FullName} and {to.FullName}"); + conversion = NullConversion.Instance; + return false; + } + } + else { - // For generic parameters, we consider them equal if they are in the same position - return aGeneric.Type == bGeneric.Type && aGeneric.Index == bGeneric.Index; + conversion = NullConversion.Instance; + return false; } - return TypeAnalysisContextEqualityComparer.Instance.Equals(a, b); } } } From f3008acf48b20a558fa1137a16376377b9b94c84 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 16:50:35 -0700 Subject: [PATCH 446/486] Fix nullable warnings for struct handler initialization --- Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs index 1c65a17b..a659793f 100644 --- a/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs @@ -28,6 +28,7 @@ public static class UnityVersionHandler private static readonly Dictionary> VersionedHandlers = new(); private static readonly Dictionary Handlers = new(); +#nullable disable internal static INativeAssemblyStructHandler assemblyStructHandler; internal static INativeAssemblyNameStructHandler assemblyNameStructHandler; internal static INativeClassStructHandler classStructHandler; @@ -39,6 +40,7 @@ public static class UnityVersionHandler internal static INativeParameterInfoStructHandler parameterInfoStructHandler; internal static INativePropertyInfoStructHandler propertyInfoStructHandler; internal static INativeTypeStructHandler typeStructHandler; +#nullable restore static UnityVersionHandler() { From a5a8463b2dc7cd2520da6c1c80a9ea14d56f3e6f Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 16:55:29 -0700 Subject: [PATCH 447/486] Do not use preview language version --- Il2CppInterop.Common/Il2CppInterop.Common.csproj | 1 - Il2CppInterop.Generator/Il2CppInterop.Generator.csproj | 1 - Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj | 1 - .../Il2CppInterop.SourceGenerator.Tests.csproj | 1 - .../Il2CppInterop.SourceGenerator.csproj | 1 - 5 files changed, 5 deletions(-) diff --git a/Il2CppInterop.Common/Il2CppInterop.Common.csproj b/Il2CppInterop.Common/Il2CppInterop.Common.csproj index 1b5bb793..ba20a2ae 100644 --- a/Il2CppInterop.Common/Il2CppInterop.Common.csproj +++ b/Il2CppInterop.Common/Il2CppInterop.Common.csproj @@ -4,7 +4,6 @@ net10.0 BepInEx, knah et al. Common API for Il2CppInterop packages - preview enable true diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index f0356bad..0bd75a13 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -7,7 +7,6 @@ net10.0 Debug;Release AnyCPU - preview enable true diff --git a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj index 711622c0..6e503d6f 100644 --- a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj +++ b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj @@ -9,7 +9,6 @@ Debug;Release AnyCPU false - preview enable true diff --git a/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj b/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj index 82d552ea..a7401499 100644 --- a/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj +++ b/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj @@ -2,7 +2,6 @@ net10.0 - latest enable enable false diff --git a/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj b/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj index b443c106..92a2cd6f 100644 --- a/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj +++ b/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj @@ -5,7 +5,6 @@ enable enable - latest true From 48c2d37ea5f6922cba18584484b1b24e0d1ebff5 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 17:24:48 -0700 Subject: [PATCH 448/486] Add to generated files --- .../Structs/VersionSpecific/Assembly/Assembly_104_0.cs | 1 + .../Structs/VersionSpecific/Assembly/Assembly_16_0.cs | 1 + .../Structs/VersionSpecific/Assembly/Assembly_20_0.cs | 1 + .../Structs/VersionSpecific/Assembly/Assembly_24_0.cs | 1 + .../Structs/VersionSpecific/Assembly/Assembly_24_1.cs | 1 + .../Structs/VersionSpecific/Assembly/Assembly_24_2.cs | 1 + .../Structs/VersionSpecific/Assembly/Interfaces.cs | 1 + .../Structs/VersionSpecific/AssemblyName/AssemblyName_16_0.cs | 1 + .../Structs/VersionSpecific/AssemblyName/AssemblyName_24_0.cs | 1 + .../Structs/VersionSpecific/AssemblyName/AssemblyName_24_1.cs | 1 + .../Structs/VersionSpecific/AssemblyName/Interfaces.cs | 1 + .../Structs/VersionSpecific/Class/Class_104_0.cs | 1 + .../Structs/VersionSpecific/Class/Class_105_0.cs | 1 + .../Structs/VersionSpecific/Class/Class_16_0.cs | 1 + .../Structs/VersionSpecific/Class/Class_19_0.cs | 1 + .../Structs/VersionSpecific/Class/Class_20_0.cs | 1 + .../Structs/VersionSpecific/Class/Class_21_0.cs | 1 + .../Structs/VersionSpecific/Class/Class_21_1.cs | 1 + .../Structs/VersionSpecific/Class/Class_21_2.cs | 1 + .../Structs/VersionSpecific/Class/Class_22_0.cs | 1 + .../Structs/VersionSpecific/Class/Class_22_1.cs | 1 + .../Structs/VersionSpecific/Class/Class_23_0.cs | 1 + .../Structs/VersionSpecific/Class/Class_23_1.cs | 1 + .../Structs/VersionSpecific/Class/Class_24_0.cs | 1 + .../Structs/VersionSpecific/Class/Class_24_1.cs | 1 + .../Structs/VersionSpecific/Class/Class_24_2.cs | 1 + .../Structs/VersionSpecific/Class/Class_24_3.cs | 1 + .../Structs/VersionSpecific/Class/Class_24_4.cs | 1 + .../Structs/VersionSpecific/Class/Class_24_5.cs | 1 + .../Structs/VersionSpecific/Class/Class_24_6.cs | 1 + .../Structs/VersionSpecific/Class/Class_24_7.cs | 1 + .../Structs/VersionSpecific/Class/Class_27_0.cs | 1 + .../Structs/VersionSpecific/Class/Class_27_1.cs | 1 + .../Structs/VersionSpecific/Class/Class_27_2.cs | 1 + .../Structs/VersionSpecific/Class/Class_27_3.cs | 1 + .../Structs/VersionSpecific/Class/Class_27_4.cs | 1 + .../Structs/VersionSpecific/Class/Class_27_5.cs | 1 + .../Structs/VersionSpecific/Class/Class_29_0.cs | 1 + .../Structs/VersionSpecific/Class/Class_29_1.cs | 1 + .../Structs/VersionSpecific/Class/Class_29_2.cs | 1 + .../Structs/VersionSpecific/Class/Class_39_0.cs | 1 + .../Structs/VersionSpecific/Class/Interfaces.cs | 1 + .../Structs/VersionSpecific/EventInfo/EventInfo_16_0.cs | 1 + .../Structs/VersionSpecific/EventInfo/EventInfo_19_0.cs | 1 + .../Structs/VersionSpecific/EventInfo/EventInfo_24_0.cs | 1 + .../Structs/VersionSpecific/EventInfo/Interfaces.cs | 1 + .../Structs/VersionSpecific/Exception/Exception_16_0.cs | 1 + .../Structs/VersionSpecific/Exception/Exception_20_0.cs | 1 + .../Structs/VersionSpecific/Exception/Exception_21_0.cs | 1 + .../Structs/VersionSpecific/Exception/Exception_22_0.cs | 1 + .../Structs/VersionSpecific/Exception/Exception_23_0.cs | 1 + .../Structs/VersionSpecific/Exception/Exception_23_1.cs | 1 + .../Structs/VersionSpecific/Exception/Exception_27_0.cs | 1 + .../Structs/VersionSpecific/Exception/Interfaces.cs | 1 + .../Structs/VersionSpecific/FieldInfo/FieldInfo_16_0.cs | 1 + .../Structs/VersionSpecific/FieldInfo/FieldInfo_19_0.cs | 1 + .../Structs/VersionSpecific/FieldInfo/FieldInfo_24_0.cs | 1 + .../Structs/VersionSpecific/FieldInfo/Interfaces.cs | 1 + .../Structs/VersionSpecific/Image/Image_16_0.cs | 1 + .../Structs/VersionSpecific/Image/Image_19_0.cs | 1 + .../Structs/VersionSpecific/Image/Image_24_0.cs | 1 + .../Structs/VersionSpecific/Image/Image_24_1.cs | 1 + .../Structs/VersionSpecific/Image/Image_24_2.cs | 1 + .../Structs/VersionSpecific/Image/Image_24_3.cs | 1 + .../Structs/VersionSpecific/Image/Image_24_4.cs | 1 + .../Structs/VersionSpecific/Image/Image_24_5.cs | 1 + .../Structs/VersionSpecific/Image/Image_24_6.cs | 1 + .../Structs/VersionSpecific/Image/Interfaces.cs | 1 + .../Structs/VersionSpecific/MethodInfo/Interfaces.cs | 1 + .../Structs/VersionSpecific/MethodInfo/MethodInfo_16_0.cs | 1 + .../Structs/VersionSpecific/MethodInfo/MethodInfo_21_0.cs | 1 + .../Structs/VersionSpecific/MethodInfo/MethodInfo_24_0.cs | 1 + .../Structs/VersionSpecific/MethodInfo/MethodInfo_24_1.cs | 1 + .../Structs/VersionSpecific/MethodInfo/MethodInfo_24_2.cs | 1 + .../Structs/VersionSpecific/MethodInfo/MethodInfo_27_0.cs | 1 + .../Structs/VersionSpecific/MethodInfo/MethodInfo_28_0.cs | 1 + .../Structs/VersionSpecific/MethodInfo/MethodInfo_29_0.cs | 1 + .../Structs/VersionSpecific/MethodInfo/MethodInfo_29_1.cs | 1 + .../Structs/VersionSpecific/MethodInfo/MethodInfo_29_2.cs | 1 + .../Structs/VersionSpecific/ParameterInfo/Interfaces.cs | 1 + .../Structs/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs | 1 + .../Structs/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs | 1 + .../Structs/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs | 1 + .../Structs/VersionSpecific/PropertyInfo/Interfaces.cs | 1 + .../Structs/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs | 1 + .../Structs/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs | 1 + .../Structs/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs | 1 + Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Interfaces.cs | 1 + Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_16_0.cs | 1 + Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_27_0.cs | 1 + Il2CppInterop.StructGenerator/CodeGen/CodeGenFile.cs | 1 + 91 files changed, 91 insertions(+) diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_104_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_104_0.cs index cc4c0420..5ad3eb7c 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_104_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_104_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_16_0.cs index 142e74b8..e6e2d19d 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_16_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_20_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_20_0.cs index 034e3003..310194bc 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_20_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_20_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_0.cs index f035e60d..d585a9b4 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_1.cs index 6e34789d..bbb6b19c 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_1.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_2.cs index f20fa1e6..169906e9 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_2.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Interfaces.cs index f1c06e7a..2535f8ee 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Interfaces.cs @@ -1,3 +1,4 @@ +// using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_16_0.cs index ea63b213..e75d5f21 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_16_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_0.cs index f9e97271..fce527fa 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_1.cs index e47501a1..b96a5d9e 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_1.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/Interfaces.cs index fbe59eb5..22dd79a4 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/Interfaces.cs @@ -1,3 +1,4 @@ +// namespace Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName { public interface INativeAssemblyNameStructHandler : INativeStructHandler diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs index 3667063e..11a6fa40 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs index 05c547bb..bd08b4f7 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs index 307f7b12..04600a83 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs index f2f7399f..12366d82 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs index 4292bae2..558bde89 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs index b1610144..7fee2c7a 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs index 16152eaf..0e9f5483 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs index 3ecd8615..1f8d8d64 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs index c980d232..71868bbd 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs index 26f02b89..59089712 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs index a18dd64e..75a85a30 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs index 40fa1791..7e429798 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs index 352db28b..822a8ac9 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs index ee39744a..c92bed06 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs index 2296ce31..cd7571e0 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs index dc2265fe..0f52bee4 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs index eea04ec1..18f7e806 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs index a2f762ef..559fa20b 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs index 66e1b42a..b0df8560 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs index df220df5..9f5e9c4b 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs index 38dfc36f..e356b96e 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs index 14f1f308..3e3e2ae4 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs index 67da67cf..26542ea5 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs index 0f3cac60..98e0b156 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs index 767a95dc..6a1d25f1 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs index f6c40e9b..e14f98f0 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs index 867fc5c3..ab4017dd 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs index f1287c72..86ca8241 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs index 24c57cf0..38b0e9fd 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs index 460c826c..65099896 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Interfaces.cs index 3c4031e3..a6c2283f 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Interfaces.cs @@ -1,3 +1,4 @@ +// using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_16_0.cs index f9683e3b..a545a5fb 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_16_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_19_0.cs index 95110105..3ac06b4a 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_19_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_24_0.cs index 3e26dee3..6c331b59 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_24_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/Interfaces.cs index 04c5bf68..44082efa 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/Interfaces.cs @@ -1,3 +1,4 @@ +// namespace Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo { public interface INativeEventInfoStructHandler : INativeStructHandler diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_16_0.cs index 5fc0fb5d..2f05efac 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_16_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_20_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_20_0.cs index dd259000..0c7a8c00 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_20_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_20_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_21_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_21_0.cs index e81a6ddd..8b807a1e 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_21_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_21_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_22_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_22_0.cs index 5b43ca78..903986a8 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_22_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_22_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_0.cs index f83f6dc7..db4c80ad 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_1.cs index 137a0dd8..ca368ca3 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_1.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_27_0.cs index a039590e..06123a1e 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_27_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Interfaces.cs index 5014269c..8224a51f 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Interfaces.cs @@ -1,3 +1,4 @@ +// namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { public interface INativeExceptionStructHandler : INativeStructHandler diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_16_0.cs index 64ef1cb0..ee9960b7 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_16_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_19_0.cs index 242748b1..455f7faa 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_19_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_24_0.cs index 86d095ae..4c0eb427 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_24_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/Interfaces.cs index d6d260fa..860e9c5c 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/Interfaces.cs @@ -1,3 +1,4 @@ +// namespace Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo { public interface INativeFieldInfoStructHandler : INativeStructHandler diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_16_0.cs index b984b3cd..2a0691bf 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_16_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_19_0.cs index b283e216..289ddcc5 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_19_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_0.cs index 2ac4d9d4..66563543 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_1.cs index e6a17008..c2405660 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_1.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_2.cs index 9509889d..8a08512f 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_2.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_3.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_3.cs index 2a2ba102..bdfd4b2d 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_3.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_3.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_4.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_4.cs index 6c5f9ebb..cf8f7da4 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_4.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_4.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_5.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_5.cs index 92dca77b..83210ca5 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_5.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_5.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_6.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_6.cs index d87a8c87..92f83dbc 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_6.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_6.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Interfaces.cs index a169ef6f..05493033 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Interfaces.cs @@ -1,3 +1,4 @@ +// namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { public interface INativeImageStructHandler : INativeStructHandler diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/Interfaces.cs index 287e1c58..3c66b046 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/Interfaces.cs @@ -1,3 +1,4 @@ +// namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { public interface INativeMethodInfoStructHandler : INativeStructHandler diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_16_0.cs index 60764aa8..5417c30c 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_16_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_21_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_21_0.cs index a4762e66..c5ecb0d3 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_21_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_21_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_0.cs index 234a98eb..df294e43 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_1.cs index 4dba8b6e..6aa96195 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_1.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_2.cs index 754b5262..7328044a 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_2.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_27_0.cs index e0c97989..a636db78 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_27_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_28_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_28_0.cs index f2d701bd..d2ed0764 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_28_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_28_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_0.cs index 4132722f..d9bdf25f 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_1.cs index 0f183e02..2635d4aa 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_1.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_2.cs index 2ccc618f..5555d139 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_2.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/Interfaces.cs index 064762cc..143a4f0a 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/Interfaces.cs @@ -1,3 +1,4 @@ +// namespace Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo { public interface INativeParameterInfoStructHandler : INativeStructHandler diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs index 88ad165b..ee0d39cc 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs index 88ccfd54..d8537686 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs index 9da6a7e7..2abf0a58 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/Interfaces.cs index cfa8dbef..bbfd2108 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/Interfaces.cs @@ -1,3 +1,4 @@ +// namespace Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo { public interface INativePropertyInfoStructHandler : INativeStructHandler diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs index 8a34356d..8b8a2eee 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs index 5b744191..c00fa984 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs index 6e059a63..0b8b0351 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Interfaces.cs index 6d9c8119..0f398b1f 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Interfaces.cs @@ -1,3 +1,4 @@ +// namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Type { public interface INativeTypeStructHandler : INativeStructHandler diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_16_0.cs index 9671ed86..dd2d3625 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_16_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Type { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_27_0.cs index 528418fd..9a3c4b46 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_27_0.cs @@ -1,3 +1,4 @@ +// using System.Runtime.InteropServices; namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Type { diff --git a/Il2CppInterop.StructGenerator/CodeGen/CodeGenFile.cs b/Il2CppInterop.StructGenerator/CodeGen/CodeGenFile.cs index 15a13337..28699522 100644 --- a/Il2CppInterop.StructGenerator/CodeGen/CodeGenFile.cs +++ b/Il2CppInterop.StructGenerator/CodeGen/CodeGenFile.cs @@ -10,6 +10,7 @@ internal class CodeGenFile private void Build(IndentedTextWriter writer) { + writer.WriteLine("// "); foreach (var @using in Usings) writer.WriteUsing(@using); if (Namespace != null) From fec313c982c78f7c8362e9e8c1bd562dc7725212 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 17:25:28 -0700 Subject: [PATCH 449/486] Suppress CS0649 warning in project file Added a PropertyGroup to Il2CppInterop.Runtime.csproj to suppress compiler warning CS0649, preventing messages about unassigned fields with default values. This helps keep build output cleaner. --- Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj index 6e503d6f..c67f6837 100644 --- a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj +++ b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj @@ -13,6 +13,11 @@ true + + + $(NoWarn);0649 + + From b07e22c73fa8c3443c54d8592afe9be5d20a4d0d Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 17:29:30 -0700 Subject: [PATCH 450/486] Nullable enable by default --- Directory.Build.props | 2 +- Il2CppInterop.CLI/Il2CppInterop.CLI.csproj | 1 - Il2CppInterop.Common/Il2CppInterop.Common.csproj | 1 - Il2CppInterop.Generator/Il2CppInterop.Generator.csproj | 1 - .../Il2CppInterop.HarmonySupport.csproj | 1 - Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj | 1 - .../Il2CppInterop.SourceGenerator.Tests.csproj | 1 - .../Il2CppInterop.SourceGenerator.csproj | 1 - .../Il2CppInterop.StructGenerator.csproj | 1 - 9 files changed, 1 insertion(+), 9 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index d69ce520..adff3584 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,7 +5,7 @@ ../bin/NuGet ../bin/$(MSBuildProjectName) latest - disable + enable true latest logo_icon.png diff --git a/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj b/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj index 4c5343e3..22177a3b 100644 --- a/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj +++ b/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj @@ -11,7 +11,6 @@ CLI tool for generating managed proxy assemblies for Il2Cpp Debug;Release AnyCPU - enable true diff --git a/Il2CppInterop.Common/Il2CppInterop.Common.csproj b/Il2CppInterop.Common/Il2CppInterop.Common.csproj index ba20a2ae..75be4f96 100644 --- a/Il2CppInterop.Common/Il2CppInterop.Common.csproj +++ b/Il2CppInterop.Common/Il2CppInterop.Common.csproj @@ -4,7 +4,6 @@ net10.0 BepInEx, knah et al. Common API for Il2CppInterop packages - enable true diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index 0bd75a13..1be3676a 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -7,7 +7,6 @@ net10.0 Debug;Release AnyCPU - enable true diff --git a/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj b/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj index 35046f8e..c0026e78 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj +++ b/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj @@ -3,7 +3,6 @@ Module to allow using Harmony with Il2CppInterop assemblies net10.0 - enable true diff --git a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj index c67f6837..f1b6191f 100644 --- a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj +++ b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj @@ -9,7 +9,6 @@ Debug;Release AnyCPU false - enable true diff --git a/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj b/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj index a7401499..ecb66781 100644 --- a/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj +++ b/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj @@ -3,7 +3,6 @@ net10.0 enable - enable false diff --git a/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj b/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj index 92a2cd6f..0186908e 100644 --- a/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj +++ b/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj @@ -3,7 +3,6 @@ netstandard2.0 enable - enable true diff --git a/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj b/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj index f8f1e8b7..cd3fe086 100644 --- a/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj +++ b/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj @@ -3,7 +3,6 @@ net10.0 Exe - enable false $(NETCoreSdkRuntimeIdentifier) From ea9234402f5b0973e7a908a3143149207b9c3cd4 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 17:36:28 -0700 Subject: [PATCH 451/486] Remove Configurations and Platforms from csproj files Removed the and properties from Il2CppInterop.CLI.csproj, Il2CppInterop.Generator.csproj, and Il2CppInterop.Runtime.csproj to simplify project configuration. No other changes were made. --- Il2CppInterop.CLI/Il2CppInterop.CLI.csproj | 2 -- Il2CppInterop.Generator/Il2CppInterop.Generator.csproj | 2 -- Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj | 2 -- 3 files changed, 6 deletions(-) diff --git a/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj b/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj index 22177a3b..42915d9c 100644 --- a/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj +++ b/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj @@ -9,8 +9,6 @@ Il2CppInterop.CLI BepInEx CLI tool for generating managed proxy assemblies for Il2Cpp - Debug;Release - AnyCPU true diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index 1be3676a..c5400eac 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -5,8 +5,6 @@ knah, BepInEx et al. Library for generating assemblies and metadata for calling Il2Cpp functions from .NET net10.0 - Debug;Release - AnyCPU true diff --git a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj index f1b6191f..69975d93 100644 --- a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj +++ b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj @@ -6,8 +6,6 @@ Runtime tools for bridging .NET and Il2Cpp together net10.0 true - Debug;Release - AnyCPU false true From 5425cbf69e6888a24e0026105240c9aa163e6ef7 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 17:41:13 -0700 Subject: [PATCH 452/486] Add PackageId to csproj files and update packaging config Added to Il2CppInterop.Common and HarmonySupport projects. Removed false from StructGenerator to use default packaging behavior. --- Il2CppInterop.Common/Il2CppInterop.Common.csproj | 1 + .../Il2CppInterop.HarmonySupport.csproj | 3 ++- .../Il2CppInterop.StructGenerator.csproj | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Il2CppInterop.Common/Il2CppInterop.Common.csproj b/Il2CppInterop.Common/Il2CppInterop.Common.csproj index 75be4f96..85d39638 100644 --- a/Il2CppInterop.Common/Il2CppInterop.Common.csproj +++ b/Il2CppInterop.Common/Il2CppInterop.Common.csproj @@ -1,6 +1,7 @@  + Il2CppInterop.Common net10.0 BepInEx, knah et al. Common API for Il2CppInterop packages diff --git a/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj b/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj index c0026e78..237103ae 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj +++ b/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj @@ -1,6 +1,7 @@ - + + Il2CppInterop.HarmonySupport Module to allow using Harmony with Il2CppInterop assemblies net10.0 true diff --git a/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj b/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj index cd3fe086..5414d78b 100644 --- a/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj +++ b/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj @@ -3,7 +3,6 @@ net10.0 Exe - false $(NETCoreSdkRuntimeIdentifier) From 0c53c2841a0c4a105eee45c220ff3160f36a72e7 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 17:48:19 -0700 Subject: [PATCH 453/486] Use Authors property from Directory.Build.props --- Il2CppInterop.Common/Il2CppInterop.Common.csproj | 1 - Il2CppInterop.Generator/Il2CppInterop.Generator.csproj | 1 - Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj | 1 - 3 files changed, 3 deletions(-) diff --git a/Il2CppInterop.Common/Il2CppInterop.Common.csproj b/Il2CppInterop.Common/Il2CppInterop.Common.csproj index 85d39638..02380625 100644 --- a/Il2CppInterop.Common/Il2CppInterop.Common.csproj +++ b/Il2CppInterop.Common/Il2CppInterop.Common.csproj @@ -3,7 +3,6 @@ Il2CppInterop.Common net10.0 - BepInEx, knah et al. Common API for Il2CppInterop packages true diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index c5400eac..4f9acaae 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -2,7 +2,6 @@ Il2CppInterop.Generator - knah, BepInEx et al. Library for generating assemblies and metadata for calling Il2Cpp functions from .NET net10.0 true diff --git a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj index 69975d93..62af594b 100644 --- a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj +++ b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj @@ -2,7 +2,6 @@ Il2CppInterop.Runtime - knah, BepInEx et al. Runtime tools for bridging .NET and Il2Cpp together net10.0 true From d235a490de71e29090402a625734127309eba8f4 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 20:29:20 -0700 Subject: [PATCH 454/486] Annotate project for AOT compatibility --- Directory.Build.props | 1 + Il2CppInterop.Common/Il2CppInternalsAccess.cs | 4 + Il2CppInterop.Common/Il2CppType.cs | 7 + .../DelegateConversionProcessingLayer.cs | 151 ++++++++---------- .../AssemblyAnalysisContextExtensions.cs | 1 - .../InjectedTypeAnalysisContextExtensions.cs | 21 ++- .../TypeAnalysisContextExtensions.cs | 7 - ...ferenceAssemblyInjectionProcessingLayer.cs | 79 +++++++-- .../Il2CppInteropDetour.cs | 18 ++- .../Il2CppInteropDetourFactory.cs | 8 + Il2CppInterop.Runtime/DelegateSupport.cs | 9 +- .../Extensions/AssemblyExtensions.cs | 2 + .../INativeMethodInfoStructExtensions.cs | 2 + Il2CppInterop.Runtime/GenerationInternals.cs | 3 + .../Il2CppTypePointerStore.cs | 3 + Il2CppInterop.Runtime/Injection/Hook.cs | 9 ++ .../Hooks/Class_FromIl2CppType_Hook.cs | 3 + .../Injection/Hooks/Class_FromName_Hook.cs | 3 + .../Hooks/Class_GetFieldDefaultValue_Hook.cs | 5 + ...GetTypeInfoFromTypeDefinitionIndex_Hook.cs | 5 + .../Injection/InvokerSignatureHash.cs | 3 + .../Injection/NamedSignatureHash.cs | 3 + .../Injection/TrampolineBuilder.cs | 5 + .../Injection/TrampolineSignatureHash.cs | 2 + .../Injection/TypeInjector.cs | 64 ++++++-- .../Il2CppToMonoDelegateReference.cs | 9 +- Il2CppInterop.Runtime/RuntimeInvoke.cs | 10 +- .../Structs/UnityVersionHandler.cs | 7 + .../Il2CppInterop.SourceGenerator.csproj | 1 + .../InjectedTypeGenerator.cs | 4 + 30 files changed, 314 insertions(+), 135 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index adff3584..411d224a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -14,6 +14,7 @@ true embedded enable + true diff --git a/Il2CppInterop.Common/Il2CppInternalsAccess.cs b/Il2CppInterop.Common/Il2CppInternalsAccess.cs index e50f367b..dfa37d92 100644 --- a/Il2CppInterop.Common/Il2CppInternalsAccess.cs +++ b/Il2CppInterop.Common/Il2CppInternalsAccess.cs @@ -1,8 +1,11 @@ +using System.Diagnostics.CodeAnalysis; using System.Reflection; using Il2CppInterop.Common.Attributes; namespace Il2CppInterop.Common; +[RequiresUnreferencedCode("This API uses reflection to access fields in the corresponding Il2CppInternals type.")] +[RequiresDynamicCode("This API generically instantiates the corresponding Il2CppInternals type if necessary.")] public static class Il2CppInternalsAccess { private static FieldInfo? GetFieldInfo(Type declaringType, string prefix, int index) @@ -44,6 +47,7 @@ public static class Il2CppInternalsAccess return GetFieldInfo(declaringType, "MethodInfoPtr_", index); } + [RequiresUnreferencedCode("This API uses reflection to access fields in the corresponding Il2CppInternals type and to access property metadata for the method's declaring type.")] public static FieldInfo? GetIl2CppFieldInfoPointerFieldForGeneratedFieldAccessor(MethodBase method) { var declaringType = method.DeclaringType; diff --git a/Il2CppInterop.Common/Il2CppType.cs b/Il2CppInterop.Common/Il2CppType.cs index d66b8539..4a478733 100644 --- a/Il2CppInterop.Common/Il2CppType.cs +++ b/Il2CppInterop.Common/Il2CppType.cs @@ -1,4 +1,5 @@ using System.Buffers.Binary; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -139,6 +140,7 @@ public static void WritePointer(nint pointer, Span span) } } + [RequiresDynamicCode("")] public static nint GetClassPointer(Type type) { if (type == typeof(void)) @@ -152,10 +154,13 @@ public static nint GetClassPointer(Type type) public static nint GetClassPointer() where T : IIl2CppType { +#pragma warning disable IL2059 // The type passed to the RunClassConstructor is not statically known, Trimmer can't make sure that its static constructor is available. RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); +#pragma warning restore IL2059 // The type passed to the RunClassConstructor is not statically known, Trimmer can't make sure that its static constructor is available. return Il2CppClassPointerStore.NativeClassPointer; } + [RequiresDynamicCode("")] public static void SetClassPointer(Type type, nint classPointer) { typeof(Il2CppType) @@ -166,7 +171,9 @@ public static void SetClassPointer(Type type, nint classPointer) public static void SetClassPointer(nint classPointer) where T : IIl2CppType { +#pragma warning disable IL2059 // The type passed to the RunClassConstructor is not statically known, Trimmer can't make sure that its static constructor is available. RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); +#pragma warning restore IL2059 // The type passed to the RunClassConstructor is not statically known, Trimmer can't make sure that its static constructor is available. if (Il2CppClassPointerStore.NativeClassPointer != classPointer) { if (Il2CppClassPointerStore.NativeClassPointer == nint.Zero) diff --git a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs index ed6d6e73..a54a1674 100644 --- a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs +++ b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using Cpp2IL.Core.Api; using Cpp2IL.Core.Model.Contexts; @@ -16,7 +17,7 @@ public class DelegateConversionProcessingLayer : Cpp2IlProcessingLayer public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { - PolyfillActionFuncDelegates(appContext); + PolyfillActionFuncDelegates(appContext, out var actionTypes, out var funcTypes); var multicastDelegateType = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.MulticastDelegate"); var asyncCallbackType = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.AsyncCallback"); @@ -121,57 +122,17 @@ public override void Process(ApplicationAnalysisContext appContext, Action typeof(Func<>), - 1 => typeof(Func<,>), - 2 => typeof(Func<,,>), - 3 => typeof(Func<,,,>), - 4 => typeof(Func<,,,,>), - 5 => typeof(Func<,,,,,>), - 6 => typeof(Func<,,,,,,>), - 7 => typeof(Func<,,,,,,,>), - 8 => typeof(Func<,,,,,,,,>), - 9 => typeof(Func<,,,,,,,,,>), - 10 => typeof(Func<,,,,,,,,,,>), - 11 => typeof(Func<,,,,,,,,,,,>), - 12 => typeof(Func<,,,,,,,,,,,,>), - 13 => typeof(Func<,,,,,,,,,,,,,>), - 14 => typeof(Func<,,,,,,,,,,,,,,>), - 15 => typeof(Func<,,,,,,,,,,,,,,,>), - 16 => typeof(Func<,,,,,,,,,,,,,,,,>), - _ => default!, // unreachable - }; - managedDelegateType = appContext.ResolveTypeOrThrow(systemType) + managedDelegateType = funcTypes[invokeMethod.Parameters.Count] .MakeGenericInstanceType(invokeMethod.Parameters.Select(p => p.ParameterType).Append(invokeMethod.ReturnType)); } else if (invokeMethod.Parameters.Count > 0) { - var systemType = invokeMethod.Parameters.Count switch - { - 1 => typeof(Action<>), - 2 => typeof(Action<,>), - 3 => typeof(Action<,,>), - 4 => typeof(Action<,,,>), - 5 => typeof(Action<,,,,>), - 6 => typeof(Action<,,,,,>), - 7 => typeof(Action<,,,,,,>), - 8 => typeof(Action<,,,,,,,>), - 9 => typeof(Action<,,,,,,,,>), - 10 => typeof(Action<,,,,,,,,,>), - 11 => typeof(Action<,,,,,,,,,,>), - 12 => typeof(Action<,,,,,,,,,,,>), - 13 => typeof(Action<,,,,,,,,,,,,>), - 14 => typeof(Action<,,,,,,,,,,,,,>), - 15 => typeof(Action<,,,,,,,,,,,,,,>), - 16 => typeof(Action<,,,,,,,,,,,,,,,>), - _ => default!, // unreachable - }; - managedDelegateType = appContext.ResolveTypeOrThrow(systemType).MakeGenericInstanceType(invokeMethod.Parameters.Select(p => p.ParameterType)); + managedDelegateType = actionTypes[invokeMethod.Parameters.Count] + .MakeGenericInstanceType(invokeMethod.Parameters.Select(p => p.ParameterType)); } else { - managedDelegateType = appContext.ResolveTypeOrThrow(typeof(Action)); + managedDelegateType = actionTypes[0]; } } else @@ -276,55 +237,69 @@ public override void Process(ApplicationAnalysisContext appContext, Action - /// - private static void PolyfillActionFuncDelegates(ApplicationAnalysisContext appContext) + /// + /// + /// + private static void PolyfillActionFuncDelegates(ApplicationAnalysisContext appContext, out TypeAnalysisContext[] actionTypes, out TypeAnalysisContext[] funcTypes) { - var mscorlib = appContext.AssembliesByName["mscorlib"]; + var mscorlib = appContext.Mscorlib; - ReadOnlySpan types = +#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code +#pragma warning disable IL2111 // Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. + actionTypes = [ - typeof(Action), - typeof(Action<>), - typeof(Action<,>), - typeof(Action<,,>), - typeof(Action<,,,>), - typeof(Action<,,,,>), - typeof(Action<,,,,,>), - typeof(Action<,,,,,,>), - typeof(Action<,,,,,,,>), - typeof(Action<,,,,,,,,>), - typeof(Action<,,,,,,,,,>), - typeof(Action<,,,,,,,,,,>), - typeof(Action<,,,,,,,,,,,>), - typeof(Action<,,,,,,,,,,,,>), - typeof(Action<,,,,,,,,,,,,,>), - typeof(Action<,,,,,,,,,,,,,,>), - typeof(Action<,,,,,,,,,,,,,,,>), - typeof(Func<>), - typeof(Func<,>), - typeof(Func<,,>), - typeof(Func<,,,>), - typeof(Func<,,,,>), - typeof(Func<,,,,,>), - typeof(Func<,,,,,,>), - typeof(Func<,,,,,,,>), - typeof(Func<,,,,,,,,>), - typeof(Func<,,,,,,,,,>), - typeof(Func<,,,,,,,,,,>), - typeof(Func<,,,,,,,,,,,>), - typeof(Func<,,,,,,,,,,,,>), - typeof(Func<,,,,,,,,,,,,,>), - typeof(Func<,,,,,,,,,,,,,,>), - typeof(Func<,,,,,,,,,,,,,,,>), - typeof(Func<,,,,,,,,,,,,,,,,>), + GetOrInjectType(mscorlib, typeof(Action)), + GetOrInjectType(mscorlib, typeof(Action<>)), + GetOrInjectType(mscorlib, typeof(Action<,>)), + GetOrInjectType(mscorlib, typeof(Action<,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,,,,,,,>)), ]; - foreach (var type in types) - { - if (mscorlib.GetTypeByFullName(type.FullName!) is not null) - continue; + funcTypes = + [ + GetOrInjectType(mscorlib, typeof(Func<>)), + GetOrInjectType(mscorlib, typeof(Func<,>)), + GetOrInjectType(mscorlib, typeof(Func<,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,,,,,,>)), + GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,,,,,,,>)), + ]; +#pragma warning restore IL2111 // Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. +#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code - mscorlib.InjectType(type).InjectContentFromSourceType(); + static TypeAnalysisContext GetOrInjectType(AssemblyAnalysisContext mscorlib, [DynamicallyAccessedMembers(InjectedTypeAnalysisContextExtensions.AccessedMemberTypes)] Type type) + { + var result = mscorlib.GetTypeByFullName(type.FullName!); + if (result is null) + { + var injectedType = mscorlib.InjectType(type); + injectedType.InjectContentFromSourceType(type); + result = injectedType; + } + return result; } } } diff --git a/Il2CppInterop.Generator/Extensions/AssemblyAnalysisContextExtensions.cs b/Il2CppInterop.Generator/Extensions/AssemblyAnalysisContextExtensions.cs index 78025f9b..22a1591d 100644 --- a/Il2CppInterop.Generator/Extensions/AssemblyAnalysisContextExtensions.cs +++ b/Il2CppInterop.Generator/Extensions/AssemblyAnalysisContextExtensions.cs @@ -24,7 +24,6 @@ public InjectedTypeAnalysisContext InjectType(Type type) result.GenericParameters.Add(genericParameterContext); } } - result.SourceType = type; return result; } diff --git a/Il2CppInterop.Generator/Extensions/InjectedTypeAnalysisContextExtensions.cs b/Il2CppInterop.Generator/Extensions/InjectedTypeAnalysisContextExtensions.cs index aa8784cf..2bad53d4 100644 --- a/Il2CppInterop.Generator/Extensions/InjectedTypeAnalysisContextExtensions.cs +++ b/Il2CppInterop.Generator/Extensions/InjectedTypeAnalysisContextExtensions.cs @@ -1,4 +1,5 @@ -using System.Reflection; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; using System.Runtime.CompilerServices; using Cpp2IL.Core.Model.Contexts; using LibCpp2IL.BinaryStructures; @@ -7,13 +8,21 @@ namespace Il2CppInterop.Generator.Extensions; internal static class InjectedTypeAnalysisContextExtensions { + public const DynamicallyAccessedMemberTypes AccessedMemberTypes = DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.PublicEvents + | DynamicallyAccessedMemberTypes.PublicMethods + | DynamicallyAccessedMemberTypes.PublicConstructors + | DynamicallyAccessedMemberTypes.NonPublicFields + | DynamicallyAccessedMemberTypes.NonPublicProperties + | DynamicallyAccessedMemberTypes.NonPublicEvents + | DynamicallyAccessedMemberTypes.NonPublicMethods + | DynamicallyAccessedMemberTypes.NonPublicConstructors; + extension(InjectedTypeAnalysisContext type) { - public void InjectContentFromSourceType() + public void InjectContentFromSourceType([DynamicallyAccessedMembers(AccessedMemberTypes)] Type sourceType) { - var sourceType = type.SourceType; - ArgumentNullException.ThrowIfNull(sourceType); - var appContext = type.AppContext; type.SetDefaultBaseType(sourceType.BaseType != null @@ -133,7 +142,7 @@ public void SetDefaultBaseType(TypeAnalysisContext? baseType) } } - static IEnumerable GetPublicAndProtectedMethods(Type type) + static IEnumerable GetPublicAndProtectedMethods([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type type) { var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); foreach (var constructor in constructors) diff --git a/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs b/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs index 5efc4249..b846af39 100644 --- a/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs +++ b/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs @@ -68,13 +68,6 @@ public string CSharpName } } - [MaybeNull] - public Type SourceType - { - get => type.GetExtraData("SourceType"); - set => type.PutExtraData("SourceType", value); - } - [MaybeNull] public MethodAnalysisContext PointerConstructor { diff --git a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs index 4492d8a7..044bc84d 100644 --- a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs +++ b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs @@ -1,4 +1,5 @@ -using System.Reflection; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; using Cpp2IL.Core.Api; using Cpp2IL.Core.Model.Contexts; using Il2CppInterop.Common; @@ -17,7 +18,9 @@ public class ReferenceAssemblyInjectionProcessingLayer : Cpp2IlProcessingLayer public override string Name => "Inject required references into the Cpp2IL context system"; public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { - Type[] il2CppInteropCommonTypes = + // Types need to be provided twice, so that the linker can find them + + ReadOnlySpan il2CppInteropCommonTypes = [ typeof(IL2CPP), typeof(ObjectPointer), @@ -34,9 +37,26 @@ public override void Process(ApplicationAnalysisContext appContext, Action), ]; - InjectTypes(appContext, typeof(ObjectPointer).Assembly, il2CppInteropCommonTypes); + { + var injectedAssembly = CreateTypes(appContext, typeof(IL2CPP).Assembly, il2CppInteropCommonTypes); + + InjectContentFromSourceType(injectedAssembly, typeof(IL2CPP)); + InjectContentFromSourceType(injectedAssembly, typeof(ObjectPointer)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppType)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppObjectPool)); + + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppMemberAttribute)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppMethodAttribute)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppFieldAttribute)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppPropertyAttribute)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppEventAttribute)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppTypeAttribute)); + + InjectContentFromSourceType(injectedAssembly, typeof(IIl2CppType)); + InjectContentFromSourceType(injectedAssembly, typeof(IIl2CppType<>)); + } - Type[] il2CppInteropRuntimeTypes = + ReadOnlySpan il2CppInteropRuntimeTypes = [ typeof(Il2CppArrayBase), typeof(Il2CppArrayBase<>), @@ -49,16 +69,42 @@ public override void Process(ApplicationAnalysisContext appContext, Action), typeof(ByReference<>), typeof(ByReference), - typeof(FieldAccess), typeof(IIl2CppException), - typeof(RuntimeInvoke), typeof(NativeBoxing), typeof(GenerationInternals), ]; - InjectTypes(appContext, typeof(Il2CppArrayBase).Assembly, il2CppInteropRuntimeTypes); + { + var injectedAssembly = CreateTypes(appContext, typeof(Il2CppArrayBase).Assembly, il2CppInteropRuntimeTypes); + + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppArrayBase)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppArrayBase<>)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppArrayRank1<>)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppArrayRank2<>)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppArrayRank3<>)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppArrayRank4<>)); + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppArrayRank5<>)); + +#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + InjectContentFromSourceType(injectedAssembly, typeof(Il2CppException)); +#pragma warning disable IL2111 // Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. + InjectContentFromSourceType(injectedAssembly, typeof(TypeInjector)); +#pragma warning restore IL2111 // Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. + InjectContentFromSourceType(injectedAssembly, typeof(DelegateSupport)); + InjectContentFromSourceType(injectedAssembly, typeof(RuntimeInvoke)); +#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + InjectContentFromSourceType(injectedAssembly, typeof(FieldAccess)); + InjectContentFromSourceType(injectedAssembly, typeof(Pointer<>)); + InjectContentFromSourceType(injectedAssembly, typeof(ByReference<>)); + InjectContentFromSourceType(injectedAssembly, typeof(ByReference)); + InjectContentFromSourceType(injectedAssembly, typeof(IIl2CppException)); + InjectContentFromSourceType(injectedAssembly, typeof(NativeBoxing)); + InjectContentFromSourceType(injectedAssembly, typeof(GenerationInternals)); + } } /// @@ -67,22 +113,25 @@ public override void Process(ApplicationAnalysisContext appContext, ActionThe /// The assembly /// The types to be injected from . Must be in order of inheritance - private static void InjectTypes(ApplicationAnalysisContext appContext, Assembly assembly, Type[] types) + private static InjectedAssemblyAnalysisContext CreateTypes(ApplicationAnalysisContext appContext, Assembly assembly, ReadOnlySpan types) { - var il2CppInteropRuntime = appContext.InjectAssembly(assembly); + var injectedAssembly = appContext.InjectAssembly(assembly); - il2CppInteropRuntime.IsReferenceAssembly = true; + injectedAssembly.IsReferenceAssembly = true; var typeContextArray = new InjectedTypeAnalysisContext[types.Length]; for (var i = 0; i < types.Length; i++) { - typeContextArray[i] = il2CppInteropRuntime.InjectType(types[i]); + typeContextArray[i] = injectedAssembly.InjectType(types[i]); } - for (var index = 0; index < types.Length; index++) - { - typeContextArray[index].InjectContentFromSourceType(); - } + return injectedAssembly; + } + + private static void InjectContentFromSourceType(AssemblyAnalysisContext assembly, [DynamicallyAccessedMembers(InjectedTypeAnalysisContextExtensions.AccessedMemberTypes)] Type sourceType) + { + var type = (InjectedTypeAnalysisContext)assembly.GetTypeByFullNameOrThrow(sourceType); + type.InjectContentFromSourceType(sourceType); } } diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs index bb92843a..83b05704 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs @@ -1,4 +1,5 @@ -using System.Reflection; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; using Il2CppInterop.Common; @@ -33,6 +34,8 @@ private static readonly MethodInfo ReportExceptionMethodInfo public DynamicMethodDefinition SourceMethodCloneIL { get; private set; } public MethodInfo SourceMethodClone { get; private set; } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] public Il2CppInteropDetour(MethodBase source, INativeMethodInfoStruct nativeSource, MethodBase target) { Source = source; @@ -61,6 +64,8 @@ public Il2CppInteropDetour(MethodBase source, INativeMethodInfoStruct nativeSour } } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] private DynamicMethodDefinition CopyOriginal() { try @@ -101,6 +106,8 @@ private DynamicMethodDefinition CopyOriginal() } } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] private MethodInfo ProcessWrapper(MethodReference outerRef, string innerPrefix) { var dmd = CreateWrappedDMD(outerRef); @@ -118,6 +125,9 @@ instr.Operand is MethodReference inner && return dmd.Generate(); } + + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] private MethodInfo ProcessPointerPatchedLeaf(MethodReference leafRef) { var dmd = CreateWrappedDMD(leafRef); @@ -144,7 +154,10 @@ private DynamicMethodDefinition CreateWrappedDMD(MethodReference methodRef) return dmd; } + [RequiresDynamicCode("")] +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public void Apply() +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. { if (NativeSource.MethodPointer == default) { @@ -208,6 +221,8 @@ private static Type GetReturnType(MethodBase methodOrConstructor) return methodOrConstructor is ConstructorInfo ? typeof(void) : ((MethodInfo)methodOrConstructor).ReturnType; } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] private DynamicMethodDefinition GenerateNativeToManagedThunk() { // managedParams are the interop types used on the managed side @@ -323,6 +338,7 @@ private DynamicMethodDefinition GenerateNativeToManagedThunk() private static void ReportException(Exception ex) => Logger.Instance.LogError(ex, "During invoking native->managed trampoline"); + [RequiresDynamicCode("")] private static void EmitConvertArgumentToManaged(ILGenerator il, int argIndex, Type managedParamType) diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs index 34e002d5..74c50324 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs @@ -11,7 +11,13 @@ public sealed class Il2CppInteropDetourFactory(IDetourFactory? fallback = null) { private readonly IDetourFactory _fallback = fallback ?? DetourFactory.Current; + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] +#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. public ICoreDetour CreateDetour(CreateDetourRequest request) +#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. +#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. { ArgumentNullException.ThrowIfNull(request.Source); ArgumentNullException.ThrowIfNull(request.Target); @@ -24,6 +30,8 @@ public ICoreDetour CreateDetour(CreateDetourRequest request) return _fallback.CreateDetour(request); } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] private static bool TryCreateDetour(CreateDetourRequest request, [NotNullWhen(true)] out Il2CppInteropDetour? detour) { var declaringType = request.Source.DeclaringType; diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index 6d9bd144..cdafd507 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Il2CppInterop.Common; @@ -16,18 +17,24 @@ public static class DelegateSupport { private static readonly ConcurrentDictionary NativeToManagedTrampolines = new(); + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] private static Delegate GetOrCreateNativeToManagedTrampoline(Type delegateType) { return NativeToManagedTrampolines.GetOrAdd(delegateType, CreateNativeToManagedTrampoline); } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] private static Delegate CreateNativeToManagedTrampoline(Type delegateType) { var invokeMethod = Il2CppToMonoDelegateReference.GetOrCreateInvokeMethod(delegateType); return TrampolineBuilder.CreateTrampoline(invokeMethod, false); } - public static TIl2Cpp? ConvertDelegate(Delegate @delegate) where TIl2Cpp : Il2CppSystem.Delegate, IIl2CppType + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] + public static TIl2Cpp? ConvertDelegate<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TIl2Cpp>(Delegate @delegate) where TIl2Cpp : Il2CppSystem.Delegate, IIl2CppType { if (@delegate == null) return null; diff --git a/Il2CppInterop.Runtime/Extensions/AssemblyExtensions.cs b/Il2CppInterop.Runtime/Extensions/AssemblyExtensions.cs index 7b04d8da..1c460484 100644 --- a/Il2CppInterop.Runtime/Extensions/AssemblyExtensions.cs +++ b/Il2CppInterop.Runtime/Extensions/AssemblyExtensions.cs @@ -10,7 +10,9 @@ public static Type[] GetTypesSafe(this Assembly assembly) { try { +#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code return assembly.GetTypes(); +#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code } catch (ReflectionTypeLoadException ex) { diff --git a/Il2CppInterop.Runtime/Extensions/INativeMethodInfoStructExtensions.cs b/Il2CppInterop.Runtime/Extensions/INativeMethodInfoStructExtensions.cs index 3f3e79aa..b6ac2a47 100644 --- a/Il2CppInterop.Runtime/Extensions/INativeMethodInfoStructExtensions.cs +++ b/Il2CppInterop.Runtime/Extensions/INativeMethodInfoStructExtensions.cs @@ -27,6 +27,8 @@ public unsafe ReadOnlySpan GetNameSpan() return new ReadOnlySpan((void*)namePtr, length); } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] [return: NotNullIfNotNull(nameof(generatedMethod))] public static unsafe INativeMethodInfoStruct? FromGeneratedMethod(MethodBase? generatedMethod) { diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index cb68c736..58ecaa3d 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using Il2CppInterop.Common; @@ -41,6 +42,7 @@ public static partial class GenerationInternals } } + [RequiresDynamicCode("")] public static Il2CppSystem.Type ManagedTypeToIl2CppType(Type type) { var classPointer = Il2CppType.GetClassPointer(type); @@ -52,6 +54,7 @@ public static Il2CppSystem.Type ManagedTypeToIl2CppType(Type type) return Il2CppSystem.Type.FromClassPointer(classPointer); } + [RequiresDynamicCode("")] public static unsafe Il2CppSystem.TypedReference MakeRefAny(void* value) where T : IIl2CppType { Il2CppSystem.TypedReference result = default; diff --git a/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs b/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs index 5598fc8f..a953a9a7 100644 --- a/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs +++ b/Il2CppInterop.Runtime/Il2CppTypePointerStore.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using Il2CppInterop.Common; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.Structs; @@ -6,6 +7,7 @@ namespace Il2CppInterop.Runtime; internal static class Il2CppTypePointerStore { + [RequiresDynamicCode("")] public static nint GetNativeTypePointer(System.Type type) { if (type == typeof(void)) @@ -22,6 +24,7 @@ internal static unsafe class Il2CppTypePointerStore where T : IIl2CppType { public static nint NativeTypePointer { + [RequiresDynamicCode("")] get { if (field == default) diff --git a/Il2CppInterop.Runtime/Injection/Hook.cs b/Il2CppInterop.Runtime/Injection/Hook.cs index 7168586f..324facac 100644 --- a/Il2CppInterop.Runtime/Injection/Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hook.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Injection.Hooks; @@ -14,6 +15,8 @@ internal static class Hook private static readonly Class_FromIl2CppType_Hook FromIl2CppTypeHook = new(); private static readonly Class_FromName_Hook FromNameHook = new(); + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] internal static void ApplyInjectionHooks() { GetTypeInfoFromTypeDefinitionIndexHook.ApplyHook(); @@ -39,7 +42,11 @@ internal abstract class Hook where T : Delegate public T Original => _original; public abstract string TargetMethodName { get; } + public abstract T GetDetour(); + + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] public abstract IntPtr FindTargetMethod(); public virtual void TargetMethodNotFound() @@ -47,6 +54,8 @@ public virtual void TargetMethodNotFound() throw new Exception($"Required target method {TargetMethodName} not found"); } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] public void ApplyHook() { if (_isApplied) return; diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs index ad5a899f..382e4f01 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.InteropServices; using Il2CppInterop.Common; @@ -38,6 +39,8 @@ internal readonly struct Il2CppType return Original(type, throwOnError); } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] public override IntPtr FindTargetMethod() { var classFromTypeAPI = Il2CppModule.GetExport(nameof(IL2CPP.il2cpp_class_from_il2cpp_type)); diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs index 02f68ade..87d1ee8e 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.InteropServices; using Il2CppInterop.Common; @@ -33,6 +34,8 @@ internal unsafe class Class_FromName_Hook : Hook typeof(Il2CppMethodInfo*), ]; + [RequiresUnreferencedCode("")] internal static Delegate CreateTrampoline(MethodInfo monoMethod, bool callVirt) { Debug.Assert(monoMethod.DeclaringType is not null); diff --git a/Il2CppInterop.Runtime/Injection/TrampolineSignatureHash.cs b/Il2CppInterop.Runtime/Injection/TrampolineSignatureHash.cs index 2831f711..ce76adfb 100644 --- a/Il2CppInterop.Runtime/Injection/TrampolineSignatureHash.cs +++ b/Il2CppInterop.Runtime/Injection/TrampolineSignatureHash.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.IO.Hashing; using System.Reflection; using Il2CppInterop.Runtime.Extensions; @@ -9,6 +10,7 @@ internal readonly record struct TrampolineSignatureHash { private readonly UInt128 _hash; + [RequiresDynamicCode("")] public TrampolineSignatureHash(MethodInfo methodInfo) { XxHash128 hash = new(); diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 6d6e6db4..066bbfcb 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -2,6 +2,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -36,16 +37,21 @@ public static unsafe class TypeInjector /// /// The type to check. /// True if the type is preexisting, false otherwise. + [RequiresDynamicCode("")] public static bool IsPreexistingType(Type type) { return Il2CppType.GetClassPointer(type) is not 0 && !RegisteredTypes.Contains(type); } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] public static void RegisterTypeInIl2Cpp() where T : IIl2CppType { RegisterTypeInIl2Cpp(typeof(T)); } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] private static void RegisterTypeInIl2Cpp(Type type) { if (Il2CppType.GetClassPointer(type) is not 0) @@ -538,12 +544,14 @@ private static int LowestInterfaceOffset(INativeClassStruct classPointer) return result; } - private static Dictionary CreateHashToMethodInfoDictionary(Type type) + [RequiresDynamicCode("")] + private static Dictionary CreateHashToMethodInfoDictionary([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.AllMethods)] Type type) { return GetAllIl2CppMethods(type).ToDictionary(m => new NamedSignatureHash(m)); } - private static Dictionary CreateMethodInfoToHashDictionary(Type type) + [RequiresDynamicCode("")] + private static Dictionary CreateMethodInfoToHashDictionary([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.AllMethods)] Type type) { return GetAllIl2CppMethods(type).ToDictionary(m => m, m => new NamedSignatureHash(m)); } @@ -584,10 +592,22 @@ private static Dictionary CreateNativeMethodInfoToHa return dict; } - private static IEnumerable GetAllIl2CppMethods(Type type) => type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static).Where(IsIl2CppMethod); - private static IEnumerable GetIl2CppMethods(Type type) => type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(IsIl2CppMethod); - private static IEnumerable GetIl2CppProperties(Type type) => type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(IsIl2CppProperty); - private static IEnumerable<(Type FieldType, FieldAttributes Attributes, string Name)> GetIl2CppFields(Type type) + private static IEnumerable GetAllIl2CppMethods([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.AllMethods)] Type type) + { + return type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static).Where(IsIl2CppMethod); + } + + private static IEnumerable GetIl2CppMethods([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type type) + { + return type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(IsIl2CppMethod); + } + + private static IEnumerable GetIl2CppProperties([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] Type type) + { + return type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(IsIl2CppProperty); + } + + private static IEnumerable<(Type FieldType, FieldAttributes Attributes, string Name)> GetIl2CppFields([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] Type type) { List<(Type, FieldAttributes, string)> fields = new(); foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)) @@ -628,12 +648,12 @@ private static Dictionary CreateNativeMethodInfoToHa return fields; } - private static IEnumerable GetIl2CppInstanceFieldTypes(Type type) + private static IEnumerable GetIl2CppInstanceFieldTypes([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] Type type) { return GetIl2CppFields(type).Where(f => !f.Attributes.HasFlag(FieldAttributes.Static)).Select(f => f.FieldType); } - private static void ValidateTypeUsingReflection(Type type) + private static void ValidateTypeUsingReflection([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] Type type) { // Enums are transformed into structs during generation if (type.IsEnum) @@ -694,7 +714,9 @@ private static void ValidateTypeUsingReflection(Type type) // This will throw if the type does not implement IIl2CppType where T is the type itself // because T has a self-referential constraint that cannot be satisfied if the type does not implement the interface correctly. // If https://github.com/dotnet/runtime/issues/28033 is implemented, we can replace this with a more direct check. +#pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. typeof(IIl2CppType<>).MakeGenericType(type); +#pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. } catch { @@ -702,7 +724,8 @@ private static void ValidateTypeUsingReflection(Type type) } } - private static int CalculateVTableUpperBoundUsingReflection(Type type) + [RequiresUnreferencedCode("")] + private static int CalculateVTableUpperBoundUsingReflection([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] Type type) { var count = 0; foreach (var interfaceType in type.GetInterfaces().Where(IsIl2CppInterface)) @@ -721,14 +744,21 @@ private static int CalculateVTableUpperBoundUsingReflection(Type type) } return int.Min(count, ushort.MaxValue); - static int CountIl2CppMethods(Type type) => type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Count(IsIl2CppMethod); + static int CountIl2CppMethods([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type type) + { + return type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Count(IsIl2CppMethod); + } } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] public static void InjectEnumValues(Dictionary valuesToAdd) where TEnum : Il2CppSystem.IEnum { InjectEnumValues(typeof(TEnum), valuesToAdd); } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] public static void InjectEnumValues(Type type, Dictionary valuesToAdd) { ArgumentNullException.ThrowIfNull(type); @@ -805,6 +835,8 @@ static Il2CppSystem.Type TypeFromClassPointer(nint classPointer, string? typeNam } } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] private static void RegisterEnumInIl2Cpp(Type type) { var baseEnum = UnityVersionHandler.Wrap((Il2CppClass*)Il2CppType.GetClassPointer()); @@ -992,6 +1024,8 @@ static void Method(IntPtr obj, Il2CppMethodInfo* methodInfo) } } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] private static Il2CppMethodInfo* ConvertMethodInfo(MethodInfo monoMethod, INativeClassStruct declaringClass) { if (monoMethod.ContainsGenericParameters) @@ -1045,12 +1079,14 @@ static void Method(IntPtr obj, Il2CppMethodInfo* methodInfo) return converted.MethodInfoPointer; } + [RequiresDynamicCode("")] private static Delegate GetOrCreateInvoker(MethodInfo monoMethod) { return InvokerCache.GetOrAdd(new InvokerSignatureHash(monoMethod), static (signatureHash, monoMethodInner) => CreateInvoker(signatureHash, monoMethodInner), monoMethod); } + [RequiresDynamicCode("")] private static Delegate CreateInvoker(InvokerSignatureHash signatureHash, MethodInfo monoMethod) { Debug.Assert(monoMethod.DeclaringType is not null); @@ -1155,6 +1191,8 @@ private static Delegate CreateInvoker(InvokerSignatureHash signatureHash, Method return @delegate; } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] private static Delegate CreateTrampoline(MethodInfo monoMethod, bool callVirt) { var @delegate = TrampolineBuilder.CreateTrampoline(monoMethod, callVirt); @@ -1162,6 +1200,7 @@ private static Delegate CreateTrampoline(MethodInfo monoMethod, bool callVirt) return @delegate; } + [RequiresDynamicCode("")] private static (string AssemblyName, string Namespace, string Name) GetFullyQualifiedName(Type type) { var methodInfo = typeof(TypeInjector).GetMethod(nameof(GetFullyQualifiedNameGeneric), BindingFlags.NonPublic | BindingFlags.Static)!.MakeGenericMethod(type); @@ -1211,14 +1250,15 @@ private static Il2CppMethodFlags MethodAttributesToMethodFlags(MethodAttributes return result; } - private static Type GetEnumUnderlyingType(Type enumType) + private static Type GetEnumUnderlyingType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] Type enumType) { // Single instance field var instanceField = enumType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Single(); return instanceField.FieldType; } - private static (string Name, object Value)[] GetEnumNamesAndValues(Type enumType) + [RequiresUnreferencedCode("")] + private static (string Name, object Value)[] GetEnumNamesAndValues([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] Type enumType) { var fields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static); if (AnyFieldWrongType(enumType, fields)) diff --git a/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs index ba0e1228..16d7df13 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -49,12 +50,16 @@ partial void LogErrorIl2CppFinalize(Exception exception) /// /// The type of the delegate to cast and invoke. /// The dynamic method. - internal static MethodInfo GetOrCreateInvokeMethod(Type delegateType) + [RequiresDynamicCode("")] + internal static MethodInfo GetOrCreateInvokeMethod([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type delegateType) { +#pragma warning disable IL2111 // Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. return _methodInfoCache.GetOrAdd(delegateType, CreateInvokeMethod); +#pragma warning restore IL2111 // Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. } - private static MethodInfo CreateInvokeMethod(Type delegateType) + [RequiresDynamicCode("")] + private static MethodInfo CreateInvokeMethod([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type delegateType) { var delegateInvokeMethod = delegateType.GetMethod("Invoke") ?? throw new InvalidOperationException($"Delegate type {delegateType.FullName} does not have an Invoke method."); diff --git a/Il2CppInterop.Runtime/RuntimeInvoke.cs b/Il2CppInterop.Runtime/RuntimeInvoke.cs index d4a2430e..e5172e32 100644 --- a/Il2CppInterop.Runtime/RuntimeInvoke.cs +++ b/Il2CppInterop.Runtime/RuntimeInvoke.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -100,6 +101,8 @@ private static bool IsValueType() return typeof(T).IsValueType; } + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] public static T ResolveICall(string signature) where T : Delegate { var icallPtr = IL2CPP.il2cpp_resolve_icall(signature); @@ -112,7 +115,8 @@ public static T ResolveICall(string signature) where T : Delegate return GenerateDelegateForICall(icallPtr); } - private static T GenerateDelegateForMissingICall(string signature) where T : Delegate + [RequiresDynamicCode("")] + private static T GenerateDelegateForMissingICall<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(string signature) where T : Delegate { var invoke = typeof(T).GetMethod("Invoke")!; @@ -127,7 +131,9 @@ private static T GenerateDelegateForMissingICall(string signature) where T : return (T)trampoline.CreateDelegate(typeof(T)); } - private static T GenerateDelegateForICall(nint icallPtr) where T : Delegate + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] + private static T GenerateDelegateForICall<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] T>(nint icallPtr) where T : Delegate { var invoke = typeof(T).GetMethod("Invoke")!; diff --git a/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs index a659793f..5d88c819 100644 --- a/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs @@ -56,10 +56,17 @@ static UnityVersionHandler() !t.IsAbstract && interfacesOfInterest.Any(i => i.IsAssignableFrom(t)))) foreach (var startVersion in handlerImpl.GetCustomAttributes()) { +#pragma warning disable IL2072 // Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations. var instance = Activator.CreateInstance(handlerImpl)!; +#pragma warning restore IL2072 // Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations. + +#pragma warning disable IL2075 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations. foreach (var i in handlerImpl.GetInterfaces()) + { if (interfacesOfInterest.Contains(i)) VersionedHandlers[i].Add((UnityVersion.Parse(startVersion.StartVersion), instance)); + } +#pragma warning restore IL2075 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations. } foreach (var handlerList in VersionedHandlers.Values) diff --git a/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj b/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj index 0186908e..a6e97a68 100644 --- a/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj +++ b/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj @@ -3,6 +3,7 @@ netstandard2.0 enable + false true diff --git a/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs b/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs index fdd061a3..92e59925 100644 --- a/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs +++ b/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs @@ -407,7 +407,11 @@ private static void EmitInternalsClass(IndentedTextWriter writer, TypeModel mode writer.WriteLine("{"); writer.Indent++; + writer.WriteLineNoTabs("#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code"); + writer.WriteLineNoTabs("#pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling."); writer.WriteLine($"global::Il2CppInterop.Runtime.Injection.TypeInjector.RegisterTypeInIl2Cpp<{model.TypeName}>();"); + writer.WriteLineNoTabs("#pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling."); + writer.WriteLineNoTabs("#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code"); if (isValueType) { From b83306b68b621ddea7ecb6de3cdb1e7ba45705e1 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 20:37:15 -0700 Subject: [PATCH 455/486] Formatting --- Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs index a54a1674..cff5c28e 100644 --- a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs +++ b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs @@ -237,8 +237,8 @@ public override void Process(ApplicationAnalysisContext appContext, Action - /// - /// + /// + /// /// private static void PolyfillActionFuncDelegates(ApplicationAnalysisContext appContext, out TypeAnalysisContext[] actionTypes, out TypeAnalysisContext[] funcTypes) { From 1c9ef794fb72c1757e8622d670100370cf04d79f Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 21:34:49 -0700 Subject: [PATCH 456/486] Correct documentation for IsInjected property --- .../Extensions/ContextWithDataStorageExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Il2CppInterop.Generator/Extensions/ContextWithDataStorageExtensions.cs b/Il2CppInterop.Generator/Extensions/ContextWithDataStorageExtensions.cs index 7c9ef8ea..c6cf3d70 100644 --- a/Il2CppInterop.Generator/Extensions/ContextWithDataStorageExtensions.cs +++ b/Il2CppInterop.Generator/Extensions/ContextWithDataStorageExtensions.cs @@ -57,7 +57,7 @@ public bool IsUnstripped /// /// /// For memory efficiency, this is only set at the top-level. If a type is injected, its members are not marked as injected, even though they obviously are. - /// For the purpose of this property, nested types are not considered "members" and must be marked as injected separately. + /// For the purpose of this property, nested types are considered "members". /// public bool IsInjected { From 5f5df583488ca0c69b82e771fc5967f169c373ab Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 17 May 2026 21:36:02 -0700 Subject: [PATCH 457/486] Explicit conversion operator from the Il2Cpp delegate type to the managed delegate type --- .../DelegateConversionProcessingLayer.cs | 87 +++++++++++++++---- .../TypeAnalysisContextExtensions.cs | 7 ++ .../UserFriendlyOverloadProcessingLayer.cs | 14 +-- 3 files changed, 83 insertions(+), 25 deletions(-) diff --git a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs index cff5c28e..6655c9ad 100644 --- a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs +++ b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs @@ -70,9 +70,12 @@ public override void Process(ApplicationAnalysisContext appContext, Action(new() + addition.PutExtraData(new() { Instructions = [ @@ -89,9 +92,12 @@ public override void Process(ApplicationAnalysisContext appContext, Action(new() + subtraction.PutExtraData(new() { Instructions = [ @@ -144,6 +150,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action(new() { - Instructions = - [ - new Instruction(CilOpCodes.Ldarg_0), - new Instruction(CilOpCodes.Call, delegateSupportMethod.MakeGenericInstanceMethod(concreteType)), - new Instruction(CilOpCodes.Ret), - ] - }); + var explicitConversion = new InjectedMethodAnalysisContext( + type, + "op_Explicit", + concreteType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, + [managedDelegateType]) + { + IsInjected = true, + }; + type.Methods.Add(explicitConversion); + explicitConversion.PutExtraData(new() + { + Instructions = + [ + new Instruction(CilOpCodes.Ldarg_0), + new Instruction(CilOpCodes.Call, delegateSupportMethod.MakeGenericInstanceMethod(concreteType)), + new Instruction(CilOpCodes.Ret), + ] + }); + } + + // Explicit conversion operator from the Il2Cpp delegate type to the managed delegate type. + { + var explicitConversion = new InjectedMethodAnalysisContext( + type, + "op_Explicit", + managedDelegateType, + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, + [concreteType]) + { + IsInjected = true, + }; + type.Methods.Add(explicitConversion); + + MethodAnalysisContext managedDelegateConstructor; + if (managedDelegateType is GenericInstanceTypeAnalysisContext genericInstance) + { + managedDelegateConstructor = genericInstance.GenericType.Methods.Single(m => m.IsInstanceConstructor).MakeConcreteGenericMethod(genericInstance.GenericArguments, []); + } + else + { + managedDelegateConstructor = managedDelegateType.Methods.Single(m => m.IsInstanceConstructor); + } + + explicitConversion.PutExtraData(new() + { + Instructions = + [ + new Instruction(CilOpCodes.Ldarg_0), + new Instruction(CilOpCodes.Ldftn, invokeMethod.MaybeMakeConcreteGeneric(type.GenericParameters, [])), + new Instruction(CilOpCodes.Newobj, managedDelegateConstructor), + new Instruction(CilOpCodes.Ret), + ] + }); + } } } } diff --git a/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs b/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs index b846af39..2dfe2491 100644 --- a/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs +++ b/Il2CppInterop.Generator/Extensions/TypeAnalysisContextExtensions.cs @@ -117,6 +117,13 @@ public List StaticConstructorInstructions set => type.PutExtraData("StaticConstructorInstructions", value); } + [MaybeNull] + public TypeAnalysisContext ManagedDelegateType + { + get => type.GetExtraData("ManagedDelegateType"); + set => type.PutExtraData("ManagedDelegateType", value); + } + public KnownTypeCode KnownType { get => type.GetExtraStruct("KnownType", KnownTypeCode.None); diff --git a/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs b/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs index ff19d422..826e3e27 100644 --- a/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs +++ b/Il2CppInterop.Generator/UserFriendlyOverloadProcessingLayer.cs @@ -98,7 +98,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action to T[] + // Change Il2CppArrayBase to T[] if (parameter.ParameterType is GenericInstanceTypeAnalysisContext { GenericType: { Namespace: ArrayNamespace, Name: ArrayClassName }, GenericArguments: [var elementType] }) { parameterTypes[i] = visitor.Replace(elementType).MakeSzArrayType(); @@ -107,7 +107,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action m.Name == "op_Explicit") + var managedDelegateType = genericInstance.GenericType.ManagedDelegateType; + explicitConversionMethod = genericInstance.GenericType.Methods.SingleOrDefault(m => m.Name == "op_Explicit" && m.Parameters[0].ParameterType == managedDelegateType) ?.MakeConcreteGeneric(genericInstance.GenericArguments, []); } else { - explicitConversionMethod = parameter.ParameterType.Methods.SingleOrDefault(m => m.Name == "op_Explicit"); + var managedDelegateType = parameter.ParameterType.ManagedDelegateType; + explicitConversionMethod = parameter.ParameterType.Methods.SingleOrDefault(m => m.Name == "op_Explicit" && m.Parameters[0].ParameterType == managedDelegateType); } if (explicitConversionMethod is not null) { @@ -139,7 +141,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action Date: Sun, 17 May 2026 21:46:29 -0700 Subject: [PATCH 458/486] Update NuGet package versions across projects Bump Microsoft.Extensions.Logging, System.IO.Hashing, and Basic.Reference.Assemblies.Net100 to latest patch versions in relevant project files. No functional or logic changes included. --- Il2CppInterop.CLI/Il2CppInterop.CLI.csproj | 4 ++-- Il2CppInterop.Common/Il2CppInterop.Common.csproj | 2 +- Il2CppInterop.Generator/Il2CppInterop.Generator.csproj | 2 +- Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj | 2 +- .../Il2CppInterop.StructGenerator.csproj | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj b/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj index 42915d9c..acf4371b 100644 --- a/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj +++ b/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj @@ -17,8 +17,8 @@ - - + + diff --git a/Il2CppInterop.Common/Il2CppInterop.Common.csproj b/Il2CppInterop.Common/Il2CppInterop.Common.csproj index 02380625..2ffa912e 100644 --- a/Il2CppInterop.Common/Il2CppInterop.Common.csproj +++ b/Il2CppInterop.Common/Il2CppInterop.Common.csproj @@ -9,7 +9,7 @@ - + diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index 4f9acaae..76893b48 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -9,7 +9,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj index 62af594b..dced718d 100644 --- a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj +++ b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj @@ -16,7 +16,7 @@ - + diff --git a/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj b/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj index 5414d78b..80583e0f 100644 --- a/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj +++ b/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj @@ -10,7 +10,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 006e8812c99aae40fe1e81f79a34b0d8058959ae Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Mon, 18 May 2026 23:59:18 -0700 Subject: [PATCH 459/486] Use injected interfaces in SystemInterfaceProcessingLayer --- .../SystemInterfaceProcessingLayer.cs | 66 ++++++++++++++++--- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs b/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs index 93f7c5c4..bcdb6674 100644 --- a/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs +++ b/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs @@ -19,11 +19,58 @@ public sealed class SystemInterfaceProcessingLayer : Cpp2IlProcessingLayer public override string Id => "system_interface_implementations"; public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { + // The reason we inject some new interfaces instead of just adding methods to the existing Il2Cpp interfaces is partially because + // `Il2CppSystem.Runtime.CompilerServices.ICriticalNotifyCompletion` does not always inherit from + // `Il2CppSystem.Runtime.CompilerServices.INotifyCompletion`, even though `System.Runtime.CompilerServices.ICriticalNotifyCompletion` + // always inherits from `System.Runtime.CompilerServices.INotifyCompletion`. + // Without these injected interfaces, types that implement `Il2CppSystem.Runtime.CompilerServices.ICriticalNotifyCompletion` + // cause a TypeLoadException if they do not also implement `Il2CppSystem.Runtime.CompilerServices.INotifyCompletion`. + // The TypeLoadException would come from `System.Runtime.CompilerServices.INotifyCompletion::OnCompleted` not being implemented. + + // Injected interfaces circumvent this issue by: + // * Recreating the entire interface hierarchy of the system interfaces in a new namespace (`Il2CppInterop.SystemInterfaces`) + // * Implementing the system interfaces on the injected interfaces + // * Making the Il2Cpp interfaces inherit from the injected interfaces instead of the system interfaces + var pairs = FindPairs(appContext); + // Create interfaces in Il2CppInterop.SystemInterfaces + var systemToInjectedMap = new Dictionary(); + foreach ((_, var systemInterface) in pairs) + { + var injectedInterface = appContext.Il2CppMscorlib.InjectType( + "Il2CppInterop.SystemInterfaces", + systemInterface.Name, + null, + TypeAttributes.NotPublic | TypeAttributes.Interface | TypeAttributes.Abstract); + injectedInterface.CopyGenericParameters(systemInterface, true); + injectedInterface.InterfaceContexts.Add(systemInterface.MaybeMakeGenericInstanceType(injectedInterface.GenericParameters)); + + systemToInjectedMap[systemInterface] = injectedInterface; + + // Add generic parameters to the dictionary too + for (var i = 0; i < systemInterface.GenericParameters.Count; i++) + { + systemToInjectedMap[systemInterface.GenericParameters[i]] = injectedInterface.GenericParameters[i]; + } + } + + // Assign inheritance to the injected interfaces + { + var visitor = new TypeReplacementVisitor(systemToInjectedMap); + foreach ((_, var systemInterface) in pairs) + { + var injectedInterface = systemToInjectedMap[systemInterface]; + foreach (var systemBaseInterface in systemInterface.InterfaceContexts) + { + injectedInterface.InterfaceContexts.Add(visitor.Replace(systemBaseInterface)); + } + } + } + foreach (var (il2CppInterface, systemInterface) in pairs) { - ImplementInterface(il2CppInterface, systemInterface); + ImplementInterface(il2CppInterface, systemToInjectedMap[systemInterface], systemInterface); } } @@ -59,10 +106,8 @@ static bool IsPublic(TypeAnalysisContext? type) } } - private static void ImplementInterface(TypeAnalysisContext il2CppInterface, TypeAnalysisContext systemInterface) + private static void ImplementInterface(TypeAnalysisContext il2CppInterface, TypeAnalysisContext injectedInterface, TypeAnalysisContext systemInterface) { - il2CppInterface.InterfaceContexts.Add(systemInterface.MaybeMakeGenericInstanceType(il2CppInterface.GenericParameters)); - foreach (var systemMethod in systemInterface.Methods) { if (systemMethod.IsStatic) @@ -71,11 +116,11 @@ private static void ImplementInterface(TypeAnalysisContext il2CppInterface, Type } var attributes = (systemMethod.Attributes & ~(MethodAttributes.Abstract | MethodAttributes.MemberAccessMask)) | MethodAttributes.Private | MethodAttributes.Final | MethodAttributes.NewSlot; - var injectedMethod = new InjectedMethodAnalysisContext(il2CppInterface, $"{systemInterface.FullName}.{systemMethod.Name}", systemMethod.ReturnType, attributes, []) + var injectedMethod = new InjectedMethodAnalysisContext(injectedInterface, $"{systemInterface.FullName}.{systemMethod.Name}", systemMethod.ReturnType, attributes, []) { IsInjected = true, }; - il2CppInterface.Methods.Add(injectedMethod); + injectedInterface.Methods.Add(injectedMethod); injectedMethod.CopyGenericParameters(systemMethod, true); @@ -88,7 +133,7 @@ private static void ImplementInterface(TypeAnalysisContext il2CppInterface, Type injectedMethod.Parameters.Add(new InjectedParameterAnalysisContext(parameter.Name, visitor.Replace(parameter.ParameterType), parameter.Attributes, parameter.ParameterIndex, injectedMethod)); } - injectedMethod.Overrides.Add(systemMethod.MaybeMakeConcreteGeneric(il2CppInterface.GenericParameters, injectedMethod.GenericParameters)); + injectedMethod.Overrides.Add(systemMethod.MaybeMakeConcreteGeneric(injectedInterface.GenericParameters, injectedMethod.GenericParameters)); var il2CppMethod = FindIl2CppMethod(il2CppInterface, systemMethod.Name, injectedMethod, out var returnConversion, out var parameterConversions); @@ -107,13 +152,14 @@ private static void ImplementInterface(TypeAnalysisContext il2CppInterface, Type List instructions = []; instructions.Add(CilOpCodes.Ldarg_0); + instructions.Add(CilOpCodes.Castclass, il2CppInterface.MaybeMakeGenericInstanceType(injectedInterface.GenericParameters)); for (var i = 0; i < injectedMethod.Parameters.Count; i++) { var parameter = injectedMethod.Parameters[i]; instructions.Add(CilOpCodes.Ldarg, parameter); parameterConversions[i].Add(instructions); } - instructions.Add(CilOpCodes.Callvirt, il2CppMethod.MaybeMakeConcreteGeneric(il2CppInterface.GenericParameters, injectedMethod.GenericParameters)); + instructions.Add(CilOpCodes.Callvirt, il2CppMethod.MaybeMakeConcreteGeneric(injectedInterface.GenericParameters, injectedMethod.GenericParameters)); returnConversion.Add(instructions); instructions.Add(CilOpCodes.Ret); @@ -122,6 +168,10 @@ private static void ImplementInterface(TypeAnalysisContext il2CppInterface, Type Instructions = instructions }); } + + // Make the Il2Cpp interface inherit from the injected interface + Debug.Assert(il2CppInterface.GenericParameters.Count == injectedInterface.GenericParameters.Count); + il2CppInterface.InterfaceContexts.Add(injectedInterface.MaybeMakeGenericInstanceType(il2CppInterface.GenericParameters)); } private static MethodAnalysisContext? FindIl2CppMethod(TypeAnalysisContext il2CppInterface, string methodName, MethodAnalysisContext injectedMethod, out Conversion returnConversion, out Conversion[] parameterConversions) From ca2af476446da7512d0bef6a2f211f7e4650a649 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Tue, 16 Jun 2026 12:26:05 -0700 Subject: [PATCH 460/486] Include Il2Cppmscorlib.dll in NuGet package build Switched to single-target net10.0. Added logic to pack Il2Cppmscorlib.dll into the NuGet package, with paths based on build configuration. Ensured Il2Cppmscorlib is built before packaging by adding a pre-pack MSBuild target. --- .../Il2CppInterop.Generator.csproj | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index 76893b48..3f8d2605 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -3,7 +3,7 @@ Il2CppInterop.Generator Library for generating assemblies and metadata for calling Il2Cpp functions from .NET - net10.0 + net10.0 true @@ -21,4 +21,17 @@ + + + + + + + + + + + + + From 8236f88e5e5a49d74a9ba54c09976645fb033c51 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:56:43 -0700 Subject: [PATCH 461/486] Update package versions: Cpp2IL.Core and PolySharp Updated AssetRipper.Cpp2IL.Core to 1.0.6 and PolySharp to 1.16.0 for improved compatibility and features. --- Il2CppInterop.Generator/Il2CppInterop.Generator.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index 3f8d2605..3d634853 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -8,9 +8,9 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive From b45c79da77d72834aaaaf7f2a99fe7d51e56b431 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 20 Jun 2026 23:01:14 -0700 Subject: [PATCH 462/486] Fix source generator output for structs --- .../{ => Generation}/InjectedClassTests.cs | 2 +- .../Generation/InjectedStructTests.cs | 279 ++++++++++++++++++ .../SimpleAnalyzerTests.cs | 25 -- .../InjectedTypeGenerator.cs | 17 +- Il2CppInterop.SourceGenerator/TypeModel.cs | 5 +- 5 files changed, 297 insertions(+), 31 deletions(-) rename Il2CppInterop.SourceGenerator.Tests/{ => Generation}/InjectedClassTests.cs (97%) create mode 100644 Il2CppInterop.SourceGenerator.Tests/Generation/InjectedStructTests.cs delete mode 100644 Il2CppInterop.SourceGenerator.Tests/SimpleAnalyzerTests.cs diff --git a/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs b/Il2CppInterop.SourceGenerator.Tests/Generation/InjectedClassTests.cs similarity index 97% rename from Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs rename to Il2CppInterop.SourceGenerator.Tests/Generation/InjectedClassTests.cs index 44fffbfe..72788bce 100644 --- a/Il2CppInterop.SourceGenerator.Tests/InjectedClassTests.cs +++ b/Il2CppInterop.SourceGenerator.Tests/Generation/InjectedClassTests.cs @@ -1,4 +1,4 @@ -namespace Il2CppInterop.SourceGenerator.Tests; +namespace Il2CppInterop.SourceGenerator.Tests.Generation; public class InjectedClassTests : SourceGenerationTests { diff --git a/Il2CppInterop.SourceGenerator.Tests/Generation/InjectedStructTests.cs b/Il2CppInterop.SourceGenerator.Tests/Generation/InjectedStructTests.cs new file mode 100644 index 00000000..c6f3dd89 --- /dev/null +++ b/Il2CppInterop.SourceGenerator.Tests/Generation/InjectedStructTests.cs @@ -0,0 +1,279 @@ +namespace Il2CppInterop.SourceGenerator.Tests.Generation; + +public class InjectedStructTests : SourceGenerationTests +{ + [Test] + public Task StructWithNoMembers() + { + var testCode = """ + using Il2CppInterop.Common.Attributes; + + [InjectedType] + public partial struct Sample + { + } + """; + + var expectedGeneratedCode = """ + // + #nullable enable + + [global::Il2CppInterop.Common.Attributes.Il2CppType(typeof(Il2CppInternals))] + public partial struct Sample : + global::Il2CppSystem.IValueType, + global::Il2CppInterop.Common.IIl2CppType + { + [global::Il2CppInterop.Common.Attributes.Il2CppMethod] + public global::Il2CppSystem.Boolean Equals(global::Il2CppSystem.IObject obj) + { + return this.Equals((object)obj); + } + + [global::Il2CppInterop.Common.Attributes.Il2CppMethod(Name = "GetHashCode")] + public global::Il2CppSystem.Int32 GetIl2CppHashCode() + { + return this.GetHashCode(); + } + + [global::Il2CppInterop.Common.Attributes.Il2CppMethod(Name = "ToString")] + public global::Il2CppSystem.String ToIl2CppString() + { + return this.ToString(); + } + + nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Common.Il2CppType.GetClassPointer(); + + readonly global::Il2CppInterop.Common.ObjectPointer global::Il2CppInterop.Common.IIl2CppType.BoxNative() => global::Il2CppInterop.Runtime.NativeBoxing.BoxValueType(in this); + + static int global::Il2CppInterop.Common.IIl2CppType.Size => Il2CppInternals.Size; + + static Sample global::Il2CppInterop.Common.IIl2CppType.ReadFromSpan(global::System.ReadOnlySpan span) + { + #nullable disable + return new Sample + { + }; + #nullable restore + } + + static void global::Il2CppInterop.Common.IIl2CppType.WriteToSpan(Sample value, global::System.Span span) + { + } + + static Sample() + { + global::System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(Il2CppInternals).TypeHandle); + } + } + + file static class Il2CppInternals + { + public static readonly int Size; + + static Il2CppInternals() + { + #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + #pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. + global::Il2CppInterop.Runtime.Injection.TypeInjector.RegisterTypeInIl2Cpp(); + #pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. + #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + Size = global::Il2CppInterop.Common.IL2CPP.il2cpp_class_value_size(global::Il2CppInterop.Common.Il2CppType.GetClassPointer(), out _); + } + } + + """; + + return TestGeneration(testCode, "Sample.g.cs", expectedGeneratedCode); + } + + [Test] + public Task StructContainingPrimitiveFieldsWithAttributes() + { + var testCode = """ + using Il2CppInterop.Common.Attributes; + + [InjectedType] + public partial struct Sample + { + [Il2CppField] + public Il2CppSystem.Int32 intValue; + [Il2CppField] + public Il2CppSystem.String stringValue; + } + """; + + var expectedGeneratedCode = """ + // + #nullable enable + + [global::Il2CppInterop.Common.Attributes.Il2CppType(typeof(Il2CppInternals))] + public partial struct Sample : + global::Il2CppSystem.IValueType, + global::Il2CppInterop.Common.IIl2CppType + { + [global::Il2CppInterop.Common.Attributes.Il2CppMethod] + public global::Il2CppSystem.Boolean Equals(global::Il2CppSystem.IObject obj) + { + return this.Equals((object)obj); + } + + [global::Il2CppInterop.Common.Attributes.Il2CppMethod(Name = "GetHashCode")] + public global::Il2CppSystem.Int32 GetIl2CppHashCode() + { + return this.GetHashCode(); + } + + [global::Il2CppInterop.Common.Attributes.Il2CppMethod(Name = "ToString")] + public global::Il2CppSystem.String ToIl2CppString() + { + return this.ToString(); + } + + nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Common.Il2CppType.GetClassPointer(); + + readonly global::Il2CppInterop.Common.ObjectPointer global::Il2CppInterop.Common.IIl2CppType.BoxNative() => global::Il2CppInterop.Runtime.NativeBoxing.BoxValueType(in this); + + static int global::Il2CppInterop.Common.IIl2CppType.Size => Il2CppInternals.Size; + + static Sample global::Il2CppInterop.Common.IIl2CppType.ReadFromSpan(global::System.ReadOnlySpan span) + { + #nullable disable + return new Sample + { + intValue = global::Il2CppInterop.Common.Il2CppType.ReadFromSpanAtOffset(span, Il2CppInternals.FieldOffset_0), + stringValue = global::Il2CppInterop.Common.Il2CppType.ReadFromSpanAtOffset(span, Il2CppInternals.FieldOffset_1), + }; + #nullable restore + } + + static void global::Il2CppInterop.Common.IIl2CppType.WriteToSpan(Sample value, global::System.Span span) + { + global::Il2CppInterop.Common.Il2CppType.WriteToSpanAtOffset(value.intValue, span, Il2CppInternals.FieldOffset_0); + global::Il2CppInterop.Common.Il2CppType.WriteToSpanAtOffset(value.stringValue, span, Il2CppInternals.FieldOffset_1); + } + + static Sample() + { + global::System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(Il2CppInternals).TypeHandle); + } + } + + file static class Il2CppInternals + { + public static readonly int Size; + public static readonly int FieldOffset_0; // intValue + public static readonly int FieldOffset_1; // stringValue + + static Il2CppInternals() + { + #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + #pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. + global::Il2CppInterop.Runtime.Injection.TypeInjector.RegisterTypeInIl2Cpp(); + #pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. + #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + Size = global::Il2CppInterop.Common.IL2CPP.il2cpp_class_value_size(global::Il2CppInterop.Common.Il2CppType.GetClassPointer(), out _); + FieldOffset_0 = global::Il2CppInterop.Runtime.FieldAccess.GetFieldOffset(global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Common.Il2CppType.GetClassPointer(), "intValue")); + FieldOffset_1 = global::Il2CppInterop.Runtime.FieldAccess.GetFieldOffset(global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Common.Il2CppType.GetClassPointer(), "stringValue")); + } + } + + """; + + return TestGeneration(testCode, "Sample.g.cs", expectedGeneratedCode); + } + + [Test] + public Task StructContainingPrimitiveFieldsWithoutAttributes() + { + // Il2CppField attributes are optional for instance struct fields + var testCode = """ + using Il2CppInterop.Common.Attributes; + + [InjectedType] + public partial struct Sample + { + public Il2CppSystem.Int32 intValue; + public Il2CppSystem.String stringValue; + } + """; + + var expectedGeneratedCode = """ + // + #nullable enable + + [global::Il2CppInterop.Common.Attributes.Il2CppType(typeof(Il2CppInternals))] + public partial struct Sample : + global::Il2CppSystem.IValueType, + global::Il2CppInterop.Common.IIl2CppType + { + [global::Il2CppInterop.Common.Attributes.Il2CppMethod] + public global::Il2CppSystem.Boolean Equals(global::Il2CppSystem.IObject obj) + { + return this.Equals((object)obj); + } + + [global::Il2CppInterop.Common.Attributes.Il2CppMethod(Name = "GetHashCode")] + public global::Il2CppSystem.Int32 GetIl2CppHashCode() + { + return this.GetHashCode(); + } + + [global::Il2CppInterop.Common.Attributes.Il2CppMethod(Name = "ToString")] + public global::Il2CppSystem.String ToIl2CppString() + { + return this.ToString(); + } + + nint global::Il2CppInterop.Common.IIl2CppType.ObjectClass => global::Il2CppInterop.Common.Il2CppType.GetClassPointer(); + + readonly global::Il2CppInterop.Common.ObjectPointer global::Il2CppInterop.Common.IIl2CppType.BoxNative() => global::Il2CppInterop.Runtime.NativeBoxing.BoxValueType(in this); + + static int global::Il2CppInterop.Common.IIl2CppType.Size => Il2CppInternals.Size; + + static Sample global::Il2CppInterop.Common.IIl2CppType.ReadFromSpan(global::System.ReadOnlySpan span) + { + #nullable disable + return new Sample + { + intValue = global::Il2CppInterop.Common.Il2CppType.ReadFromSpanAtOffset(span, Il2CppInternals.FieldOffset_0), + stringValue = global::Il2CppInterop.Common.Il2CppType.ReadFromSpanAtOffset(span, Il2CppInternals.FieldOffset_1), + }; + #nullable restore + } + + static void global::Il2CppInterop.Common.IIl2CppType.WriteToSpan(Sample value, global::System.Span span) + { + global::Il2CppInterop.Common.Il2CppType.WriteToSpanAtOffset(value.intValue, span, Il2CppInternals.FieldOffset_0); + global::Il2CppInterop.Common.Il2CppType.WriteToSpanAtOffset(value.stringValue, span, Il2CppInternals.FieldOffset_1); + } + + static Sample() + { + global::System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(Il2CppInternals).TypeHandle); + } + } + + file static class Il2CppInternals + { + public static readonly int Size; + public static readonly int FieldOffset_0; // intValue + public static readonly int FieldOffset_1; // stringValue + + static Il2CppInternals() + { + #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + #pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. + global::Il2CppInterop.Runtime.Injection.TypeInjector.RegisterTypeInIl2Cpp(); + #pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. + #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + Size = global::Il2CppInterop.Common.IL2CPP.il2cpp_class_value_size(global::Il2CppInterop.Common.Il2CppType.GetClassPointer(), out _); + FieldOffset_0 = global::Il2CppInterop.Runtime.FieldAccess.GetFieldOffset(global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Common.Il2CppType.GetClassPointer(), "intValue")); + FieldOffset_1 = global::Il2CppInterop.Runtime.FieldAccess.GetFieldOffset(global::Il2CppInterop.Runtime.FieldAccess.GetFieldInfo(global::Il2CppInterop.Common.Il2CppType.GetClassPointer(), "stringValue")); + } + } + + """; + + return TestGeneration(testCode, "Sample.g.cs", expectedGeneratedCode); + } +} diff --git a/Il2CppInterop.SourceGenerator.Tests/SimpleAnalyzerTests.cs b/Il2CppInterop.SourceGenerator.Tests/SimpleAnalyzerTests.cs deleted file mode 100644 index e1f78a72..00000000 --- a/Il2CppInterop.SourceGenerator.Tests/SimpleAnalyzerTests.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Text; - -namespace Il2CppInterop.SourceGenerator.Tests; - -public class SimpleAnalyzerTests : AnalyzerTests -{ - [Test] - public Task TypeNotPartial() - { - var testCode = """ - using Il2CppInterop.Common.Attributes; - [InjectedType] - public class Sample : Il2CppSystem.Object - { - } - """; - - var expectedDiagnostic = new DiagnosticResult(InjectedTypeAnalyzer.MustBePartial) - .WithSpan(LinePositionSpan.FindInSource(testCode, "Sample")) - .WithArguments("Sample"); - - return TestDiagnostic(testCode, expectedDiagnostic); - } -} diff --git a/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs b/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs index 92e59925..a4386ed9 100644 --- a/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs +++ b/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs @@ -109,11 +109,22 @@ private static void EmitPartialType(IndentedTextWriter writer, TypeModel model) foreach (var member in model.Members) { if (member.IsStatic) + { EmitStaticIl2CppProperty(writer, member); + } + else if (model.TypeKind == TypeKind.Struct) + { + // It is an error to use [Il2CppField] on an instance property of a value type. + continue; + } else if (member.Kind == MemberKind.Il2Cpp) + { EmitIl2CppProperty(writer, member); + } else + { EmitManagedProperty(writer, member); + } writer.WriteLineNoTabs(); } @@ -304,10 +315,8 @@ private static void EmitInterfaceMembers(IndentedTextWriter writer, TypeModel mo if (model.TypeKind == TypeKind.Struct) { // BoxNative - writer.WriteLine("readonly global::Il2CppInterop.Common.ObjectPointer global::Il2CppInterop.Common.IIl2CppType.BoxNative() =>"); - writer.Indent++; - writer.WriteLine($"global::Il2CppInterop.Runtime.NativeBoxing.BoxValueType<{typeName}>(in this);"); - writer.Indent--; + writer.WriteLine($"readonly global::Il2CppInterop.Common.ObjectPointer global::Il2CppInterop.Common.IIl2CppType.BoxNative() => global::Il2CppInterop.Runtime.NativeBoxing.BoxValueType<{typeName}>(in this);"); + writer.WriteLineNoTabs(); // Size writer.WriteLine($"static int global::Il2CppInterop.Common.IIl2CppType<{typeName}>.Size => Il2CppInternals.Size;"); diff --git a/Il2CppInterop.SourceGenerator/TypeModel.cs b/Il2CppInterop.SourceGenerator/TypeModel.cs index 2fc8efe1..195d636f 100644 --- a/Il2CppInterop.SourceGenerator/TypeModel.cs +++ b/Il2CppInterop.SourceGenerator/TypeModel.cs @@ -40,8 +40,11 @@ bool IsAbstract ct.ThrowIfCancellationRequested(); var attrs = field.GetAttributes(); - if (!attrs.Any(a => a.AttributeClass.IsType("Il2CppFieldAttribute", ["Il2CppInterop", "Common", "Attributes"]))) + if (field.IsStatic && !attrs.Any(a => a.AttributeClass.IsType("Il2CppFieldAttribute", ["Il2CppInterop", "Common", "Attributes"]))) + { + // Il2CppFieldAttribute is required for static fields, but not for instance fields. continue; + } members.Add(new MemberModel( Name: field.Name, From b6fdd263bad14ac47b78701fd170251dc0c42cdc Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 20 Jun 2026 23:20:02 -0700 Subject: [PATCH 463/486] Fix incorrect warning for fields in injected structs --- .../AnalyzerTests.cs | 6 + .../Diagnostics/PartialTypeAnalyzerTests.cs | 42 +++++++ .../UninjectedInstanceFieldAnalyzerTests.cs | 106 ++++++++++++++++++ .../InjectedTypeAnalyzer.cs | 22 ++-- 4 files changed, 168 insertions(+), 8 deletions(-) create mode 100644 Il2CppInterop.SourceGenerator.Tests/Diagnostics/PartialTypeAnalyzerTests.cs create mode 100644 Il2CppInterop.SourceGenerator.Tests/Diagnostics/UninjectedInstanceFieldAnalyzerTests.cs diff --git a/Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs b/Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs index bb437a67..a349145e 100644 --- a/Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs +++ b/Il2CppInterop.SourceGenerator.Tests/AnalyzerTests.cs @@ -34,4 +34,10 @@ protected async Task TestDiagnostics(string testCode, params IEnumerable +/// Tests for the diagnostic, which is raised when a type marked with [InjectedType] is not also marked as partial. +/// +public class PartialTypeAnalyzerTests : AnalyzerTests +{ + [Test] + public Task DiagnosticWhenTypeNotPartial() + { + var testCode = """ + using Il2CppInterop.Common.Attributes; + [InjectedType] + public class Sample : Il2CppSystem.Object + { + } + """; + + var expectedDiagnostic = new DiagnosticResult(InjectedTypeAnalyzer.MustBePartial) + .WithSpan(LinePositionSpan.FindInSource(testCode, "Sample")) + .WithArguments("Sample"); + + return TestDiagnostic(testCode, expectedDiagnostic); + } + + [Test] + public Task NoDiagnosticsWhenTypeIsCorrectlyMarkedPartial() + { + var testCode = """ + using Il2CppInterop.Common.Attributes; + [InjectedType] + public partial class Sample : Il2CppSystem.Object + { + } + """; + + return TestNoDiagnostics(testCode); + } +} diff --git a/Il2CppInterop.SourceGenerator.Tests/Diagnostics/UninjectedInstanceFieldAnalyzerTests.cs b/Il2CppInterop.SourceGenerator.Tests/Diagnostics/UninjectedInstanceFieldAnalyzerTests.cs new file mode 100644 index 00000000..62692ea6 --- /dev/null +++ b/Il2CppInterop.SourceGenerator.Tests/Diagnostics/UninjectedInstanceFieldAnalyzerTests.cs @@ -0,0 +1,106 @@ +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; + +namespace Il2CppInterop.SourceGenerator.Tests.Diagnostics; + +/// +/// Tests for the diagnostic, which is raised when a struct marked with [InjectedType] contains instance fields that are not marked with [Il2CppField]. +/// +public class UninjectedInstanceFieldAnalyzerTests : AnalyzerTests +{ + [Test] + public Task NoDiagnosticsForClassContainingNoInstanceFields() + { + var testCode = """ + using Il2CppInterop.Common.Attributes; + [InjectedType] + public partial class Sample : Il2CppSystem.Object + { + } + """; + + return TestNoDiagnostics(testCode); + } + + [Test] + public Task NoDiagnosticsForClassContainingStaticField() + { + var testCode = """ + using Il2CppInterop.Common.Attributes; + [InjectedType] + public partial class Sample : Il2CppSystem.Object + { + public static int value; + } + """; + + return TestNoDiagnostics(testCode); + } + + [Test] + public Task DiagnosticForClassContainingUninjectedInstanceField() + { + var testCode = """ + using Il2CppInterop.Common.Attributes; + [InjectedType] + public partial class Sample : Il2CppSystem.Object + { + public int value; + } + """; + + var expectedDiagnostic = new DiagnosticResult(InjectedTypeAnalyzer.ShouldNotHaveUninjectedInstanceFields) + .WithSpan(LinePositionSpan.FindInSource(testCode, "value")) + .WithArguments("Sample", "value"); + + return TestDiagnostic(testCode, expectedDiagnostic); + } + + [Test] + public Task NoDiagnosticsForStructContainingNoInstanceFields() + { + var testCode = """ + using Il2CppInterop.Common.Attributes; + [InjectedType] + public partial struct Sample + { + } + """; + + return TestNoDiagnostics(testCode); + } + + [Test] + public Task NoDiagnosticsForStructContainingInstanceFieldsWithIl2CppFieldAttributes() + { + var testCode = """ + using Il2CppInterop.Common.Attributes; + [InjectedType] + public partial struct Sample + { + [Il2CppField] + public Il2CppSystem.Int32 intValue; + [Il2CppField] + public Il2CppSystem.String stringValue; + } + """; + + return TestNoDiagnostics(testCode); + } + + [Test] + public Task NoDiagnosticsForStructContainingInstanceFieldsWithoutIl2CppFieldAttributes() + { + var testCode = """ + using Il2CppInterop.Common.Attributes; + [InjectedType] + public partial struct Sample + { + public Il2CppSystem.Int32 intValue; + public Il2CppSystem.String stringValue; + } + """; + + return TestNoDiagnostics(testCode); + } +} diff --git a/Il2CppInterop.SourceGenerator/InjectedTypeAnalyzer.cs b/Il2CppInterop.SourceGenerator/InjectedTypeAnalyzer.cs index 604b83c5..8d468c88 100644 --- a/Il2CppInterop.SourceGenerator/InjectedTypeAnalyzer.cs +++ b/Il2CppInterop.SourceGenerator/InjectedTypeAnalyzer.cs @@ -394,16 +394,22 @@ private static void CheckFieldPropertiesMustBePartial( private static void CheckNoUninjectedInstanceMembers( SyntaxNodeAnalysisContext context, TypeDeclarationSyntax tds, INamedTypeSymbol symbol) { - foreach (var field in tds.Members.OfType() - .Where(f => !f.Modifiers.Any(SyntaxKind.StaticKeyword))) + // Instance fields in structs are automatically injected, so we don't need to check for them. + if (tds is not StructDeclarationSyntax) { - foreach (var variable in field.Declaration.Variables) + foreach (var field in tds.Members.OfType()) { - context.ReportDiagnostic(Diagnostic.Create( - ShouldNotHaveUninjectedInstanceFields, - variable.Identifier.GetLocation(), - symbol.Name, - variable.Identifier.Text)); + if (field.Modifiers.Any(SyntaxKind.StaticKeyword)) + continue; + + foreach (var variable in field.Declaration.Variables) + { + context.ReportDiagnostic(Diagnostic.Create( + ShouldNotHaveUninjectedInstanceFields, + variable.Identifier.GetLocation(), + symbol.Name, + variable.Identifier.Text)); + } } } } From eafedbfa1a296b4b55f405455cee00d93a5426c9 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 21 Jun 2026 00:36:55 -0700 Subject: [PATCH 464/486] Make internal calls more intuitive and efficient --- .../InitializationClassProcessingLayer.cs | 5 +- .../MethodInvokerProcessingLayer.cs | 222 +++++++++++------- .../NativeMethodBodyProcessingLayer.cs | 26 +- Il2CppInterop.Runtime/RuntimeInvoke.cs | 10 +- 4 files changed, 151 insertions(+), 112 deletions(-) diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index f89c19ed..b3c70ce2 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -359,16 +359,15 @@ public override void Process(ApplicationAnalysisContext appContext, Action parameterTypes; IEnumerable parameterNames; - // Wrap parameters in ByReference<> to align with NativeMethodBodyProcessingLayer if (method.IsStatic) { - parameterTypes = method.Parameters.Select(p => byReference.MakeGenericInstanceType([p.ParameterType])); + parameterTypes = method.Parameters.Select(p => p.ParameterType); parameterNames = Enumerable.Range(0, method.Parameters.Count).Select(i => $"param_{i}"); } else { var thisParameterType = type.IsValueType ? byReference.MakeGenericInstanceType([type]) : type; - parameterTypes = method.Parameters.Select(p => byReference.MakeGenericInstanceType([p.ParameterType])).Prepend(thisParameterType); + parameterTypes = method.Parameters.Select(p => p.ParameterType).Prepend(thisParameterType); parameterNames = Enumerable.Range(0, method.Parameters.Count).Select(i => $"param_{i}").Prepend("this"); } diff --git a/Il2CppInterop.Generator/MethodInvokerProcessingLayer.cs b/Il2CppInterop.Generator/MethodInvokerProcessingLayer.cs index 8fa05a47..fe9017e5 100644 --- a/Il2CppInterop.Generator/MethodInvokerProcessingLayer.cs +++ b/Il2CppInterop.Generator/MethodInvokerProcessingLayer.cs @@ -67,54 +67,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action instantiatedType, }; - InjectedMethodAnalysisContext implementationMethod; - { - var name = GetNonConflictingName(method.IsInstanceConstructor ? "UnsafeConstructor" : $"UnsafeImplementation_{method.Name.Replace('.', '_')}", existingNames); - - implementationMethod = new InjectedMethodAnalysisContext( - type, - name, - type, // Placeholder return type - MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static, - []) - { - IsInjected = true, - }; - type.Methods.Add(implementationMethod); - - method.UnsafeImplementationMethod = implementationMethod; - - implementationMethod.CopyGenericParameters(method, true, true); - - var visitor = TypeReplacementVisitor.CreateForMethodCopying(method, implementationMethod); - - implementationMethod.SetDefaultReturnType(visitor.Replace(method.ReturnType)); - - if (!method.IsStatic) - { - var newParameter = new InjectedParameterAnalysisContext( - null, - byReference.MakeGenericInstanceType([redirectedType]), - ParameterAttributes.None, - 0, - implementationMethod); - implementationMethod.Parameters.Add(newParameter); - } - - foreach (var originalParameter in method.Parameters) - { - var newParameterType = byReference.MakeGenericInstanceType([visitor.Replace(originalParameter.ParameterType)]); - - var newParameter = new InjectedParameterAnalysisContext( - originalParameter.Name, - newParameterType, - originalParameter.Attributes, - implementationMethod.Parameters.Count, - implementationMethod); - implementationMethod.Parameters.Add(newParameter); - } - } - + InjectedMethodAnalysisContext? helper = null; InjectedMethodAnalysisContext? valueTypeHelper = null; InjectedMethodAnalysisContext? referenceTypeHelper = null; if (method.IsStatic) @@ -127,7 +80,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action instructions = new(); + if (type.IsValueType) + { + valueTypeHelper = helper; + } + else + { + referenceTypeHelper = helper; + } + } - var thisIsLocal = !type.IsValueType; - var localVariablesOffset = thisIsLocal ? 0 : 1; - var localVariablesCount = thisIsLocal ? method.Parameters.Count + 1 : method.Parameters.Count; - LocalVariable[] localVariables = new LocalVariable[localVariablesCount]; + var isUnstrippedICall = method.IsUnstripped && method.ICallDelegateField is not null; - for (var i = localVariablesOffset; i < helper.Parameters.Count; i++) + InjectedMethodAnalysisContext? implementationMethod; + if (isUnstrippedICall) + { + // The ICall delegate is the implementation, so we don't need to generate a separate method for it. + implementationMethod = null; + } + else + { + var name = GetNonConflictingName(method.IsInstanceConstructor ? "UnsafeConstructor" : $"UnsafeImplementation_{method.Name.Replace('.', '_')}", existingNames); + + implementationMethod = new InjectedMethodAnalysisContext( + type, + name, + type, // Placeholder return type + MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static, + []) { - var parameter = helper.Parameters[i]; - var parameterLocal = new LocalVariable(byReference.MakeGenericInstanceType([parameter.ParameterType])); - localVariables[i - localVariablesOffset] = parameterLocal; + IsInjected = true, + }; + type.Methods.Add(implementationMethod); - instructions.Add(CilOpCodes.Call, il2CppTypeHelper_SizeOf.MakeGenericInstanceMethod(parameter.ParameterType)); - instructions.Add(CilOpCodes.Conv_U); - instructions.Add(CilOpCodes.Localloc); - instructions.Add(CilOpCodes.Newobj, byReference_Constructor.MakeConcreteGeneric([parameter.ParameterType], [])); - instructions.Add(CilOpCodes.Stloc, parameterLocal); + method.UnsafeImplementationMethod = implementationMethod; - instructions.Add(CilOpCodes.Ldloca, parameterLocal); - instructions.Add(CilOpCodes.Ldarg, parameter); - instructions.Add(CilOpCodes.Call, byReference_SetValue.MakeConcreteGeneric([parameter.ParameterType], [])); - } + implementationMethod.CopyGenericParameters(method, true, true); - if (!thisIsLocal) - { - instructions.Add(CilOpCodes.Ldarg, helper.Parameters[0]); - } + var visitor = TypeReplacementVisitor.CreateForMethodCopying(method, implementationMethod); + + implementationMethod.SetDefaultReturnType(visitor.Replace(method.ReturnType)); - foreach (var parameterLocal in localVariables) + if (!method.IsStatic) { - instructions.Add(CilOpCodes.Ldloc, parameterLocal); + var newParameter = new InjectedParameterAnalysisContext( + null, + byReference.MakeGenericInstanceType([redirectedType]), + ParameterAttributes.None, + 0, + implementationMethod); + implementationMethod.Parameters.Add(newParameter); } - instructions.Add(CilOpCodes.Call, implementationMethod.MaybeMakeConcreteGeneric(type.GenericParameters, helper.GenericParameters)); + foreach (var originalParameter in method.Parameters) + { + var newParameterType = byReference.MakeGenericInstanceType([visitor.Replace(originalParameter.ParameterType)]); - instructions.Add(CilOpCodes.Ret); + var newParameter = new InjectedParameterAnalysisContext( + originalParameter.Name, + newParameterType, + originalParameter.Attributes, + implementationMethod.Parameters.Count, + implementationMethod); + implementationMethod.Parameters.Add(newParameter); + } + } - helper.PutExtraData(new NativeMethodBody() + if (helper is not null) + { + if (isUnstrippedICall) { - Instructions = instructions, - LocalVariables = localVariables, - }); + Debug.Assert(method.DeclaringType?.GenericParameters.Count == 0 && method.GenericParameters.Count == 0); - if (type.IsValueType) - { - valueTypeHelper = helper; + List instructions = new(1 + helper.Parameters.Count + 2); + instructions.Add(CilOpCodes.Ldsfld, method.ICallDelegateField); + foreach (var parameter in helper.Parameters) + { + instructions.Add(CilOpCodes.Ldarg, parameter); + } + instructions.Add(CilOpCodes.Callvirt, method.ICallDelegateField!.FieldType.GetMethodByName("Invoke")); + instructions.Add(CilOpCodes.Ret); + + helper.PutExtraData(new NativeMethodBody() + { + Instructions = instructions, + LocalVariables = [], + }); } else { - referenceTypeHelper = helper; + List instructions = new(); + + var thisIsLocal = !type.IsValueType; + var localVariablesOffset = thisIsLocal ? 0 : 1; + var localVariablesCount = thisIsLocal ? method.Parameters.Count + 1 : method.Parameters.Count; + LocalVariable[] localVariables = new LocalVariable[localVariablesCount]; + + for (var i = localVariablesOffset; i < helper.Parameters.Count; i++) + { + var parameter = helper.Parameters[i]; + var parameterLocal = new LocalVariable(byReference.MakeGenericInstanceType([parameter.ParameterType])); + localVariables[i - localVariablesOffset] = parameterLocal; + + instructions.Add(CilOpCodes.Call, il2CppTypeHelper_SizeOf.MakeGenericInstanceMethod(parameter.ParameterType)); + instructions.Add(CilOpCodes.Conv_U); + instructions.Add(CilOpCodes.Localloc); + instructions.Add(CilOpCodes.Newobj, byReference_Constructor.MakeConcreteGeneric([parameter.ParameterType], [])); + instructions.Add(CilOpCodes.Stloc, parameterLocal); + + instructions.Add(CilOpCodes.Ldloca, parameterLocal); + instructions.Add(CilOpCodes.Ldarg, parameter); + instructions.Add(CilOpCodes.Call, byReference_SetValue.MakeConcreteGeneric([parameter.ParameterType], [])); + } + + if (!thisIsLocal) + { + instructions.Add(CilOpCodes.Ldarg, helper.Parameters[0]); + } + + foreach (var parameterLocal in localVariables) + { + instructions.Add(CilOpCodes.Ldloc, parameterLocal); + } + + instructions.Add(CilOpCodes.Call, implementationMethod!.MaybeMakeConcreteGeneric(type.GenericParameters, helper.GenericParameters)); + + instructions.Add(CilOpCodes.Ret); + + helper.PutExtraData(new NativeMethodBody() + { + Instructions = instructions, + LocalVariables = localVariables, + }); } } @@ -306,6 +340,26 @@ public override void Process(ApplicationAnalysisContext appContext, Action instructions = new(1 + method.Parameters.Count + 2); + instructions.Add(CilOpCodes.Ldsfld, method.ICallDelegateField); + foreach (var parameter in method.Parameters) + { + instructions.Add(CilOpCodes.Ldarg, parameter); + } + instructions.Add(CilOpCodes.Callvirt, method.ICallDelegateField!.FieldType.GetMethodByName("Invoke")); + instructions.Add(CilOpCodes.Ret); + + method.PutExtraData(new NativeMethodBody() + { + Instructions = instructions, + LocalVariables = [], + }); + } else { Debug.Assert(method.IsStatic); @@ -336,7 +390,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action instructions2 = new(1 + implementation.Parameters.Count + 2); - instructions2.Add(CilOpCodes.Ldsfld, icallDelegateField); - foreach (var parameter in implementation.Parameters) - { - instructions2.Add(CilOpCodes.Ldarg, parameter); - } - instructions2.Add(CilOpCodes.Callvirt, icallDelegateField.FieldType.GetMethodByName("Invoke")); - instructions2.Add(CilOpCodes.Ret); - implementation.PutExtraData(new NativeMethodBody() - { - Instructions = instructions2, - LocalVariables = [], - }); - } + // Unstripped methods have no native code, so we skip them here. continue; } diff --git a/Il2CppInterop.Runtime/RuntimeInvoke.cs b/Il2CppInterop.Runtime/RuntimeInvoke.cs index e5172e32..c6b60c9c 100644 --- a/Il2CppInterop.Runtime/RuntimeInvoke.cs +++ b/Il2CppInterop.Runtime/RuntimeInvoke.cs @@ -141,7 +141,6 @@ public static T ResolveICall(string signature) where T : Delegate invoke.ReturnType, invoke.GetParameters().Select(it => it.ParameterType).ToArray(), typeof(RuntimeInvoke), true); var bodyBuilder = trampoline.GetILGenerator(); - var sizeOfMethod = typeof(Il2CppType).GetMethod(nameof(Il2CppType.SizeOf))!; var parameters = invoke.GetParameters(); var parameterTypes = new Type[parameters.Length]; var locals = new LocalBuilder[parameters.Length]; @@ -150,18 +149,15 @@ public static T ResolveICall(string signature) where T : Delegate var parameter = parameters[i]; var parameterType = parameter.ParameterType; - // Parameter is a ByReference, and we need to get the underlying type T - var elementType = parameterType.GenericTypeArguments[0]; - - var nativeStruct = TrampolineBuilder.GetNativeType(elementType); + var nativeStruct = TrampolineBuilder.GetNativeType(parameterType); parameterTypes[i] = nativeStruct; var nativeLocal = bodyBuilder.DeclareLocal(nativeStruct); locals[i] = nativeLocal; - bodyBuilder.Emit(OpCodes.Ldarga, i); + bodyBuilder.Emit(OpCodes.Ldarg, i); bodyBuilder.Emit(OpCodes.Ldloca, nativeLocal); - bodyBuilder.Emit(OpCodes.Call, parameterType.GetMethod(nameof(ByReference<>.CopyToUnmanaged))!.MakeGenericMethod(nativeStruct)); + bodyBuilder.Emit(OpCodes.Call, typeof(Il2CppType).GetMethod(nameof(Il2CppType.WriteToPointer))!.MakeGenericMethod(parameterType)); } foreach (var local in locals) From 6f0ecca8d211331a401a97235b3e39bf6bf0ea86 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 21 Jun 2026 20:27:09 -0700 Subject: [PATCH 465/486] Add FromSystemType for System.Type to Il2CppSystem.Type Introduce FromSystemType in Il2CppSystemTypeExtensions to convert System.Type to Il2CppSystem.Type using class pointers. Refactor ManagedTypeToIl2CppType to use this new method. Add [RequiresDynamicCode] attribute and necessary using directive. --- .../Extensions/Il2CppSystemTypeExtensions.cs | 15 ++++++++++++++- Il2CppInterop.Runtime/GenerationInternals.cs | 8 +------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs index 6ccaa241..bda9ade7 100644 --- a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs +++ b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs @@ -1,4 +1,5 @@ -using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using Il2CppInterop.Common; using Il2CppSystem; @@ -26,6 +27,18 @@ public static Type FromClassPointer(nint classPointer) return Type.FromTypePointer(il2CppType); } + [RequiresDynamicCode("")] + public static Type FromSystemType(System.Type systemType) + { + var classPointer = Il2CppType.GetClassPointer(systemType); + if (classPointer == default) + { + throw new System.ArgumentException($"{systemType} does not have a corresponding IL2CPP class pointer", nameof(systemType)); + } + + return FromClassPointer(classPointer); + } + public nint ToTypePointer() { return type.TypeHandle.value; diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index 58ecaa3d..e74578d5 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -45,13 +45,7 @@ public static partial class GenerationInternals [RequiresDynamicCode("")] public static Il2CppSystem.Type ManagedTypeToIl2CppType(Type type) { - var classPointer = Il2CppType.GetClassPointer(type); - if (classPointer == IntPtr.Zero) - { - throw new ArgumentException($"{type} does not have a corresponding IL2CPP class pointer"); - } - - return Il2CppSystem.Type.FromClassPointer(classPointer); + return Il2CppSystem.Type.FromSystemType(type); } [RequiresDynamicCode("")] From 61dfb8759e049c2f93c159dc2a0f5f39774d83ef Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 21 Jun 2026 21:14:05 -0700 Subject: [PATCH 466/486] Handle missing base interfaces in SystemInterfaceProcessingLayer --- .../SystemInterfaceProcessingLayer.cs | 81 ++++++++++++++----- 1 file changed, 61 insertions(+), 20 deletions(-) diff --git a/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs b/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs index bcdb6674..d767bb36 100644 --- a/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs +++ b/Il2CppInterop.Generator/SystemInterfaceProcessingLayer.cs @@ -35,23 +35,27 @@ public override void Process(ApplicationAnalysisContext appContext, Action(); + var systemToInjectedMap = new Dictionary(TypeAnalysisContextEqualityComparer.Instance); foreach ((_, var systemInterface) in pairs) { - var injectedInterface = appContext.Il2CppMscorlib.InjectType( - "Il2CppInterop.SystemInterfaces", - systemInterface.Name, - null, - TypeAttributes.NotPublic | TypeAttributes.Interface | TypeAttributes.Abstract); - injectedInterface.CopyGenericParameters(systemInterface, true); - injectedInterface.InterfaceContexts.Add(systemInterface.MaybeMakeGenericInstanceType(injectedInterface.GenericParameters)); - - systemToInjectedMap[systemInterface] = injectedInterface; - - // Add generic parameters to the dictionary too - for (var i = 0; i < systemInterface.GenericParameters.Count; i++) + var injectedInterface = CreateInjectedInterface(systemInterface); + AddPairToMap(systemToInjectedMap, systemInterface, injectedInterface); + } + + // Find any missing base interfaces + { + for (var i = 0; i < pairs.Count; i++) { - systemToInjectedMap[systemInterface.GenericParameters[i]] = injectedInterface.GenericParameters[i]; + (_, var systemInterface) = pairs[i]; + foreach (var systemBaseInterface in systemInterface.InterfaceContexts.Select(RemoveTypeArgumentsIfPresent)) + { + if (!systemToInjectedMap.ContainsKey(systemBaseInterface)) + { + var injectedBaseInterface = CreateInjectedInterface(systemBaseInterface); + AddPairToMap(systemToInjectedMap, systemBaseInterface, injectedBaseInterface); + pairs.Add((null, systemBaseInterface)); + } + } } } @@ -74,9 +78,36 @@ public override void Process(ApplicationAnalysisContext appContext, Action FindPairs(ApplicationAnalysisContext appContext) + private static TypeAnalysisContext RemoveTypeArgumentsIfPresent(TypeAnalysisContext type) => type is GenericInstanceTypeAnalysisContext genericInstance + ? genericInstance.GenericType + : type; + + private static InjectedTypeAnalysisContext CreateInjectedInterface(TypeAnalysisContext systemInterface) + { + var injectedInterface = systemInterface.AppContext.Il2CppMscorlib.InjectType( + "Il2CppInterop.SystemInterfaces", + systemInterface.Name, + null, + TypeAttributes.NotPublic | TypeAttributes.Interface | TypeAttributes.Abstract); + injectedInterface.CopyGenericParameters(systemInterface, true); + injectedInterface.InterfaceContexts.Add(systemInterface.MaybeMakeGenericInstanceType(injectedInterface.GenericParameters)); + return injectedInterface; + } + + private static void AddPairToMap(Dictionary systemToInjectedMap, TypeAnalysisContext systemInterface, InjectedTypeAnalysisContext injectedInterface) { - List<(TypeAnalysisContext, TypeAnalysisContext)> pairs = []; + systemToInjectedMap[systemInterface] = injectedInterface; + + // Add generic parameters to the dictionary too + for (var i = 0; i < systemInterface.GenericParameters.Count; i++) + { + systemToInjectedMap[systemInterface.GenericParameters[i]] = injectedInterface.GenericParameters[i]; + } + } + + private static List<(TypeAnalysisContext?, TypeAnalysisContext)> FindPairs(ApplicationAnalysisContext appContext) + { + List<(TypeAnalysisContext?, TypeAnalysisContext)> pairs = []; foreach (var type in appContext.Il2CppMscorlib.Types) { if (type.IsInterface) @@ -106,7 +137,7 @@ static bool IsPublic(TypeAnalysisContext? type) } } - private static void ImplementInterface(TypeAnalysisContext il2CppInterface, TypeAnalysisContext injectedInterface, TypeAnalysisContext systemInterface) + private static void ImplementInterface(TypeAnalysisContext? il2CppInterface, TypeAnalysisContext injectedInterface, TypeAnalysisContext systemInterface) { foreach (var systemMethod in systemInterface.Methods) { @@ -150,6 +181,8 @@ private static void ImplementInterface(TypeAnalysisContext il2CppInterface, Type continue; } + Debug.Assert(il2CppInterface is not null); + List instructions = []; instructions.Add(CilOpCodes.Ldarg_0); instructions.Add(CilOpCodes.Castclass, il2CppInterface.MaybeMakeGenericInstanceType(injectedInterface.GenericParameters)); @@ -170,15 +203,23 @@ private static void ImplementInterface(TypeAnalysisContext il2CppInterface, Type } // Make the Il2Cpp interface inherit from the injected interface - Debug.Assert(il2CppInterface.GenericParameters.Count == injectedInterface.GenericParameters.Count); - il2CppInterface.InterfaceContexts.Add(injectedInterface.MaybeMakeGenericInstanceType(il2CppInterface.GenericParameters)); + if (il2CppInterface is not null) + { + Debug.Assert(il2CppInterface.GenericParameters.Count == injectedInterface.GenericParameters.Count); + il2CppInterface.InterfaceContexts.Add(injectedInterface.MaybeMakeGenericInstanceType(il2CppInterface.GenericParameters)); + } } - private static MethodAnalysisContext? FindIl2CppMethod(TypeAnalysisContext il2CppInterface, string methodName, MethodAnalysisContext injectedMethod, out Conversion returnConversion, out Conversion[] parameterConversions) + private static MethodAnalysisContext? FindIl2CppMethod(TypeAnalysisContext? il2CppInterface, string methodName, MethodAnalysisContext injectedMethod, out Conversion returnConversion, out Conversion[] parameterConversions) { returnConversion = NullConversion.Instance; parameterConversions = new Conversion[injectedMethod.Parameters.Count]; + if (il2CppInterface is null) + { + return null; + } + // Search in reverse order because the most user-friendly overloads will be last (they always get added to the end of the list). // This ensures correct behavior for array parameters, which have special handling in the user-friendly overload processing layer. for (var il2CppMethodIndex = il2CppInterface.Methods.Count - 1; il2CppMethodIndex >= 0; il2CppMethodIndex--) From 81a92a2f5eafec6612115027ddac7b70c24c5e3e Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 21 Jun 2026 22:05:06 -0700 Subject: [PATCH 467/486] Improve InvalidConstraintChecker --- .../InitializationClassProcessingLayer.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index b3c70ce2..9a42776a 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -569,6 +569,7 @@ public override bool Visit(GenericInstanceTypeAnalysisContext type) if (!IsObject(type.GenericArguments[i])) continue; + // Check if any of the constraints on this generic parameter are not satisfied by object. foreach (var constraint in type.GenericType.GenericParameters[i].ConstraintTypes) { if (IsObject(constraint)) @@ -576,6 +577,21 @@ public override bool Visit(GenericInstanceTypeAnalysisContext type) if (!IsInjectedOrReference(constraint)) return true; } + + // Check if any of the constraints on any of the declaring types' generic parameters might not be satisfied by object. + // Specifically, we check if a constraint references the target generic parameter. + // Obviously, this could have false positives, but it shouldn't have any false negatives. + var visitor = new TargetTypeFinder(type.GenericType.GenericParameters[i]); + for (var j = 0; j < type.GenericType.GenericParameters.Count; j++) + { + if (j == i) + continue; + foreach (var constraint in type.GenericType.GenericParameters[j].ConstraintTypes) + { + if (visitor.Visit(constraint)) + return true; + } + } } return base.Visit(type); } @@ -591,5 +607,10 @@ private static bool IsObject(TypeAnalysisContext type) { return type.KnownType is KnownTypeCode.Il2CppSystem_IObject; } + + private sealed class TargetTypeFinder(GenericParameterTypeAnalysisContext targetType) : BooleanOrTypeVisitor + { + public override bool Visit(GenericParameterTypeAnalysisContext type) => type == targetType; + } } } From 41243eeffee7d3ece07d40f8cb9e66dbda3fd598 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Mon, 22 Jun 2026 01:13:49 -0700 Subject: [PATCH 468/486] Rename obfuscated virtual methods --- .../MethodAnalysisContextExtensions.cs | 104 ++++++++++++++++++ Il2CppInterop.Generator/Il2CppGame.cs | 1 + .../Il2CppInterop.Generator.csproj | 2 +- .../OverrideRenamingProcessingLayer.cs | 40 +++++++ 4 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 Il2CppInterop.Generator/OverrideRenamingProcessingLayer.cs diff --git a/Il2CppInterop.Generator/Extensions/MethodAnalysisContextExtensions.cs b/Il2CppInterop.Generator/Extensions/MethodAnalysisContextExtensions.cs index 76042245..810b1454 100644 --- a/Il2CppInterop.Generator/Extensions/MethodAnalysisContextExtensions.cs +++ b/Il2CppInterop.Generator/Extensions/MethodAnalysisContextExtensions.cs @@ -2,6 +2,8 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using Cpp2IL.Core.Model.Contexts; +using Cpp2IL.Core.Utils; +using LibCpp2IL; namespace Il2CppInterop.Generator.Extensions; @@ -66,6 +68,66 @@ public int InitializationClassIndex set => method.PutExtraStruct("InitializationClassIndex", value); } + public MethodAnalysisContext? UltimateBaseMethod + { + get + { + var currentBaseMethod = method.BaseMethodFixed; + if (currentBaseMethod is null) + return null; + MethodAnalysisContext? nextBaseMethod; + while (true) + { + nextBaseMethod = currentBaseMethod.BaseMethodFixed; + if (nextBaseMethod is not null) + { + currentBaseMethod = nextBaseMethod; + } + else + { + break; + } + } + return currentBaseMethod; + } + } + + public MethodAnalysisContext? BaseMethodFixed + { + get + { + if (method.Definition == null) + return null; + + var vtable = method.DeclaringType?.Definition?.VTable; + if (vtable == null) + return null; + + for (var i = 0; i < vtable.Length; ++i) + { + var vtableEntry = vtable[i]; + if (vtableEntry is null or { Type: not MetadataUsageType.MethodDef } || vtableEntry.AsMethod() != method.Definition) + continue; + + if (IsInterfaceSlot(method, i)) + { + continue; + } + + var baseType = method.DeclaringType?.DefaultBaseType; + while (baseType is not null) + { + if (TryGetMethodForSlot(baseType, i, out var method2)) + { + return method2; + } + baseType = baseType.DefaultBaseType; + } + } + return null; + } + } + public bool IsInstanceConstructor => method.Name == ".ctor"; public bool IsStaticConstructor => method.Name == ".cctor"; public bool IsConstructor => method.IsInstanceConstructor || method.IsStaticConstructor; @@ -106,4 +168,46 @@ public MethodAnalysisContext MaybeMakeConcreteGeneric(IReadOnlyCollection= interfaceOffset.offset) + { + var interfaceTypeContext = interfaceOffset.Type.ToContext(method.CustomAttributeAssembly); + if (interfaceTypeContext != null && TryGetMethodForSlot(interfaceTypeContext, slot - interfaceOffset.offset, out _)) + { + return true; + } + } + } + return false; + } + + private static bool TryGetMethodForSlot(TypeAnalysisContext declaringType, int slot, [NotNullWhen(true)] out MethodAnalysisContext? method) + { + if (declaringType is GenericInstanceTypeAnalysisContext genericInstanceType) + { + var genericMethod = genericInstanceType.GenericType.Methods.FirstOrDefault(m => m.Slot == slot); + if (genericMethod is not null) + { + method = new ConcreteGenericMethodAnalysisContext(genericMethod, genericInstanceType.GenericArguments, []); + return true; + } + } + else + { + var baseMethod = declaringType.Methods.FirstOrDefault(m => m.Slot == slot); + if (baseMethod is not null) + { + method = baseMethod; + return true; + } + } + + method = null; + return false; + } } diff --git a/Il2CppInterop.Generator/Il2CppGame.cs b/Il2CppInterop.Generator/Il2CppGame.cs index 96b0e4fb..d4beef9c 100644 --- a/Il2CppInterop.Generator/Il2CppGame.cs +++ b/Il2CppInterop.Generator/Il2CppGame.cs @@ -76,6 +76,7 @@ public static List GetDefaultProcessingLayers() => [ new AttributeAnalysisProcessingLayer(), // Needed for recovery of unmanaged constraints //new StableRenamingProcessingLayer(), + new OverrideRenamingProcessingLayer(), // Must be before CleanRenamingProcessingLayer new UnstripProcessingLayer(), // Can be disabled for performance during development new InterfaceOverrideProcessingLayer(), new InvalidFieldRemovalProcessingLayer(), diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index 3d634853..56de393e 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -8,7 +8,7 @@ - + all diff --git a/Il2CppInterop.Generator/OverrideRenamingProcessingLayer.cs b/Il2CppInterop.Generator/OverrideRenamingProcessingLayer.cs new file mode 100644 index 00000000..6ec7af97 --- /dev/null +++ b/Il2CppInterop.Generator/OverrideRenamingProcessingLayer.cs @@ -0,0 +1,40 @@ +using Cpp2IL.Core.Api; +using Cpp2IL.Core.Model.Contexts; + +namespace Il2CppInterop.Generator; + +/// +/// Poorly implemented obfuscation can cause method names to differ between base and derived methods, which causes issues for virtual method dispatch if not corrected. +/// +public class OverrideRenamingProcessingLayer : Cpp2IlProcessingLayer +{ + public override string Name => "Override Name Changes"; + public override string Id => "overridenamechanges"; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) + { + foreach (var assembly in appContext.Assemblies) + { + if (assembly.IsReferenceAssembly || assembly.IsInjected) + continue; + foreach (var type in assembly.Types) + { + if (type.IsInjected) + continue; + RenameMembers(type); + } + } + } + private static void RenameMembers(TypeAnalysisContext type) + { + foreach (var method in type.Methods) + { + if (method.IsInjected) + continue; + var baseMethod = method.UltimateBaseMethod; + if (baseMethod is not null && baseMethod.DefaultName != method.DefaultName) + { + method.Name = baseMethod.Name; + } + } + } +} From 6dcfb7b6cb8a0c7167343ffe80f3f162bb5d2d48 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Mon, 22 Jun 2026 01:15:27 -0700 Subject: [PATCH 469/486] Fix some structs having the abstract flag --- .../AttributesOverrideProcessingLayer.cs | 31 ++++++++++++------- Il2CppInterop.Generator/Il2CppGame.cs | 2 +- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/Il2CppInterop.Generator/AttributesOverrideProcessingLayer.cs b/Il2CppInterop.Generator/AttributesOverrideProcessingLayer.cs index b55aa3f4..f3aeac04 100644 --- a/Il2CppInterop.Generator/AttributesOverrideProcessingLayer.cs +++ b/Il2CppInterop.Generator/AttributesOverrideProcessingLayer.cs @@ -31,7 +31,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action GetDefaultProcessingLayers() => new UnstripProcessingLayer(), // Can be disabled for performance during development new InterfaceOverrideProcessingLayer(), new InvalidFieldRemovalProcessingLayer(), + new AttributesOverrideProcessingLayer(), // Must be before Il2CppRenamingProcessingLayer new Il2CppRenamingProcessingLayer(), new CleanRenamingProcessingLayer(), new ConflictRenamingProcessingLayer(), - new AttributesOverrideProcessingLayer(), new PublicizerProcessingLayer(), new MscorlibAssemblyInjectionProcessingLayer(), new KnownTypeAssignmentProcessingLayer(), From dddd9835e33d4f67326580967973b36b11a8ca5b Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Mon, 22 Jun 2026 01:17:02 -0700 Subject: [PATCH 470/486] Handle reference types inheriting from Il2CppSystem.ValueType --- .../ObjectOverridesProcessingLayer.cs | 6 +++--- .../ReferenceReplacementProcessingLayer.cs | 10 ++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Il2CppInterop.Generator/ObjectOverridesProcessingLayer.cs b/Il2CppInterop.Generator/ObjectOverridesProcessingLayer.cs index 5bdedff4..94cfb7f2 100644 --- a/Il2CppInterop.Generator/ObjectOverridesProcessingLayer.cs +++ b/Il2CppInterop.Generator/ObjectOverridesProcessingLayer.cs @@ -56,11 +56,11 @@ private static void ImplementVirtualMethodsOnStructsAndEnums(ApplicationAnalysis foreach (var type in assembly.Types) { - if (type.DefaultBaseType != il2CppSystemEnum && type.DefaultBaseType != il2CppSystemValueType) + if (!type.IsValueType) continue; - if (type == il2CppSystemEnum) - continue; + Debug.Assert(type.DefaultBaseType == il2CppSystemEnum || type.DefaultBaseType == il2CppSystemValueType); + Debug.Assert(type != il2CppSystemEnum); if (type.IsInjected) continue; diff --git a/Il2CppInterop.Generator/ReferenceReplacementProcessingLayer.cs b/Il2CppInterop.Generator/ReferenceReplacementProcessingLayer.cs index 1196fd0e..ed7af996 100644 --- a/Il2CppInterop.Generator/ReferenceReplacementProcessingLayer.cs +++ b/Il2CppInterop.Generator/ReferenceReplacementProcessingLayer.cs @@ -51,11 +51,17 @@ public override void Process(ApplicationAnalysisContext appContext, Action Date: Mon, 22 Jun 2026 10:47:26 -0700 Subject: [PATCH 471/486] Implement UnboxNative on the Il2Cpp array types --- .../InteropTypes/Arrays/Il2CppArrayRank1.cs | 2 +- .../InteropTypes/Arrays/Il2CppArrayRank2.cs | 14 +++++++------- .../InteropTypes/Arrays/Il2CppArrayRank3.cs | 14 +++++++------- .../InteropTypes/Arrays/Il2CppArrayRank4.cs | 14 +++++++------- .../InteropTypes/Arrays/Il2CppArrayRank5.cs | 14 +++++++------- 5 files changed, 29 insertions(+), 29 deletions(-) diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank1.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank1.cs index 6aa8f431..d2fc317f 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank1.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank1.cs @@ -162,10 +162,10 @@ public static explicit operator Span(Il2CppArrayRank1? array) #endregion #region IIl2CppType Implementation - static int IIl2CppType>.Size => IntPtr.Size; nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); static void IIl2CppType>.WriteToSpan(Il2CppArrayRank1? value, Span span) => Il2CppType.WriteReference(value, span); static Il2CppArrayRank1? IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => Il2CppType.ReadReference>(span); + static Il2CppArrayRank1 IIl2CppType>.UnboxNative(ObjectPointer pointer) => new(pointer); #endregion #region Collection Implementation diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs index 7354ecb7..5e2bedc2 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank2.cs @@ -7,10 +7,6 @@ namespace Il2CppInterop.Runtime.InteropTypes.Arrays; public sealed class Il2CppArrayRank2 : Il2CppArrayBase, IIl2CppType> where T : IIl2CppType { - static int IIl2CppType>.Size => IntPtr.Size; - - nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); - static Il2CppArrayRank2() { SetClassPointer, T>(2); @@ -45,9 +41,6 @@ public Il2CppArrayRank2(T[,] values) : this(values.GetLength(0), values.GetLengt } public ByReference GetElementAddress(int index0, int index1) => GetElementAddress([index0, index1]); - static void IIl2CppType>.WriteToSpan(Il2CppArrayRank2? value, Span span) => Il2CppType.WriteReference(value, span); - static Il2CppArrayRank2? IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => Il2CppType.ReadReference>(span); - [return: NotNullIfNotNull(nameof(array))] public static explicit operator Il2CppArrayRank2?(T[,]? array) => array is null ? null : new(array); @@ -69,4 +62,11 @@ public Il2CppArrayRank2(T[,] values) : this(values.GetLength(0), values.GetLengt } return result; } + + #region IIl2CppType Implementation + nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); + static void IIl2CppType>.WriteToSpan(Il2CppArrayRank2? value, Span span) => Il2CppType.WriteReference(value, span); + static Il2CppArrayRank2? IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => Il2CppType.ReadReference>(span); + static Il2CppArrayRank2 IIl2CppType>.UnboxNative(ObjectPointer pointer) => new(pointer); + #endregion } diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs index 352f29f3..6bbcffac 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank3.cs @@ -7,10 +7,6 @@ namespace Il2CppInterop.Runtime.InteropTypes.Arrays; public sealed class Il2CppArrayRank3 : Il2CppArrayBase, IIl2CppType> where T : IIl2CppType { - static int IIl2CppType>.Size => IntPtr.Size; - - nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); - static Il2CppArrayRank3() { SetClassPointer, T>(3); @@ -49,9 +45,6 @@ public Il2CppArrayRank3(T[,,] values) : this(values.GetLength(0), values.GetLeng } public ByReference GetElementAddress(int index0, int index1, int index2) => GetElementAddress([index0, index1, index2]); - static void IIl2CppType>.WriteToSpan(Il2CppArrayRank3? value, Span span) => Il2CppType.WriteReference(value, span); - static Il2CppArrayRank3? IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => Il2CppType.ReadReference>(span); - [return: NotNullIfNotNull(nameof(array))] public static explicit operator Il2CppArrayRank3?(T[,,]? array) => array is null ? null : new(array); @@ -77,4 +70,11 @@ public Il2CppArrayRank3(T[,,] values) : this(values.GetLength(0), values.GetLeng } return result; } + + #region IIl2CppType Implementation + nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); + static void IIl2CppType>.WriteToSpan(Il2CppArrayRank3? value, Span span) => Il2CppType.WriteReference(value, span); + static Il2CppArrayRank3? IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => Il2CppType.ReadReference>(span); + static Il2CppArrayRank3 IIl2CppType>.UnboxNative(ObjectPointer pointer) => new(pointer); + #endregion } diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank4.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank4.cs index 48df612e..336769a4 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank4.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank4.cs @@ -7,10 +7,6 @@ namespace Il2CppInterop.Runtime.InteropTypes.Arrays; public sealed class Il2CppArrayRank4 : Il2CppArrayBase, IIl2CppType> where T : IIl2CppType { - static int IIl2CppType>.Size => IntPtr.Size; - - nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); - static Il2CppArrayRank4() { SetClassPointer, T>(4); @@ -54,9 +50,6 @@ public Il2CppArrayRank4(T[,,,] values) : this(values.GetLength(0), values.GetLen public ByReference GetElementAddress(int index0, int index1, int index2, int index3) => GetElementAddress([index0, index1, index2, index3]); - static void IIl2CppType>.WriteToSpan(Il2CppArrayRank4? value, Span span) => Il2CppType.WriteReference(value, span); - static Il2CppArrayRank4? IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => Il2CppType.ReadReference>(span); - [return: NotNullIfNotNull(nameof(array))] public static explicit operator Il2CppArrayRank4?(T[,,,]? array) => array is null ? null : new(array); @@ -86,4 +79,11 @@ public Il2CppArrayRank4(T[,,,] values) : this(values.GetLength(0), values.GetLen } return result; } + + #region IIl2CppType Implementation + nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); + static void IIl2CppType>.WriteToSpan(Il2CppArrayRank4? value, Span span) => Il2CppType.WriteReference(value, span); + static Il2CppArrayRank4? IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => Il2CppType.ReadReference>(span); + static Il2CppArrayRank4 IIl2CppType>.UnboxNative(ObjectPointer pointer) => new(pointer); + #endregion } diff --git a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank5.cs b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank5.cs index 31ecff41..a3e33caf 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank5.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Arrays/Il2CppArrayRank5.cs @@ -7,10 +7,6 @@ namespace Il2CppInterop.Runtime.InteropTypes.Arrays; public sealed class Il2CppArrayRank5 : Il2CppArrayBase, IIl2CppType> where T : IIl2CppType { - static int IIl2CppType>.Size => IntPtr.Size; - - nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); - static Il2CppArrayRank5() { SetClassPointer, T>(5); @@ -58,9 +54,6 @@ public Il2CppArrayRank5(T[,,,,] values) : this(values.GetLength(0), values.GetLe public ByReference GetElementAddress(int index0, int index1, int index2, int index3, int index4) => GetElementAddress([index0, index1, index2, index3, index4]); - static void IIl2CppType>.WriteToSpan(Il2CppArrayRank5? value, Span span) => Il2CppType.WriteReference(value, span); - static Il2CppArrayRank5? IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => Il2CppType.ReadReference>(span); - [return: NotNullIfNotNull(nameof(array))] public static explicit operator Il2CppArrayRank5?(T[,,,,]? array) => array is null ? null : new(array); @@ -94,4 +87,11 @@ public Il2CppArrayRank5(T[,,,,] values) : this(values.GetLength(0), values.GetLe } return result; } + + #region IIl2CppType Implementation + nint IIl2CppType.ObjectClass => Il2CppType.GetClassPointer>(); + static void IIl2CppType>.WriteToSpan(Il2CppArrayRank5? value, Span span) => Il2CppType.WriteReference(value, span); + static Il2CppArrayRank5? IIl2CppType>.ReadFromSpan(ReadOnlySpan span) => Il2CppType.ReadReference>(span); + static Il2CppArrayRank5 IIl2CppType>.UnboxNative(ObjectPointer pointer) => new(pointer); + #endregion } From a540dd1faf51696e624810dd527d207949bc646b Mon Sep 17 00:00:00 2001 From: RaptorRush135 <112044769+RaptorRush135@users.noreply.github.com> Date: Tue, 23 Jun 2026 00:04:57 -0600 Subject: [PATCH 472/486] Fix IL2CPP string return P/Invokes (#13) --- Il2CppInterop.Common/IL2CPP.cs | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/Il2CppInterop.Common/IL2CPP.cs b/Il2CppInterop.Common/IL2CPP.cs index 83d36377..c7994ba7 100644 --- a/Il2CppInterop.Common/IL2CPP.cs +++ b/Il2CppInterop.Common/IL2CPP.cs @@ -1,5 +1,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; namespace Il2CppInterop.Common; @@ -191,12 +192,12 @@ public static unsafe partial class IL2CPP [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - [return: MarshalAs(UnmanagedType.LPUTF8Str)] + [return: MarshalUsing(typeof(Il2CppStringMarshaller))] public static partial string il2cpp_class_get_name(nint klass); [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - [return: MarshalAs(UnmanagedType.LPUTF8Str)] + [return: MarshalUsing(typeof(Il2CppStringMarshaller))] public static partial string il2cpp_class_get_namespace(nint klass); [LibraryImport("GameAssembly")] @@ -348,7 +349,7 @@ public static unsafe partial class IL2CPP [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - [return: MarshalAs(UnmanagedType.LPUTF8Str)] + [return: MarshalUsing(typeof(Il2CppStringMarshaller))] public static partial string il2cpp_field_get_name(nint field); [LibraryImport("GameAssembly")] @@ -467,7 +468,7 @@ public static unsafe partial class IL2CPP [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - [return: MarshalAs(UnmanagedType.LPUTF8Str)] + [return: MarshalUsing(typeof(Il2CppStringMarshaller))] public static partial string il2cpp_method_get_name(nint method); [LibraryImport("GameAssembly")] @@ -520,7 +521,7 @@ public static unsafe partial class IL2CPP [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - [return: MarshalAs(UnmanagedType.LPUTF8Str)] + [return: MarshalUsing(typeof(Il2CppStringMarshaller))] public static partial string il2cpp_method_get_param_name(nint method, uint index); [LibraryImport("GameAssembly")] @@ -565,7 +566,7 @@ public static unsafe partial class IL2CPP [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - [return: MarshalAs(UnmanagedType.LPUTF8Str)] + [return: MarshalUsing(typeof(Il2CppStringMarshaller))] public static partial string il2cpp_property_get_name(nint prop); [LibraryImport("GameAssembly")] @@ -754,7 +755,7 @@ public static unsafe partial class IL2CPP [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - [return: MarshalAs(UnmanagedType.LPUTF8Str)] + [return: MarshalUsing(typeof(Il2CppStringMarshaller))] public static partial string il2cpp_type_get_name(nint type); [LibraryImport("GameAssembly")] @@ -781,12 +782,12 @@ public static unsafe partial class IL2CPP [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - [return: MarshalAs(UnmanagedType.LPUTF8Str)] + [return: MarshalUsing(typeof(Il2CppStringMarshaller))] public static partial string il2cpp_image_get_name(nint image); [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - [return: MarshalAs(UnmanagedType.LPUTF8Str)] + [return: MarshalUsing(typeof(Il2CppStringMarshaller))] public static partial string il2cpp_image_get_filename(nint image); [LibraryImport("GameAssembly")] @@ -854,4 +855,17 @@ public static unsafe partial class IL2CPP [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] public static partial void il2cpp_custom_attrs_free(nint ainfo); + + [CustomMarshaller(typeof(string), MarshalMode.ManagedToUnmanagedOut, typeof(Il2CppStringMarshaller))] + private static class Il2CppStringMarshaller + { + public static string? ConvertToManaged(byte* unmanaged) + => Marshal.PtrToStringUTF8((nint)unmanaged); + + public static void Free(byte* unmanaged) + { + // Intentionally empty, il2cpp owns this pointer + _ = unmanaged; + } + } } From 5a0a18c2e8ad383df0a886c11c8805feabd09203 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Tue, 23 Jun 2026 01:18:26 -0700 Subject: [PATCH 473/486] Catch exceptions in Il2CppRuntimeClassInit --- Il2CppInterop.Runtime/GenerationInternals.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index e74578d5..0172bfb6 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -288,8 +288,17 @@ private static IntPtr GetMethodInfoForMissingMethod(string methodName) } public static void Il2CppRuntimeClassInit(nint @class) { - if (@class != nint.Zero) - IL2CPP.il2cpp_runtime_class_init(@class); + try + { + if (@class != nint.Zero) + { + IL2CPP.il2cpp_runtime_class_init(@class); + } + } + catch (Exception ex) + { + Logger.Instance.LogError(ex, "Error initializing class {ClassName}", IL2CPP.il2cpp_class_get_name(@class)); + } } public static nint GetIl2CppClass(string assemblyName, string namespaze, string className) From ceca0bd41b71161036050200ebbbc316c7284a54 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Tue, 23 Jun 2026 02:03:32 -0700 Subject: [PATCH 474/486] Fix null reference in FindClassInit --- Il2CppInterop.Runtime/Injection/ClassInitializer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Il2CppInterop.Runtime/Injection/ClassInitializer.cs b/Il2CppInterop.Runtime/Injection/ClassInitializer.cs index d5a10c59..9e1cc652 100644 --- a/Il2CppInterop.Runtime/Injection/ClassInitializer.cs +++ b/Il2CppInterop.Runtime/Injection/ClassInitializer.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using Il2CppInterop.Common; @@ -18,7 +19,7 @@ public static void Invoke(Il2CppClass* klass) ClassInit.Invoke(klass); } - private static readonly SignatureDefinition[] s_ClassInitSignatures = + private static IEnumerable s_ClassInitSignatures => [ new SignatureDefinition { From 6f9d7f8c074ec576cfd915f6e726ae5694dcfe61 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Tue, 23 Jun 2026 21:14:53 -0700 Subject: [PATCH 475/486] Implement system for lazy type initialization --- Il2CppInterop.Common/Il2CppObjectPool.cs | 31 +++- .../Extensions/Il2CppSystemTypeExtensions.cs | 163 +++++++++++++++++- Il2CppInterop.Runtime/GenerationInternals.cs | 7 + Il2Cppmscorlib/Type.cs | 78 +++++---- 4 files changed, 240 insertions(+), 39 deletions(-) diff --git a/Il2CppInterop.Common/Il2CppObjectPool.cs b/Il2CppInterop.Common/Il2CppObjectPool.cs index 2f5d8af4..514fcc45 100644 --- a/Il2CppInterop.Common/Il2CppObjectPool.cs +++ b/Il2CppInterop.Common/Il2CppObjectPool.cs @@ -1,4 +1,6 @@ using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; namespace Il2CppInterop.Common; @@ -13,6 +15,8 @@ public static void Remove(nint ptr) s_cache.TryRemove(ptr, out _); } + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "This will never be called in a trimmed context.")] + [UnconditionalSuppressMessage("AOT", "IL3050:Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.", Justification = "This will never be called in an AOT context.")] public static object? Get(nint ptr) { if (ptr == nint.Zero) @@ -26,8 +30,11 @@ public static void Remove(nint ptr) var ownClass = IL2CPP.il2cpp_object_get_class(ptr); if (!s_initializers.TryGetValue(ownClass, out var initializer)) { - var className = IL2CPP.il2cpp_class_get_name(ownClass); - throw new InvalidOperationException($"No initializer found for class {className}"); + var systemType = EnsureClassInitialized(ownClass); + if (!s_initializers.TryGetValue(ownClass, out initializer)) + { + throw new InvalidOperationException($"No initializer found for class {systemType}"); + } } var newObj = initializer.Invoke((ObjectPointer)ptr); @@ -73,4 +80,24 @@ public object Invoke(ObjectPointer obj) return initializer(obj); } } + + [RequiresDynamicCode("")] + [RequiresUnreferencedCode("")] + private static Type EnsureClassInitialized(nint classPointer) + { + ArgumentOutOfRangeException.ThrowIfZero(classPointer); + var il2CppSystemType = Il2CppSystemTypeFromClassPointer(null, classPointer); + var systemType = Il2CppSystemTypeToSystemType(null, il2CppSystemType); + RuntimeHelpers.RunClassConstructor(systemType.TypeHandle); + return systemType; + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "FromClassPointer")] + [return: UnsafeAccessorType("Il2CppSystem.Type, Il2Cppmscorlib")] + static extern object Il2CppSystemTypeFromClassPointer([UnsafeAccessorType("Il2CppInterop.Runtime.Extensions.Il2CppSystemTypeExtensions, Il2CppInterop.Runtime")] object? obj, nint classPointer); + + [RequiresDynamicCode("")] + [RequiresUnreferencedCode("")] + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "ToSystemType")] + static extern Type Il2CppSystemTypeToSystemType([UnsafeAccessorType("Il2CppInterop.Runtime.Extensions.Il2CppSystemTypeExtensions, Il2CppInterop.Runtime")] object? obj, [UnsafeAccessorType("Il2CppSystem.Type, Il2Cppmscorlib")] object il2CppSystemType); + } } diff --git a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs index bda9ade7..6f527ab1 100644 --- a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs +++ b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs @@ -1,6 +1,10 @@ -using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Runtime.CompilerServices; using Il2CppInterop.Common; +using Il2CppInterop.Runtime.InteropTypes; +using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; namespace Il2CppInterop.Runtime.Extensions; @@ -17,6 +21,7 @@ public static Type FromTypePointer(nint typePointer) return Type.internal_from_handle(typePointer); } + // Note: This method is referenced via UnsafeAccessor in Il2CppObjectPool public static Type FromClassPointer(nint classPointer) { var il2CppType = IL2CPP.il2cpp_class_get_type(classPointer); @@ -39,6 +44,57 @@ public static Type FromSystemType(System.Type systemType) return FromClassPointer(classPointer); } + // Note: This method is referenced via UnsafeAccessor in Il2CppObjectPool + [RequiresDynamicCode("")] + [RequiresUnreferencedCode("")] + public System.Type ToSystemType() + { + if (type.IsTypeDefinition) + { + return GetSystemTypeDefinition(type); + } + else if (type.ContainsGenericParameters) + { + throw new System.NotSupportedException($"Cannot convert type {type.FullName} to a system type because it contains generic parameters."); + } + else if (type.IsByRef) + { + return typeof(ByReference<>).MakeGenericType(type.GetElementType().ToSystemType()); + } + else if (type.IsPointer) + { + return typeof(Pointer<>).MakeGenericType(type.GetElementType().ToSystemType()); + } + else if (type.IsSZArray) + { + return typeof(Il2CppArrayRank1<>).MakeGenericType(type.GetElementType().ToSystemType()); + } + else if (type.IsArray) + { + int rank = type.GetArrayRank(); + var arrayGenericType = rank switch + { + 1 => typeof(Il2CppArrayRank1<>), + 2 => typeof(Il2CppArrayRank2<>), + 3 => typeof(Il2CppArrayRank3<>), + 4 => typeof(Il2CppArrayRank4<>), + 5 => typeof(Il2CppArrayRank5<>), + _ => throw new System.NotSupportedException($"Cannot convert type {type.FullName} to a system type because it is an array with rank {rank}, which is not supported.") + }; + return arrayGenericType.MakeGenericType(type.GetElementType().ToSystemType()); + } + else if (type.IsGenericType) + { + var genericTypeDefinition = type.GetGenericTypeDefinition().ToSystemType(); + var genericArguments = type.GetGenericArguments().Select(t => t.ToSystemType()).ToArray(); + return genericTypeDefinition.MakeGenericType(genericArguments); + } + else + { + throw new System.NotSupportedException($"Cannot convert type {type.FullName} to a system type."); + } + } + public nint ToTypePointer() { return type.TypeHandle.value; @@ -56,4 +112,109 @@ public nint ToClassPointer() return IL2CPP.il2cpp_class_from_type(type.ToTypePointer()); } } + + [RequiresDynamicCode("")] + [RequiresUnreferencedCode("")] + private static System.Type GetSystemTypeDefinition(Type type) + { + if (type.IsNested) + { + var declaringType = GetSystemTypeDefinition(type.DeclaringType); + var il2CppTypeName = type.NameOrDefault ?? ""; + return TryGetNestedSystemType(declaringType, il2CppTypeName) + ?? throw new System.NullReferenceException($"Could not find system type for nested type {il2CppTypeName} in declaring type {declaringType.FullName}"); + } + else + { + return TryGetTopLevelSystemType(type.Assembly.GetName().Name ?? "", type.Namespace ?? "", type.NameOrDefault ?? "") + ?? throw new System.NullReferenceException($"Could not find system type for top-level type {type.FullName}"); + } + } + + [RequiresDynamicCode("")] + private static System.Type? TryGetNestedSystemType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] System.Type declaringType, string il2CppTypeName) + { + foreach (var nestedType in declaringType.GetNestedTypes(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic)) + { + if (!nestedType.IsAssignableTo(typeof(IIl2CppType))) + { + continue; + } + + var name = typeof(Il2CppType).GetMethod(nameof(Il2CppType.GetName))!.MakeGenericMethod(nestedType).Invoke(null, null) as string ?? string.Empty; + if (string.Equals(name, il2CppTypeName, System.StringComparison.Ordinal)) + { + return nestedType; + } + } + return null; + } + + [RequiresUnreferencedCode("")] + [RequiresDynamicCode("")] + private static System.Type? TryGetTopLevelSystemType(string il2CppAssemblyName, string il2CppTypeNamespace, string il2CppTypeName) + { + var systemAssembly = TryGetSystemAssembly(il2CppAssemblyName); + + if (systemAssembly == null) + { + return null; + } + + foreach (var type in systemAssembly.GetTypes()) + { + if (type.IsNested || !type.IsAssignableTo(typeof(IIl2CppType))) + { + continue; + } + var (typeNamespace, typeName) = GetIl2CppTypeNamespaceAndName(type); + if (string.Equals(typeNamespace, il2CppTypeNamespace, System.StringComparison.Ordinal) && + string.Equals(typeName, il2CppTypeName, System.StringComparison.Ordinal)) + { + return type; + } + } + + return null; + + [RequiresDynamicCode("")] + static (string Namespace, string Name) GetIl2CppTypeNamespaceAndName(System.Type systemType) + { + var @namespace = typeof(Il2CppType).GetMethod(nameof(Il2CppType.GetNamespace))!.MakeGenericMethod(systemType).Invoke(null, null) as string ?? string.Empty; + var name = typeof(Il2CppType).GetMethod(nameof(Il2CppType.GetName))!.MakeGenericMethod(systemType).Invoke(null, null) as string ?? string.Empty; + return (@namespace, name); + } + } + + private static System.Reflection.Assembly? TryGetSystemAssembly(string il2CppAssemblyName) + { + return TryGetSystemAssemblyImplementation(il2CppAssemblyName) ?? TryGetSystemAssemblyImplementation("Il2Cpp" + il2CppAssemblyName); + + static System.Reflection.Assembly? TryGetSystemAssemblyImplementation(string exactName) + { + var alternateName = exactName.EndsWith(".dll", System.StringComparison.OrdinalIgnoreCase) + ? exactName.Substring(0, exactName.Length - 4) + : exactName + ".dll"; + + foreach (var assembly in System.AppDomain.CurrentDomain.GetAssemblies()) + { + var name = assembly.GetName().Name; + if (string.Equals(name, exactName, System.StringComparison.OrdinalIgnoreCase) || + string.Equals(name, alternateName, System.StringComparison.OrdinalIgnoreCase)) + { + return assembly; + } + } + return null; + } + } + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "GetGenericArguments")] + [return: UnsafeAccessorType($"Il2CppInterop.Runtime.InteropTypes.Arrays.{nameof(Il2CppArrayRank1<>)}`1[[Il2CppSystem.Type, Il2Cppmscorlib]]")] + private static extern object GetGenericArgumentsInternal(Type type); + + private static IReadOnlyList GetGenericArguments(this Type type) + { + return (IReadOnlyList)GetGenericArgumentsInternal(type); + } } diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index 0172bfb6..8f8c6fc1 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -48,6 +48,13 @@ public static Il2CppSystem.Type ManagedTypeToIl2CppType(Type type) return Il2CppSystem.Type.FromSystemType(type); } + [RequiresDynamicCode("")] + [RequiresUnreferencedCode("")] + public static Type Il2CppTypeToManagedType(Il2CppSystem.Type type) + { + return type.ToSystemType(); + } + [RequiresDynamicCode("")] public static unsafe Il2CppSystem.TypedReference MakeRefAny(void* value) where T : IIl2CppType { diff --git a/Il2Cppmscorlib/Type.cs b/Il2Cppmscorlib/Type.cs index 9871b690..03dd41b1 100644 --- a/Il2Cppmscorlib/Type.cs +++ b/Il2Cppmscorlib/Type.cs @@ -12,44 +12,50 @@ public abstract class Type : Object, IIl2CppType public RuntimeTypeHandle _impl { get; set; } - public abstract Type GetNestedType(String name, BindingFlags bindingAttr); + public Assembly Assembly => throw null; + + public Boolean ContainsGenericParameters => throw null; - public static Type internal_from_handle(IntPtr handle) - { - throw null; - } - - public virtual RuntimeTypeHandle TypeHandle - { - get - { - throw null; - } - } - - public Boolean IsPrimitive - { - get - { - throw null; - } - } - - public Boolean IsByRef - { - get - { - throw null; - } - } - - public MethodInfo GetMethod(String name) - { - throw null; - } + public Type DeclaringType => throw null; public abstract String FullName { get; } + public Boolean IsArray => throw null; + + public Boolean IsByRef => throw null; + + public Boolean IsGenericType => throw null; + + public Boolean IsGenericTypeDefinition => throw null; + + public Boolean IsNested => throw null; + + public Boolean IsPointer => throw null; + + public Boolean IsPrimitive => throw null; + + public Boolean IsSZArray => throw null; + + public Boolean IsTypeDefinition => throw null; + + public String NameOrDefault => throw null; + + public String Namespace => throw null; + + public virtual RuntimeTypeHandle TypeHandle => throw null; + + public Int32 GetArrayRank() => throw null; + + public Type GetElementType() => throw null; + + public Type GetGenericTypeDefinition() => throw null; + + public MethodInfo GetMethod(String name) => throw null; + + public abstract Type GetNestedType(String name, BindingFlags bindingAttr); + + public static Type internal_from_handle(IntPtr handle) => throw null; + public Type MakeByRefType() => throw null; public Type MakeGenericType(Type[] typeArguments) => throw null; @@ -59,6 +65,6 @@ public MethodInfo GetMethod(String name) public static Boolean operator ==(Type left, Type right) => throw null; public static Boolean operator !=(Type left, Type right) => throw null; - public override bool Equals(object obj) => throw new System.NotImplementedException(); - public override int GetHashCode() => throw new System.NotImplementedException(); + public override bool Equals(object obj) => throw null; + public override int GetHashCode() => throw null; } From a640f4b5f666407dee6bd78c7fd2bde381f2073b Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Tue, 23 Jun 2026 21:52:20 -0700 Subject: [PATCH 476/486] Improve AOT annotations * Replace pragma directives with suppression attributes * Add additional annotation attributes where necessary * Remove system delegate unstripping from DelegateConversionProcessingLayer, as it's no longer needed --- Il2CppInterop.Common/Il2CppType.cs | 6 +- .../DelegateConversionProcessingLayer.cs | 90 +++++-------------- ...ferenceAssemblyInjectionProcessingLayer.cs | 7 +- .../Il2CppInteropDetour.cs | 3 +- .../Il2CppInteropDetourFactory.cs | 6 +- Il2CppInterop.Runtime/DelegateSupport.cs | 4 +- .../Extensions/AssemblyExtensions.cs | 4 +- .../Injection/TypeInjector.cs | 3 +- .../Il2CppToMonoDelegateReference.cs | 3 +- 9 files changed, 35 insertions(+), 91 deletions(-) diff --git a/Il2CppInterop.Common/Il2CppType.cs b/Il2CppInterop.Common/Il2CppType.cs index 4a478733..bdaa03ce 100644 --- a/Il2CppInterop.Common/Il2CppType.cs +++ b/Il2CppInterop.Common/Il2CppType.cs @@ -152,11 +152,10 @@ public static nint GetClassPointer(Type type) .Invoke(null, null)!; } + [SuppressMessage("Trimming", "IL2059:The type passed to the RunClassConstructor is not statically known, Trimmer can't make sure that its static constructor is available.", Justification = "This will never be called in a trimmed context.")] public static nint GetClassPointer() where T : IIl2CppType { -#pragma warning disable IL2059 // The type passed to the RunClassConstructor is not statically known, Trimmer can't make sure that its static constructor is available. RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); -#pragma warning restore IL2059 // The type passed to the RunClassConstructor is not statically known, Trimmer can't make sure that its static constructor is available. return Il2CppClassPointerStore.NativeClassPointer; } @@ -169,11 +168,10 @@ public static void SetClassPointer(Type type, nint classPointer) .Invoke(null, [classPointer]); } + [SuppressMessage("Trimming", "IL2059:The type passed to the RunClassConstructor is not statically known, Trimmer can't make sure that its static constructor is available.", Justification = "This will never be called in a trimmed context.")] public static void SetClassPointer(nint classPointer) where T : IIl2CppType { -#pragma warning disable IL2059 // The type passed to the RunClassConstructor is not statically known, Trimmer can't make sure that its static constructor is available. RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); -#pragma warning restore IL2059 // The type passed to the RunClassConstructor is not statically known, Trimmer can't make sure that its static constructor is available. if (Il2CppClassPointerStore.NativeClassPointer != classPointer) { if (Il2CppClassPointerStore.NativeClassPointer == nint.Zero) diff --git a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs index 6655c9ad..251c83d9 100644 --- a/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs +++ b/Il2CppInterop.Generator/DelegateConversionProcessingLayer.cs @@ -1,5 +1,4 @@ using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Reflection; using Cpp2IL.Core.Api; using Cpp2IL.Core.Model.Contexts; @@ -15,9 +14,14 @@ public class DelegateConversionProcessingLayer : Cpp2IlProcessingLayer public override string Id => "delegate_conversion"; + /// + /// The maximum number of parameters that a System.Action or System.Func delegate can have. + /// + private const int MaxSystemDelegateParameters = 16; + public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { - PolyfillActionFuncDelegates(appContext, out var actionTypes, out var funcTypes); + GetActionFuncDelegates(appContext, out var actionTypes, out var funcTypes); var multicastDelegateType = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.MulticastDelegate"); var asyncCallbackType = appContext.Mscorlib.GetTypeByFullNameOrThrow("System.AsyncCallback"); @@ -122,7 +126,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action - /// mscorlib only contains Action and Func delegates with up to 8 parameters. - /// However, System.Private.CoreLib contains Action and Func delegates with up to 16 parameters. - /// This method will create the Action and Func delegates with more than 8 parameters, - /// so that they can be used when the mscorlib assembly references are replaced with System.Private.CoreLib references. - /// - /// - /// - /// - private static void PolyfillActionFuncDelegates(ApplicationAnalysisContext appContext, out TypeAnalysisContext[] actionTypes, out TypeAnalysisContext[] funcTypes) + private static void GetActionFuncDelegates(ApplicationAnalysisContext appContext, out TypeAnalysisContext[] actionTypes, out TypeAnalysisContext[] funcTypes) { var mscorlib = appContext.Mscorlib; -#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code -#pragma warning disable IL2111 // Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. - actionTypes = - [ - GetOrInjectType(mscorlib, typeof(Action)), - GetOrInjectType(mscorlib, typeof(Action<>)), - GetOrInjectType(mscorlib, typeof(Action<,>)), - GetOrInjectType(mscorlib, typeof(Action<,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Action<,,,,,,,,,,,,,,,>)), - ]; - - funcTypes = - [ - GetOrInjectType(mscorlib, typeof(Func<>)), - GetOrInjectType(mscorlib, typeof(Func<,>)), - GetOrInjectType(mscorlib, typeof(Func<,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,,,,,,>)), - GetOrInjectType(mscorlib, typeof(Func<,,,,,,,,,,,,,,,,>)), - ]; -#pragma warning restore IL2111 // Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. -#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code - - static TypeAnalysisContext GetOrInjectType(AssemblyAnalysisContext mscorlib, [DynamicallyAccessedMembers(InjectedTypeAnalysisContextExtensions.AccessedMemberTypes)] Type type) + actionTypes = Enumerable.Range(0, MaxSystemDelegateParameters + 1) + .Select(i => GetActionType(mscorlib, i)) + .ToArray(); + + funcTypes = Enumerable.Range(0, MaxSystemDelegateParameters + 1) + .Select(i => GetFuncType(mscorlib, i)) + .ToArray(); + + static TypeAnalysisContext GetActionType(AssemblyAnalysisContext mscorlib, int parameterCount) => parameterCount switch { - var result = mscorlib.GetTypeByFullName(type.FullName!); - if (result is null) - { - var injectedType = mscorlib.InjectType(type); - injectedType.InjectContentFromSourceType(type); - result = injectedType; - } - return result; - } + 0 => mscorlib.GetTypeByFullNameOrThrow("System.Action"), + _ => mscorlib.GetTypeByFullNameOrThrow($"System.Action`{parameterCount}"), + }; + static TypeAnalysisContext GetFuncType(AssemblyAnalysisContext mscorlib, int parameterCount) => mscorlib.GetTypeByFullNameOrThrow($"System.Func`{parameterCount + 1}"); } } diff --git a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs index 044bc84d..5fbea1a9 100644 --- a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs +++ b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs @@ -16,6 +16,9 @@ public class ReferenceAssemblyInjectionProcessingLayer : Cpp2IlProcessingLayer { public override string Id => "reference_assembly_injector"; public override string Name => "Inject required references into the Cpp2IL context system"; + + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "The accessed members are never invoked by this processing layer, only viewed for reference.")] + [SuppressMessage("Trimming", "IL2111:Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method.", Justification = "The accessed members are never invoked by this processing layer, only viewed for reference.")] public override void Process(ApplicationAnalysisContext appContext, Action? progressCallback = null) { // Types need to be provided twice, so that the linker can find them @@ -89,14 +92,10 @@ public override void Process(ApplicationAnalysisContext appContext, Action)); InjectContentFromSourceType(injectedAssembly, typeof(Il2CppArrayRank5<>)); -#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code InjectContentFromSourceType(injectedAssembly, typeof(Il2CppException)); -#pragma warning disable IL2111 // Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. InjectContentFromSourceType(injectedAssembly, typeof(TypeInjector)); -#pragma warning restore IL2111 // Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. InjectContentFromSourceType(injectedAssembly, typeof(DelegateSupport)); InjectContentFromSourceType(injectedAssembly, typeof(RuntimeInvoke)); -#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code InjectContentFromSourceType(injectedAssembly, typeof(FieldAccess)); InjectContentFromSourceType(injectedAssembly, typeof(Pointer<>)); InjectContentFromSourceType(injectedAssembly, typeof(ByReference<>)); diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs index 83b05704..4f32c7d3 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs @@ -155,9 +155,8 @@ private DynamicMethodDefinition CreateWrappedDMD(MethodReference methodRef) } [RequiresDynamicCode("")] -#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. + [SuppressMessage("AOT", "IL3051:'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides.", Justification = "The constructor for this class requires dynamic code generation, which warns the user before this method can ever be called.")] public void Apply() -#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. { if (NativeSource.MethodPointer == default) { diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs index 74c50324..45ba9322 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetourFactory.cs @@ -13,11 +13,9 @@ public sealed class Il2CppInteropDetourFactory(IDetourFactory? fallback = null) [RequiresUnreferencedCode("")] [RequiresDynamicCode("")] -#pragma warning disable IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. -#pragma warning disable IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. + [SuppressMessage("Trimming", "IL2046:'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides.", Justification = "This method will never be called in a trimmed context.")] + [SuppressMessage("AOT", "IL3051:'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides.", Justification = "This method will never be called in an AOT context.")] public ICoreDetour CreateDetour(CreateDetourRequest request) -#pragma warning restore IL3051 // 'RequiresDynamicCodeAttribute' annotations must match across all interface implementations or overrides. -#pragma warning restore IL2046 // 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. { ArgumentNullException.ThrowIfNull(request.Source); ArgumentNullException.ThrowIfNull(request.Target); diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index cdafd507..0ec0fcf4 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -19,14 +19,14 @@ public static class DelegateSupport [RequiresUnreferencedCode("")] [RequiresDynamicCode("")] - private static Delegate GetOrCreateNativeToManagedTrampoline(Type delegateType) + private static Delegate GetOrCreateNativeToManagedTrampoline([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type delegateType) { return NativeToManagedTrampolines.GetOrAdd(delegateType, CreateNativeToManagedTrampoline); } [RequiresUnreferencedCode("")] [RequiresDynamicCode("")] - private static Delegate CreateNativeToManagedTrampoline(Type delegateType) + private static Delegate CreateNativeToManagedTrampoline([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type delegateType) { var invokeMethod = Il2CppToMonoDelegateReference.GetOrCreateInvokeMethod(delegateType); return TrampolineBuilder.CreateTrampoline(invokeMethod, false); diff --git a/Il2CppInterop.Runtime/Extensions/AssemblyExtensions.cs b/Il2CppInterop.Runtime/Extensions/AssemblyExtensions.cs index 1c460484..4d51ea11 100644 --- a/Il2CppInterop.Runtime/Extensions/AssemblyExtensions.cs +++ b/Il2CppInterop.Runtime/Extensions/AssemblyExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; @@ -6,13 +7,12 @@ namespace Il2CppInterop.Runtime.Extensions; internal static class AssemblyExtensions { + [RequiresUnreferencedCode("")] public static Type[] GetTypesSafe(this Assembly assembly) { try { -#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code return assembly.GetTypes(); -#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code } catch (ReflectionTypeLoadException ex) { diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 066bbfcb..f92b1f5c 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -653,6 +653,7 @@ private static IEnumerable GetIl2CppInstanceFieldTypes([DynamicallyAccesse return GetIl2CppFields(type).Where(f => !f.Attributes.HasFlag(FieldAttributes.Static)).Select(f => f.FieldType); } + [RequiresDynamicCode("Calls System.Type.MakeGenericType(params Type[])")] private static void ValidateTypeUsingReflection([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] Type type) { // Enums are transformed into structs during generation @@ -714,9 +715,7 @@ private static void ValidateTypeUsingReflection([DynamicallyAccessedMembers(Dyna // This will throw if the type does not implement IIl2CppType where T is the type itself // because T has a self-referential constraint that cannot be satisfied if the type does not implement the interface correctly. // If https://github.com/dotnet/runtime/issues/28033 is implemented, we can replace this with a more direct check. -#pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. typeof(IIl2CppType<>).MakeGenericType(type); -#pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. } catch { diff --git a/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs index 16d7df13..71527cb4 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs @@ -51,11 +51,10 @@ partial void LogErrorIl2CppFinalize(Exception exception) /// The type of the delegate to cast and invoke. /// The dynamic method. [RequiresDynamicCode("")] + [RequiresUnreferencedCode("")] internal static MethodInfo GetOrCreateInvokeMethod([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type delegateType) { -#pragma warning disable IL2111 // Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. return _methodInfoCache.GetOrAdd(delegateType, CreateInvokeMethod); -#pragma warning restore IL2111 // Method with parameters or return value with `DynamicallyAccessedMembersAttribute` is accessed via reflection. Trimmer can't guarantee availability of the requirements of the method. } [RequiresDynamicCode("")] From 95f71e81855aba70c6c063ad99c0254ceca43c7c Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 24 Jun 2026 01:21:45 -0700 Subject: [PATCH 477/486] Source generate UnityVersionHandler initialization --- .../Structs/UnityVersionHandler.cs | 164 ++++---------- .../Assembly/Assembly_104_0.cs | 4 + .../VersionSpecific/Assembly/Assembly_16_0.cs | 5 + .../VersionSpecific/Assembly/Assembly_20_0.cs | 5 + .../VersionSpecific/Assembly/Assembly_24_0.cs | 4 + .../VersionSpecific/Assembly/Assembly_24_1.cs | 7 + .../VersionSpecific/Assembly/Assembly_24_2.cs | 7 + .../Assembly/UnityVersionHandler.cs | 69 ++++++ .../AssemblyName/AssemblyName_16_0.cs | 4 + .../AssemblyName/AssemblyName_24_0.cs | 7 + .../AssemblyName/AssemblyName_24_1.cs | 7 + .../AssemblyName/UnityVersionHandler.cs | 49 +++++ .../VersionSpecific/Class/Class_104_0.cs | 4 + .../VersionSpecific/Class/Class_105_0.cs | 4 + .../VersionSpecific/Class/Class_16_0.cs | 5 + .../VersionSpecific/Class/Class_19_0.cs | 5 + .../VersionSpecific/Class/Class_20_0.cs | 5 + .../VersionSpecific/Class/Class_21_0.cs | 5 + .../VersionSpecific/Class/Class_21_1.cs | 5 + .../VersionSpecific/Class/Class_21_2.cs | 4 + .../VersionSpecific/Class/Class_22_0.cs | 4 + .../VersionSpecific/Class/Class_22_1.cs | 4 + .../VersionSpecific/Class/Class_23_0.cs | 4 + .../VersionSpecific/Class/Class_23_1.cs | 4 + .../VersionSpecific/Class/Class_24_0.cs | 4 + .../VersionSpecific/Class/Class_24_1.cs | 4 + .../VersionSpecific/Class/Class_24_2.cs | 5 + .../VersionSpecific/Class/Class_24_3.cs | 5 + .../VersionSpecific/Class/Class_24_4.cs | 4 + .../VersionSpecific/Class/Class_24_5.cs | 5 + .../VersionSpecific/Class/Class_24_6.cs | 5 + .../VersionSpecific/Class/Class_24_7.cs | 4 + .../VersionSpecific/Class/Class_27_0.cs | 4 + .../VersionSpecific/Class/Class_27_1.cs | 4 + .../VersionSpecific/Class/Class_27_2.cs | 4 + .../VersionSpecific/Class/Class_27_3.cs | 4 + .../VersionSpecific/Class/Class_27_4.cs | 4 + .../VersionSpecific/Class/Class_27_5.cs | 5 + .../VersionSpecific/Class/Class_29_0.cs | 5 + .../VersionSpecific/Class/Class_29_1.cs | 4 + .../VersionSpecific/Class/Class_29_2.cs | 5 + .../VersionSpecific/Class/Class_39_0.cs | 4 + .../Class/UnityVersionHandler.cs | 181 ++++++++++++++++ .../EventInfo/EventInfo_16_0.cs | 5 + .../EventInfo/EventInfo_19_0.cs | 5 + .../EventInfo/EventInfo_24_0.cs | 4 + .../EventInfo/UnityVersionHandler.cs | 33 +++ .../Exception/Exception_16_0.cs | 5 + .../Exception/Exception_20_0.cs | 5 + .../Exception/Exception_21_0.cs | 5 + .../Exception/Exception_22_0.cs | 4 + .../Exception/Exception_23_0.cs | 5 + .../Exception/Exception_23_1.cs | 4 + .../Exception/Exception_27_0.cs | 4 + .../Exception/UnityVersionHandler.cs | 57 +++++ .../FieldInfo/FieldInfo_16_0.cs | 5 + .../FieldInfo/FieldInfo_19_0.cs | 5 + .../FieldInfo/FieldInfo_24_0.cs | 4 + .../FieldInfo/UnityVersionHandler.cs | 33 +++ .../VersionSpecific/Image/Image_16_0.cs | 5 + .../VersionSpecific/Image/Image_19_0.cs | 5 + .../VersionSpecific/Image/Image_24_0.cs | 5 + .../VersionSpecific/Image/Image_24_1.cs | 5 + .../VersionSpecific/Image/Image_24_2.cs | 4 + .../VersionSpecific/Image/Image_24_3.cs | 4 + .../VersionSpecific/Image/Image_24_4.cs | 4 + .../VersionSpecific/Image/Image_24_5.cs | 4 + .../VersionSpecific/Image/Image_24_6.cs | 4 + .../Image/UnityVersionHandler.cs | 65 ++++++ .../MethodInfo/MethodInfo_16_0.cs | 5 + .../MethodInfo/MethodInfo_21_0.cs | 5 + .../MethodInfo/MethodInfo_24_0.cs | 4 + .../MethodInfo/MethodInfo_24_1.cs | 4 + .../MethodInfo/MethodInfo_24_2.cs | 4 + .../MethodInfo/MethodInfo_27_0.cs | 4 + .../MethodInfo/MethodInfo_28_0.cs | 4 + .../MethodInfo/MethodInfo_29_0.cs | 6 + .../MethodInfo/MethodInfo_29_1.cs | 5 + .../MethodInfo/MethodInfo_29_2.cs | 4 + .../MethodInfo/UnityVersionHandler.cs | 73 +++++++ .../ParameterInfo/ParameterInfo_16_0.cs | 4 + .../ParameterInfo/ParameterInfo_24_0.cs | 4 + .../ParameterInfo/ParameterInfo_27_0.cs | 4 + .../ParameterInfo/UnityVersionHandler.cs | 25 +++ .../PropertyInfo/PropertyInfo_16_0.cs | 5 + .../PropertyInfo/PropertyInfo_19_0.cs | 5 + .../PropertyInfo/PropertyInfo_24_0.cs | 4 + .../PropertyInfo/UnityVersionHandler.cs | 33 +++ .../Structs/VersionSpecific/Type/Type_16_0.cs | 4 + .../Structs/VersionSpecific/Type/Type_27_0.cs | 4 + .../Type/UnityVersionHandler.cs | 21 ++ .../CodeGen/CodeGenElement.cs | 13 +- .../CodeGen/CodeGenProperty.cs | 18 +- .../CppTypeExtensions.cs | 13 ++ .../DictionaryExtensions.cs | 16 ++ .../Il2CppStructWrapperGenerator.cs | 204 ++++++++++++------ .../NativeStructGenerator.cs | 8 +- .../StructHandlerGenerator.cs | 7 + .../TypeGenerators/Il2CppAssemblyGenerator.cs | 6 +- .../Il2CppAssemblyNameGenerator.cs | 6 +- .../TypeGenerators/Il2CppClassGenerator.cs | 6 +- .../Il2CppEventInfoGenerator.cs | 6 +- .../Il2CppExceptionGenerator.cs | 6 +- .../Il2CppFieldInfoGenerator.cs | 6 +- .../TypeGenerators/Il2CppImageGenerator.cs | 6 +- .../Il2CppMethodInfoGenerator.cs | 6 +- .../Il2CppParameterInfoGenerator.cs | 6 +- .../Il2CppPropertyInfoGenerator.cs | 6 +- .../TypeGenerators/Il2CppTypeGenerator.cs | 5 +- .../VersionSpecificGenerator.cs | 15 +- 110 files changed, 1270 insertions(+), 253 deletions(-) create mode 100644 Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/UnityVersionHandler.cs create mode 100644 Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/UnityVersionHandler.cs create mode 100644 Il2CppInterop.Runtime/Structs/VersionSpecific/Class/UnityVersionHandler.cs create mode 100644 Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/UnityVersionHandler.cs create mode 100644 Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/UnityVersionHandler.cs create mode 100644 Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/UnityVersionHandler.cs create mode 100644 Il2CppInterop.Runtime/Structs/VersionSpecific/Image/UnityVersionHandler.cs create mode 100644 Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/UnityVersionHandler.cs create mode 100644 Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/UnityVersionHandler.cs create mode 100644 Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/UnityVersionHandler.cs create mode 100644 Il2CppInterop.Runtime/Structs/VersionSpecific/Type/UnityVersionHandler.cs create mode 100644 Il2CppInterop.StructGenerator/CppTypeExtensions.cs create mode 100644 Il2CppInterop.StructGenerator/DictionaryExtensions.cs diff --git a/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs index 5d88c819..1a9c62c9 100644 --- a/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/UnityVersionHandler.cs @@ -1,11 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; using System.Runtime.InteropServices; using AssetRipper.Primitives; -using Il2CppInterop.Common; -using Il2CppInterop.Runtime.Extensions; using Il2CppInterop.Runtime.Startup; using Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly; using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; @@ -18,60 +13,13 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo; using Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo; using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; -using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime.Structs; -public static class UnityVersionHandler +public static partial class UnityVersionHandler { - private static readonly Type[] InterfacesOfInterest; - private static readonly Dictionary> VersionedHandlers = new(); - private static readonly Dictionary Handlers = new(); - -#nullable disable - internal static INativeAssemblyStructHandler assemblyStructHandler; - internal static INativeAssemblyNameStructHandler assemblyNameStructHandler; - internal static INativeClassStructHandler classStructHandler; - internal static INativeEventInfoStructHandler eventInfoStructHandler; - internal static INativeExceptionStructHandler exceptionStructHandler; - internal static INativeFieldInfoStructHandler fieldInfoStructHandler; - internal static INativeImageStructHandler imageStructHandler; - internal static INativeMethodInfoStructHandler methodInfoStructHandler; - internal static INativeParameterInfoStructHandler parameterInfoStructHandler; - internal static INativePropertyInfoStructHandler propertyInfoStructHandler; - internal static INativeTypeStructHandler typeStructHandler; -#nullable restore - static UnityVersionHandler() { - var allTypes = typeof(UnityVersionHandler).Assembly.GetTypesSafe(); - var interfacesOfInterest = allTypes.Where(t => - t.IsInterface && typeof(INativeStructHandler).IsAssignableFrom(t) && t != typeof(INativeStructHandler)) - .ToArray(); - InterfacesOfInterest = interfacesOfInterest; - - foreach (var i in interfacesOfInterest) VersionedHandlers[i] = new List<(UnityVersion Version, object Handler)>(); - - foreach (var handlerImpl in allTypes.Where(t => - !t.IsAbstract && interfacesOfInterest.Any(i => i.IsAssignableFrom(t)))) - foreach (var startVersion in handlerImpl.GetCustomAttributes()) - { -#pragma warning disable IL2072 // Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations. - var instance = Activator.CreateInstance(handlerImpl)!; -#pragma warning restore IL2072 // Target parameter argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations. - -#pragma warning disable IL2075 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations. - foreach (var i in handlerImpl.GetInterfaces()) - { - if (interfacesOfInterest.Contains(i)) - VersionedHandlers[i].Add((UnityVersion.Parse(startVersion.StartVersion), instance)); - } -#pragma warning restore IL2075 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The return value of the source method does not have matching annotations. - } - - foreach (var handlerList in VersionedHandlers.Values) - handlerList.Sort((a, b) => -a.Version.CompareTo(b.Version)); - RecalculateHandlers(); } @@ -84,172 +32,152 @@ static UnityVersionHandler() internal static void RecalculateHandlers() { - Handlers.Clear(); var unityVersion = Il2CppInteropRuntime.Instance.UnityVersion; - foreach (var type in InterfacesOfInterest) - foreach (var valueTuple in VersionedHandlers[type]) - { - if (valueTuple.Version > unityVersion) continue; - - Handlers[type] = valueTuple.Handler; - break; - } - HasGetMethodFromReflection = unityVersion.GreaterThanOrEquals(2018, 2, 0, UnityVersionType.Beta, 6); IsMetadataV29OrHigher = unityVersion.GreaterThanOrEquals(2021, 2, 0); HasShimForGetMethod = unityVersion.GreaterThanOrEquals(2020, 3, 41) || IsMetadataV29OrHigher; - assemblyStructHandler = GetHandler(); - assemblyNameStructHandler = GetHandler(); - classStructHandler = GetHandler(); - eventInfoStructHandler = GetHandler(); - exceptionStructHandler = GetHandler(); - fieldInfoStructHandler = GetHandler(); - imageStructHandler = GetHandler(); - methodInfoStructHandler = GetHandler(); - parameterInfoStructHandler = GetHandler(); - propertyInfoStructHandler = GetHandler(); - typeStructHandler = GetHandler(); - } - - private static T GetHandler() - { - if (Handlers.TryGetValue(typeof(T), out var result)) - return (T)result; - - Logger.Instance.LogError("No direct for {TypeFullName} found for Unity {UnityVersion}; this likely indicates a severe error somewhere", typeof(T).FullName, Il2CppInteropRuntime.Instance.UnityVersion); - - throw new ApplicationException("No handler"); + SetAssemblyNameStructHandler(unityVersion); + SetAssemblyStructHandler(unityVersion); + SetClassStructHandler(unityVersion); + SetEventInfoStructHandler(unityVersion); + SetExceptionStructHandler(unityVersion); + SetFieldInfoStructHandler(unityVersion); + SetImageStructHandler(unityVersion); + SetMethodInfoStructHandler(unityVersion); + SetParameterInfoStructHandler(unityVersion); + SetPropertyInfoStructHandler(unityVersion); + SetTypeStructHandler(unityVersion); } //Assemblies public static INativeAssemblyStruct NewAssembly() { - return assemblyStructHandler.CreateNewStruct(); + return AssemblyStructHandler.CreateNewStruct(); } public static unsafe INativeAssemblyStruct Wrap(Il2CppAssembly* assemblyPointer) { - return assemblyStructHandler.Wrap(assemblyPointer); + return AssemblyStructHandler.Wrap(assemblyPointer); } public static int AssemblySize() { - return assemblyStructHandler.Size; + return AssemblyStructHandler.Size; } //Assembly Names public static INativeAssemblyNameStruct NewAssemblyName() { - return assemblyNameStructHandler.CreateNewStruct(); + return AssemblyNameStructHandler.CreateNewStruct(); } public static unsafe INativeAssemblyNameStruct Wrap(Il2CppAssemblyName* assemblyNamePointer) { - return assemblyNameStructHandler.Wrap(assemblyNamePointer); + return AssemblyNameStructHandler.Wrap(assemblyNamePointer); } public static int AssemblyNameSize() { - return assemblyNameStructHandler.Size; + return AssemblyNameStructHandler.Size; } //Classes public static INativeClassStruct NewClass(int vTableSlots) { - return classStructHandler.CreateNewStruct(vTableSlots); + return ClassStructHandler.CreateNewStruct(vTableSlots); } public static unsafe INativeClassStruct Wrap(Il2CppClass* classPointer) { - return classStructHandler.Wrap(classPointer); + return ClassStructHandler.Wrap(classPointer); } public static int ClassSize() { - return classStructHandler.Size; + return ClassStructHandler.Size; } //Events public static INativeEventInfoStruct NewEvent() { - return eventInfoStructHandler.CreateNewStruct(); + return EventInfoStructHandler.CreateNewStruct(); } public static unsafe INativeEventInfoStruct Wrap(Il2CppEventInfo* eventInfoPointer) { - return eventInfoStructHandler.Wrap(eventInfoPointer); + return EventInfoStructHandler.Wrap(eventInfoPointer); } public static int EventSize() { - return eventInfoStructHandler.Size; + return EventInfoStructHandler.Size; } //Exceptions public static INativeExceptionStruct NewException() { - return exceptionStructHandler.CreateNewStruct(); + return ExceptionStructHandler.CreateNewStruct(); } public static unsafe INativeExceptionStruct Wrap(Il2CppException* exceptionPointer) { - return exceptionStructHandler.Wrap(exceptionPointer); + return ExceptionStructHandler.Wrap(exceptionPointer); } public static int ExceptionSize() { - return exceptionStructHandler.Size; + return ExceptionStructHandler.Size; } //Fields public static INativeFieldInfoStruct NewField() { - return fieldInfoStructHandler.CreateNewStruct(); + return FieldInfoStructHandler.CreateNewStruct(); } public static unsafe INativeFieldInfoStruct Wrap(Il2CppFieldInfo* fieldInfoPointer) { - return fieldInfoStructHandler.Wrap(fieldInfoPointer); + return FieldInfoStructHandler.Wrap(fieldInfoPointer); } public static int FieldInfoSize() { - return fieldInfoStructHandler.Size; + return FieldInfoStructHandler.Size; } //Images public static INativeImageStruct NewImage() { - return imageStructHandler.CreateNewStruct(); + return ImageStructHandler.CreateNewStruct(); } public static unsafe INativeImageStruct Wrap(Il2CppImage* imagePointer) { - return imageStructHandler.Wrap(imagePointer); + return ImageStructHandler.Wrap(imagePointer); } public static int ImageSize() { - return imageStructHandler.Size; + return ImageStructHandler.Size; } //Methods public static INativeMethodInfoStruct NewMethod() { - return methodInfoStructHandler.CreateNewStruct(); + return MethodInfoStructHandler.CreateNewStruct(); } public static unsafe INativeMethodInfoStruct Wrap(Il2CppMethodInfo* methodPointer) { - return methodInfoStructHandler.Wrap(methodPointer); + return MethodInfoStructHandler.Wrap(methodPointer); } public static int MethodSize() { - return methodInfoStructHandler.Size; + return MethodInfoStructHandler.Size; } //Parameters @@ -258,7 +186,7 @@ public static int MethodSize() if (count == 0) return []; - var elementSize = parameterInfoStructHandler.Size; + var elementSize = ParameterInfoStructHandler.Size; var totalSize = elementSize * count; var startPointer = Marshal.AllocHGlobal(totalSize); new Span(startPointer.ToPointer(), totalSize).Clear(); @@ -272,44 +200,44 @@ public static int MethodSize() public static unsafe INativeParameterInfoStruct Wrap(Il2CppParameterInfo* parameterInfo) { - return parameterInfoStructHandler.Wrap(parameterInfo); + return ParameterInfoStructHandler.Wrap(parameterInfo); } public static unsafe INativeParameterInfoStruct Wrap(Il2CppParameterInfo* parameterInfo, int index) { - var address = (nint)parameterInfo + index * parameterInfoStructHandler.Size; - return parameterInfoStructHandler.Wrap((Il2CppParameterInfo*)address); + var address = (nint)parameterInfo + index * ParameterInfoStructHandler.Size; + return ParameterInfoStructHandler.Wrap((Il2CppParameterInfo*)address); } //Properties public static INativePropertyInfoStruct NewProperty() { - return propertyInfoStructHandler.CreateNewStruct(); + return PropertyInfoStructHandler.CreateNewStruct(); } public static unsafe INativePropertyInfoStruct Wrap(Il2CppPropertyInfo* propertyInfoPointer) { - return propertyInfoStructHandler.Wrap(propertyInfoPointer); + return PropertyInfoStructHandler.Wrap(propertyInfoPointer); } public static int ParameterInfoSize() { - return parameterInfoStructHandler.Size; + return ParameterInfoStructHandler.Size; } //Types public static INativeTypeStruct NewType() { - return typeStructHandler.CreateNewStruct(); + return TypeStructHandler.CreateNewStruct(); } public static unsafe INativeTypeStruct Wrap(Il2CppTypeStruct* typePointer) { - return typeStructHandler.Wrap(typePointer); + return TypeStructHandler.Wrap(typePointer); } public static int TypeSize() { - return typeStructHandler.Size; + return TypeStructHandler.Size; } } diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_104_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_104_0.cs index 5ad3eb7c..196db1fc 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_104_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_104_0.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly [ApplicableToUnityVersionsSince("6000.5.0")] public unsafe class NativeAssemblyStructHandler_104_0 : INativeAssemblyStructHandler { + private NativeAssemblyStructHandler_104_0() + { + } public INativeAssemblyStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -18,6 +21,7 @@ public INativeAssemblyStruct Wrap(Il2CppAssembly* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeAssemblyStructHandler_104_0 Instance { get; } = new(); public int Size => sizeof(Il2CppAssembly_104_0); internal unsafe struct Il2CppAssembly_104_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_16_0.cs index e6e2d19d..9e132bdc 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_16_0.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly { [ApplicableToUnityVersionsSince("5.2.2")] + [ApplicableToUnityVersionsSince("5.4.0")] public unsafe class NativeAssemblyStructHandler_16_0 : INativeAssemblyStructHandler { + private NativeAssemblyStructHandler_16_0() + { + } public INativeAssemblyStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -18,6 +22,7 @@ public INativeAssemblyStruct Wrap(Il2CppAssembly* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeAssemblyStructHandler_16_0 Instance { get; } = new(); public int Size => sizeof(Il2CppAssembly_16_0); internal unsafe struct Il2CppAssembly_16_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_20_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_20_0.cs index 310194bc..972cec10 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_20_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_20_0.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly { [ApplicableToUnityVersionsSince("5.3.2p1")] + [ApplicableToUnityVersionsSince("5.4.0b4")] public unsafe class NativeAssemblyStructHandler_20_0 : INativeAssemblyStructHandler { + private NativeAssemblyStructHandler_20_0() + { + } public INativeAssemblyStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -18,6 +22,7 @@ public INativeAssemblyStruct Wrap(Il2CppAssembly* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeAssemblyStructHandler_20_0 Instance { get; } = new(); public int Size => sizeof(Il2CppAssembly_20_0); internal unsafe struct Il2CppAssembly_20_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_0.cs index d585a9b4..65854098 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_0.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeAssemblyStructHandler_24_0 : INativeAssemblyStructHandler { + private NativeAssemblyStructHandler_24_0() + { + } public INativeAssemblyStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -18,6 +21,7 @@ public INativeAssemblyStruct Wrap(Il2CppAssembly* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeAssemblyStructHandler_24_0 Instance { get; } = new(); public int Size => sizeof(Il2CppAssembly_24_0); internal unsafe struct Il2CppAssembly_24_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_1.cs index bbb6b19c..3ce09abd 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_1.cs @@ -4,8 +4,14 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly { [ApplicableToUnityVersionsSince("2018.3.0")] + [ApplicableToUnityVersionsSince("2019.1.0")] + [ApplicableToUnityVersionsSince("2020.1.0")] + [ApplicableToUnityVersionsSince("2020.2.0")] public unsafe class NativeAssemblyStructHandler_24_1 : INativeAssemblyStructHandler { + private NativeAssemblyStructHandler_24_1() + { + } public INativeAssemblyStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -18,6 +24,7 @@ public INativeAssemblyStruct Wrap(Il2CppAssembly* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeAssemblyStructHandler_24_1 Instance { get; } = new(); public int Size => sizeof(Il2CppAssembly_24_1); internal unsafe struct Il2CppAssembly_24_1 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_2.cs index 169906e9..f017e9f4 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/Assembly_24_2.cs @@ -4,8 +4,14 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly { [ApplicableToUnityVersionsSince("2018.4.34")] + [ApplicableToUnityVersionsSince("2019.4.15")] + [ApplicableToUnityVersionsSince("2020.1.11")] + [ApplicableToUnityVersionsSince("2020.2.0b7")] public unsafe class NativeAssemblyStructHandler_24_2 : INativeAssemblyStructHandler { + private NativeAssemblyStructHandler_24_2() + { + } public INativeAssemblyStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -18,6 +24,7 @@ public INativeAssemblyStruct Wrap(Il2CppAssembly* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeAssemblyStructHandler_24_2 Instance { get; } = new(); public int Size => sizeof(Il2CppAssembly_24_2); internal unsafe struct Il2CppAssembly_24_2 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/UnityVersionHandler.cs new file mode 100644 index 00000000..f36f2a3f --- /dev/null +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/UnityVersionHandler.cs @@ -0,0 +1,69 @@ +// +using AssetRipper.Primitives; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly; +namespace Il2CppInterop.Runtime.Structs +{ + public partial class UnityVersionHandler + { + private static void SetAssemblyStructHandler(UnityVersion version) + { + if (version >= new UnityVersion(6000, 5, 0, UnityVersionType.Alpha, 0)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_104_0.Instance; + } + else if (version >= new UnityVersion(2020, 2, 0, UnityVersionType.Beta, 7)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_24_2.Instance; + } + else if (version >= new UnityVersion(2020, 2, 0, UnityVersionType.Alpha, 0)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_24_1.Instance; + } + else if (version >= new UnityVersion(2020, 1, 11, UnityVersionType.Alpha, 0)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_24_2.Instance; + } + else if (version >= new UnityVersion(2020, 1, 0, UnityVersionType.Alpha, 0)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_24_1.Instance; + } + else if (version >= new UnityVersion(2019, 4, 15, UnityVersionType.Alpha, 0)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_24_2.Instance; + } + else if (version >= new UnityVersion(2019, 1, 0, UnityVersionType.Alpha, 0)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_24_1.Instance; + } + else if (version >= new UnityVersion(2018, 4, 34, UnityVersionType.Alpha, 0)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_24_2.Instance; + } + else if (version >= new UnityVersion(2018, 3, 0, UnityVersionType.Alpha, 0)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_24_1.Instance; + } + else if (version >= new UnityVersion(2018, 1, 0, UnityVersionType.Beta, 5)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_24_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Beta, 4)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_20_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Alpha, 0)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_16_0.Instance; + } + else if (version >= new UnityVersion(5, 3, 2, UnityVersionType.Patch, 1)) + { + AssemblyStructHandler = NativeAssemblyStructHandler_20_0.Instance; + } + else + { + AssemblyStructHandler = NativeAssemblyStructHandler_16_0.Instance; + } + } + private static INativeAssemblyStructHandler AssemblyStructHandler { get; set; } = NativeAssemblyStructHandler_16_0.Instance; + } +} diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_16_0.cs index e75d5f21..7b5cb6f9 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_16_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeAssemblyNameStructHandler_16_0 : INativeAssemblyNameStructHandler { + private NativeAssemblyNameStructHandler_16_0() + { + } public INativeAssemblyNameStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeAssemblyNameStruct Wrap(Il2CppAssemblyName* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeAssemblyNameStructHandler_16_0 Instance { get; } = new(); public int Size => sizeof(Il2CppAssemblyName_16_0); internal unsafe struct Il2CppAssemblyName_16_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_0.cs index fce527fa..31d91374 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_0.cs @@ -3,8 +3,14 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName { [ApplicableToUnityVersionsSince("2018.1.0b5")] + [ApplicableToUnityVersionsSince("2019.1.0")] + [ApplicableToUnityVersionsSince("2020.1.0")] + [ApplicableToUnityVersionsSince("2020.2.0")] public unsafe class NativeAssemblyNameStructHandler_24_0 : INativeAssemblyNameStructHandler { + private NativeAssemblyNameStructHandler_24_0() + { + } public INativeAssemblyNameStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +23,7 @@ public INativeAssemblyNameStruct Wrap(Il2CppAssemblyName* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeAssemblyNameStructHandler_24_0 Instance { get; } = new(); public int Size => sizeof(Il2CppAssemblyName_24_0); internal unsafe struct Il2CppAssemblyName_24_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_1.cs index b96a5d9e..961fb43a 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/AssemblyName_24_1.cs @@ -3,8 +3,14 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName { [ApplicableToUnityVersionsSince("2018.4.34")] + [ApplicableToUnityVersionsSince("2019.4.15")] + [ApplicableToUnityVersionsSince("2020.1.11")] + [ApplicableToUnityVersionsSince("2020.2.0b7")] public unsafe class NativeAssemblyNameStructHandler_24_1 : INativeAssemblyNameStructHandler { + private NativeAssemblyNameStructHandler_24_1() + { + } public INativeAssemblyNameStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +23,7 @@ public INativeAssemblyNameStruct Wrap(Il2CppAssemblyName* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeAssemblyNameStructHandler_24_1 Instance { get; } = new(); public int Size => sizeof(Il2CppAssemblyName_24_1); internal unsafe struct Il2CppAssemblyName_24_1 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/UnityVersionHandler.cs new file mode 100644 index 00000000..1876ce83 --- /dev/null +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/UnityVersionHandler.cs @@ -0,0 +1,49 @@ +// +using AssetRipper.Primitives; +using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; +namespace Il2CppInterop.Runtime.Structs +{ + public partial class UnityVersionHandler + { + private static void SetAssemblyNameStructHandler(UnityVersion version) + { + if (version >= new UnityVersion(2020, 2, 0, UnityVersionType.Beta, 7)) + { + AssemblyNameStructHandler = NativeAssemblyNameStructHandler_24_1.Instance; + } + else if (version >= new UnityVersion(2020, 2, 0, UnityVersionType.Alpha, 0)) + { + AssemblyNameStructHandler = NativeAssemblyNameStructHandler_24_0.Instance; + } + else if (version >= new UnityVersion(2020, 1, 11, UnityVersionType.Alpha, 0)) + { + AssemblyNameStructHandler = NativeAssemblyNameStructHandler_24_1.Instance; + } + else if (version >= new UnityVersion(2020, 1, 0, UnityVersionType.Alpha, 0)) + { + AssemblyNameStructHandler = NativeAssemblyNameStructHandler_24_0.Instance; + } + else if (version >= new UnityVersion(2019, 4, 15, UnityVersionType.Alpha, 0)) + { + AssemblyNameStructHandler = NativeAssemblyNameStructHandler_24_1.Instance; + } + else if (version >= new UnityVersion(2019, 1, 0, UnityVersionType.Alpha, 0)) + { + AssemblyNameStructHandler = NativeAssemblyNameStructHandler_24_0.Instance; + } + else if (version >= new UnityVersion(2018, 4, 34, UnityVersionType.Alpha, 0)) + { + AssemblyNameStructHandler = NativeAssemblyNameStructHandler_24_1.Instance; + } + else if (version >= new UnityVersion(2018, 1, 0, UnityVersionType.Beta, 5)) + { + AssemblyNameStructHandler = NativeAssemblyNameStructHandler_24_0.Instance; + } + else + { + AssemblyNameStructHandler = NativeAssemblyNameStructHandler_16_0.Instance; + } + } + private static INativeAssemblyNameStructHandler AssemblyNameStructHandler { get; set; } = NativeAssemblyNameStructHandler_16_0.Instance; + } +} diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs index 11a6fa40..d9e0a1c9 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("6000.5.0")] public unsafe class NativeClassStructHandler_104_0 : INativeClassStructHandler { + private NativeClassStructHandler_104_0() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_104_0 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_104_0); internal unsafe struct Il2CppClass_104_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs index bd08b4f7..94ca7463 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("6000.5.0a5")] public unsafe class NativeClassStructHandler_105_0 : INativeClassStructHandler { + private NativeClassStructHandler_105_0() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_105_0 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_105_0); internal unsafe struct Il2CppClass_105_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs index 04600a83..de8396bb 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.2.2")] + [ApplicableToUnityVersionsSince("5.4.0")] public unsafe class NativeClassStructHandler_16_0 : INativeClassStructHandler { + private NativeClassStructHandler_16_0() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -20,6 +24,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_16_0 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_16_0); internal unsafe struct Il2CppClass_16_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs index 12366d82..d430d6d3 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.3.1p3")] + [ApplicableToUnityVersionsSince("5.4.0b3")] public unsafe class NativeClassStructHandler_19_0 : INativeClassStructHandler { + private NativeClassStructHandler_19_0() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -20,6 +24,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_19_0 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_19_0); internal unsafe struct Il2CppClass_19_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs index 558bde89..1f308bfe 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.3.2p2")] + [ApplicableToUnityVersionsSince("5.4.0b8")] public unsafe class NativeClassStructHandler_20_0 : INativeClassStructHandler { + private NativeClassStructHandler_20_0() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -20,6 +24,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_20_0 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_20_0); internal unsafe struct Il2CppClass_20_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs index 7fee2c7a..1b3c2161 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.3.5p1")] + [ApplicableToUnityVersionsSince("5.4.0b19")] public unsafe class NativeClassStructHandler_21_0 : INativeClassStructHandler { + private NativeClassStructHandler_21_0() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -20,6 +24,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_21_0 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_21_0); internal unsafe struct Il2CppClass_21_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs index 0e9f5483..0131b4b6 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("5.3.5p3")] + [ApplicableToUnityVersionsSince("5.4.0b22")] public unsafe class NativeClassStructHandler_21_1 : INativeClassStructHandler { + private NativeClassStructHandler_21_1() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -20,6 +24,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_21_1 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_21_1); internal unsafe struct Il2CppClass_21_1 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs index 1f8d8d64..945efab6 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.4.3p4")] public unsafe class NativeClassStructHandler_21_2 : INativeClassStructHandler { + private NativeClassStructHandler_21_2() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -20,6 +23,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_21_2 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_21_2); internal unsafe struct Il2CppClass_21_2 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs index 71868bbd..cd8ff3a5 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.5.0")] public unsafe class NativeClassStructHandler_22_0 : INativeClassStructHandler { + private NativeClassStructHandler_22_0() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -20,6 +23,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_22_0 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_22_0); internal unsafe struct Il2CppClass_22_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs index 59089712..cd26678b 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.5.0p2")] public unsafe class NativeClassStructHandler_22_1 : INativeClassStructHandler { + private NativeClassStructHandler_22_1() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -20,6 +23,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_22_1 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_22_1); internal unsafe struct Il2CppClass_22_1 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs index 75a85a30..1dbdabe9 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.6.0")] public unsafe class NativeClassStructHandler_23_0 : INativeClassStructHandler { + private NativeClassStructHandler_23_0() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -20,6 +23,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_23_0 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_23_0); internal unsafe struct Il2CppClass_23_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs index 7e429798..445d25be 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("5.6.0b3")] public unsafe class NativeClassStructHandler_23_1 : INativeClassStructHandler { + private NativeClassStructHandler_23_1() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -20,6 +23,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_23_1 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_23_1); internal unsafe struct Il2CppClass_23_1 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs index 822a8ac9..637a0e5f 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeClassStructHandler_24_0 : INativeClassStructHandler { + private NativeClassStructHandler_24_0() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_24_0 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_24_0); internal unsafe struct Il2CppClass_24_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs index c92bed06..bcf52b55 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("2018.2.0")] public unsafe class NativeClassStructHandler_24_1 : INativeClassStructHandler { + private NativeClassStructHandler_24_1() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_24_1 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_24_1); internal unsafe struct Il2CppClass_24_1 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs index cd7571e0..5769a1a5 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2018.3.0")] + [ApplicableToUnityVersionsSince("2019.1.0")] public unsafe class NativeClassStructHandler_24_2 : INativeClassStructHandler { + private NativeClassStructHandler_24_2() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +22,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_24_2 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_24_2); internal unsafe struct Il2CppClass_24_2 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs index 0f52bee4..6c4645a4 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2018.3.0b11")] + [ApplicableToUnityVersionsSince("2019.1.0a8")] public unsafe class NativeClassStructHandler_24_3 : INativeClassStructHandler { + private NativeClassStructHandler_24_3() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +22,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_24_3 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_24_3); internal unsafe struct Il2CppClass_24_3 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs index 18f7e806..f7efc51e 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("2018.3.8")] public unsafe class NativeClassStructHandler_24_4 : INativeClassStructHandler { + private NativeClassStructHandler_24_4() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_24_4 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_24_4); internal unsafe struct Il2CppClass_24_4 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs index 559fa20b..3b079ae7 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2019.1.0a11")] + [ApplicableToUnityVersionsSince("2019.2.0")] public unsafe class NativeClassStructHandler_24_5 : INativeClassStructHandler { + private NativeClassStructHandler_24_5() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +22,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_24_5 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_24_5); internal unsafe struct Il2CppClass_24_5 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs index b0df8560..debe7f9a 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2019.1.0b5")] + [ApplicableToUnityVersionsSince("2019.2.0a6")] public unsafe class NativeClassStructHandler_24_6 : INativeClassStructHandler { + private NativeClassStructHandler_24_6() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +22,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_24_6 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_24_6); internal unsafe struct Il2CppClass_24_6 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs index 9f5e9c4b..8cb596a2 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("2020.2.0")] public unsafe class NativeClassStructHandler_24_7 : INativeClassStructHandler { + private NativeClassStructHandler_24_7() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_24_7 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_24_7); internal unsafe struct Il2CppClass_24_7 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs index e356b96e..15ada696 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("2020.3.20")] public unsafe class NativeClassStructHandler_27_0 : INativeClassStructHandler { + private NativeClassStructHandler_27_0() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_27_0 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_27_0); internal unsafe struct Il2CppClass_27_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs index 3e3e2ae4..daea850b 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("2021.1.0")] public unsafe class NativeClassStructHandler_27_1 : INativeClassStructHandler { + private NativeClassStructHandler_27_1() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_27_1 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_27_1); internal unsafe struct Il2CppClass_27_1 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs index 26542ea5..a3249a77 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("2021.1.24")] public unsafe class NativeClassStructHandler_27_2 : INativeClassStructHandler { + private NativeClassStructHandler_27_2() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_27_2 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_27_2); internal unsafe struct Il2CppClass_27_2 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs index 98e0b156..2dbe748f 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("2021.2.0")] public unsafe class NativeClassStructHandler_27_3 : INativeClassStructHandler { + private NativeClassStructHandler_27_3() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_27_3 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_27_3); internal unsafe struct Il2CppClass_27_3 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs index 6a1d25f1..d57a7a52 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("2021.2.0a12")] public unsafe class NativeClassStructHandler_27_4 : INativeClassStructHandler { + private NativeClassStructHandler_27_4() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_27_4 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_27_4); internal unsafe struct Il2CppClass_27_4 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs index e14f98f0..ac9830f5 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2021.2.0a21")] + [ApplicableToUnityVersionsSince("2022.1.0")] public unsafe class NativeClassStructHandler_27_5 : INativeClassStructHandler { + private NativeClassStructHandler_27_5() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +22,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_27_5 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_27_5); internal unsafe struct Il2CppClass_27_5 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs index ab4017dd..806c5016 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2021.2.0b13")] + [ApplicableToUnityVersionsSince("2022.1.0a10")] public unsafe class NativeClassStructHandler_29_0 : INativeClassStructHandler { + private NativeClassStructHandler_29_0() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +22,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_29_0 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_29_0); internal unsafe struct Il2CppClass_29_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs index 86ca8241..a46b49aa 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("2022.2.0")] public unsafe class NativeClassStructHandler_29_1 : INativeClassStructHandler { + private NativeClassStructHandler_29_1() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_29_1 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_29_1); internal unsafe struct Il2CppClass_29_1 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs index 38b0e9fd..b2e86fc1 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs @@ -4,8 +4,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("2023.1.0a15")] + [ApplicableToUnityVersionsSince("6000.4.0")] public unsafe class NativeClassStructHandler_29_2 : INativeClassStructHandler { + private NativeClassStructHandler_29_2() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +22,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_29_2 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_29_2); internal unsafe struct Il2CppClass_29_2 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs index 65099896..6e5cdd61 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs @@ -6,6 +6,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class [ApplicableToUnityVersionsSince("6000.3.3")] public unsafe class NativeClassStructHandler_39_0 : INativeClassStructHandler { + private NativeClassStructHandler_39_0() + { + } public INativeClassStruct CreateNewStruct(int vTableSlots) { nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); @@ -18,6 +21,7 @@ public INativeClassStruct Wrap(Il2CppClass* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeClassStructHandler_39_0 Instance { get; } = new(); public int Size => sizeof(Il2CppClass_39_0); internal unsafe struct Il2CppClass_39_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/UnityVersionHandler.cs new file mode 100644 index 00000000..bed5de32 --- /dev/null +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/UnityVersionHandler.cs @@ -0,0 +1,181 @@ +// +using AssetRipper.Primitives; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Class; +namespace Il2CppInterop.Runtime.Structs +{ + public partial class UnityVersionHandler + { + private static void SetClassStructHandler(UnityVersion version) + { + if (version >= new UnityVersion(6000, 5, 0, UnityVersionType.Alpha, 5)) + { + ClassStructHandler = NativeClassStructHandler_105_0.Instance; + } + else if (version >= new UnityVersion(6000, 5, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_104_0.Instance; + } + else if (version >= new UnityVersion(6000, 4, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_29_2.Instance; + } + else if (version >= new UnityVersion(6000, 3, 3, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_39_0.Instance; + } + else if (version >= new UnityVersion(2023, 1, 0, UnityVersionType.Alpha, 15)) + { + ClassStructHandler = NativeClassStructHandler_29_2.Instance; + } + else if (version >= new UnityVersion(2022, 2, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_29_1.Instance; + } + else if (version >= new UnityVersion(2022, 1, 0, UnityVersionType.Alpha, 10)) + { + ClassStructHandler = NativeClassStructHandler_29_0.Instance; + } + else if (version >= new UnityVersion(2022, 1, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_27_5.Instance; + } + else if (version >= new UnityVersion(2021, 2, 0, UnityVersionType.Beta, 13)) + { + ClassStructHandler = NativeClassStructHandler_29_0.Instance; + } + else if (version >= new UnityVersion(2021, 2, 0, UnityVersionType.Alpha, 21)) + { + ClassStructHandler = NativeClassStructHandler_27_5.Instance; + } + else if (version >= new UnityVersion(2021, 2, 0, UnityVersionType.Alpha, 12)) + { + ClassStructHandler = NativeClassStructHandler_27_4.Instance; + } + else if (version >= new UnityVersion(2021, 2, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_27_3.Instance; + } + else if (version >= new UnityVersion(2021, 1, 24, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_27_2.Instance; + } + else if (version >= new UnityVersion(2021, 1, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_27_1.Instance; + } + else if (version >= new UnityVersion(2020, 3, 20, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_27_0.Instance; + } + else if (version >= new UnityVersion(2020, 2, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_24_7.Instance; + } + else if (version >= new UnityVersion(2019, 2, 0, UnityVersionType.Alpha, 6)) + { + ClassStructHandler = NativeClassStructHandler_24_6.Instance; + } + else if (version >= new UnityVersion(2019, 2, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_24_5.Instance; + } + else if (version >= new UnityVersion(2019, 1, 0, UnityVersionType.Beta, 5)) + { + ClassStructHandler = NativeClassStructHandler_24_6.Instance; + } + else if (version >= new UnityVersion(2019, 1, 0, UnityVersionType.Alpha, 11)) + { + ClassStructHandler = NativeClassStructHandler_24_5.Instance; + } + else if (version >= new UnityVersion(2019, 1, 0, UnityVersionType.Alpha, 8)) + { + ClassStructHandler = NativeClassStructHandler_24_3.Instance; + } + else if (version >= new UnityVersion(2019, 1, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_24_2.Instance; + } + else if (version >= new UnityVersion(2018, 3, 8, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_24_4.Instance; + } + else if (version >= new UnityVersion(2018, 3, 0, UnityVersionType.Beta, 11)) + { + ClassStructHandler = NativeClassStructHandler_24_3.Instance; + } + else if (version >= new UnityVersion(2018, 3, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_24_2.Instance; + } + else if (version >= new UnityVersion(2018, 2, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_24_1.Instance; + } + else if (version >= new UnityVersion(2018, 1, 0, UnityVersionType.Beta, 5)) + { + ClassStructHandler = NativeClassStructHandler_24_0.Instance; + } + else if (version >= new UnityVersion(5, 6, 0, UnityVersionType.Beta, 3)) + { + ClassStructHandler = NativeClassStructHandler_23_1.Instance; + } + else if (version >= new UnityVersion(5, 6, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_23_0.Instance; + } + else if (version >= new UnityVersion(5, 5, 0, UnityVersionType.Patch, 2)) + { + ClassStructHandler = NativeClassStructHandler_22_1.Instance; + } + else if (version >= new UnityVersion(5, 5, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_22_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 3, UnityVersionType.Patch, 4)) + { + ClassStructHandler = NativeClassStructHandler_21_2.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Beta, 22)) + { + ClassStructHandler = NativeClassStructHandler_21_1.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Beta, 19)) + { + ClassStructHandler = NativeClassStructHandler_21_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Beta, 8)) + { + ClassStructHandler = NativeClassStructHandler_20_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Beta, 3)) + { + ClassStructHandler = NativeClassStructHandler_19_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Alpha, 0)) + { + ClassStructHandler = NativeClassStructHandler_16_0.Instance; + } + else if (version >= new UnityVersion(5, 3, 5, UnityVersionType.Patch, 3)) + { + ClassStructHandler = NativeClassStructHandler_21_1.Instance; + } + else if (version >= new UnityVersion(5, 3, 5, UnityVersionType.Patch, 1)) + { + ClassStructHandler = NativeClassStructHandler_21_0.Instance; + } + else if (version >= new UnityVersion(5, 3, 2, UnityVersionType.Patch, 2)) + { + ClassStructHandler = NativeClassStructHandler_20_0.Instance; + } + else if (version >= new UnityVersion(5, 3, 1, UnityVersionType.Patch, 3)) + { + ClassStructHandler = NativeClassStructHandler_19_0.Instance; + } + else + { + ClassStructHandler = NativeClassStructHandler_16_0.Instance; + } + } + private static INativeClassStructHandler ClassStructHandler { get; set; } = NativeClassStructHandler_16_0.Instance; + } +} diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_16_0.cs index a545a5fb..56caf8f8 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_16_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo { [ApplicableToUnityVersionsSince("5.2.2")] + [ApplicableToUnityVersionsSince("5.4.0")] public unsafe class NativeEventInfoStructHandler_16_0 : INativeEventInfoStructHandler { + private NativeEventInfoStructHandler_16_0() + { + } public INativeEventInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeEventInfoStruct Wrap(Il2CppEventInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeEventInfoStructHandler_16_0 Instance { get; } = new(); public int Size => sizeof(Il2CppEventInfo_16_0); internal unsafe struct Il2CppEventInfo_16_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_19_0.cs index 3ac06b4a..bdc199e9 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_19_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo { [ApplicableToUnityVersionsSince("5.3.1p3")] + [ApplicableToUnityVersionsSince("5.4.0b3")] public unsafe class NativeEventInfoStructHandler_19_0 : INativeEventInfoStructHandler { + private NativeEventInfoStructHandler_19_0() + { + } public INativeEventInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeEventInfoStruct Wrap(Il2CppEventInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeEventInfoStructHandler_19_0 Instance { get; } = new(); public int Size => sizeof(Il2CppEventInfo_19_0); internal unsafe struct Il2CppEventInfo_19_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_24_0.cs index 6c331b59..4de97f15 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/EventInfo_24_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeEventInfoStructHandler_24_0 : INativeEventInfoStructHandler { + private NativeEventInfoStructHandler_24_0() + { + } public INativeEventInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeEventInfoStruct Wrap(Il2CppEventInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeEventInfoStructHandler_24_0 Instance { get; } = new(); public int Size => sizeof(Il2CppEventInfo_24_0); internal unsafe struct Il2CppEventInfo_24_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/UnityVersionHandler.cs new file mode 100644 index 00000000..cb00e623 --- /dev/null +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/UnityVersionHandler.cs @@ -0,0 +1,33 @@ +// +using AssetRipper.Primitives; +using Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo; +namespace Il2CppInterop.Runtime.Structs +{ + public partial class UnityVersionHandler + { + private static void SetEventInfoStructHandler(UnityVersion version) + { + if (version >= new UnityVersion(2018, 3, 0, UnityVersionType.Alpha, 0)) + { + EventInfoStructHandler = NativeEventInfoStructHandler_24_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Beta, 3)) + { + EventInfoStructHandler = NativeEventInfoStructHandler_19_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Alpha, 0)) + { + EventInfoStructHandler = NativeEventInfoStructHandler_16_0.Instance; + } + else if (version >= new UnityVersion(5, 3, 1, UnityVersionType.Patch, 3)) + { + EventInfoStructHandler = NativeEventInfoStructHandler_19_0.Instance; + } + else + { + EventInfoStructHandler = NativeEventInfoStructHandler_16_0.Instance; + } + } + private static INativeEventInfoStructHandler EventInfoStructHandler { get; set; } = NativeEventInfoStructHandler_16_0.Instance; + } +} diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_16_0.cs index 2f05efac..b1ef932a 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_16_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { [ApplicableToUnityVersionsSince("5.2.2")] + [ApplicableToUnityVersionsSince("5.4.0")] public unsafe class NativeExceptionStructHandler_16_0 : INativeExceptionStructHandler { + private NativeExceptionStructHandler_16_0() + { + } public INativeExceptionStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeExceptionStructHandler_16_0 Instance { get; } = new(); public int Size => sizeof(Il2CppException_16_0); internal unsafe struct Il2CppException_16_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_20_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_20_0.cs index 0c7a8c00..b66fc1bc 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_20_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_20_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { [ApplicableToUnityVersionsSince("5.3.2p2")] + [ApplicableToUnityVersionsSince("5.4.0b8")] public unsafe class NativeExceptionStructHandler_20_0 : INativeExceptionStructHandler { + private NativeExceptionStructHandler_20_0() + { + } public INativeExceptionStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeExceptionStructHandler_20_0 Instance { get; } = new(); public int Size => sizeof(Il2CppException_20_0); internal unsafe struct Il2CppException_20_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_21_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_21_0.cs index 8b807a1e..0eacd21d 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_21_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_21_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { [ApplicableToUnityVersionsSince("5.3.4p3")] + [ApplicableToUnityVersionsSince("5.4.0b15")] public unsafe class NativeExceptionStructHandler_21_0 : INativeExceptionStructHandler { + private NativeExceptionStructHandler_21_0() + { + } public INativeExceptionStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeExceptionStructHandler_21_0 Instance { get; } = new(); public int Size => sizeof(Il2CppException_21_0); internal unsafe struct Il2CppException_21_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_22_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_22_0.cs index 903986a8..b0b7276a 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_22_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_22_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception [ApplicableToUnityVersionsSince("5.5.0")] public unsafe class NativeExceptionStructHandler_22_0 : INativeExceptionStructHandler { + private NativeExceptionStructHandler_22_0() + { + } public INativeExceptionStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeExceptionStructHandler_22_0 Instance { get; } = new(); public int Size => sizeof(Il2CppException_22_0); internal unsafe struct Il2CppException_22_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_0.cs index db4c80ad..0a412ae8 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception { [ApplicableToUnityVersionsSince("5.6.0b3")] + [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeExceptionStructHandler_23_0 : INativeExceptionStructHandler { + private NativeExceptionStructHandler_23_0() + { + } public INativeExceptionStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeExceptionStructHandler_23_0 Instance { get; } = new(); public int Size => sizeof(Il2CppException_23_0); internal unsafe struct Il2CppException_23_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_1.cs index ca368ca3..761f0f05 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_23_1.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception [ApplicableToUnityVersionsSince("5.6.0b6")] public unsafe class NativeExceptionStructHandler_23_1 : INativeExceptionStructHandler { + private NativeExceptionStructHandler_23_1() + { + } public INativeExceptionStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeExceptionStructHandler_23_1 Instance { get; } = new(); public int Size => sizeof(Il2CppException_23_1); internal unsafe struct Il2CppException_23_1 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_27_0.cs index 06123a1e..a27826dc 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/Exception_27_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Exception [ApplicableToUnityVersionsSince("2021.2.0a19")] public unsafe class NativeExceptionStructHandler_27_0 : INativeExceptionStructHandler { + private NativeExceptionStructHandler_27_0() + { + } public INativeExceptionStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeExceptionStruct Wrap(Il2CppException* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeExceptionStructHandler_27_0 Instance { get; } = new(); public int Size => sizeof(Il2CppException_27_0); internal unsafe struct Il2CppException_27_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/UnityVersionHandler.cs new file mode 100644 index 00000000..ac46f93c --- /dev/null +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/UnityVersionHandler.cs @@ -0,0 +1,57 @@ +// +using AssetRipper.Primitives; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Exception; +namespace Il2CppInterop.Runtime.Structs +{ + public partial class UnityVersionHandler + { + private static void SetExceptionStructHandler(UnityVersion version) + { + if (version >= new UnityVersion(2021, 2, 0, UnityVersionType.Alpha, 19)) + { + ExceptionStructHandler = NativeExceptionStructHandler_27_0.Instance; + } + else if (version >= new UnityVersion(2018, 1, 0, UnityVersionType.Beta, 5)) + { + ExceptionStructHandler = NativeExceptionStructHandler_23_0.Instance; + } + else if (version >= new UnityVersion(5, 6, 0, UnityVersionType.Beta, 6)) + { + ExceptionStructHandler = NativeExceptionStructHandler_23_1.Instance; + } + else if (version >= new UnityVersion(5, 6, 0, UnityVersionType.Beta, 3)) + { + ExceptionStructHandler = NativeExceptionStructHandler_23_0.Instance; + } + else if (version >= new UnityVersion(5, 5, 0, UnityVersionType.Alpha, 0)) + { + ExceptionStructHandler = NativeExceptionStructHandler_22_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Beta, 15)) + { + ExceptionStructHandler = NativeExceptionStructHandler_21_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Beta, 8)) + { + ExceptionStructHandler = NativeExceptionStructHandler_20_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Alpha, 0)) + { + ExceptionStructHandler = NativeExceptionStructHandler_16_0.Instance; + } + else if (version >= new UnityVersion(5, 3, 4, UnityVersionType.Patch, 3)) + { + ExceptionStructHandler = NativeExceptionStructHandler_21_0.Instance; + } + else if (version >= new UnityVersion(5, 3, 2, UnityVersionType.Patch, 2)) + { + ExceptionStructHandler = NativeExceptionStructHandler_20_0.Instance; + } + else + { + ExceptionStructHandler = NativeExceptionStructHandler_16_0.Instance; + } + } + private static INativeExceptionStructHandler ExceptionStructHandler { get; set; } = NativeExceptionStructHandler_16_0.Instance; + } +} diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_16_0.cs index ee9960b7..16ce6c24 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_16_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo { [ApplicableToUnityVersionsSince("5.2.2")] + [ApplicableToUnityVersionsSince("5.4.0")] public unsafe class NativeFieldInfoStructHandler_16_0 : INativeFieldInfoStructHandler { + private NativeFieldInfoStructHandler_16_0() + { + } public INativeFieldInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeFieldInfoStruct Wrap(Il2CppFieldInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeFieldInfoStructHandler_16_0 Instance { get; } = new(); public int Size => sizeof(Il2CppFieldInfo_16_0); internal unsafe struct Il2CppFieldInfo_16_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_19_0.cs index 455f7faa..7acdf102 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_19_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo { [ApplicableToUnityVersionsSince("5.3.1p3")] + [ApplicableToUnityVersionsSince("5.4.0b3")] public unsafe class NativeFieldInfoStructHandler_19_0 : INativeFieldInfoStructHandler { + private NativeFieldInfoStructHandler_19_0() + { + } public INativeFieldInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeFieldInfoStruct Wrap(Il2CppFieldInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeFieldInfoStructHandler_19_0 Instance { get; } = new(); public int Size => sizeof(Il2CppFieldInfo_19_0); internal unsafe struct Il2CppFieldInfo_19_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_24_0.cs index 4c0eb427..0c51d75f 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/FieldInfo_24_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeFieldInfoStructHandler_24_0 : INativeFieldInfoStructHandler { + private NativeFieldInfoStructHandler_24_0() + { + } public INativeFieldInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeFieldInfoStruct Wrap(Il2CppFieldInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeFieldInfoStructHandler_24_0 Instance { get; } = new(); public int Size => sizeof(Il2CppFieldInfo_24_0); internal unsafe struct Il2CppFieldInfo_24_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/UnityVersionHandler.cs new file mode 100644 index 00000000..04528a6b --- /dev/null +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/UnityVersionHandler.cs @@ -0,0 +1,33 @@ +// +using AssetRipper.Primitives; +using Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo; +namespace Il2CppInterop.Runtime.Structs +{ + public partial class UnityVersionHandler + { + private static void SetFieldInfoStructHandler(UnityVersion version) + { + if (version >= new UnityVersion(2018, 3, 0, UnityVersionType.Alpha, 0)) + { + FieldInfoStructHandler = NativeFieldInfoStructHandler_24_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Beta, 3)) + { + FieldInfoStructHandler = NativeFieldInfoStructHandler_19_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Alpha, 0)) + { + FieldInfoStructHandler = NativeFieldInfoStructHandler_16_0.Instance; + } + else if (version >= new UnityVersion(5, 3, 1, UnityVersionType.Patch, 3)) + { + FieldInfoStructHandler = NativeFieldInfoStructHandler_19_0.Instance; + } + else + { + FieldInfoStructHandler = NativeFieldInfoStructHandler_16_0.Instance; + } + } + private static INativeFieldInfoStructHandler FieldInfoStructHandler { get; set; } = NativeFieldInfoStructHandler_16_0.Instance; + } +} diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_16_0.cs index 2a0691bf..f7c98cb7 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_16_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("5.2.2")] + [ApplicableToUnityVersionsSince("5.4.0")] public unsafe class NativeImageStructHandler_16_0 : INativeImageStructHandler { + private NativeImageStructHandler_16_0() + { + } public INativeImageStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeImageStructHandler_16_0 Instance { get; } = new(); public int Size => sizeof(Il2CppImage_16_0); internal unsafe struct Il2CppImage_16_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_19_0.cs index 289ddcc5..dc25ce7a 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_19_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("5.3.1p3")] + [ApplicableToUnityVersionsSince("5.4.0b3")] public unsafe class NativeImageStructHandler_19_0 : INativeImageStructHandler { + private NativeImageStructHandler_19_0() + { + } public INativeImageStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeImageStructHandler_19_0 Instance { get; } = new(); public int Size => sizeof(Il2CppImage_19_0); internal unsafe struct Il2CppImage_19_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_0.cs index 66563543..8b6efe91 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("2017.1.0")] + [ApplicableToUnityVersionsSince("2017.2.0")] public unsafe class NativeImageStructHandler_24_0 : INativeImageStructHandler { + private NativeImageStructHandler_24_0() + { + } public INativeImageStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeImageStructHandler_24_0 Instance { get; } = new(); public int Size => sizeof(Il2CppImage_24_0); internal unsafe struct Il2CppImage_24_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_1.cs index c2405660..03727d7c 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_1.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image { [ApplicableToUnityVersionsSince("2017.1.2p1")] + [ApplicableToUnityVersionsSince("2017.2.0p2")] public unsafe class NativeImageStructHandler_24_1 : INativeImageStructHandler { + private NativeImageStructHandler_24_1() + { + } public INativeImageStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeImageStructHandler_24_1 Instance { get; } = new(); public int Size => sizeof(Il2CppImage_24_1); internal unsafe struct Il2CppImage_24_1 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_2.cs index 8a08512f..018d3e43 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_2.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image [ApplicableToUnityVersionsSince("2018.1.0")] public unsafe class NativeImageStructHandler_24_2 : INativeImageStructHandler { + private NativeImageStructHandler_24_2() + { + } public INativeImageStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeImageStructHandler_24_2 Instance { get; } = new(); public int Size => sizeof(Il2CppImage_24_2); internal unsafe struct Il2CppImage_24_2 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_3.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_3.cs index bdfd4b2d..da01dae9 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_3.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_3.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeImageStructHandler_24_3 : INativeImageStructHandler { + private NativeImageStructHandler_24_3() + { + } public INativeImageStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeImageStructHandler_24_3 Instance { get; } = new(); public int Size => sizeof(Il2CppImage_24_3); internal unsafe struct Il2CppImage_24_3 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_4.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_4.cs index cf8f7da4..c662c641 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_4.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_4.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeImageStructHandler_24_4 : INativeImageStructHandler { + private NativeImageStructHandler_24_4() + { + } public INativeImageStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeImageStructHandler_24_4 Instance { get; } = new(); public int Size => sizeof(Il2CppImage_24_4); internal unsafe struct Il2CppImage_24_4 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_5.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_5.cs index 83210ca5..5d6fa7e6 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_5.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_5.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image [ApplicableToUnityVersionsSince("2019.1.0a12")] public unsafe class NativeImageStructHandler_24_5 : INativeImageStructHandler { + private NativeImageStructHandler_24_5() + { + } public INativeImageStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeImageStructHandler_24_5 Instance { get; } = new(); public int Size => sizeof(Il2CppImage_24_5); internal unsafe struct Il2CppImage_24_5 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_6.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_6.cs index 92f83dbc..f8cbb24f 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_6.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/Image_24_6.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Image [ApplicableToUnityVersionsSince("2020.2.0")] public unsafe class NativeImageStructHandler_24_6 : INativeImageStructHandler { + private NativeImageStructHandler_24_6() + { + } public INativeImageStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -20,6 +23,7 @@ public INativeImageStruct Wrap(Il2CppImage* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeImageStructHandler_24_6 Instance { get; } = new(); public int Size => sizeof(Il2CppImage_24_6); internal unsafe struct Il2CppImage_24_6 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/UnityVersionHandler.cs new file mode 100644 index 00000000..a9f4bacb --- /dev/null +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/UnityVersionHandler.cs @@ -0,0 +1,65 @@ +// +using AssetRipper.Primitives; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Image; +namespace Il2CppInterop.Runtime.Structs +{ + public partial class UnityVersionHandler + { + private static void SetImageStructHandler(UnityVersion version) + { + if (version >= new UnityVersion(2020, 2, 0, UnityVersionType.Alpha, 0)) + { + ImageStructHandler = NativeImageStructHandler_24_6.Instance; + } + else if (version >= new UnityVersion(2019, 1, 0, UnityVersionType.Alpha, 12)) + { + ImageStructHandler = NativeImageStructHandler_24_5.Instance; + } + else if (version >= new UnityVersion(2018, 3, 0, UnityVersionType.Alpha, 0)) + { + ImageStructHandler = NativeImageStructHandler_24_4.Instance; + } + else if (version >= new UnityVersion(2018, 1, 0, UnityVersionType.Beta, 5)) + { + ImageStructHandler = NativeImageStructHandler_24_3.Instance; + } + else if (version >= new UnityVersion(2018, 1, 0, UnityVersionType.Alpha, 0)) + { + ImageStructHandler = NativeImageStructHandler_24_2.Instance; + } + else if (version >= new UnityVersion(2017, 2, 0, UnityVersionType.Patch, 2)) + { + ImageStructHandler = NativeImageStructHandler_24_1.Instance; + } + else if (version >= new UnityVersion(2017, 2, 0, UnityVersionType.Alpha, 0)) + { + ImageStructHandler = NativeImageStructHandler_24_0.Instance; + } + else if (version >= new UnityVersion(2017, 1, 2, UnityVersionType.Patch, 1)) + { + ImageStructHandler = NativeImageStructHandler_24_1.Instance; + } + else if (version >= new UnityVersion(2017, 1, 0, UnityVersionType.Alpha, 0)) + { + ImageStructHandler = NativeImageStructHandler_24_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Beta, 3)) + { + ImageStructHandler = NativeImageStructHandler_19_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Alpha, 0)) + { + ImageStructHandler = NativeImageStructHandler_16_0.Instance; + } + else if (version >= new UnityVersion(5, 3, 1, UnityVersionType.Patch, 3)) + { + ImageStructHandler = NativeImageStructHandler_19_0.Instance; + } + else + { + ImageStructHandler = NativeImageStructHandler_16_0.Instance; + } + } + private static INativeImageStructHandler ImageStructHandler { get; set; } = NativeImageStructHandler_16_0.Instance; + } +} diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_16_0.cs index 5417c30c..f667ccf4 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_16_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("5.2.2")] + [ApplicableToUnityVersionsSince("5.4.0")] public unsafe class NativeMethodInfoStructHandler_16_0 : INativeMethodInfoStructHandler { + private NativeMethodInfoStructHandler_16_0() + { + } public INativeMethodInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeMethodInfoStructHandler_16_0 Instance { get; } = new(); public int Size => sizeof(Il2CppMethodInfo_16_0); internal unsafe struct Il2CppMethodInfo_16_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_21_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_21_0.cs index c5ecb0d3..737e94f2 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_21_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_21_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("5.3.5p3")] + [ApplicableToUnityVersionsSince("5.4.0b22")] public unsafe class NativeMethodInfoStructHandler_21_0 : INativeMethodInfoStructHandler { + private NativeMethodInfoStructHandler_21_0() + { + } public INativeMethodInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeMethodInfoStructHandler_21_0 Instance { get; } = new(); public int Size => sizeof(Il2CppMethodInfo_21_0); internal unsafe struct Il2CppMethodInfo_21_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_0.cs index df294e43..6f4c3021 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2018.1.0b5")] public unsafe class NativeMethodInfoStructHandler_24_0 : INativeMethodInfoStructHandler { + private NativeMethodInfoStructHandler_24_0() + { + } public INativeMethodInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeMethodInfoStructHandler_24_0 Instance { get; } = new(); public int Size => sizeof(Il2CppMethodInfo_24_0); internal unsafe struct Il2CppMethodInfo_24_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_1.cs index 6aa96195..43dfca87 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_1.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2018.1.0f1")] public unsafe class NativeMethodInfoStructHandler_24_1 : INativeMethodInfoStructHandler { + private NativeMethodInfoStructHandler_24_1() + { + } public INativeMethodInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeMethodInfoStructHandler_24_1 Instance { get; } = new(); public int Size => sizeof(Il2CppMethodInfo_24_1); internal unsafe struct Il2CppMethodInfo_24_1 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_2.cs index 7328044a..aa568f13 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_24_2.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeMethodInfoStructHandler_24_2 : INativeMethodInfoStructHandler { + private NativeMethodInfoStructHandler_24_2() + { + } public INativeMethodInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeMethodInfoStructHandler_24_2 Instance { get; } = new(); public int Size => sizeof(Il2CppMethodInfo_24_2); internal unsafe struct Il2CppMethodInfo_24_2 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_27_0.cs index a636db78..8be8f2c2 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_27_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2021.2.0")] public unsafe class NativeMethodInfoStructHandler_27_0 : INativeMethodInfoStructHandler { + private NativeMethodInfoStructHandler_27_0() + { + } public INativeMethodInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeMethodInfoStructHandler_27_0 Instance { get; } = new(); public int Size => sizeof(Il2CppMethodInfo_27_0); internal unsafe struct Il2CppMethodInfo_27_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_28_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_28_0.cs index d2ed0764..c223e495 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_28_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_28_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2021.2.0b7")] public unsafe class NativeMethodInfoStructHandler_28_0 : INativeMethodInfoStructHandler { + private NativeMethodInfoStructHandler_28_0() + { + } public INativeMethodInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeMethodInfoStructHandler_28_0 Instance { get; } = new(); public int Size => sizeof(Il2CppMethodInfo_28_0); internal unsafe struct Il2CppMethodInfo_28_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_0.cs index d9bdf25f..ede252ea 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_0.cs @@ -3,8 +3,13 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("2021.2.0b8")] + [ApplicableToUnityVersionsSince("2022.1.0")] + [ApplicableToUnityVersionsSince("2022.1.0b7")] public unsafe class NativeMethodInfoStructHandler_29_0 : INativeMethodInfoStructHandler { + private NativeMethodInfoStructHandler_29_0() + { + } public INativeMethodInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +22,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeMethodInfoStructHandler_29_0 Instance { get; } = new(); public int Size => sizeof(Il2CppMethodInfo_29_0); internal unsafe struct Il2CppMethodInfo_29_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_1.cs index 2635d4aa..24afa685 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_1.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo { [ApplicableToUnityVersionsSince("2021.2.0b13")] + [ApplicableToUnityVersionsSince("2022.1.0a10")] public unsafe class NativeMethodInfoStructHandler_29_1 : INativeMethodInfoStructHandler { + private NativeMethodInfoStructHandler_29_1() + { + } public INativeMethodInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeMethodInfoStructHandler_29_1 Instance { get; } = new(); public int Size => sizeof(Il2CppMethodInfo_29_1); internal unsafe struct Il2CppMethodInfo_29_1 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_2.cs index 5555d139..ba16e672 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/MethodInfo_29_2.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo [ApplicableToUnityVersionsSince("2023.2.0a22")] public unsafe class NativeMethodInfoStructHandler_29_2 : INativeMethodInfoStructHandler { + private NativeMethodInfoStructHandler_29_2() + { + } public INativeMethodInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeMethodInfoStruct Wrap(Il2CppMethodInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeMethodInfoStructHandler_29_2 Instance { get; } = new(); public int Size => sizeof(Il2CppMethodInfo_29_2); internal unsafe struct Il2CppMethodInfo_29_2 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/UnityVersionHandler.cs new file mode 100644 index 00000000..56813c0f --- /dev/null +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/UnityVersionHandler.cs @@ -0,0 +1,73 @@ +// +using AssetRipper.Primitives; +using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; +namespace Il2CppInterop.Runtime.Structs +{ + public partial class UnityVersionHandler + { + private static void SetMethodInfoStructHandler(UnityVersion version) + { + if (version >= new UnityVersion(2023, 2, 0, UnityVersionType.Alpha, 22)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_29_2.Instance; + } + else if (version >= new UnityVersion(2022, 1, 0, UnityVersionType.Beta, 7)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_29_0.Instance; + } + else if (version >= new UnityVersion(2022, 1, 0, UnityVersionType.Alpha, 10)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_29_1.Instance; + } + else if (version >= new UnityVersion(2022, 1, 0, UnityVersionType.Alpha, 0)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_29_0.Instance; + } + else if (version >= new UnityVersion(2021, 2, 0, UnityVersionType.Beta, 13)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_29_1.Instance; + } + else if (version >= new UnityVersion(2021, 2, 0, UnityVersionType.Beta, 8)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_29_0.Instance; + } + else if (version >= new UnityVersion(2021, 2, 0, UnityVersionType.Beta, 7)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_28_0.Instance; + } + else if (version >= new UnityVersion(2021, 2, 0, UnityVersionType.Alpha, 0)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_27_0.Instance; + } + else if (version >= new UnityVersion(2018, 3, 0, UnityVersionType.Alpha, 0)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_24_2.Instance; + } + else if (version >= new UnityVersion(2018, 1, 0, UnityVersionType.Final, 1)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_24_1.Instance; + } + else if (version >= new UnityVersion(2018, 1, 0, UnityVersionType.Beta, 5)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_24_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Beta, 22)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_21_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Alpha, 0)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_16_0.Instance; + } + else if (version >= new UnityVersion(5, 3, 5, UnityVersionType.Patch, 3)) + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_21_0.Instance; + } + else + { + MethodInfoStructHandler = NativeMethodInfoStructHandler_16_0.Instance; + } + } + private static INativeMethodInfoStructHandler MethodInfoStructHandler { get; set; } = NativeMethodInfoStructHandler_16_0.Instance; + } +} diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs index ee0d39cc..6bb9e29e 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_16_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeParameterInfoStructHandler_16_0 : INativeParameterInfoStructHandler { + private NativeParameterInfoStructHandler_16_0() + { + } public INativeParameterInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeParameterInfoStruct Wrap(Il2CppParameterInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeParameterInfoStructHandler_16_0 Instance { get; } = new(); public int Size => sizeof(Il2CppParameterInfo_16_0); internal unsafe struct Il2CppParameterInfo_16_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs index d8537686..156a1ab3 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_24_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativeParameterInfoStructHandler_24_0 : INativeParameterInfoStructHandler { + private NativeParameterInfoStructHandler_24_0() + { + } public INativeParameterInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeParameterInfoStruct Wrap(Il2CppParameterInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeParameterInfoStructHandler_24_0 Instance { get; } = new(); public int Size => sizeof(Il2CppParameterInfo_24_0); internal unsafe struct Il2CppParameterInfo_24_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs index 2abf0a58..05b339e9 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/ParameterInfo_27_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo [ApplicableToUnityVersionsSince("2021.2.0")] public unsafe class NativeParameterInfoStructHandler_27_0 : INativeParameterInfoStructHandler { + private NativeParameterInfoStructHandler_27_0() + { + } public INativeParameterInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeParameterInfoStruct Wrap(Il2CppParameterInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeParameterInfoStructHandler_27_0 Instance { get; } = new(); public int Size => sizeof(Il2CppParameterInfo_27_0); internal unsafe struct Il2CppParameterInfo_27_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/UnityVersionHandler.cs new file mode 100644 index 00000000..2a27a1f1 --- /dev/null +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/UnityVersionHandler.cs @@ -0,0 +1,25 @@ +// +using AssetRipper.Primitives; +using Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo; +namespace Il2CppInterop.Runtime.Structs +{ + public partial class UnityVersionHandler + { + private static void SetParameterInfoStructHandler(UnityVersion version) + { + if (version >= new UnityVersion(2021, 2, 0, UnityVersionType.Alpha, 0)) + { + ParameterInfoStructHandler = NativeParameterInfoStructHandler_27_0.Instance; + } + else if (version >= new UnityVersion(2018, 3, 0, UnityVersionType.Alpha, 0)) + { + ParameterInfoStructHandler = NativeParameterInfoStructHandler_24_0.Instance; + } + else + { + ParameterInfoStructHandler = NativeParameterInfoStructHandler_16_0.Instance; + } + } + private static INativeParameterInfoStructHandler ParameterInfoStructHandler { get; set; } = NativeParameterInfoStructHandler_16_0.Instance; + } +} diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs index 8b8a2eee..b759f1b6 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_16_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo { [ApplicableToUnityVersionsSince("5.2.2")] + [ApplicableToUnityVersionsSince("5.4.0")] public unsafe class NativePropertyInfoStructHandler_16_0 : INativePropertyInfoStructHandler { + private NativePropertyInfoStructHandler_16_0() + { + } public INativePropertyInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativePropertyInfoStruct Wrap(Il2CppPropertyInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativePropertyInfoStructHandler_16_0 Instance { get; } = new(); public int Size => sizeof(Il2CppPropertyInfo_16_0); internal unsafe struct Il2CppPropertyInfo_16_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs index c00fa984..e909415f 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_19_0.cs @@ -3,8 +3,12 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo { [ApplicableToUnityVersionsSince("5.3.1p3")] + [ApplicableToUnityVersionsSince("5.4.0b3")] public unsafe class NativePropertyInfoStructHandler_19_0 : INativePropertyInfoStructHandler { + private NativePropertyInfoStructHandler_19_0() + { + } public INativePropertyInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +21,7 @@ public INativePropertyInfoStruct Wrap(Il2CppPropertyInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativePropertyInfoStructHandler_19_0 Instance { get; } = new(); public int Size => sizeof(Il2CppPropertyInfo_19_0); internal unsafe struct Il2CppPropertyInfo_19_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs index 0b8b0351..bb25d2ea 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/PropertyInfo_24_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo [ApplicableToUnityVersionsSince("2018.3.0")] public unsafe class NativePropertyInfoStructHandler_24_0 : INativePropertyInfoStructHandler { + private NativePropertyInfoStructHandler_24_0() + { + } public INativePropertyInfoStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativePropertyInfoStruct Wrap(Il2CppPropertyInfo* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativePropertyInfoStructHandler_24_0 Instance { get; } = new(); public int Size => sizeof(Il2CppPropertyInfo_24_0); internal unsafe struct Il2CppPropertyInfo_24_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/UnityVersionHandler.cs new file mode 100644 index 00000000..5ede8c26 --- /dev/null +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/UnityVersionHandler.cs @@ -0,0 +1,33 @@ +// +using AssetRipper.Primitives; +using Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo; +namespace Il2CppInterop.Runtime.Structs +{ + public partial class UnityVersionHandler + { + private static void SetPropertyInfoStructHandler(UnityVersion version) + { + if (version >= new UnityVersion(2018, 3, 0, UnityVersionType.Alpha, 0)) + { + PropertyInfoStructHandler = NativePropertyInfoStructHandler_24_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Beta, 3)) + { + PropertyInfoStructHandler = NativePropertyInfoStructHandler_19_0.Instance; + } + else if (version >= new UnityVersion(5, 4, 0, UnityVersionType.Alpha, 0)) + { + PropertyInfoStructHandler = NativePropertyInfoStructHandler_16_0.Instance; + } + else if (version >= new UnityVersion(5, 3, 1, UnityVersionType.Patch, 3)) + { + PropertyInfoStructHandler = NativePropertyInfoStructHandler_19_0.Instance; + } + else + { + PropertyInfoStructHandler = NativePropertyInfoStructHandler_16_0.Instance; + } + } + private static INativePropertyInfoStructHandler PropertyInfoStructHandler { get; set; } = NativePropertyInfoStructHandler_16_0.Instance; + } +} diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_16_0.cs index dd2d3625..912e72df 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_16_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Type [ApplicableToUnityVersionsSince("5.2.2")] public unsafe class NativeTypeStructHandler_16_0 : INativeTypeStructHandler { + private NativeTypeStructHandler_16_0() + { + } public INativeTypeStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeTypeStruct Wrap(Il2CppTypeStruct* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeTypeStructHandler_16_0 Instance { get; } = new(); public int Size => sizeof(Il2CppType_16_0); internal unsafe struct Il2CppType_16_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_27_0.cs index 9a3c4b46..3dd58093 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/Type_27_0.cs @@ -5,6 +5,9 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Type [ApplicableToUnityVersionsSince("2021.1.0")] public unsafe class NativeTypeStructHandler_27_0 : INativeTypeStructHandler { + private NativeTypeStructHandler_27_0() + { + } public INativeTypeStruct CreateNewStruct() { nint ptr = Marshal.AllocHGlobal(Size); @@ -17,6 +20,7 @@ public INativeTypeStruct Wrap(Il2CppTypeStruct* ptr) if (ptr == null) return null; return new NativeStructWrapper((nint)ptr); } + public static NativeTypeStructHandler_27_0 Instance { get; } = new(); public int Size => sizeof(Il2CppType_27_0); internal unsafe struct Il2CppType_27_0 { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/UnityVersionHandler.cs new file mode 100644 index 00000000..ac56d6aa --- /dev/null +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/UnityVersionHandler.cs @@ -0,0 +1,21 @@ +// +using AssetRipper.Primitives; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs +{ + public partial class UnityVersionHandler + { + private static void SetTypeStructHandler(UnityVersion version) + { + if (version >= new UnityVersion(2021, 1, 0, UnityVersionType.Alpha, 0)) + { + TypeStructHandler = NativeTypeStructHandler_27_0.Instance; + } + else + { + TypeStructHandler = NativeTypeStructHandler_16_0.Instance; + } + } + private static INativeTypeStructHandler TypeStructHandler { get; set; } = NativeTypeStructHandler_16_0.Instance; + } +} diff --git a/Il2CppInterop.StructGenerator/CodeGen/CodeGenElement.cs b/Il2CppInterop.StructGenerator/CodeGen/CodeGenElement.cs index 848dd4d8..e677d4e4 100644 --- a/Il2CppInterop.StructGenerator/CodeGen/CodeGenElement.cs +++ b/Il2CppInterop.StructGenerator/CodeGen/CodeGenElement.cs @@ -15,6 +15,7 @@ public CodeGenElement(ElementProtection? protection, string name) public bool IsStatic { get; set; } public bool IsUnsafe { get; set; } + public bool IsPartial { get; set; } public string Name { get; } public ElementProtection? Protection { get; } @@ -22,14 +23,10 @@ public string Keywords { get { - if (IsStatic) - { - return IsUnsafe ? "static unsafe " : "static "; - } - else - { - return IsUnsafe ? "unsafe " : string.Empty; - } + var staticKeyword = IsStatic ? "static " : string.Empty; + var unsafeKeyword = IsUnsafe ? "unsafe " : string.Empty; + var partialKeyword = IsPartial ? "partial " : string.Empty; + return string.Concat(staticKeyword, unsafeKeyword, partialKeyword); } } diff --git a/Il2CppInterop.StructGenerator/CodeGen/CodeGenProperty.cs b/Il2CppInterop.StructGenerator/CodeGen/CodeGenProperty.cs index 7abe7b62..fcd97adc 100644 --- a/Il2CppInterop.StructGenerator/CodeGen/CodeGenProperty.cs +++ b/Il2CppInterop.StructGenerator/CodeGen/CodeGenProperty.cs @@ -22,6 +22,14 @@ public CodeGenProperty(string propertyType, ElementProtection? protection, strin public bool HasGet => GetMethod != null || ImmediateGet != null || EmptyGet; public bool HasSet => SetMethod != null || EmptySet; + /// + /// An optional initializer for the property. If provided, this will be used to initialize the property with a default value. + /// + /// + /// This is only used if either or is . + /// + public string? Initializer { get; set; } + public override void Build(IndentedTextWriter writer) { base.Build(writer); @@ -38,7 +46,15 @@ public override void Build(IndentedTextWriter writer) writer.Write(" {"); if (EmptyGet) writer.Write(" get;"); if (EmptySet) writer.Write(" set;"); - writer.WriteLine(" }"); + if (!string.IsNullOrEmpty(Initializer)) + { + writer.WriteLine($" }} = {Initializer};"); + } + else + { + + writer.WriteLine(" }"); + } } else { diff --git a/Il2CppInterop.StructGenerator/CppTypeExtensions.cs b/Il2CppInterop.StructGenerator/CppTypeExtensions.cs new file mode 100644 index 00000000..3978a416 --- /dev/null +++ b/Il2CppInterop.StructGenerator/CppTypeExtensions.cs @@ -0,0 +1,13 @@ +using CppAst; + +namespace Il2CppInterop.StructGenerator; + +internal static class CppTypeExtensions +{ + public static CppClass? AsClass(this CppType? type) => type switch + { + CppClass cppClass => cppClass, + CppTypedef cppTypedef => cppTypedef.ElementType.AsClass(), + _ => null + }; +} diff --git a/Il2CppInterop.StructGenerator/DictionaryExtensions.cs b/Il2CppInterop.StructGenerator/DictionaryExtensions.cs new file mode 100644 index 00000000..d8da8feb --- /dev/null +++ b/Il2CppInterop.StructGenerator/DictionaryExtensions.cs @@ -0,0 +1,16 @@ +namespace Il2CppInterop.StructGenerator; + +internal static class DictionaryExtensions +{ + public static TValue GetOrAdd(this Dictionary dictionary, TKey key) + where TKey : notnull + where TValue : new() + { + if (!dictionary.TryGetValue(key, out var value)) + { + value = new TValue(); + dictionary[key] = value; + } + return value; + } +} diff --git a/Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs b/Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs index 7b05bd71..b5ef8e12 100644 --- a/Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs +++ b/Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs @@ -8,7 +8,7 @@ namespace Il2CppInterop.StructGenerator; public static partial class Il2CppStructWrapperGenerator { - private static readonly Dictionary> SGenerators = []; + private static readonly Dictionary>> SClassNameToGenerators = []; internal static ILogger? Logger { get; set; } private static VersionSpecificGenerator? VisitClass(CppClass @class, int metadataVersion, UnityVersion unityVersion) @@ -19,33 +19,31 @@ public static partial class Il2CppStructWrapperGenerator @class.Name = rename; if (!Config.ClassNames.Contains(@class.Name)) return null; - var existingVersionGeneratorCount = - SGenerators[metadataVersion].Count(x => x.CppClassName == @class.Name); + + var generatorsByMetadataVersion = SClassNameToGenerators.GetOrAdd(@class.Name); + var generatorsForMetadataVersion = generatorsByMetadataVersion.GetOrAdd(metadataVersion); + + var existingVersionGeneratorCount = generatorsForMetadataVersion.Count; if (!Config.TryCreateGenerator(@class, $"{metadataVersion}_{existingVersionGeneratorCount}", out var generator)) return null; - foreach (var field in generator.NativeStructGenerator.FieldsToImport.ToList()) + foreach ((var field, var cppField) in generator.NativeStructGenerator.FieldsToImport) { - var cppField = generator.NativeStructGenerator.CppClass.Fields.Single(x => x.Name == field.Name); - - var typeClass = cppField.Type as CppClass ?? (cppField.Type as CppTypedef)?.ElementType as CppClass; + var typeClass = cppField.Type.AsClass(); if (typeClass != null) { var gen = VisitClass(typeClass, metadataVersion, unityVersion); if (gen == null) continue; - field.FieldType = - $"{gen.HandlerGenerator.HandlerClass.Name}.{gen.NativeStructGenerator.NativeStruct.Name}"; - generator.NativeStructGenerator.FieldsToImport.Remove(field); - if (Config.ClassNames.Contains(gen.NativeStructGenerator.CppClass.Name)) - generator.ExtraUsings.Add( - $"Il2CppInterop.Runtime.Structs.VersionSpecific.{gen.NativeStructGenerator.CppClass.Name.Replace("Il2Cpp", null)}"); + field.FieldType = $"{gen.HandlerGenerator.HandlerClass.Name}.{gen.NativeStructGenerator.NativeStruct.Name}"; + generator.ExtraUsings.Add(gen.Namespace); } } + generator.NativeStructGenerator.FieldsToImport.Clear(); generator.SetupElements(); - var existingGenerators = SGenerators.Values.SelectMany(x => x).Where(x => x.CppClassName == generator.CppClassName); + var existingGenerators = generatorsByMetadataVersion.SelectMany(x => x.Value); foreach (var existingGenerator in existingGenerators) { if (existingGenerator.NativeStructGenerator.NativeStruct == generator.NativeStructGenerator.NativeStruct) @@ -56,7 +54,7 @@ public static partial class Il2CppStructWrapperGenerator } generator.ApplicableVersions.Add(unityVersion); - SGenerators[metadataVersion].Add(generator); + generatorsForMetadataVersion.Add(generator); return generator; } @@ -71,21 +69,13 @@ public static void Generate(Il2CppStructWrapperGeneratorOptions options) .Select(x => (x, UnityVersion.Parse(Path.GetFileNameWithoutExtension(x)))).OrderBy(x => x.Item2)) { var headerText = File.ReadAllText(headerPath); - var metadataMatch = MetadataVersionRegex.Match(headerText); - int metadataVersion; - if (metadataMatch.Success) - { - metadataVersion = int.Parse(metadataMatch.Groups[1].Value); - } - else + if (!TryGetMetadataVersion(headerText, out var metadataVersion)) { Logger?.LogWarning("{} has an invalid metadata version", version); continue; } - if (!SGenerators.ContainsKey(metadataVersion)) - SGenerators[metadataVersion] = []; var compilation = CppParser.Parse(ProcessHeaderText(headerText), new CppParserOptions { @@ -100,7 +90,7 @@ public static void Generate(Il2CppStructWrapperGeneratorOptions options) continue; } // If this is the first version with this major.minor.build, strip the rest of the information. - var actualVersion = version.Major == previousVersion.Major && version.Minor == previousVersion.Minor && version.Build == previousVersion.Build + var actualVersion = version.Equals(previousVersion.Major, previousVersion.Minor, previousVersion.Build) ? version : new UnityVersion(version.Major, version.Minor, version.Build); foreach (var @class in compilation.Classes) @@ -111,55 +101,129 @@ public static void Generate(Il2CppStructWrapperGeneratorOptions options) } Logger?.LogInformation("Building version specific classes"); - Dictionary> versionToGeneratorLookup = []; - foreach (var generator in SGenerators.Values.SelectMany(x => x)) - { - if (!versionToGeneratorLookup.TryGetValue(generator.GetType(), out var versionDictionary)) - versionDictionary = versionToGeneratorLookup[generator.GetType()] = []; - - foreach (var version in generator.ApplicableVersions) - versionDictionary[version] = generator; - } - foreach (var kvp in versionToGeneratorLookup) + foreach ((var className, var generatorsByMetadataVersion) in SClassNameToGenerators) { + Dictionary versionToGeneratorLookup = []; + foreach (var generator in generatorsByMetadataVersion.SelectMany(x => x.Value)) + { + foreach (var version in generator.ApplicableVersions) + { + versionToGeneratorLookup.Add(version, generator); + } + } + VersionSpecificGenerator? last = null; - foreach (var kvp2 in kvp.Value.Where(kvp2 => last is null || last != kvp2.Value)) + List<(UnityVersion Version, VersionSpecificGenerator Generator)> list = []; + foreach ((var version, var generator) in versionToGeneratorLookup.OrderBy(kvp => kvp.Key)) { - var versionString = kvp2.Key is { Type: UnityVersionType.Alpha, TypeNumber: 0 } - ? kvp2.Key.ToStringWithoutType() - : kvp2.Key.ToString(); - kvp2.Value.HandlerGenerator.HandlerClass.Attributes.Add( - $"ApplicableToUnityVersionsSince(\"{versionString}\")"); - last = kvp2.Value; + if (last is not null && last == generator) + continue; + + var versionString = version is { Type: UnityVersionType.Alpha, TypeNumber: 0 } + ? version.ToStringWithoutType() + : version.ToString(); + generator.HandlerGenerator.HandlerClass.Attributes.Add($"ApplicableToUnityVersionsSince(\"{versionString}\")"); + last = generator; + list.Add((version, generator)); } - } - HashSet generatorNames = []; - foreach (var generator in SGenerators.Values.SelectMany(x => x)) - { - var generatorOutputDirectory = Path.Join(options.OutputDirectory, generator.NativeStructGenerator.CppClass.Name.Replace("Il2Cpp", null)); - Directory.CreateDirectory(generatorOutputDirectory); - CodeGenFile file = new() + var generatorOutputDirectory = Path.Join(options.OutputDirectory, className.Replace("Il2Cpp", null)); + foreach (var generator in generatorsByMetadataVersion.SelectMany(x => x.Value)) { - Namespace = $"Il2CppInterop.Runtime.Structs.VersionSpecific.{generator.NativeStructGenerator.CppClass.Name.Replace("Il2Cpp", null)}", - Usings = - { - "System.Runtime.InteropServices" - }, - Elements = + Directory.CreateDirectory(generatorOutputDirectory); + CodeGenFile file = new() { - generator.HandlerGenerator.HandlerClass - } - }; - file.Usings.AddRange(generator.ExtraUsings); - file.WriteTo(Path.Join(generatorOutputDirectory, $"{generator.NativeStructGenerator.NativeStruct.Name.Replace("Il2Cpp", null)}.cs")); - if (generatorNames.Add(generator.CppClassName)) + Namespace = generator.Namespace, + Usings = + { + "System.Runtime.InteropServices" + }, + Elements = + { + generator.HandlerGenerator.HandlerClass + } + }; + file.Usings.AddRange(generator.ExtraUsings); + file.WriteTo(Path.Join(generatorOutputDirectory, $"{generator.GeneratorName}_{generator.MetadataSuffix}.cs")); + } + + // Use the first generator for this class to generate the interface file, since all generators for a given class will have the same interface. + var firstGenerator = list[0].Generator; { - // The first time we encounter a generator for a given class, we also generate the interface. - var interfacesFile = generator.GenerateInterfacesFile(); + var interfacesFile = firstGenerator.GenerateInterfacesFile(); interfacesFile.WriteTo(Path.Join(generatorOutputDirectory, "Interfaces.cs")); } + + // Generate the UnityVersionHandler partial class for this class + { + var unityVersionHandlerClass = new CodeGenClass(ElementProtection.Public, "UnityVersionHandler") + { + IsPartial = true, + Properties = + { + new CodeGenProperty(firstGenerator.HandlerInterface, ElementProtection.Private, $"{firstGenerator.GeneratorName}StructHandler") + { + EmptyGet = true, + EmptySet = true, + IsStatic = true, + Initializer = $"{firstGenerator.HandlerName}.Instance" + } + }, + Methods = + { + new CodeGenMethod("void", ElementProtection.Private, $"Set{firstGenerator.GeneratorName}StructHandler") + { + IsStatic = true, + Parameters = + { + new CodeGenParameter("UnityVersion", "version") + }, + MethodBodyBuilder = writer => + { + if (list.Count == 1) + { + writer.WriteLine($"{firstGenerator.GeneratorName}StructHandler = {firstGenerator.HandlerName}.Instance;"); + return; + } + + for (var i = list.Count - 1; i >= 0; i--) + { + var (version, generator) = list[i]; + if (i == 0) + { + writer.WriteLine("else"); + } + else + { + writer.Write(i == list.Count - 1 ? "if" : "else if"); + writer.WriteLine($" (version >= new UnityVersion({version.Major}, {version.Minor}, {version.Build}, UnityVersionType.{version.Type}, {version.TypeNumber}))"); + } + writer.WriteLine("{"); + writer.Indent++; + writer.WriteLine($"{generator.GeneratorName}StructHandler = {generator.HandlerName}.Instance;"); + writer.Indent--; + writer.WriteLine("}"); + } + } + } + } + }; + var unityVersionHandlerFile = new CodeGenFile() + { + Namespace = "Il2CppInterop.Runtime.Structs", + Usings = + { + "AssetRipper.Primitives", + firstGenerator.Namespace, + }, + Elements = + { + unityVersionHandlerClass + } + }; + unityVersionHandlerFile.WriteTo(Path.Join(generatorOutputDirectory, "UnityVersionHandler.cs")); + } } Logger = null; @@ -209,6 +273,20 @@ typedef struct ParameterInfo return processedHeaderText; } + private static bool TryGetMetadataVersion(string headerText, out int metadataVersion) + { + var match = MetadataVersionRegex.Match(headerText); + if (match.Success) + { + return int.TryParse(match.Groups[1].Value, out metadataVersion); + } + else + { + metadataVersion = default; + return false; + } + } + [GeneratedRegex(@"const int METADATA_VERSION = ([0-9]+);")] private static partial Regex MetadataVersionRegex { get; } } diff --git a/Il2CppInterop.StructGenerator/NativeStructGenerator.cs b/Il2CppInterop.StructGenerator/NativeStructGenerator.cs index cfefeb4e..82271617 100644 --- a/Il2CppInterop.StructGenerator/NativeStructGenerator.cs +++ b/Il2CppInterop.StructGenerator/NativeStructGenerator.cs @@ -16,7 +16,10 @@ public NativeStructGenerator(string metadataSuffix, CppClass cppClass) FillStruct(); } - public List FieldsToImport { get; } = []; + /// + /// Fields whose types might need to be imported from other namespaces + /// + public List<(CodeGenField, CppField)> FieldsToImport { get; } = []; public CodeGenStruct NativeStruct { get; } public CppClass CppClass { get; } @@ -84,7 +87,8 @@ void FinalizeBitfield() { FinalizeBitfield(); CodeGenField codeGenField = new(normalizedType, ElementProtection.Public, GetFieldName(field)); - if (needsImport) FieldsToImport.Add(codeGenField); + if (needsImport) + FieldsToImport.Add((codeGenField, field)); NativeStruct.Fields.Add(codeGenField); } } diff --git a/Il2CppInterop.StructGenerator/StructHandlerGenerator.cs b/Il2CppInterop.StructGenerator/StructHandlerGenerator.cs index 091478e6..906f1e06 100644 --- a/Il2CppInterop.StructGenerator/StructHandlerGenerator.cs +++ b/Il2CppInterop.StructGenerator/StructHandlerGenerator.cs @@ -15,10 +15,17 @@ public StructHandlerGenerator(string name, string handlerInterface, string nativ IsUnsafe = true, InterfaceNames = { handlerInterface } }; + HandlerClass.Properties.Add(new CodeGenProperty(name, ElementProtection.Public, "Instance") + { + EmptyGet = true, + IsStatic = true, + Initializer = "new()" + }); HandlerClass.Properties.Add(new CodeGenProperty("int", ElementProtection.Public, "Size") { ImmediateGet = $"sizeof({nativeStructGen.NativeStruct.Name})" }); + HandlerClass.Methods.Add(new CodeGenConstructor(name, ElementProtection.Private)); CodeGenMethod createNewMethod = new(nativeInterface, ElementProtection.Public, "CreateNewStruct") { MethodBodyBuilder = writer => diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppAssemblyGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppAssemblyGenerator.cs index 2283920f..e000b462 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppAssemblyGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppAssemblyGenerator.cs @@ -9,11 +9,7 @@ public Il2CppAssemblyGenerator(string metadataSuffix, CppClass nativeClass) : ba { } - public override string CppClassName => "Il2CppAssembly"; - protected override string HandlerName => "NativeAssemblyStructHandler"; - protected override string HandlerInterface => "INativeAssemblyStructHandler"; - protected override string NativeInterface => "INativeAssemblyStruct"; - protected override string NativeStub => "Il2CppAssembly"; + public override string GeneratorName => "Assembly"; protected override IReadOnlyList? WrapperProperties => [ diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppAssemblyNameGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppAssemblyNameGenerator.cs index 4f36d963..10c76d5f 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppAssemblyNameGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppAssemblyNameGenerator.cs @@ -9,11 +9,7 @@ public Il2CppAssemblyNameGenerator(string metadataSuffix, CppClass nativeClass) { } - public override string CppClassName => "Il2CppAssemblyName"; - protected override string HandlerName => "NativeAssemblyNameStructHandler"; - protected override string HandlerInterface => "INativeAssemblyNameStructHandler"; - protected override string NativeInterface => "INativeAssemblyNameStruct"; - protected override string NativeStub => "Il2CppAssemblyName"; + public override string GeneratorName => "AssemblyName"; protected override IReadOnlyList? WrapperProperties => [ diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs index f7b8e039..8a84932a 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs @@ -14,11 +14,7 @@ public Il2CppClassGenerator(string metadataSuffix, CppClass nativeClass) : base( ExtraUsings.Add("Il2CppInterop.Runtime.Structs.VersionSpecific.Type"); } - public override string CppClassName => "Il2CppClass"; - protected override string HandlerName => "NativeClassStructHandler"; - protected override string HandlerInterface => "INativeClassStructHandler"; - protected override string NativeInterface => "INativeClassStruct"; - protected override string NativeStub => "Il2CppClass"; + public override string GeneratorName => "Class"; protected override IEnumerable? CreateNewParameters => [new CodeGenParameter("int", "vTableSlots")]; diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppEventInfoGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppEventInfoGenerator.cs index fe9be9ad..08d94379 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppEventInfoGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppEventInfoGenerator.cs @@ -9,11 +9,7 @@ public Il2CppEventInfoGenerator(string metadataSuffix, CppClass nativeClass) : b { } - public override string CppClassName => "Il2CppEventInfo"; - protected override string HandlerName => "NativeEventInfoStructHandler"; - protected override string HandlerInterface => "INativeEventInfoStructHandler"; - protected override string NativeInterface => "INativeEventInfoStruct"; - protected override string NativeStub => "Il2CppEventInfo"; + public override string GeneratorName => "EventInfo"; protected override IReadOnlyList? WrapperProperties => [ diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppExceptionGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppExceptionGenerator.cs index 8fe5ddd2..da562551 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppExceptionGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppExceptionGenerator.cs @@ -9,11 +9,7 @@ public Il2CppExceptionGenerator(string metadataSuffix, CppClass nativeClass) : b { } - public override string CppClassName => "Il2CppException"; - protected override string HandlerName => "NativeExceptionStructHandler"; - protected override string HandlerInterface => "INativeExceptionStructHandler"; - protected override string NativeInterface => "INativeExceptionStruct"; - protected override string NativeStub => "Il2CppException"; + public override string GeneratorName => "Exception"; protected override IReadOnlyList? WrapperProperties => [ diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppFieldInfoGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppFieldInfoGenerator.cs index 9a66ed70..94e029d0 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppFieldInfoGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppFieldInfoGenerator.cs @@ -9,11 +9,7 @@ public Il2CppFieldInfoGenerator(string metadataSuffix, CppClass nativeClass) : b { } - public override string CppClassName => "Il2CppFieldInfo"; - protected override string HandlerName => "NativeFieldInfoStructHandler"; - protected override string HandlerInterface => "INativeFieldInfoStructHandler"; - protected override string NativeInterface => "INativeFieldInfoStruct"; - protected override string NativeStub => "Il2CppFieldInfo"; + public override string GeneratorName => "FieldInfo"; protected override IReadOnlyList? WrapperProperties => [ diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppImageGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppImageGenerator.cs index 650a6a1d..fdef4e93 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppImageGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppImageGenerator.cs @@ -10,11 +10,7 @@ public Il2CppImageGenerator(string metadataSuffix, CppClass nativeClass) : base( { } - public override string CppClassName => "Il2CppImage"; - protected override string HandlerName => "NativeImageStructHandler"; - protected override string HandlerInterface => "INativeImageStructHandler"; - protected override string NativeInterface => "INativeImageStruct"; - protected override string NativeStub => "Il2CppImage"; + public override string GeneratorName => "Image"; protected override IReadOnlyList? WrapperProperties => [ diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppMethodInfoGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppMethodInfoGenerator.cs index 0f5cd173..60f2404b 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppMethodInfoGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppMethodInfoGenerator.cs @@ -9,11 +9,7 @@ public Il2CppMethodInfoGenerator(string metadataSuffix, CppClass nativeClass) : { } - public override string CppClassName => "Il2CppMethodInfo"; - protected override string HandlerName => "NativeMethodInfoStructHandler"; - protected override string HandlerInterface => "INativeMethodInfoStructHandler"; - protected override string NativeInterface => "INativeMethodInfoStruct"; - protected override string NativeStub => "Il2CppMethodInfo"; + public override string GeneratorName => "MethodInfo"; protected override IReadOnlyList? WrapperProperties => [ diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppParameterInfoGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppParameterInfoGenerator.cs index 604b83cd..55227e91 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppParameterInfoGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppParameterInfoGenerator.cs @@ -9,11 +9,7 @@ public Il2CppParameterInfoGenerator(string metadataSuffix, CppClass nativeClass) { } - public override string CppClassName => "Il2CppParameterInfo"; - protected override string HandlerName => "NativeParameterInfoStructHandler"; - protected override string HandlerInterface => "INativeParameterInfoStructHandler"; - protected override string NativeInterface => "INativeParameterInfoStruct"; - protected override string NativeStub => "Il2CppParameterInfo"; + public override string GeneratorName => "ParameterInfo"; protected override IReadOnlyList? WrapperProperties => [ diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppPropertyInfoGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppPropertyInfoGenerator.cs index f5e4d601..c660b1e5 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppPropertyInfoGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppPropertyInfoGenerator.cs @@ -9,11 +9,7 @@ public Il2CppPropertyInfoGenerator(string metadataSuffix, CppClass nativeClass) { } - public override string CppClassName => "Il2CppPropertyInfo"; - protected override string HandlerName => "NativePropertyInfoStructHandler"; - protected override string HandlerInterface => "INativePropertyInfoStructHandler"; - protected override string NativeInterface => "INativePropertyInfoStruct"; - protected override string NativeStub => "Il2CppPropertyInfo"; + public override string GeneratorName => "PropertyInfo"; protected override IReadOnlyList? WrapperProperties => [ diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppTypeGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppTypeGenerator.cs index 6377407c..f36aa38a 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppTypeGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppTypeGenerator.cs @@ -9,10 +9,7 @@ public Il2CppTypeGenerator(string metadataSuffix, CppClass nativeClass) : base(m { } - public override string CppClassName => "Il2CppType"; - protected override string HandlerName => "NativeTypeStructHandler"; - protected override string HandlerInterface => "INativeTypeStructHandler"; - protected override string NativeInterface => "INativeTypeStruct"; + public override string GeneratorName => "Type"; protected override string NativeStub => "Il2CppTypeStruct"; protected override IReadOnlyList? WrapperProperties => diff --git a/Il2CppInterop.StructGenerator/VersionSpecificGenerator.cs b/Il2CppInterop.StructGenerator/VersionSpecificGenerator.cs index 15eeded7..94ed970e 100644 --- a/Il2CppInterop.StructGenerator/VersionSpecificGenerator.cs +++ b/Il2CppInterop.StructGenerator/VersionSpecificGenerator.cs @@ -12,7 +12,7 @@ public VersionSpecificGenerator(string metadataSuffix, CppClass nativeClass) MetadataSuffix = metadataSuffix; NativeStructGenerator = new NativeStructGenerator(MetadataSuffix, nativeClass); - HandlerGenerator = new StructHandlerGenerator($"{HandlerName}_{MetadataSuffix}", HandlerInterface, + HandlerGenerator = new StructHandlerGenerator(HandlerName, HandlerInterface, NativeInterface, NativeStub, NativeStructGenerator, CreateNewParameters, CreateNewExtraBody) { SizeProviderOverride = SizeOverride @@ -32,11 +32,12 @@ public VersionSpecificGenerator(string metadataSuffix, CppClass nativeClass) HandlerGenerator.HandlerClass.NestedElements.Add(WrapperGenerator.WrapperClass); } - public abstract string CppClassName { get; } - protected abstract string HandlerName { get; } - protected abstract string HandlerInterface { get; } - protected abstract string NativeInterface { get; } - protected abstract string NativeStub { get; } + public string Namespace => $"Il2CppInterop.Runtime.Structs.VersionSpecific.{GeneratorName}"; + public abstract string GeneratorName { get; } + public string HandlerName => $"Native{GeneratorName}StructHandler_{MetadataSuffix}"; + public string HandlerInterface => $"INative{GeneratorName}StructHandler"; + public string NativeInterface => $"INative{GeneratorName}Struct"; + protected virtual string NativeStub => $"Il2Cpp{GeneratorName}"; protected virtual IEnumerable? CreateNewParameters => null; protected virtual string? SizeOverride => null; @@ -249,7 +250,7 @@ public CodeGenFile GenerateInterfacesFile() } var file = new CodeGenFile() { - Namespace = $"Il2CppInterop.Runtime.Structs.VersionSpecific.{NativeStructGenerator.CppClass.Name.Replace("Il2Cpp", null)}", + Namespace = Namespace, Elements = { handlerInterface, From e55b1ef19ff7cdef6eb739b2a71e9d518be50c8c Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 24 Jun 2026 01:25:48 -0700 Subject: [PATCH 478/486] Fix minor issue with previous commit --- .../Structs/VersionSpecific/Assembly/UnityVersionHandler.cs | 2 +- .../Structs/VersionSpecific/AssemblyName/UnityVersionHandler.cs | 2 +- .../Structs/VersionSpecific/Class/UnityVersionHandler.cs | 2 +- .../Structs/VersionSpecific/EventInfo/UnityVersionHandler.cs | 2 +- .../Structs/VersionSpecific/Exception/UnityVersionHandler.cs | 2 +- .../Structs/VersionSpecific/FieldInfo/UnityVersionHandler.cs | 2 +- .../Structs/VersionSpecific/Image/UnityVersionHandler.cs | 2 +- .../Structs/VersionSpecific/MethodInfo/UnityVersionHandler.cs | 2 +- .../VersionSpecific/ParameterInfo/UnityVersionHandler.cs | 2 +- .../Structs/VersionSpecific/PropertyInfo/UnityVersionHandler.cs | 2 +- .../Structs/VersionSpecific/Type/UnityVersionHandler.cs | 2 +- Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs | 1 + 12 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/UnityVersionHandler.cs index f36f2a3f..be549872 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Assembly/UnityVersionHandler.cs @@ -3,7 +3,7 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.Assembly; namespace Il2CppInterop.Runtime.Structs { - public partial class UnityVersionHandler + public static partial class UnityVersionHandler { private static void SetAssemblyStructHandler(UnityVersion version) { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/UnityVersionHandler.cs index 1876ce83..bffe6d28 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/AssemblyName/UnityVersionHandler.cs @@ -3,7 +3,7 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.AssemblyName; namespace Il2CppInterop.Runtime.Structs { - public partial class UnityVersionHandler + public static partial class UnityVersionHandler { private static void SetAssemblyNameStructHandler(UnityVersion version) { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/UnityVersionHandler.cs index bed5de32..7d4134b3 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/UnityVersionHandler.cs @@ -3,7 +3,7 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.Class; namespace Il2CppInterop.Runtime.Structs { - public partial class UnityVersionHandler + public static partial class UnityVersionHandler { private static void SetClassStructHandler(UnityVersion version) { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/UnityVersionHandler.cs index cb00e623..8d2d52fa 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/EventInfo/UnityVersionHandler.cs @@ -3,7 +3,7 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.EventInfo; namespace Il2CppInterop.Runtime.Structs { - public partial class UnityVersionHandler + public static partial class UnityVersionHandler { private static void SetEventInfoStructHandler(UnityVersion version) { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/UnityVersionHandler.cs index ac46f93c..79075aa4 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Exception/UnityVersionHandler.cs @@ -3,7 +3,7 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.Exception; namespace Il2CppInterop.Runtime.Structs { - public partial class UnityVersionHandler + public static partial class UnityVersionHandler { private static void SetExceptionStructHandler(UnityVersion version) { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/UnityVersionHandler.cs index 04528a6b..e9726a68 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/FieldInfo/UnityVersionHandler.cs @@ -3,7 +3,7 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.FieldInfo; namespace Il2CppInterop.Runtime.Structs { - public partial class UnityVersionHandler + public static partial class UnityVersionHandler { private static void SetFieldInfoStructHandler(UnityVersion version) { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/UnityVersionHandler.cs index a9f4bacb..7cf66958 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Image/UnityVersionHandler.cs @@ -3,7 +3,7 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.Image; namespace Il2CppInterop.Runtime.Structs { - public partial class UnityVersionHandler + public static partial class UnityVersionHandler { private static void SetImageStructHandler(UnityVersion version) { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/UnityVersionHandler.cs index 56813c0f..9926a1bc 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/MethodInfo/UnityVersionHandler.cs @@ -3,7 +3,7 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.MethodInfo; namespace Il2CppInterop.Runtime.Structs { - public partial class UnityVersionHandler + public static partial class UnityVersionHandler { private static void SetMethodInfoStructHandler(UnityVersion version) { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/UnityVersionHandler.cs index 2a27a1f1..116bdf5c 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/ParameterInfo/UnityVersionHandler.cs @@ -3,7 +3,7 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.ParameterInfo; namespace Il2CppInterop.Runtime.Structs { - public partial class UnityVersionHandler + public static partial class UnityVersionHandler { private static void SetParameterInfoStructHandler(UnityVersion version) { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/UnityVersionHandler.cs index 5ede8c26..7a09c668 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/PropertyInfo/UnityVersionHandler.cs @@ -3,7 +3,7 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.PropertyInfo; namespace Il2CppInterop.Runtime.Structs { - public partial class UnityVersionHandler + public static partial class UnityVersionHandler { private static void SetPropertyInfoStructHandler(UnityVersion version) { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/UnityVersionHandler.cs index ac56d6aa..546eda11 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Type/UnityVersionHandler.cs @@ -3,7 +3,7 @@ using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; namespace Il2CppInterop.Runtime.Structs { - public partial class UnityVersionHandler + public static partial class UnityVersionHandler { private static void SetTypeStructHandler(UnityVersion version) { diff --git a/Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs b/Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs index b5ef8e12..68e22d8d 100644 --- a/Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs +++ b/Il2CppInterop.StructGenerator/Il2CppStructWrapperGenerator.cs @@ -160,6 +160,7 @@ public static void Generate(Il2CppStructWrapperGeneratorOptions options) var unityVersionHandlerClass = new CodeGenClass(ElementProtection.Public, "UnityVersionHandler") { IsPartial = true, + IsStatic = true, Properties = { new CodeGenProperty(firstGenerator.HandlerInterface, ElementProtection.Private, $"{firstGenerator.GeneratorName}StructHandler") From 85559c5e8dd92a305cecf4c905d975981315c6ea Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Mon, 6 Jul 2026 19:21:42 -0700 Subject: [PATCH 479/486] Push pending changes for Il2CppSystemTypeExtensions --- .../Extensions/Il2CppSystemTypeExtensions.cs | 28 +++++++++++++++++-- Il2Cppmscorlib/Reflection/RuntimeAssembly.cs | 5 ++++ Il2Cppmscorlib/Type.cs | 14 ++++++---- 3 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 Il2Cppmscorlib/Reflection/RuntimeAssembly.cs diff --git a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs index 6f527ab1..ed1dfdfe 100644 --- a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs +++ b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs @@ -6,11 +6,20 @@ using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem; +using Il2CppSystem.Reflection; namespace Il2CppInterop.Runtime.Extensions; internal static class Il2CppSystemTypeExtensions { + static Il2CppSystemTypeExtensions() + { + RuntimeHelpers.RunClassConstructor(typeof(String).TypeHandle); + RuntimeHelpers.RunClassConstructor(typeof(Type).TypeHandle); + RuntimeHelpers.RunClassConstructor(typeof(RuntimeType).TypeHandle); + RuntimeHelpers.RunClassConstructor(typeof(AssemblyName).TypeHandle); + RuntimeHelpers.RunClassConstructor(typeof(RuntimeAssembly).TypeHandle); + } extension(Type type) { public static Type FromTypePointer(nint typePointer) @@ -120,13 +129,13 @@ private static System.Type GetSystemTypeDefinition(Type type) if (type.IsNested) { var declaringType = GetSystemTypeDefinition(type.DeclaringType); - var il2CppTypeName = type.NameOrDefault ?? ""; + var il2CppTypeName = type.Name ?? ""; return TryGetNestedSystemType(declaringType, il2CppTypeName) ?? throw new System.NullReferenceException($"Could not find system type for nested type {il2CppTypeName} in declaring type {declaringType.FullName}"); } else { - return TryGetTopLevelSystemType(type.Assembly.GetName().Name ?? "", type.Namespace ?? "", type.NameOrDefault ?? "") + return TryGetTopLevelSystemType(type.Assembly.GetName().Name ?? "", type.Namespace ?? "", type.Name ?? "") ?? throw new System.NullReferenceException($"Could not find system type for top-level type {type.FullName}"); } } @@ -188,7 +197,14 @@ private static System.Type GetSystemTypeDefinition(Type type) private static System.Reflection.Assembly? TryGetSystemAssembly(string il2CppAssemblyName) { - return TryGetSystemAssemblyImplementation(il2CppAssemblyName) ?? TryGetSystemAssemblyImplementation("Il2Cpp" + il2CppAssemblyName); + if (il2CppAssemblyName.StartsWith("Unity", System.StringComparison.Ordinal)) + { + return TryGetSystemAssemblyImplementation(il2CppAssemblyName) ?? TryGetSystemAssemblyImplementation("Il2Cpp" + il2CppAssemblyName); + } + else + { + return TryGetSystemAssemblyImplementation("Il2Cpp" + il2CppAssemblyName) ?? TryGetSystemAssemblyImplementation(il2CppAssemblyName); + } static System.Reflection.Assembly? TryGetSystemAssemblyImplementation(string exactName) { @@ -209,6 +225,12 @@ private static System.Type GetSystemTypeDefinition(Type type) } } + private static bool IsTypeDefinition(Type type) + { + // IsTypeDefinition has a simple implementation and is frequently stripped, so we implement it here to avoid relying on unstripping. + return !type.HasElementType && !type.IsConstructedGenericType && !type.IsGenericParameter; + } + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "GetGenericArguments")] [return: UnsafeAccessorType($"Il2CppInterop.Runtime.InteropTypes.Arrays.{nameof(Il2CppArrayRank1<>)}`1[[Il2CppSystem.Type, Il2Cppmscorlib]]")] private static extern object GetGenericArgumentsInternal(Type type); diff --git a/Il2Cppmscorlib/Reflection/RuntimeAssembly.cs b/Il2Cppmscorlib/Reflection/RuntimeAssembly.cs new file mode 100644 index 00000000..6c602981 --- /dev/null +++ b/Il2Cppmscorlib/Reflection/RuntimeAssembly.cs @@ -0,0 +1,5 @@ +namespace Il2CppSystem.Reflection; + +public abstract class RuntimeAssembly : Assembly +{ +} diff --git a/Il2Cppmscorlib/Type.cs b/Il2Cppmscorlib/Type.cs index 03dd41b1..e49620e6 100644 --- a/Il2Cppmscorlib/Type.cs +++ b/Il2Cppmscorlib/Type.cs @@ -3,7 +3,7 @@ namespace Il2CppSystem; -public abstract class Type : Object, IIl2CppType +public abstract class Type : MemberInfo, IIl2CppType { static int IIl2CppType.Size => throw null; nint IIl2CppType.ObjectClass => throw null; @@ -16,14 +16,18 @@ public abstract class Type : Object, IIl2CppType public Boolean ContainsGenericParameters => throw null; - public Type DeclaringType => throw null; - public abstract String FullName { get; } + public Boolean HasElementType => throw null; + public Boolean IsArray => throw null; public Boolean IsByRef => throw null; + public Boolean IsConstructedGenericType => throw null; + + public Boolean IsGenericParameter => throw null; + public Boolean IsGenericType => throw null; public Boolean IsGenericTypeDefinition => throw null; @@ -36,9 +40,7 @@ public abstract class Type : Object, IIl2CppType public Boolean IsSZArray => throw null; - public Boolean IsTypeDefinition => throw null; - - public String NameOrDefault => throw null; + public Boolean IsTypeDefinition => !HasElementType && !IsConstructedGenericType && !IsGenericParameter; public String Namespace => throw null; From 0ef3f8e3a178d944c7bfb00154423238aed900ce Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Tue, 7 Jul 2026 13:08:15 -0700 Subject: [PATCH 480/486] Add missing change --- Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs index ed1dfdfe..0c71e5a6 100644 --- a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs +++ b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs @@ -24,9 +24,6 @@ static Il2CppSystemTypeExtensions() { public static Type FromTypePointer(nint typePointer) { - // Ensure Il2CppSystem.RuntimeType is initialized before we call Il2CppSystem.Type.internal_from_handle - RuntimeHelpers.RunClassConstructor(typeof(RuntimeType).TypeHandle); - return Type.internal_from_handle(typePointer); } From 49ab3d7e272f63eb3db6b09932cbb43f8d4c7e1c Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Tue, 7 Jul 2026 21:53:47 -0700 Subject: [PATCH 481/486] Fix outdated test --- .../Generation/InjectedClassTests.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Il2CppInterop.SourceGenerator.Tests/Generation/InjectedClassTests.cs b/Il2CppInterop.SourceGenerator.Tests/Generation/InjectedClassTests.cs index 72788bce..01d25bc3 100644 --- a/Il2CppInterop.SourceGenerator.Tests/Generation/InjectedClassTests.cs +++ b/Il2CppInterop.SourceGenerator.Tests/Generation/InjectedClassTests.cs @@ -52,7 +52,11 @@ file static class Il2CppInternals static Il2CppInternals() { + #pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code + #pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. global::Il2CppInterop.Runtime.Injection.TypeInjector.RegisterTypeInIl2Cpp(); + #pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling. + #pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code } } From cba4f5772a453b4c0dc742692a4839f31ce21da1 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Tue, 7 Jul 2026 22:40:21 -0700 Subject: [PATCH 482/486] Replace static virtual properties for naming with custom attributes --- .../Attributes/Il2CppAssemblyAttribute.cs | 7 + .../Attributes/Il2CppTypeAttribute.cs | 8 + .../Attributes/InjectedTypeAttribute.cs | 5 +- Il2CppInterop.Common/IIl2CppType.cs | 27 --- Il2CppInterop.Common/Il2CppObjectPool.cs | 2 +- Il2CppInterop.Common/Il2CppType.cs | 39 ++++- .../InitializationClassProcessingLayer.cs | 20 +++ .../MarshallingProcessingLayer.cs | 154 +----------------- ...ferenceAssemblyInjectionProcessingLayer.cs | 2 + .../Extensions/Il2CppSystemTypeExtensions.cs | 19 +-- .../Injection/Hooks/Class_FromName_Hook.cs | 4 +- .../Injection/TypeInjector.cs | 25 +-- .../Il2CppToMonoDelegateReference.cs | 2 +- .../InjectedTypeGenerator.cs | 32 ++-- Il2CppInterop.SourceGenerator/TypeModel.cs | 13 +- 15 files changed, 115 insertions(+), 244 deletions(-) create mode 100644 Il2CppInterop.Common/Attributes/Il2CppAssemblyAttribute.cs diff --git a/Il2CppInterop.Common/Attributes/Il2CppAssemblyAttribute.cs b/Il2CppInterop.Common/Attributes/Il2CppAssemblyAttribute.cs new file mode 100644 index 00000000..8f25e9f9 --- /dev/null +++ b/Il2CppInterop.Common/Attributes/Il2CppAssemblyAttribute.cs @@ -0,0 +1,7 @@ +namespace Il2CppInterop.Common.Attributes; + +[AttributeUsage(AttributeTargets.Assembly)] +public sealed class Il2CppAssemblyAttribute : Attribute +{ + public string? Name { get; init; } +} diff --git a/Il2CppInterop.Common/Attributes/Il2CppTypeAttribute.cs b/Il2CppInterop.Common/Attributes/Il2CppTypeAttribute.cs index b4ca89a2..430c0da6 100644 --- a/Il2CppInterop.Common/Attributes/Il2CppTypeAttribute.cs +++ b/Il2CppInterop.Common/Attributes/Il2CppTypeAttribute.cs @@ -4,4 +4,12 @@ public sealed class Il2CppTypeAttribute(Type internals) : Attribute { public Type Internals { get; } = internals; + /// + /// The name of the type. If not specified, it will be inferred from the managed type's name. + /// + public string? Name { get; init; } + /// + /// The namespace of the type. If not specified, it will be inferred from the managed type's namespace. + /// + public string? Namespace { get; init; } } diff --git a/Il2CppInterop.Common/Attributes/InjectedTypeAttribute.cs b/Il2CppInterop.Common/Attributes/InjectedTypeAttribute.cs index c2989a5d..6413ed69 100644 --- a/Il2CppInterop.Common/Attributes/InjectedTypeAttribute.cs +++ b/Il2CppInterop.Common/Attributes/InjectedTypeAttribute.cs @@ -11,8 +11,7 @@ public sealed class InjectedTypeAttribute : Attribute /// public string? Name { get; init; } /// - /// The file name of the assembly that the type is defined in. - /// If not specified, the assembly name will be inferred from the type's containing assembly. + /// The namespace of the type. If not specified, it will be inferred from the managed type's namespace. /// - public string? Assembly { get; init; } + public string? Namespace { get; init; } } diff --git a/Il2CppInterop.Common/IIl2CppType.cs b/Il2CppInterop.Common/IIl2CppType.cs index cb6bc49f..78d3b1ef 100644 --- a/Il2CppInterop.Common/IIl2CppType.cs +++ b/Il2CppInterop.Common/IIl2CppType.cs @@ -43,33 +43,6 @@ static virtual int Size } } /// - /// The file name of the assembly that the type is defined in - /// - /// - /// Technically, this is the image name, not the assembly name. - /// In practice, the assembly name has no file extension, whereas the image name does. - /// - static virtual string AssemblyName - { - get - { - var result = typeof(TSelf).Assembly.GetName().Name; - return string.IsNullOrEmpty(result) - ? "Assembly-CSharp.dll" - : result.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) - ? result - : $"{result}.dll"; - } - } - /// - /// The namespace of type - /// - static virtual string Namespace => typeof(TSelf).Namespace ?? ""; - /// - /// The class name of the type - /// - static virtual string Name => typeof(TSelf).Name; - /// /// Writes the native representation of the value to the provided span. The span is required to be at least bytes long. /// /// The value to write. diff --git a/Il2CppInterop.Common/Il2CppObjectPool.cs b/Il2CppInterop.Common/Il2CppObjectPool.cs index 514fcc45..e4187ece 100644 --- a/Il2CppInterop.Common/Il2CppObjectPool.cs +++ b/Il2CppInterop.Common/Il2CppObjectPool.cs @@ -33,7 +33,7 @@ public static void Remove(nint ptr) var systemType = EnsureClassInitialized(ownClass); if (!s_initializers.TryGetValue(ownClass, out initializer)) { - throw new InvalidOperationException($"No initializer found for class {systemType}"); + throw new InvalidOperationException($"No object initializer found for class {systemType}"); } } diff --git a/Il2CppInterop.Common/Il2CppType.cs b/Il2CppInterop.Common/Il2CppType.cs index bdaa03ce..6400fa41 100644 --- a/Il2CppInterop.Common/Il2CppType.cs +++ b/Il2CppInterop.Common/Il2CppType.cs @@ -1,7 +1,9 @@ using System.Buffers.Binary; using System.Diagnostics.CodeAnalysis; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using Il2CppInterop.Common.Attributes; namespace Il2CppInterop.Common; @@ -50,19 +52,44 @@ public static unsafe void StoreObject(void* ptr, T? value) where T : IIl2CppT value.WriteToPointer(ptr); } - public static string GetAssemblyName() where T : IIl2CppType + /// + /// The file name of the assembly + /// + /// + /// Note: this is the image name, not the assembly name. + /// In practice, the assembly name has no file extension, whereas the image name does. + /// + public static string GetImageName(Assembly assembly) { - return T.AssemblyName; + var name = assembly.GetCustomAttribute()?.Name; + if (string.IsNullOrEmpty(name)) + name = assembly.GetName().Name; + if (string.IsNullOrEmpty(name)) + return "Assembly-CSharp.dll"; // This line should be unreachable, but just in case, we return the default assembly name. + + return name.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) ? name : $"{name}.dll"; + } + + /// + /// The file name of the assembly that the type is defined in + /// + /// + /// Note: this is the image name, not the assembly name. + /// In practice, the assembly name has no file extension, whereas the image name does. + /// + public static string GetImageName(Type type) + { + return GetImageName(type.Assembly); } - public static string GetNamespace() where T : IIl2CppType + public static string GetNamespace(Type type) { - return T.Namespace; + return type.GetCustomAttribute()?.Namespace ?? type.Namespace ?? ""; } - public static string GetName() where T : IIl2CppType + public static string GetName(Type type) { - return T.Name; + return type.GetCustomAttribute()?.Name ?? type.Name; } public static void WriteToSpan(this T? value, Span span) where T : IIl2CppType diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index 9a42776a..48ce0ee8 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -66,6 +66,12 @@ public override void Process(ApplicationAnalysisContext appContext, Action p.Name == nameof(Il2CppTypeAttribute.Namespace)); + var il2CppTypeAttributeNameProperty = il2CppTypeAttribute.Properties.Single(p => p.Name == nameof(Il2CppTypeAttribute.Name)); + + var il2CppAssemblyAttribute = appContext.ResolveTypeOrThrow(typeof(Il2CppAssemblyAttribute)); + var il2CppAssemblyAttributeConstructor = il2CppAssemblyAttribute.GetMethodByName(".ctor"); + var il2CppAssemblyAttributeNameProperty = il2CppAssemblyAttribute.Properties.Single(p => p.Name == nameof(Il2CppAssemblyAttribute.Name)); var tokenLessMethodCount = 0; @@ -77,6 +83,14 @@ public override void Process(ApplicationAnalysisContext appContext, Action)); var iil2CppTypeGeneric_get_Size = iil2CppTypeGeneric.GetMethodByName($"get_{nameof(IIl2CppType<>.Size)}"); - var iil2CppTypeGeneric_get_AssemblyName = iil2CppTypeGeneric.GetMethodByName($"get_{nameof(IIl2CppType<>.AssemblyName)}"); - var iil2CppTypeGeneric_get_Namespace = iil2CppTypeGeneric.GetMethodByName($"get_{nameof(IIl2CppType<>.Namespace)}"); - var iil2CppTypeGeneric_get_Name = iil2CppTypeGeneric.GetMethodByName($"get_{nameof(IIl2CppType<>.Name)}"); var iil2CppTypeGeneric_ReadFromSpan = iil2CppTypeGeneric.GetMethodByName(nameof(IIl2CppType<>.ReadFromSpan)); var iil2CppTypeGeneric_WriteToSpan = iil2CppTypeGeneric.GetMethodByName(nameof(IIl2CppType<>.WriteToSpan)); @@ -32,10 +29,6 @@ public override void Process(ApplicationAnalysisContext appContext, Action m.Name == nameof(Il2CppType.GetClassPointer) && m.GenericParameters.Count == 1); - var il2CppSystemIObject = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.IObject"); - var il2CppSystemIValueType = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.IValueType"); - var il2CppSystemIEnum = appContext.Il2CppMscorlib.GetTypeByFullNameOrThrow("Il2CppSystem.IEnum"); - foreach (var assembly in appContext.Assemblies) { if (assembly.IsReferenceAssembly || assembly.IsInjected) @@ -43,7 +36,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action.AssemblyName)}"; - var method = new InjectedMethodAnalysisContext( - type, - methodName, - instantiated_iil2CppTypeGeneric_get_AssemblyName.ReturnType, - MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, - []) - { - IsInjected = true, - }; - type.Methods.Add(method); - method.Overrides.Add(instantiated_iil2CppTypeGeneric_get_AssemblyName); - - method.PutExtraData(new NativeMethodBody() - { - Instructions = - [ - new Instruction(CilOpCodes.Ldstr, assembly.ImageName), - new Instruction(CilOpCodes.Ret), - ], - }); - - var propertyName = $"{instantiatedIl2CppTypeGeneric.FullName}.{nameof(IIl2CppType<>.AssemblyName)}"; - var property = new InjectedPropertyAnalysisContext( - propertyName, - method.ReturnType, - method, - null, - PropertyAttributes.None, - type) - { - IsInjected = true, - }; - type.Properties.Add(property); - } - - // Namespace - if (type.Namespace != nameReferenceType.DefaultNamespace) - { - var instantiated_iil2CppTypeGeneric_get_Namespace = new ConcreteGenericMethodAnalysisContext(iil2CppTypeGeneric_get_Namespace, [instantiatedType], []); - var methodName = $"{instantiatedIl2CppTypeGeneric.FullName}.get_{nameof(IIl2CppType<>.Namespace)}"; - var method = new InjectedMethodAnalysisContext( - type, - methodName, - instantiated_iil2CppTypeGeneric_get_Namespace.ReturnType, - MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, - []) - { - IsInjected = true, - }; - type.Methods.Add(method); - method.Overrides.Add(instantiated_iil2CppTypeGeneric_get_Namespace); - - method.PutExtraData(new NativeMethodBody() - { - Instructions = - [ - new Instruction(CilOpCodes.Ldstr, nameReferenceType.DefaultNamespace), - new Instruction(CilOpCodes.Ret), - ], - }); - - var propertyName = $"{instantiatedIl2CppTypeGeneric.FullName}.{nameof(IIl2CppType<>.Namespace)}"; - var property = new InjectedPropertyAnalysisContext( - propertyName, - method.ReturnType, - method, - null, - PropertyAttributes.None, - type) - { - IsInjected = true, - }; - type.Properties.Add(property); - } - - // Name - if (type.Name != nameReferenceType.DefaultName) - { - var instantiated_iil2CppTypeGeneric_get_Name = new ConcreteGenericMethodAnalysisContext(iil2CppTypeGeneric_get_Name, [instantiatedType], []); - var methodName = $"{instantiatedIl2CppTypeGeneric.FullName}.get_{nameof(IIl2CppType<>.Name)}"; - var method = new InjectedMethodAnalysisContext( - type, - methodName, - instantiated_iil2CppTypeGeneric_get_Name.ReturnType, - MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.SpecialName, - []) - { - IsInjected = true, - }; - type.Methods.Add(method); - method.Overrides.Add(instantiated_iil2CppTypeGeneric_get_Name); - - method.PutExtraData(new NativeMethodBody() - { - Instructions = - [ - new Instruction(CilOpCodes.Ldstr, nameReferenceType.DefaultName), - new Instruction(CilOpCodes.Ret), - ], - }); - - var propertyName = $"{instantiatedIl2CppTypeGeneric.FullName}.{nameof(IIl2CppType<>.Name)}"; - var property = new InjectedPropertyAnalysisContext( - propertyName, - method.ReturnType, - method, - null, - PropertyAttributes.None, - type) - { - IsInjected = true, - }; - type.Properties.Add(property); - } - var instanceFieldCount = type.Fields.Count(f => !f.IsStatic); // ReadFromSpan diff --git a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs index 5fbea1a9..552d6f60 100644 --- a/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs +++ b/Il2CppInterop.Generator/ReferenceAssemblyInjectionProcessingLayer.cs @@ -36,6 +36,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action), @@ -54,6 +55,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action)); diff --git a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs index 0c71e5a6..1054acef 100644 --- a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs +++ b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs @@ -119,7 +119,6 @@ public nint ToClassPointer() } } - [RequiresDynamicCode("")] [RequiresUnreferencedCode("")] private static System.Type GetSystemTypeDefinition(Type type) { @@ -137,7 +136,6 @@ private static System.Type GetSystemTypeDefinition(Type type) } } - [RequiresDynamicCode("")] private static System.Type? TryGetNestedSystemType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)] System.Type declaringType, string il2CppTypeName) { foreach (var nestedType in declaringType.GetNestedTypes(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic)) @@ -147,8 +145,7 @@ private static System.Type GetSystemTypeDefinition(Type type) continue; } - var name = typeof(Il2CppType).GetMethod(nameof(Il2CppType.GetName))!.MakeGenericMethod(nestedType).Invoke(null, null) as string ?? string.Empty; - if (string.Equals(name, il2CppTypeName, System.StringComparison.Ordinal)) + if (string.Equals(Il2CppType.GetName(nestedType), il2CppTypeName, System.StringComparison.Ordinal)) { return nestedType; } @@ -157,7 +154,6 @@ private static System.Type GetSystemTypeDefinition(Type type) } [RequiresUnreferencedCode("")] - [RequiresDynamicCode("")] private static System.Type? TryGetTopLevelSystemType(string il2CppAssemblyName, string il2CppTypeNamespace, string il2CppTypeName) { var systemAssembly = TryGetSystemAssembly(il2CppAssemblyName); @@ -173,23 +169,14 @@ private static System.Type GetSystemTypeDefinition(Type type) { continue; } - var (typeNamespace, typeName) = GetIl2CppTypeNamespaceAndName(type); - if (string.Equals(typeNamespace, il2CppTypeNamespace, System.StringComparison.Ordinal) && - string.Equals(typeName, il2CppTypeName, System.StringComparison.Ordinal)) + if (string.Equals(Il2CppType.GetNamespace(type), il2CppTypeNamespace, System.StringComparison.Ordinal) && + string.Equals(Il2CppType.GetName(type), il2CppTypeName, System.StringComparison.Ordinal)) { return type; } } return null; - - [RequiresDynamicCode("")] - static (string Namespace, string Name) GetIl2CppTypeNamespaceAndName(System.Type systemType) - { - var @namespace = typeof(Il2CppType).GetMethod(nameof(Il2CppType.GetNamespace))!.MakeGenericMethod(systemType).Invoke(null, null) as string ?? string.Empty; - var name = typeof(Il2CppType).GetMethod(nameof(Il2CppType.GetName))!.MakeGenericMethod(systemType).Invoke(null, null) as string ?? string.Empty; - return (@namespace, name); - } } private static System.Reflection.Assembly? TryGetSystemAssembly(string il2CppAssemblyName) diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs index 87d1ee8e..3133075f 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs @@ -44,9 +44,9 @@ public override IntPtr FindTargetMethod() return XrefScanner.JumpTargets(classFromNameAPI).Single(); } - internal static void AddTypeToLookup(string assemblyName, string namespaze, string klass, IntPtr typePointer) + internal static void AddTypeToLookup(string imageName, string namespaze, string klass, IntPtr typePointer) { - var image = AssemblyInjector.GetOrCreateImage(assemblyName).ImagePointer; + var image = AssemblyInjector.GetOrCreateImage(imageName).ImagePointer; s_ClassNameLookup.Add(((IntPtr)image, namespaze, klass), typePointer); } } diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index f92b1f5c..214df9e7 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -74,8 +74,8 @@ private static void RegisterTypeInIl2Cpp(Type type) var classPointer = UnityVersionHandler.NewClass(vtableUpperBound); // Initialize as much of the class pointer as possible without touching other types. - (var assemblyName, var @namespace, var name) = GetFullyQualifiedName(type); - classPointer.Image = AssemblyInjector.GetOrCreateImage(assemblyName).ImagePointer; + (var imageName, var @namespace, var name) = GetFullyQualifiedName(type); + classPointer.Image = AssemblyInjector.GetOrCreateImage(imageName).ImagePointer; classPointer.Name = Marshal.StringToCoTaskMemUTF8(name); classPointer.Namespace = Marshal.StringToCoTaskMemUTF8(@namespace); classPointer.ElementClass = classPointer.Class = classPointer.CastClass = classPointer.ClassPointer; @@ -104,7 +104,7 @@ private static void RegisterTypeInIl2Cpp(Type type) NeedsVTableSet.Add(type, vtableUpperBound); NeedsFieldsSet.Add(type); Il2CppType.SetClassPointer(type, (nint)classPointer.ClassPointer); - Class_FromName_Hook.AddTypeToLookup(assemblyName, @namespace, name, (nint)classPointer.ClassPointer); + Class_FromName_Hook.AddTypeToLookup(imageName, @namespace, name, (nint)classPointer.ClassPointer); // Ensure that all other types that this type depends on are at least registered { @@ -847,8 +847,8 @@ private static void RegisterEnumInIl2Cpp(Type type) UnityVersionHandler.Wrap( (Il2CppClass*)Il2CppType.GetClassPointer(GetEnumUnderlyingType(type))); - (var assemblyName, var @namespace, var name) = GetFullyQualifiedName(type); - il2cppEnum.Image = AssemblyInjector.GetOrCreateImage(assemblyName).ImagePointer; + (var imageName, var @namespace, var name) = GetFullyQualifiedName(type); + il2cppEnum.Image = AssemblyInjector.GetOrCreateImage(imageName).ImagePointer; il2cppEnum.Class = il2cppEnum.CastClass = il2cppEnum.ElementClass = elementClass.ClassPointer; il2cppEnum.Parent = baseEnum.ClassPointer; il2cppEnum.ActualSize = il2cppEnum.InstanceSize = @@ -928,7 +928,7 @@ private static void RegisterEnumInIl2Cpp(Type type) il2cppEnum.TypeHierarchy[il2cppEnum.TypeHierarchyDepth - 1] = il2cppEnum.ClassPointer; Il2CppType.SetClassPointer(type, il2cppEnum.Pointer); - Class_FromName_Hook.AddTypeToLookup(assemblyName, @namespace, name, il2cppEnum.Pointer); + Class_FromName_Hook.AddTypeToLookup(imageName, @namespace, name, il2cppEnum.Pointer); } private static bool IsIl2CppInterface(Type type) @@ -1199,18 +1199,9 @@ private static Delegate CreateTrampoline(MethodInfo monoMethod, bool callVirt) return @delegate; } - [RequiresDynamicCode("")] - private static (string AssemblyName, string Namespace, string Name) GetFullyQualifiedName(Type type) - { - var methodInfo = typeof(TypeInjector).GetMethod(nameof(GetFullyQualifiedNameGeneric), BindingFlags.NonPublic | BindingFlags.Static)!.MakeGenericMethod(type); - return methodInfo.Invoke(null, null) is ValueTuple result - ? result - : throw new InvalidOperationException("GetFullyQualifiedName should return a ValueTuple"); - } - - private static (string AssemblyName, string Namespace, string Name) GetFullyQualifiedNameGeneric() where T : IIl2CppType + private static (string ImageName, string Namespace, string Name) GetFullyQualifiedName(Type type) { - return (T.AssemblyName, T.Namespace, T.Name); + return (Il2CppType.GetImageName(type), Il2CppType.GetNamespace(type), Il2CppType.GetName(type)); } private static Il2CppClassAttributes TypeAttributesToClassAttributes(TypeAttributes typeAttributes) diff --git a/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs index 71527cb4..7d758c43 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs @@ -11,7 +11,7 @@ namespace Il2CppInterop.Runtime.InteropTypes; -[InjectedType(Assembly = "Assembly-CSharp.dll")] +[InjectedType] internal sealed partial class Il2CppToMonoDelegateReference : Object { [Il2CppField] diff --git a/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs b/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs index a4386ed9..bb2c2787 100644 --- a/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs +++ b/Il2CppInterop.SourceGenerator/InjectedTypeGenerator.cs @@ -32,10 +32,13 @@ public void Initialize(IncrementalGeneratorInitializationContext context) { var injectedTypeAttr = ctx.Attributes[0]; - var assemblyName = injectedTypeAttr.NamedArguments - .FirstOrDefault(a => a.Key == "Assembly") + var @namespace = injectedTypeAttr.NamedArguments + .FirstOrDefault(a => a.Key == "Namespace") .Value.Value as string; - return TypeModel.FromSymbol((INamedTypeSymbol)ctx.TargetSymbol, assemblyName, ct); + var name = injectedTypeAttr.NamedArguments + .FirstOrDefault(a => a.Key == "Name") + .Value.Value as string; + return TypeModel.FromSymbol((INamedTypeSymbol)ctx.TargetSymbol, @namespace, name, ct); }) .Where(static m => m is not null); @@ -55,7 +58,7 @@ private static void Emit(SourceProductionContext ctx, TypeModel model) writer.WriteLine("#nullable enable"); writer.WriteLine(); - if (model.Namespace is not null) + if (!string.IsNullOrEmpty(model.Namespace)) { writer.WriteLine($"namespace {model.Namespace}"); writer.WriteLine("{"); @@ -66,13 +69,13 @@ private static void Emit(SourceProductionContext ctx, TypeModel model) writer.WriteLineNoTabs(); EmitInternalsClass(writer, model); - if (model.Namespace is not null) + if (!string.IsNullOrEmpty(model.Namespace)) { writer.Indent--; writer.WriteLine("}"); } - var hint = model.Namespace is null + var hint = string.IsNullOrEmpty(model.Namespace) ? $"{model.TypeName}.g.cs" : $"{model.Namespace}.{model.TypeName}.g.cs"; @@ -83,7 +86,16 @@ private static void EmitPartialType(IndentedTextWriter writer, TypeModel model) { var access = model.DeclaredAccessibility?.GetAccessibilityKeyword(); - writer.WriteLine("[global::Il2CppInterop.Common.Attributes.Il2CppType(typeof(Il2CppInternals))]"); + writer.Write("[global::Il2CppInterop.Common.Attributes.Il2CppType(typeof(Il2CppInternals)"); + if (model.Il2CppNamespace is not null && !string.Equals(model.Il2CppNamespace, model.Namespace, StringComparison.Ordinal)) + { + writer.Write($", Namespace = {SymbolDisplay.FormatLiteral(model.Il2CppNamespace, true)}"); + } + if (model.Il2CppName is not null && !string.Equals(model.Il2CppName, model.TypeName, StringComparison.Ordinal)) + { + writer.Write($", Name = {SymbolDisplay.FormatLiteral(model.Il2CppName, true)}"); + } + writer.WriteLine(")]"); if (model.TypeKind == TypeKind.Struct) { @@ -378,12 +390,6 @@ private static void EmitInterfaceMembers(IndentedTextWriter writer, TypeModel mo writer.WriteLineNoTabs(); } - if (!string.IsNullOrEmpty(model.AssemblyName)) - { - writer.WriteLine($"static string global::Il2CppInterop.Common.IIl2CppType<{typeName}>.AssemblyName => \"{model.AssemblyName}\";"); - writer.WriteLineNoTabs(); - } - writer.WriteLine($"static {typeName}()"); writer.WriteLine("{"); writer.Indent++; diff --git a/Il2CppInterop.SourceGenerator/TypeModel.cs b/Il2CppInterop.SourceGenerator/TypeModel.cs index 195d636f..591dfce3 100644 --- a/Il2CppInterop.SourceGenerator/TypeModel.cs +++ b/Il2CppInterop.SourceGenerator/TypeModel.cs @@ -1,4 +1,3 @@ -using System.Collections.Immutable; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -6,10 +5,11 @@ namespace Il2CppInterop.SourceGenerator; internal sealed record TypeModel( - string? Namespace, + string Namespace, string TypeName, + string? Il2CppNamespace, + string? Il2CppName, TypeKind TypeKind, // "class", "struct", or "interface" - string? AssemblyName, EquatableArray Members, EquatableArray FinalizerMethodNames, bool NeedsObjectPointerConstructor, @@ -17,7 +17,7 @@ internal sealed record TypeModel( bool IsAbstract ) { - internal static TypeModel? FromSymbol(INamedTypeSymbol node, string? assemblyName, CancellationToken ct) + internal static TypeModel? FromSymbol(INamedTypeSymbol node, string? il2CppNamespace, string? il2CppName, CancellationToken ct) { var typeKind = node.TypeKind; @@ -117,11 +117,12 @@ bool IsAbstract return new TypeModel( Namespace: node.ContainingNamespace.IsGlobalNamespace - ? null + ? string.Empty : node.ContainingNamespace.ToDisplayString(), TypeName: node.Name, + Il2CppNamespace: il2CppNamespace, + Il2CppName: il2CppName, TypeKind: typeKind, - AssemblyName: assemblyName, Members: new EquatableArray(members), FinalizerMethodNames: new EquatableArray(finalizerMethods), NeedsObjectPointerConstructor: needsObjectPointerConstructor, From 6d1c19c315f21418a31ea44d89590168c9361b92 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Wed, 8 Jul 2026 00:54:22 -0700 Subject: [PATCH 483/486] Push missing line --- Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs index 1054acef..d3c9182f 100644 --- a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs +++ b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs @@ -55,7 +55,7 @@ public static Type FromSystemType(System.Type systemType) [RequiresUnreferencedCode("")] public System.Type ToSystemType() { - if (type.IsTypeDefinition) + if (IsTypeDefinition(type)) { return GetSystemTypeDefinition(type); } From 6ffb765097cf34343262b62f6f86e92b183ab59c Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Mon, 13 Jul 2026 12:55:41 -0700 Subject: [PATCH 484/486] Update versioned structs --- .../Injection/GenericTypeInflater.cs | 11 +- .../Injection/TypeInjector.cs | 1 + .../Structs/Il2CppStructs.cs | 8 + .../VersionSpecific/Class/Class_104_0.cs | 2 + .../VersionSpecific/Class/Class_105_0.cs | 2 + .../VersionSpecific/Class/Class_108_0.cs | 204 ++++++++++++++++++ .../VersionSpecific/Class/Class_16_0.cs | 2 + .../VersionSpecific/Class/Class_19_0.cs | 2 + .../VersionSpecific/Class/Class_20_0.cs | 2 + .../VersionSpecific/Class/Class_21_0.cs | 2 + .../VersionSpecific/Class/Class_21_1.cs | 2 + .../VersionSpecific/Class/Class_21_2.cs | 2 + .../VersionSpecific/Class/Class_22_0.cs | 2 + .../VersionSpecific/Class/Class_22_1.cs | 2 + .../VersionSpecific/Class/Class_23_0.cs | 2 + .../VersionSpecific/Class/Class_23_1.cs | 2 + .../VersionSpecific/Class/Class_24_0.cs | 2 + .../VersionSpecific/Class/Class_24_1.cs | 2 + .../VersionSpecific/Class/Class_24_2.cs | 2 + .../VersionSpecific/Class/Class_24_3.cs | 2 + .../VersionSpecific/Class/Class_24_4.cs | 2 + .../VersionSpecific/Class/Class_24_5.cs | 2 + .../VersionSpecific/Class/Class_24_6.cs | 2 + .../VersionSpecific/Class/Class_24_7.cs | 2 + .../VersionSpecific/Class/Class_27_0.cs | 2 + .../VersionSpecific/Class/Class_27_1.cs | 2 + .../VersionSpecific/Class/Class_27_2.cs | 2 + .../VersionSpecific/Class/Class_27_3.cs | 2 + .../VersionSpecific/Class/Class_27_4.cs | 2 + .../VersionSpecific/Class/Class_27_5.cs | 2 + .../VersionSpecific/Class/Class_29_0.cs | 2 + .../VersionSpecific/Class/Class_29_1.cs | 2 + .../VersionSpecific/Class/Class_29_2.cs | 2 + .../VersionSpecific/Class/Class_39_0.cs | 3 + .../VersionSpecific/Class/Interfaces.cs | 2 + .../Class/UnityVersionHandler.cs | 10 +- .../TypeGenerators/Il2CppClassGenerator.cs | 9 +- 37 files changed, 301 insertions(+), 5 deletions(-) create mode 100644 Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_108_0.cs diff --git a/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs b/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs index a44e5cb5..0566e447 100644 --- a/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs +++ b/Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs @@ -41,8 +41,15 @@ private static nint InflateGenericType(INativeClassStruct genericClassPointer, n inflatedClassPointer.Class = inflatedClassPointer.Class; inflatedClassPointer.Fields = genericClassPointer.Fields; inflatedClassPointer.Methods = genericClassPointer.Methods; - inflatedClassPointer.ImplementedInterfaces = genericClassPointer.ImplementedInterfaces; - inflatedClassPointer.InterfaceOffsets = genericClassPointer.InterfaceOffsets; + if (inflatedClassPointer.HasCombinedInterfaceData) + { + inflatedClassPointer.Interfaces = genericClassPointer.Interfaces; + } + else + { + inflatedClassPointer.ImplementedInterfaces = genericClassPointer.ImplementedInterfaces; + inflatedClassPointer.InterfaceOffsets = genericClassPointer.InterfaceOffsets; + } inflatedClassPointer.TypeHierarchy = genericClassPointer.TypeHierarchy; inflatedClassPointer.ValueType = genericClassPointer.ValueType; inflatedClassPointer.Initialized = true; diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 214df9e7..994cecd9 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -18,6 +18,7 @@ namespace Il2CppInterop.Runtime.Injection; +// Note: This currently throws NotSupportedException for v108+ (Unity 6.6+) interfaces public static unsafe class TypeInjector { private static readonly IntPtr value__Cached = Marshal.StringToCoTaskMemUTF8("value__"); diff --git a/Il2CppInterop.Runtime/Structs/Il2CppStructs.cs b/Il2CppInterop.Runtime/Structs/Il2CppStructs.cs index 8deeb873..5464de98 100644 --- a/Il2CppInterop.Runtime/Structs/Il2CppStructs.cs +++ b/Il2CppInterop.Runtime/Structs/Il2CppStructs.cs @@ -244,6 +244,14 @@ public unsafe struct Il2CppRuntimeInterfaceOffsetPair public int offset; } +[StructLayout(LayoutKind.Sequential)] +public unsafe struct Il2CppRuntimeInterfaceData +{ + public Il2CppClass* interfaceType; + public int offset; + public int depth; +} + [StructLayout(LayoutKind.Sequential)] public struct Il2CppObject { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs index d9e0a1c9..51fb5be0 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_104_0.cs @@ -130,6 +130,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -152,6 +153,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs index 94ca7463..d8187b04 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_105_0.cs @@ -130,6 +130,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -152,6 +153,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_108_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_108_0.cs new file mode 100644 index 00000000..3207207b --- /dev/null +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_108_0.cs @@ -0,0 +1,204 @@ +// +using System.Runtime.InteropServices; +using Il2CppInterop.Runtime.Structs.VersionSpecific.Type; +namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class +{ + [ApplicableToUnityVersionsSince("6000.6.0b1")] + public unsafe class NativeClassStructHandler_108_0 : INativeClassStructHandler + { + private NativeClassStructHandler_108_0() + { + } + public INativeClassStruct CreateNewStruct(int vTableSlots) + { + nint ptr = Marshal.AllocHGlobal(Size + sizeof(VirtualInvokeData) * vTableSlots); + Il2CppClass_108_0* _ = (Il2CppClass_108_0*)ptr; + *_ = default; + return new NativeStructWrapper(ptr); + } + public INativeClassStruct Wrap(Il2CppClass* ptr) + { + if (ptr == null) return null; + return new NativeStructWrapper((nint)ptr); + } + public static NativeClassStructHandler_108_0 Instance { get; } = new(); + public int Size => sizeof(Il2CppClass_108_0); + internal unsafe struct Il2CppClass_108_0 + { + public Il2CppImage* image; + public void* gc_desc; + public byte* name; + public byte* namespaze; + public NativeTypeStructHandler_27_0.Il2CppType_27_0 byval_arg; + public NativeTypeStructHandler_27_0.Il2CppType_27_0 this_arg; + public Il2CppClass* element_class; + public Il2CppClass* castClass; + public Il2CppClass* declaringType; + public Il2CppClass* parent; + public void* generic_class; + public Il2CppMetadataTypeHandle typeMetadataHandle; + public void* interopData; + public Il2CppClass* klass; + public Il2CppFieldInfo* fields; + public Il2CppMethodInfo** methods; + public Il2CppRuntimeInterfaceData* interfaces; + public void* static_fields; + public void* init_data; + public Il2CppClass** typeHierarchy; + public void* events; + public void* properties; + public void* nestedTypes; + public void* unity_user_data; + public Il2CppGCHandle initializationExceptionGCHandle; + public uint cctor_started; + public uint cctor_finished_or_no_cctor; + public ulong cctor_thread; + public Il2CppMetadataGenericContainerHandle genericContainerHandle; + public uint instance_size; + public uint stack_slot_size; + public uint actualSize; + public uint element_size; + public int native_size; + public uint static_fields_size; + public uint thread_static_fields_size; + public int thread_static_fields_offset; + public uint flags; + public uint token; + public ushort method_count; + public ushort property_count; + public ushort field_count; + public ushort event_count; + public ushort nested_type_count; + public ushort vtable_count; + public ushort interfaces_count; + public ushort interface_offsets_count; + public byte typeHierarchyDepth; + public byte genericRecursionDepth; + public byte rank; + public byte minimumAlignment; + public byte packingSize; + public Bitfield0 _bitfield0; + public Bitfield1 _bitfield1; + internal enum Bitfield0 : byte + { + BIT_initialized_and_no_error = 0, + initialized_and_no_error = (1 << BIT_initialized_and_no_error), + BIT_initialized = 1, + initialized = (1 << BIT_initialized), + BIT_enumtype = 2, + enumtype = (1 << BIT_enumtype), + BIT_nullabletype = 3, + nullabletype = (1 << BIT_nullabletype), + BIT_is_generic = 4, + is_generic = (1 << BIT_is_generic), + BIT_has_references = 5, + has_references = (1 << BIT_has_references), + BIT_init_pending = 6, + init_pending = (1 << BIT_init_pending), + BIT_size_init_pending = 7, + size_init_pending = (1 << BIT_size_init_pending), + } + internal enum Bitfield1 : byte + { + BIT_size_inited = 0, + size_inited = (1 << BIT_size_inited), + BIT_has_finalize = 1, + has_finalize = (1 << BIT_has_finalize), + BIT_has_cctor = 2, + has_cctor = (1 << BIT_has_cctor), + BIT_is_blittable = 3, + is_blittable = (1 << BIT_is_blittable), + BIT_is_import_or_windows_runtime = 4, + is_import_or_windows_runtime = (1 << BIT_is_import_or_windows_runtime), + BIT_is_vtable_initialized = 5, + is_vtable_initialized = (1 << BIT_is_vtable_initialized), + BIT_is_byref_like = 6, + is_byref_like = (1 << BIT_is_byref_like), + BIT_has_inline_array = 7, + has_inline_array = (1 << BIT_has_inline_array), + } + } + internal class NativeStructWrapper : INativeClassStruct + { + public NativeStructWrapper(nint ptr) => Pointer = ptr; + private static int _bitfield0offset = Marshal.OffsetOf(nameof(Il2CppClass_108_0._bitfield0)).ToInt32(); + private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_108_0._bitfield1)).ToInt32(); + public nint Pointer { get; } + private Il2CppClass_108_0* _ => (Il2CppClass_108_0*)Pointer; + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_108_0)); + public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; + public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); + public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => true; + public ref uint InstanceSize => ref _->instance_size; + public ref ushort VTableCount => ref _->vtable_count; + public ref ushort InterfaceCount => ref _->interfaces_count; + public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; + public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; + public ref int NativeSize => ref _->native_size; + public ref uint ActualSize => ref _->actualSize; + public ref ushort MethodCount => ref _->method_count; + public ref ushort FieldCount => ref _->field_count; + public ref Il2CppClassAttributes Flags => ref *(Il2CppClassAttributes*)&_->flags; + public ref nint Name => ref *(nint*)&_->name; + public ref nint Namespace => ref *(nint*)&_->namespaze; + public ref Il2CppImage* Image => ref _->image; + public ref Il2CppClass* Parent => ref _->parent; + public ref Il2CppClass* ElementClass => ref _->element_class; + public ref Il2CppClass* CastClass => ref _->castClass; + public ref Il2CppClass* DeclaringType => ref _->declaringType; + public ref Il2CppClass* Class => ref _->klass; + public ref Il2CppFieldInfo* Fields => ref _->fields; + public ref Il2CppMethodInfo** Methods => ref _->methods; + public ref Il2CppClass** ImplementedInterfaces => throw new System.NotSupportedException(); + public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => throw new System.NotSupportedException(); + public ref Il2CppRuntimeInterfaceData* Interfaces => ref _->interfaces; + public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; + public bool ValueType + { + get => ByValArg.ValueType && ThisArg.ValueType; + set { } + } + public bool Initialized + { + get => this.CheckBit(_bitfield0offset, (int)Il2CppClass_108_0.Bitfield0.BIT_initialized); + set => this.SetBit(_bitfield0offset, (int)Il2CppClass_108_0.Bitfield0.BIT_initialized, value); + } + public bool EnumType + { + get => this.CheckBit(_bitfield0offset, (int)Il2CppClass_108_0.Bitfield0.BIT_enumtype); + set => this.SetBit(_bitfield0offset, (int)Il2CppClass_108_0.Bitfield0.BIT_enumtype, value); + } + public bool IsGeneric + { + get => this.CheckBit(_bitfield0offset, (int)Il2CppClass_108_0.Bitfield0.BIT_is_generic); + set => this.SetBit(_bitfield0offset, (int)Il2CppClass_108_0.Bitfield0.BIT_is_generic, value); + } + public bool HasReferences + { + get => this.CheckBit(_bitfield0offset, (int)Il2CppClass_108_0.Bitfield0.BIT_has_references); + set => this.SetBit(_bitfield0offset, (int)Il2CppClass_108_0.Bitfield0.BIT_has_references, value); + } + public bool SizeInited + { + get => this.CheckBit(_bitfield1offset, (int)Il2CppClass_108_0.Bitfield1.BIT_size_inited); + set => this.SetBit(_bitfield1offset, (int)Il2CppClass_108_0.Bitfield1.BIT_size_inited, value); + } + public bool HasFinalize + { + get => this.CheckBit(_bitfield1offset, (int)Il2CppClass_108_0.Bitfield1.BIT_has_finalize); + set => this.SetBit(_bitfield1offset, (int)Il2CppClass_108_0.Bitfield1.BIT_has_finalize, value); + } + public bool IsVtableInitialized + { + get => this.CheckBit(_bitfield1offset, (int)Il2CppClass_108_0.Bitfield1.BIT_is_vtable_initialized); + set => this.SetBit(_bitfield1offset, (int)Il2CppClass_108_0.Bitfield1.BIT_is_vtable_initialized, value); + } + public bool InitializedAndNoError + { + get => this.CheckBit(_bitfield0offset, (int)Il2CppClass_108_0.Bitfield0.BIT_initialized_and_no_error); + set => this.SetBit(_bitfield0offset, (int)Il2CppClass_108_0.Bitfield0.BIT_initialized_and_no_error, value); + } + } + } +} diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs index de8396bb..cd6f1737 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_16_0.cs @@ -117,6 +117,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -139,6 +140,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs index d430d6d3..8c1814b7 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_19_0.cs @@ -118,6 +118,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -140,6 +141,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs index 1f308bfe..b67b6bf4 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_20_0.cs @@ -120,6 +120,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -142,6 +143,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs index 1b3c2161..a4ad3c03 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_0.cs @@ -120,6 +120,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -142,6 +143,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs index 0131b4b6..8eabe95a 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_1.cs @@ -120,6 +120,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -142,6 +143,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs index 945efab6..ea100a1d 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_21_2.cs @@ -120,6 +120,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -142,6 +143,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs index cd8ff3a5..f112dbee 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_0.cs @@ -120,6 +120,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -142,6 +143,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs index cd26678b..7b014603 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_22_1.cs @@ -121,6 +121,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -143,6 +144,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs index 1dbdabe9..11613ddd 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_0.cs @@ -121,6 +121,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -143,6 +144,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs index 445d25be..400bc7b0 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_23_1.cs @@ -122,6 +122,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -144,6 +145,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs index 637a0e5f..1fe38e84 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_0.cs @@ -120,6 +120,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -142,6 +143,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs index bcf52b55..4a6e2580 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_1.cs @@ -123,6 +123,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -145,6 +146,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs index 5769a1a5..5a05dd2c 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_2.cs @@ -123,6 +123,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -145,6 +146,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs index 6c4645a4..19a16b84 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_3.cs @@ -125,6 +125,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -147,6 +148,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs index f7efc51e..5de9a48e 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_4.cs @@ -125,6 +125,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -147,6 +148,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs index 3b079ae7..3831a9a6 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_5.cs @@ -126,6 +126,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -148,6 +149,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs index debe7f9a..edd0307d 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_6.cs @@ -127,6 +127,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -149,6 +150,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs index 8cb596a2..ea3e5f98 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_24_7.cs @@ -126,6 +126,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -148,6 +149,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs index 15ada696..49dd84d0 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_0.cs @@ -128,6 +128,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -150,6 +151,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs index daea850b..42ab600c 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_1.cs @@ -124,6 +124,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -146,6 +147,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs index a3249a77..42936a75 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_2.cs @@ -126,6 +126,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -148,6 +149,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs index 2dbe748f..28048438 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_3.cs @@ -126,6 +126,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -148,6 +149,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs index d57a7a52..488085c7 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_4.cs @@ -124,6 +124,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -146,6 +147,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs index ac9830f5..2b7c22d9 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_27_5.cs @@ -127,6 +127,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -149,6 +150,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs index 806c5016..86d273e1 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_0.cs @@ -129,6 +129,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -151,6 +152,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs index a46b49aa..0ce4a2e4 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_1.cs @@ -128,6 +128,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -150,6 +151,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs index b2e86fc1..9d5a9d7d 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_29_2.cs @@ -129,6 +129,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -151,6 +152,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs index 6e5cdd61..0632f826 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Class_39_0.cs @@ -4,6 +4,7 @@ namespace Il2CppInterop.Runtime.Structs.VersionSpecific.Class { [ApplicableToUnityVersionsSince("6000.3.3")] + [ApplicableToUnityVersionsSince("6000.4.0b8")] public unsafe class NativeClassStructHandler_39_0 : INativeClassStructHandler { private NativeClassStructHandler_39_0() @@ -128,6 +129,7 @@ internal class NativeStructWrapper : INativeClassStruct public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); + public bool HasCombinedInterfaceData => false; public ref uint InstanceSize => ref _->instance_size; public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; @@ -150,6 +152,7 @@ internal class NativeStructWrapper : INativeClassStruct public ref Il2CppMethodInfo** Methods => ref _->methods; public ref Il2CppClass** ImplementedInterfaces => ref _->implementedInterfaces; public ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets => ref _->interfaceOffsets; + public ref Il2CppRuntimeInterfaceData* Interfaces => throw new System.NotSupportedException(); public ref Il2CppClass** TypeHierarchy => ref _->typeHierarchy; public bool ValueType { diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Interfaces.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Interfaces.cs index a6c2283f..16d601eb 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Interfaces.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/Interfaces.cs @@ -13,6 +13,7 @@ public interface INativeClassStruct : INativeStruct unsafe Il2CppClass* ClassPointer { get; } INativeTypeStruct ByValArg { get; } INativeTypeStruct ThisArg { get; } + bool HasCombinedInterfaceData { get; } ref uint InstanceSize { get; } ref ushort VTableCount { get; } ref ushort InterfaceCount { get; } @@ -35,6 +36,7 @@ public interface INativeClassStruct : INativeStruct unsafe ref Il2CppMethodInfo** Methods { get; } unsafe ref Il2CppClass** ImplementedInterfaces { get; } unsafe ref Il2CppRuntimeInterfaceOffsetPair* InterfaceOffsets { get; } + unsafe ref Il2CppRuntimeInterfaceData* Interfaces { get; } unsafe ref Il2CppClass** TypeHierarchy { get; } bool ValueType { get; set; } bool Initialized { get; set; } diff --git a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/UnityVersionHandler.cs b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/UnityVersionHandler.cs index 7d4134b3..bf625e39 100644 --- a/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/UnityVersionHandler.cs +++ b/Il2CppInterop.Runtime/Structs/VersionSpecific/Class/UnityVersionHandler.cs @@ -7,7 +7,11 @@ public static partial class UnityVersionHandler { private static void SetClassStructHandler(UnityVersion version) { - if (version >= new UnityVersion(6000, 5, 0, UnityVersionType.Alpha, 5)) + if (version >= new UnityVersion(6000, 6, 0, UnityVersionType.Beta, 1)) + { + ClassStructHandler = NativeClassStructHandler_108_0.Instance; + } + else if (version >= new UnityVersion(6000, 5, 0, UnityVersionType.Alpha, 5)) { ClassStructHandler = NativeClassStructHandler_105_0.Instance; } @@ -15,6 +19,10 @@ private static void SetClassStructHandler(UnityVersion version) { ClassStructHandler = NativeClassStructHandler_104_0.Instance; } + else if (version >= new UnityVersion(6000, 4, 0, UnityVersionType.Beta, 8)) + { + ClassStructHandler = NativeClassStructHandler_39_0.Instance; + } else if (version >= new UnityVersion(6000, 4, 0, UnityVersionType.Alpha, 0)) { ClassStructHandler = NativeClassStructHandler_29_2.Instance; diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs index 8a84932a..8d354d97 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs @@ -68,6 +68,10 @@ protected override IReadOnlyList WrapperProperties }, byvalArg, thisArg, + new CodeGenProperty("bool", ElementProtection.Public, "HasCombinedInterfaceData") + { + ImmediateGet = GetNativeField("interfaces") is not null ? "true" : "false" + }, ]; } } @@ -112,8 +116,9 @@ protected override IReadOnlyList WrapperProperties new ByRefWrapper("Il2CppClass*", "Class", ["klass"], makeDummyIfNotExist: true), new ByRefWrapper("Il2CppFieldInfo*", "Fields", ["fields"]), new ByRefWrapper("Il2CppMethodInfo**", "Methods", ["methods"]), - new ByRefWrapper("Il2CppClass**", "ImplementedInterfaces", ["implementedInterfaces"]), - new ByRefWrapper("Il2CppRuntimeInterfaceOffsetPair*", "InterfaceOffsets", ["interfaceOffsets"]), + new ByRefWrapper("Il2CppClass**", "ImplementedInterfaces", ["implementedInterfaces"], addNotSupportedIfNotExist: true), + new ByRefWrapper("Il2CppRuntimeInterfaceOffsetPair*", "InterfaceOffsets", ["interfaceOffsets"], addNotSupportedIfNotExist: true), + new ByRefWrapper("Il2CppRuntimeInterfaceData*", "Interfaces", ["interfaces"], addNotSupportedIfNotExist: true), new ByRefWrapper("Il2CppClass**", "TypeHierarchy", ["typeHierarchy"]) ]; } From 1f168bf1f75de3a9ca1d6abfb182355dc79c7d26 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Thu, 16 Jul 2026 16:40:41 -0700 Subject: [PATCH 485/486] Update NuGet versions --- Il2CppInterop.CLI/Il2CppInterop.CLI.csproj | 6 ------ .../Il2CppInterop.Common.csproj | 2 +- Il2CppInterop.Generator/ContextResolver.cs | 16 +++++++-------- .../MethodAnalysisContextExtensions.cs | 2 +- .../Il2CppInterop.Generator.csproj | 4 ++-- .../InitializationClassProcessingLayer.cs | 2 +- .../InterfaceOverrideProcessingLayer.cs | 2 +- .../UnstripBaseProcessingLayer.cs | 20 +++++++++---------- .../Il2CppInterop.HarmonySupport.csproj | 2 +- .../Il2CppInterop.Runtime.csproj | 4 ++-- ...Il2CppInterop.SourceGenerator.Tests.csproj | 12 +++++------ .../Il2CppInterop.SourceGenerator.csproj | 4 ++-- .../Il2CppInterop.StructGenerator.csproj | 6 +++--- 13 files changed, 38 insertions(+), 44 deletions(-) diff --git a/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj b/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj index acf4371b..917b009d 100644 --- a/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj +++ b/Il2CppInterop.CLI/Il2CppInterop.CLI.csproj @@ -16,10 +16,4 @@ - - - - - - diff --git a/Il2CppInterop.Common/Il2CppInterop.Common.csproj b/Il2CppInterop.Common/Il2CppInterop.Common.csproj index 2ffa912e..49b354c6 100644 --- a/Il2CppInterop.Common/Il2CppInterop.Common.csproj +++ b/Il2CppInterop.Common/Il2CppInterop.Common.csproj @@ -9,7 +9,7 @@ - + diff --git a/Il2CppInterop.Generator/ContextResolver.cs b/Il2CppInterop.Generator/ContextResolver.cs index 9d72f8e9..dccbb2f3 100644 --- a/Il2CppInterop.Generator/ContextResolver.cs +++ b/Il2CppInterop.Generator/ContextResolver.cs @@ -9,12 +9,12 @@ namespace Il2CppInterop.Generator; public readonly struct ContextResolver { - private readonly AssemblyAnalysisContext referencedFrom; + private readonly ApplicationAnalysisContext referencedFrom; private readonly TypeAnalysisContext? referencingType; private readonly MethodAnalysisContext? referencingMethod; private readonly RuntimeContext runtimeContext; - public ContextResolver(AssemblyAnalysisContext referencedFrom, RuntimeContext runtimeContext) + public ContextResolver(ApplicationAnalysisContext referencedFrom, RuntimeContext runtimeContext) { this.referencedFrom = referencedFrom; this.runtimeContext = runtimeContext; @@ -24,7 +24,7 @@ public ContextResolver(TypeAnalysisContext referencingType, RuntimeContext runti { if (referencingType is ReferencedTypeAnalysisContext) throw new ArgumentException("Must be a simple type", nameof(referencingType)); - referencedFrom = referencingType.DeclaringAssembly; + referencedFrom = referencingType.AppContext; this.referencingType = referencingType; this.runtimeContext = runtimeContext; } @@ -33,7 +33,7 @@ public ContextResolver(MethodAnalysisContext referencingMethod, RuntimeContext r { if (referencingMethod is ConcreteGenericMethodAnalysisContext) throw new ArgumentException("Must be a simple method", nameof(referencingMethod)); - referencedFrom = referencingMethod.CustomAttributeAssembly; + referencedFrom = referencingMethod.AppContext; referencingType = referencingMethod.DeclaringType; this.referencingMethod = referencingMethod; this.runtimeContext = runtimeContext; @@ -77,14 +77,14 @@ public bool TryResolve(TypeSignature? type, [NotNullWhen(true)] out TypeAnalysis private GenericInstanceTypeAnalysisContext? Resolve(GenericInstanceTypeSignature genericInstance) { return TryResolve(genericInstance.GenericType, out var genericType) && TryResolve(genericInstance.TypeArguments, out var genericArguments) - ? new GenericInstanceTypeAnalysisContext(genericType, genericArguments, referencedFrom) + ? new GenericInstanceTypeAnalysisContext(genericType, genericArguments) : null; } private CustomModifierTypeAnalysisContext? Resolve(CustomModifierTypeSignature customModifier) { return TryResolve(customModifier.BaseType, out var baseType) && TryResolve(customModifier.ModifierType, out var modifier) - ? new CustomModifierTypeAnalysisContext(baseType, modifier, customModifier.IsRequired, referencedFrom) + ? new CustomModifierTypeAnalysisContext(baseType, modifier, customModifier.IsRequired) : null; } @@ -125,7 +125,7 @@ public bool TryResolve(TypeSignature? type, [NotNullWhen(true)] out TypeAnalysis if (assemblyName == null) return null; - if (!referencedFrom.AppContext.AssembliesByName.TryGetValue(assemblyName, out var targetAssembly)) + if (!referencedFrom.AssembliesByName.TryGetValue(assemblyName, out var targetAssembly)) return null; return targetAssembly.GetTypeByFullName(typeDefOrRef.FullName); @@ -140,7 +140,7 @@ public bool TryResolve(TypeSignature? type, [NotNullWhen(true)] out TypeAnalysis private TypeAnalysisContext? Resolve(CorLibTypeSignature corLibType) { - return referencedFrom.AppContext.Mscorlib.GetTypeByFullName(corLibType.FullName); + return referencedFrom.Mscorlib.GetTypeByFullName(corLibType.FullName); } public TypeAnalysisContext? Resolve(ITypeDescriptor? type) diff --git a/Il2CppInterop.Generator/Extensions/MethodAnalysisContextExtensions.cs b/Il2CppInterop.Generator/Extensions/MethodAnalysisContextExtensions.cs index 810b1454..b0055615 100644 --- a/Il2CppInterop.Generator/Extensions/MethodAnalysisContextExtensions.cs +++ b/Il2CppInterop.Generator/Extensions/MethodAnalysisContextExtensions.cs @@ -176,7 +176,7 @@ private static bool IsInterfaceSlot(MethodAnalysisContext method, int slot) { if (slot >= interfaceOffset.offset) { - var interfaceTypeContext = interfaceOffset.Type.ToContext(method.CustomAttributeAssembly); + var interfaceTypeContext = interfaceOffset.Type.ToContext(method.AppContext); if (interfaceTypeContext != null && TryGetMethodForSlot(interfaceTypeContext, slot - interfaceOffset.offset, out _)) { return true; diff --git a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj index 56de393e..9589b97a 100644 --- a/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj +++ b/Il2CppInterop.Generator/Il2CppInterop.Generator.csproj @@ -8,8 +8,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index 48ce0ee8..65128add 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -496,7 +496,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action 0) continue; // Skip open generics diff --git a/Il2CppInterop.Generator/InterfaceOverrideProcessingLayer.cs b/Il2CppInterop.Generator/InterfaceOverrideProcessingLayer.cs index d8594d68..2688fb92 100644 --- a/Il2CppInterop.Generator/InterfaceOverrideProcessingLayer.cs +++ b/Il2CppInterop.Generator/InterfaceOverrideProcessingLayer.cs @@ -120,7 +120,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action= interfaceOffset.offset) { - var interfaceTypeContext = interfaceOffset.Type.ToContext(type.DeclaringAssembly); + var interfaceTypeContext = interfaceOffset.Type.ToContext(type.AppContext); if (interfaceTypeContext != null && interfaceTypeContext.TryGetMethodInSlot(index - interfaceOffset.offset, out var method)) { return method; diff --git a/Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs b/Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs index b04ba5e9..3d8de209 100644 --- a/Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs +++ b/Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs @@ -284,11 +284,11 @@ protected static void InjectAssemblies(ApplicationAnalysisContext appContext, IR List<(MethodAnalysisContext, MethodDefinition)> methodsNeedingBodies = new(); foreach (var (type, typeContext) in injectedTypes) { - CopyCustomAttributes(type, typeContext, typeContext.DeclaringAssembly, runtimeContext); + CopyCustomAttributes(type, typeContext, typeContext.AppContext, runtimeContext); for (var i = 0; i < type.GenericParameters.Count; i++) { - CopyCustomAttributes(type.GenericParameters[i], typeContext.GenericParameters[i], typeContext.DeclaringAssembly, runtimeContext); + CopyCustomAttributes(type.GenericParameters[i], typeContext.GenericParameters[i], typeContext.AppContext, runtimeContext); } foreach (var field in type.Fields) @@ -537,7 +537,7 @@ private static bool TryInjectField(FieldDefinition field, TypeAnalysisContext ty fieldContext.OverrideConstantValue = field.Constant?.InterpretData(); - CopyCustomAttributes(field, fieldContext, typeContext.DeclaringAssembly, runtimeContext); + CopyCustomAttributes(field, fieldContext, typeContext.AppContext, runtimeContext); fieldContext.IsUnstripped = true; @@ -601,14 +601,14 @@ private static bool TryInjectMethod(MethodDefinition method, TypeAnalysisContext return false; } - CopyCustomAttributes(method, methodContext, typeContext.DeclaringAssembly, runtimeContext); + CopyCustomAttributes(method, methodContext, typeContext.AppContext, runtimeContext); for (var i = 0; i < method.Parameters.Count; i++) { - CopyCustomAttributes(method.Parameters[i].GetOrCreateDefinition(), methodContext.Parameters[i], typeContext.DeclaringAssembly, runtimeContext); + CopyCustomAttributes(method.Parameters[i].GetOrCreateDefinition(), methodContext.Parameters[i], typeContext.AppContext, runtimeContext); } for (var i = 0; i < method.GenericParameters.Count; i++) { - CopyCustomAttributes(method.GenericParameters[i], methodContext.GenericParameters[i], typeContext.DeclaringAssembly, runtimeContext); + CopyCustomAttributes(method.GenericParameters[i], methodContext.GenericParameters[i], typeContext.AppContext, runtimeContext); } methodContext.IsUnstripped = true; @@ -667,7 +667,7 @@ private static bool TryInjectProperty(PropertyDefinition property, TypeAnalysisC typeContext); typeContext.Properties.Add(propertyContext); - CopyCustomAttributes(property, propertyContext, typeContext.DeclaringAssembly, runtimeContext); + CopyCustomAttributes(property, propertyContext, typeContext.AppContext, runtimeContext); propertyContext.IsUnstripped = true; @@ -703,21 +703,21 @@ private static bool TryInjectEvent(EventDefinition @event, TypeAnalysisContext t typeContext); typeContext.Events.Add(eventContext); - CopyCustomAttributes(@event, eventContext, typeContext.DeclaringAssembly, runtimeContext); + CopyCustomAttributes(@event, eventContext, typeContext.AppContext, runtimeContext); eventContext.IsUnstripped = true; return true; } - private static void CopyCustomAttributes(IHasCustomAttribute source, HasCustomAttributes destination, AssemblyAnalysisContext assembly, RuntimeContext runtimeContext) + private static void CopyCustomAttributes(IHasCustomAttribute source, HasCustomAttributes destination, ApplicationAnalysisContext appContext, RuntimeContext runtimeContext) { foreach (var customAttribute in source.CustomAttributes) { if (customAttribute.Constructor is null or { Signature: null or { ParameterTypes.Count: > 0 } }) continue; // Skip custom attributes with parameters or an invalid constructor - if (!new ContextResolver(assembly, runtimeContext).TryResolve(customAttribute.Constructor, out var constructorContext)) + if (!new ContextResolver(appContext, runtimeContext).TryResolve(customAttribute.Constructor, out var constructorContext)) continue; // Skip custom attributes with an invalid constructor destination.CustomAttributes ??= []; diff --git a/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj b/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj index 237103ae..d5d8544e 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj +++ b/Il2CppInterop.HarmonySupport/Il2CppInterop.HarmonySupport.csproj @@ -8,7 +8,7 @@ - + diff --git a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj index dced718d..761eecb9 100644 --- a/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj +++ b/Il2CppInterop.Runtime/Il2CppInterop.Runtime.csproj @@ -16,8 +16,8 @@ - - + + diff --git a/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj b/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj index ecb66781..52cbcf6f 100644 --- a/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj +++ b/Il2CppInterop.SourceGenerator.Tests/Il2CppInterop.SourceGenerator.Tests.csproj @@ -7,12 +7,12 @@ - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj b/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj index a6e97a68..614d65d9 100644 --- a/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj +++ b/Il2CppInterop.SourceGenerator/Il2CppInterop.SourceGenerator.csproj @@ -9,8 +9,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj b/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj index 80583e0f..fc8115d0 100644 --- a/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj +++ b/Il2CppInterop.StructGenerator/Il2CppInterop.StructGenerator.csproj @@ -9,9 +9,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive From f46e88d0e8a5515ed7f60938aba3de5339c752fb Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 19 Jul 2026 12:24:47 -0700 Subject: [PATCH 486/486] Unstrip field offsets for explicit layout structs --- Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs b/Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs index 3d8de209..b9292acd 100644 --- a/Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs +++ b/Il2CppInterop.Generator/UnstripBaseProcessingLayer.cs @@ -537,6 +537,9 @@ private static bool TryInjectField(FieldDefinition field, TypeAnalysisContext ty fieldContext.OverrideConstantValue = field.Constant?.InterpretData(); + if (field.FieldOffset is { } offset) + fieldContext.Offset = offset; + CopyCustomAttributes(field, fieldContext, typeContext.AppContext, runtimeContext); fieldContext.IsUnstripped = true;

iS(22 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 + + + + + + + + + + + From 927978f4ea58eb1e4b6e6cdf3ea00582c7a3ae2e Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 20:33:22 -0700 Subject: [PATCH 350/486] Move ResolveICall from IL2CPP to RuntimeInvoke --- .../InitializationClassProcessingLayer.cs | 3 +- Il2CppInterop.Runtime/IL2CPP.cs | 93 ------------------- .../InteropTypes/RuntimeInvoke.cs | 93 +++++++++++++++++++ 3 files changed, 95 insertions(+), 94 deletions(-) diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index 9d643eae..956339b0 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -42,7 +42,8 @@ public override void Process(ApplicationAnalysisContext appContext, Action diff --git a/Il2CppInterop.Runtime/IL2CPP.cs b/Il2CppInterop.Runtime/IL2CPP.cs index e92a989f..cd411e74 100644 --- a/Il2CppInterop.Runtime/IL2CPP.cs +++ b/Il2CppInterop.Runtime/IL2CPP.cs @@ -1,14 +1,9 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Injection; -using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.Runtime; using Microsoft.Extensions.Logging; @@ -237,94 +232,6 @@ static IntPtr GetNestedTypeViaReflection(nint enclosingClass, string nestedTypeN } } - public static T ResolveICall(string signature) where T : Delegate - { - var icallPtr = il2cpp_resolve_icall(signature); - if (icallPtr == nint.Zero) - { - Logger.Instance.LogTrace("ICall {Signature} not resolved", signature); - return GenerateDelegateForMissingICall(signature); - } - - return GenerateDelegateForICall(icallPtr); - } - - private static T GenerateDelegateForMissingICall(string signature) where T : Delegate - { - var invoke = typeof(T).GetMethod("Invoke")!; - - var trampoline = new DynamicMethod("(missing icall delegate) " + typeof(T).FullName, - invoke.ReturnType, invoke.GetParameters().Select(it => it.ParameterType).ToArray(), typeof(IL2CPP), true); - var bodyBuilder = trampoline.GetILGenerator(); - - bodyBuilder.Emit(OpCodes.Ldstr, $"ICall with signature {signature} was not resolved"); - bodyBuilder.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor([typeof(string)])!); - bodyBuilder.Emit(OpCodes.Throw); - - return (T)trampoline.CreateDelegate(typeof(T)); - } - - private static T GenerateDelegateForICall(nint icallPtr) where T : Delegate - { - var invoke = typeof(T).GetMethod("Invoke")!; - - var trampoline = new DynamicMethod("(icall delegate) " + typeof(T).FullName, - invoke.ReturnType, invoke.GetParameters().Select(it => it.ParameterType).ToArray(), typeof(IL2CPP), true); - var bodyBuilder = trampoline.GetILGenerator(); - - var sizeOfMethod = typeof(Il2CppType).GetMethod(nameof(Il2CppType.SizeOf))!; - var parameters = invoke.GetParameters(); - var parameterTypes = new Type[parameters.Length]; - var locals = new LocalBuilder[parameters.Length]; - for (var i = 0; i < parameters.Length; i++) - { - var parameter = parameters[i]; - var parameterType = parameter.ParameterType; - - // Parameter is a ByReference, and we need to get the underlying type T - var elementType = parameterType.GenericTypeArguments[0]; - - var nativeStruct = TrampolineHelpers.NativeType(elementType); - parameterTypes[i] = nativeStruct; - - var nativeLocal = bodyBuilder.DeclareLocal(nativeStruct); - locals[i] = nativeLocal; - - bodyBuilder.Emit(OpCodes.Ldarga, i); - bodyBuilder.Emit(OpCodes.Ldloca, nativeLocal); - bodyBuilder.Emit(OpCodes.Call, parameterType.GetMethod(nameof(ByReference<>.CopyToUnmanaged))!.MakeGenericMethod(nativeStruct)); - } - - foreach (var local in locals) - { - bodyBuilder.Emit(OpCodes.Ldloc, local); - } - - bodyBuilder.Emit(OpCodes.Ldc_I8, icallPtr); - bodyBuilder.Emit(OpCodes.Conv_I); - - if (invoke.ReturnType == typeof(void)) - { - bodyBuilder.EmitCalli(OpCodes.Calli, CallingConventions.Standard, typeof(void), parameterTypes, null); - } - else - { - var returnType = invoke.ReturnType; - var nativeStruct = TrampolineHelpers.NativeType(returnType); - - bodyBuilder.EmitCalli(OpCodes.Calli, CallingConventions.Standard, nativeStruct, parameterTypes, null); - - var returnLocal = bodyBuilder.DeclareLocal(nativeStruct); - bodyBuilder.Emit(OpCodes.Stloc, returnLocal); - - bodyBuilder.Emit(OpCodes.Ldloca, returnLocal); - bodyBuilder.Emit(OpCodes.Call, typeof(Il2CppType).GetMethod(nameof(Il2CppType.ReadFromPointer))!.MakeGenericMethod(returnType)); - } - bodyBuilder.Emit(OpCodes.Ret); - - return (T)trampoline.CreateDelegate(typeof(T)); - } - // IL2CPP Functions [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] diff --git a/Il2CppInterop.Runtime/InteropTypes/RuntimeInvoke.cs b/Il2CppInterop.Runtime/InteropTypes/RuntimeInvoke.cs index 6e0d3a04..5dc12249 100644 --- a/Il2CppInterop.Runtime/InteropTypes/RuntimeInvoke.cs +++ b/Il2CppInterop.Runtime/InteropTypes/RuntimeInvoke.cs @@ -1,7 +1,12 @@ using System; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; using System.Runtime.CompilerServices; using Il2CppInterop.Common; +using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.Runtime; +using Microsoft.Extensions.Logging; using Il2CppException = Il2CppInterop.Runtime.Exceptions.Il2CppException; namespace Il2CppInterop.Runtime.InteropTypes; @@ -95,4 +100,92 @@ private static bool IsValueType() { return typeof(T).IsValueType; } + + public static T ResolveICall(string signature) where T : Delegate + { + var icallPtr = IL2CPP.il2cpp_resolve_icall(signature); + if (icallPtr == nint.Zero) + { + Logger.Instance.LogTrace("ICall {Signature} not resolved", signature); + return GenerateDelegateForMissingICall(signature); + } + + return GenerateDelegateForICall(icallPtr); + } + + private static T GenerateDelegateForMissingICall(string signature) where T : Delegate + { + var invoke = typeof(T).GetMethod("Invoke")!; + + var trampoline = new DynamicMethod("(missing icall delegate) " + typeof(T).FullName, + invoke.ReturnType, invoke.GetParameters().Select(it => it.ParameterType).ToArray(), typeof(RuntimeInvoke), true); + var bodyBuilder = trampoline.GetILGenerator(); + + bodyBuilder.Emit(OpCodes.Ldstr, $"ICall with signature {signature} was not resolved"); + bodyBuilder.Emit(OpCodes.Newobj, typeof(Exception).GetConstructor([typeof(string)])!); + bodyBuilder.Emit(OpCodes.Throw); + + return (T)trampoline.CreateDelegate(typeof(T)); + } + + private static T GenerateDelegateForICall(nint icallPtr) where T : Delegate + { + var invoke = typeof(T).GetMethod("Invoke")!; + + var trampoline = new DynamicMethod("(icall delegate) " + typeof(T).FullName, + invoke.ReturnType, invoke.GetParameters().Select(it => it.ParameterType).ToArray(), typeof(RuntimeInvoke), true); + var bodyBuilder = trampoline.GetILGenerator(); + + var sizeOfMethod = typeof(Il2CppType).GetMethod(nameof(Il2CppType.SizeOf))!; + var parameters = invoke.GetParameters(); + var parameterTypes = new Type[parameters.Length]; + var locals = new LocalBuilder[parameters.Length]; + for (var i = 0; i < parameters.Length; i++) + { + var parameter = parameters[i]; + var parameterType = parameter.ParameterType; + + // Parameter is a ByReference, and we need to get the underlying type T + var elementType = parameterType.GenericTypeArguments[0]; + + var nativeStruct = TrampolineHelpers.NativeType(elementType); + parameterTypes[i] = nativeStruct; + + var nativeLocal = bodyBuilder.DeclareLocal(nativeStruct); + locals[i] = nativeLocal; + + bodyBuilder.Emit(OpCodes.Ldarga, i); + bodyBuilder.Emit(OpCodes.Ldloca, nativeLocal); + bodyBuilder.Emit(OpCodes.Call, parameterType.GetMethod(nameof(ByReference<>.CopyToUnmanaged))!.MakeGenericMethod(nativeStruct)); + } + + foreach (var local in locals) + { + bodyBuilder.Emit(OpCodes.Ldloc, local); + } + + bodyBuilder.Emit(OpCodes.Ldc_I8, icallPtr); + bodyBuilder.Emit(OpCodes.Conv_I); + + if (invoke.ReturnType == typeof(void)) + { + bodyBuilder.EmitCalli(OpCodes.Calli, CallingConventions.Standard, typeof(void), parameterTypes, null); + } + else + { + var returnType = invoke.ReturnType; + var nativeStruct = TrampolineHelpers.NativeType(returnType); + + bodyBuilder.EmitCalli(OpCodes.Calli, CallingConventions.Standard, nativeStruct, parameterTypes, null); + + var returnLocal = bodyBuilder.DeclareLocal(nativeStruct); + bodyBuilder.Emit(OpCodes.Stloc, returnLocal); + + bodyBuilder.Emit(OpCodes.Ldloca, returnLocal); + bodyBuilder.Emit(OpCodes.Call, typeof(Il2CppType).GetMethod(nameof(Il2CppType.ReadFromPointer))!.MakeGenericMethod(returnType)); + } + bodyBuilder.Emit(OpCodes.Ret); + + return (T)trampoline.CreateDelegate(typeof(T)); + } } From a7ee96a6808f5f74b0f8a115ac559767b7aaaba3 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 21:11:13 -0700 Subject: [PATCH 351/486] Remove xref implementation --- .../Attributes/CachedScanResultsAttribute.cs | 18 -- .../Attributes/CallerCountAttribute.cs | 12 -- .../Maps/MethodAddressToTokenMap.cs | 20 -- .../Maps/MethodAddressToTokenMapBase.cs | 195 ------------------ .../Maps/MethodXrefScanCache.cs | 122 ----------- .../XrefScans/GeneratedDatabasesUtil.cs | 15 -- .../XrefScans/IXrefScannerImpl.cs | 8 - .../XrefScans/XrefInstance.cs | 20 -- .../XrefScans/XrefScanMethodDb.cs | 67 ------ .../XrefScans/XrefScanUtil.cs | 55 ----- .../XrefScans/XrefScanUtilFinder.cs | 97 --------- Il2CppInterop.Common/XrefScans/XrefScanner.cs | 136 ------------ .../XrefScans/XrefScannerManager.cs | 42 ---- Il2CppInterop.Common/XrefScans/XrefType.cs | 7 - .../Hooks/Class_FromIl2CppType_Hook.cs | 1 - .../Injection/Hooks/Class_FromName_Hook.cs | 1 - .../Hooks/Class_GetFieldDefaultValue_Hook.cs | 1 - ...GetTypeInfoFromTypeDefinitionIndex_Hook.cs | 1 - .../Injection/MemoryUtils.cs | 1 - .../Injection}/XrefScannerLowLevel.cs | 35 +++- .../Startup/Il2CppInteropRuntime.cs | 3 - .../XrefScans/XrefInstanceExtensions.cs | 29 --- .../XrefScans/XrefScanImpl.cs | 37 ---- 23 files changed, 27 insertions(+), 896 deletions(-) delete mode 100644 Il2CppInterop.Common/Attributes/CachedScanResultsAttribute.cs delete mode 100644 Il2CppInterop.Common/Attributes/CallerCountAttribute.cs delete mode 100644 Il2CppInterop.Common/Maps/MethodAddressToTokenMap.cs delete mode 100644 Il2CppInterop.Common/Maps/MethodAddressToTokenMapBase.cs delete mode 100644 Il2CppInterop.Common/Maps/MethodXrefScanCache.cs delete mode 100644 Il2CppInterop.Common/XrefScans/GeneratedDatabasesUtil.cs delete mode 100644 Il2CppInterop.Common/XrefScans/IXrefScannerImpl.cs delete mode 100644 Il2CppInterop.Common/XrefScans/XrefInstance.cs delete mode 100644 Il2CppInterop.Common/XrefScans/XrefScanMethodDb.cs delete mode 100644 Il2CppInterop.Common/XrefScans/XrefScanUtil.cs delete mode 100644 Il2CppInterop.Common/XrefScans/XrefScanUtilFinder.cs delete mode 100644 Il2CppInterop.Common/XrefScans/XrefScanner.cs delete mode 100644 Il2CppInterop.Common/XrefScans/XrefScannerManager.cs delete mode 100644 Il2CppInterop.Common/XrefScans/XrefType.cs rename {Il2CppInterop.Common/XrefScans => Il2CppInterop.Runtime/Injection}/XrefScannerLowLevel.cs (71%) delete mode 100644 Il2CppInterop.Runtime/XrefScans/XrefInstanceExtensions.cs delete mode 100644 Il2CppInterop.Runtime/XrefScans/XrefScanImpl.cs diff --git a/Il2CppInterop.Common/Attributes/CachedScanResultsAttribute.cs b/Il2CppInterop.Common/Attributes/CachedScanResultsAttribute.cs deleted file mode 100644 index 4f2396d8..00000000 --- a/Il2CppInterop.Common/Attributes/CachedScanResultsAttribute.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Il2CppInterop.Common.Attributes; - -[AttributeUsage(AttributeTargets.Method, Inherited = false)] -public class CachedScanResultsAttribute : Attribute -{ - // Data for metadata init call - public long MetadataInitFlagRva; - public long MetadataInitTokenRva; - public int RefRangeEnd; - - // Methods that call this method - public int RefRangeStart; - - public int XrefRangeEnd; - - // Items that this method calls/uses - public int XrefRangeStart; -} diff --git a/Il2CppInterop.Common/Attributes/CallerCountAttribute.cs b/Il2CppInterop.Common/Attributes/CallerCountAttribute.cs deleted file mode 100644 index ebb1043a..00000000 --- a/Il2CppInterop.Common/Attributes/CallerCountAttribute.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Il2CppInterop.Common.Attributes; - -[AttributeUsage(AttributeTargets.Method, Inherited = false)] -public class CallerCountAttribute : Attribute -{ - public readonly int Count; - - public CallerCountAttribute(int count) - { - Count = count; - } -} diff --git a/Il2CppInterop.Common/Maps/MethodAddressToTokenMap.cs b/Il2CppInterop.Common/Maps/MethodAddressToTokenMap.cs deleted file mode 100644 index 46043cac..00000000 --- a/Il2CppInterop.Common/Maps/MethodAddressToTokenMap.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Reflection; - -namespace Il2CppInterop.Common.Maps; - -public class MethodAddressToTokenMap : MethodAddressToTokenMapBase -{ - public MethodAddressToTokenMap(string filePath) : base(filePath) - { - } - - protected override Assembly LoadAssembly(string assemblyName) - { - return Assembly.Load(assemblyName); - } - - protected override MethodBase? ResolveMethod(Assembly? assembly, int token) - { - return assembly?.ManifestModule.ResolveMethod(token); - } -} diff --git a/Il2CppInterop.Common/Maps/MethodAddressToTokenMapBase.cs b/Il2CppInterop.Common/Maps/MethodAddressToTokenMapBase.cs deleted file mode 100644 index ca95c7eb..00000000 --- a/Il2CppInterop.Common/Maps/MethodAddressToTokenMapBase.cs +++ /dev/null @@ -1,195 +0,0 @@ -using System.Collections; -using System.IO.MemoryMappedFiles; -using System.Runtime.InteropServices; -using System.Text; - -namespace Il2CppInterop.Common.Maps; - -public abstract class MethodAddressToTokenMapBase : IDisposable, IEnumerable<(long, TMethod?)> -{ - public const int Magic = 0x4D544D55; // UMTM - public const int Version = 1; - public const string FileName = "MethodAddressToToken.db"; - private readonly MemoryMappedViewAccessor? myAccessor; - private readonly List myAssemblyList = new(); - - protected readonly string myFilePath; - - private readonly MethodAddressToTokenMapFileHeader myHeader; - - private readonly MemoryMappedFile? myMapFile; - - private unsafe long* myPointers; - private unsafe int* myValues; - - public MethodAddressToTokenMapBase(string filePath) - { - myFilePath = filePath; - myMapFile = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open, null, 0, MemoryMappedFileAccess.Read); - - var headerView = myMapFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); - myAccessor = headerView; - - headerView.Read(0, out myHeader); - - if (myHeader.Magic != Magic) - { - myMapFile.Dispose(); - throw new FileLoadException( - $"File magic mismatched for {filePath}; Expected {Magic:X}, got {myHeader.Magic:X}"); - } - - if (myHeader.Version != Version) - { - myMapFile.Dispose(); - throw new FileLoadException( - $"File version mismatched for {filePath}; Expected {Version}, got {myHeader.Version}"); - } - - var offset = Marshal.SizeOf(); - using var reader = new BinaryReader(myMapFile.CreateViewStream(offset, 0, MemoryMappedFileAccess.Read), - Encoding.UTF8, false); - for (var i = 0; i < myHeader.NumAssemblies; i++) - { - var assemblyName = reader.ReadString(); - myAssemblyList.Add(LoadAssembly(assemblyName)); - } - - unsafe - { - byte* pointersPointer = null; - - myAccessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pointersPointer); - - myPointers = (long*)(pointersPointer + myHeader.DataOffset); - myValues = (int*)(pointersPointer + myHeader.DataOffset + myHeader.NumMethods * 8); - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - IEnumerator<(long, TMethod?)> IEnumerable<(long, TMethod?)>.GetEnumerator() - { - return GetEnumerator(); - } - - protected abstract TAssembly? LoadAssembly(string assemblyName); - - private void ReleaseUnmanagedResources() - { - myAccessor?.SafeMemoryMappedViewHandle.ReleasePointer(); - unsafe - { - myPointers = null; - myValues = null; - } - } - - private void Dispose(bool disposing) - { - ReleaseUnmanagedResources(); - if (disposing) - { - myAccessor?.Dispose(); - myMapFile?.Dispose(); - } - } - - ~MethodAddressToTokenMapBase() - { - Dispose(false); - } - - public unsafe TMethod? Lookup(long parsedRva) - { - var left = 0; - var right = myHeader.NumMethods; - - while (right - left > 1) - { - var mid = (left + right) / 2; - var pointerAt = myPointers[mid]; - if (pointerAt > parsedRva) - right = mid; - else - left = mid; - } - - if (myPointers[left] != parsedRva) - return default; - - var dataToken = myValues[left * 2]; - var assemblyIdx = myValues[left * 2 + 1]; - - return ResolveMethod(myAssemblyList[assemblyIdx], dataToken); - } - - protected abstract TMethod? ResolveMethod(TAssembly? assembly, int token); - - public Enumerator GetEnumerator() - { - return new(this); - } - - public class Enumerator : IEnumerator<(long, TMethod?)> - { - private readonly MethodAddressToTokenMapBase myMap; - private int myOffset = -1; - - public Enumerator(MethodAddressToTokenMapBase map) - { - myMap = map; - } - - public unsafe bool MoveNext() - { - myOffset++; - if (myOffset < myMap.myHeader.NumMethods) - { - var dataToken = myMap.myValues[myOffset * 2]; - var assemblyIdx = myMap.myValues[myOffset * 2 + 1]; - - Current = (myMap.myPointers[myOffset], - myMap.ResolveMethod(myMap.myAssemblyList[assemblyIdx], dataToken)); - - return true; - } - - return false; - } - - public void Reset() - { - myOffset = -1; - } - - object IEnumerator.Current => Current; - - public void Dispose() - { - } - - public (long, TMethod?) Current { get; private set; } - } -} - -[StructLayout(LayoutKind.Sequential)] -public struct MethodAddressToTokenMapFileHeader -{ - public int Magic; - public int Version; - public int NumAssemblies; - public int NumMethods; - public int DataOffset; - - // data is long[NumMethods] pointers, (int, int)[NumMethods] (tokens, assemblyIds) -} diff --git a/Il2CppInterop.Common/Maps/MethodXrefScanCache.cs b/Il2CppInterop.Common/Maps/MethodXrefScanCache.cs deleted file mode 100644 index 5702df89..00000000 --- a/Il2CppInterop.Common/Maps/MethodXrefScanCache.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System.IO.MemoryMappedFiles; -using System.Runtime.InteropServices; -using Il2CppInterop.Common.XrefScans; - -namespace Il2CppInterop.Common.Maps; - -public class MethodXrefScanCache : IDisposable -{ - public const int Magic = 0x43584D55; // UMXC - public const int Version = 1; - public const string FileName = "MethodXrefScanCache.db"; - - public readonly FileHeader Header; - private readonly MemoryMappedViewAccessor myAccessor; - - private readonly MemoryMappedFile myMapFile; - - private unsafe MethodData* myData; - - public MethodXrefScanCache(string filePath) - { - myMapFile = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open, null, 0, MemoryMappedFileAccess.Read); - - var headerView = myMapFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); - myAccessor = headerView; - - headerView.Read(0, out Header); - - if (Header.Magic != Magic) - { - myMapFile.Dispose(); - throw new FileLoadException( - $"File magic mismatched for {filePath}; Expected {Magic:X}, got {Header.Magic:X}"); - } - - if (Header.Version != Version) - { - myMapFile.Dispose(); - throw new FileLoadException( - $"File version mismatched for {filePath}; Expected {Version}, got {Header.Version}"); - } - - var offset = Marshal.SizeOf(); - - unsafe - { - byte* pointersPointer = null; - - myAccessor.SafeMemoryMappedViewHandle.AcquirePointer(ref pointersPointer); - - myData = (MethodData*)(pointersPointer + offset); - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void ReleaseUnmanagedResources() - { - myAccessor.SafeMemoryMappedViewHandle.ReleasePointer(); - unsafe - { - myData = null; - } - } - - private void Dispose(bool disposing) - { - ReleaseUnmanagedResources(); - if (disposing) - { - myAccessor?.Dispose(); - myMapFile?.Dispose(); - } - } - - ~MethodXrefScanCache() - { - Dispose(false); - } - - internal unsafe ref MethodData GetAt(int index) - { - return ref *(myData + index); - } - - [StructLayout(LayoutKind.Sequential)] - public struct FileHeader - { - public int Magic; - public int Version; - public long InitMethodMetadataRva; - - // data is MethodData[] - } - - [StructLayout(LayoutKind.Sequential)] - public struct MethodData - { - public long Address; - public long FoundAt; - public XrefType Type; - - public XrefInstance AsXrefInstance(long baseAddress) - { - return new XrefInstance(Type, (IntPtr)(baseAddress + Address), (IntPtr)(baseAddress + FoundAt)); - } - - public static MethodData FromXrefInstance(XrefInstance instance) - { - return new MethodData - { - Address = (long)instance.Pointer, - FoundAt = (long)instance.FoundAt, - Type = instance.Type - }; - } - } -} diff --git a/Il2CppInterop.Common/XrefScans/GeneratedDatabasesUtil.cs b/Il2CppInterop.Common/XrefScans/GeneratedDatabasesUtil.cs deleted file mode 100644 index 2eac06ab..00000000 --- a/Il2CppInterop.Common/XrefScans/GeneratedDatabasesUtil.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Reflection; - -namespace Il2CppInterop.Common.XrefScans; - -internal static class GeneratedDatabasesUtil -{ - private static string? DatabasesLocationOverride => Environment.GetEnvironmentVariable("IL2CPP_INTEROP_DATABASES_LOCATION"); - - public static string GetDatabasePath(string databaseName) - { - return Path.Combine( - (DatabasesLocationOverride ?? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))!, - databaseName); - } -} diff --git a/Il2CppInterop.Common/XrefScans/IXrefScannerImpl.cs b/Il2CppInterop.Common/XrefScans/IXrefScannerImpl.cs deleted file mode 100644 index 4b8a5306..00000000 --- a/Il2CppInterop.Common/XrefScans/IXrefScannerImpl.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Il2CppInterop.Common.XrefScans; - -internal interface IXrefScannerImpl -{ - (XrefScanUtil.InitMetadataForMethod, IntPtr)? GetMetadataResolver(); - - bool XrefGlobalClassFilter(IntPtr movTarget); -} diff --git a/Il2CppInterop.Common/XrefScans/XrefInstance.cs b/Il2CppInterop.Common/XrefScans/XrefInstance.cs deleted file mode 100644 index e77fd9d0..00000000 --- a/Il2CppInterop.Common/XrefScans/XrefInstance.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Il2CppInterop.Common.XrefScans; - -public readonly struct XrefInstance -{ - public readonly XrefType Type; - public readonly nint Pointer; - public readonly nint FoundAt; - - public XrefInstance(XrefType type, nint pointer, nint foundAt) - { - Type = type; - Pointer = pointer; - FoundAt = foundAt; - } - - internal XrefInstance RelativeToBase(nint baseAddress) - { - return new XrefInstance(Type, Pointer - baseAddress, FoundAt - baseAddress); - } -} diff --git a/Il2CppInterop.Common/XrefScans/XrefScanMethodDb.cs b/Il2CppInterop.Common/XrefScans/XrefScanMethodDb.cs deleted file mode 100644 index c5d96b58..00000000 --- a/Il2CppInterop.Common/XrefScans/XrefScanMethodDb.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Diagnostics; -using System.Reflection; -using System.Runtime.InteropServices; -using Il2CppInterop.Common.Attributes; -using Il2CppInterop.Common.Maps; - -namespace Il2CppInterop.Common.XrefScans; - -public static class XrefScanMethodDb -{ - private static readonly MethodAddressToTokenMap MethodMap; - private static readonly MethodXrefScanCache XrefScanCache; - private static readonly long GameAssemblyBase; - - private static XrefScanUtil.InitMetadataForMethod? ourMetadataInitForMethodDelegate; - - static XrefScanMethodDb() - { - MethodMap = new MethodAddressToTokenMap( - GeneratedDatabasesUtil.GetDatabasePath(MethodAddressToTokenMap.FileName)); - XrefScanCache = new MethodXrefScanCache(GeneratedDatabasesUtil.GetDatabasePath(MethodXrefScanCache.FileName)); - - foreach (ProcessModule module in Process.GetCurrentProcess().Modules) - if (module.ModuleName == "GameAssembly.dll") - { - GameAssemblyBase = (long)module.BaseAddress; - break; - } - } - - public static MethodBase? TryResolvePointer(IntPtr methodStart) - { - return MethodMap.Lookup((long)methodStart - GameAssemblyBase); - } - - internal static IEnumerable ListUsers(CachedScanResultsAttribute attribute) - { - for (var i = attribute.RefRangeStart; i < attribute.RefRangeEnd; i++) - yield return XrefScanCache.GetAt(i).AsXrefInstance(GameAssemblyBase); - } - - internal static IEnumerable CachedXrefScan(CachedScanResultsAttribute attribute) - { - for (var i = attribute.XrefRangeStart; i < attribute.XrefRangeEnd; i++) - yield return XrefScanCache.GetAt(i).AsXrefInstance(GameAssemblyBase); - } - - internal static void CallMetadataInitForMethod(CachedScanResultsAttribute attribute) - { - if (attribute.MetadataInitFlagRva == 0 || attribute.MetadataInitTokenRva == 0) - return; - - if (Marshal.ReadByte((IntPtr)(GameAssemblyBase + attribute.MetadataInitFlagRva)) != 0) - return; - - if (ourMetadataInitForMethodDelegate == null) - ourMetadataInitForMethodDelegate = - Marshal.GetDelegateForFunctionPointer( - (IntPtr)(GameAssemblyBase + XrefScanCache.Header.InitMethodMetadataRva)); - - var token = Marshal.ReadInt32((IntPtr)(GameAssemblyBase + attribute.MetadataInitTokenRva)); - - ourMetadataInitForMethodDelegate(token); - - Marshal.WriteByte((IntPtr)(GameAssemblyBase + attribute.MetadataInitFlagRva), 1); - } -} diff --git a/Il2CppInterop.Common/XrefScans/XrefScanUtil.cs b/Il2CppInterop.Common/XrefScans/XrefScanUtil.cs deleted file mode 100644 index 25680158..00000000 --- a/Il2CppInterop.Common/XrefScans/XrefScanUtil.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -namespace Il2CppInterop.Common.XrefScans; - -internal static class XrefScanUtil -{ - private static InitMetadataForMethod? ourMetadataInitForMethodDelegate; - private static IntPtr ourMetadataInitForMethodPointer; - - internal static event Func<(InitMetadataForMethod, IntPtr)>? InitRuntimeUtils; - - internal static unsafe bool CallMetadataInitForMethod(MethodBase method) - { - if (ourMetadataInitForMethodPointer == IntPtr.Zero) - { - var res = XrefScannerManager.Impl.GetMetadataResolver(); - if (res is ({ } m, var p)) - { - ourMetadataInitForMethodDelegate = m; - ourMetadataInitForMethodPointer = p; - } - else - { - return false; - } - } - - var nativeMethodInfoObject = - Il2CppInteropUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(method)?.GetValue(null); - if (nativeMethodInfoObject == null) return false; - var nativeMethodInfo = (IntPtr)nativeMethodInfoObject; - var codeStart = *(IntPtr*)nativeMethodInfo; - var firstCall = XrefScannerLowLevel.JumpTargets(codeStart).FirstOrDefault(); - if (firstCall != ourMetadataInitForMethodPointer || firstCall == IntPtr.Zero) return false; - - var tokenPointer = - XrefScanUtilFinder.FindLastRcxReadAddressBeforeCallTo(codeStart, ourMetadataInitForMethodPointer); - var initFlagPointer = - XrefScanUtilFinder.FindByteWriteTargetRightAfterCallTo(codeStart, ourMetadataInitForMethodPointer); - - if (tokenPointer == IntPtr.Zero || initFlagPointer == IntPtr.Zero) return false; - - if (Marshal.ReadByte(initFlagPointer) == 0) - { - ourMetadataInitForMethodDelegate?.Invoke(Marshal.ReadInt32(tokenPointer)); - Marshal.WriteByte(initFlagPointer, 1); - } - - return true; - } - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate void InitMetadataForMethod(int metadataUsageToken); -} diff --git a/Il2CppInterop.Common/XrefScans/XrefScanUtilFinder.cs b/Il2CppInterop.Common/XrefScans/XrefScanUtilFinder.cs deleted file mode 100644 index 319a5a2e..00000000 --- a/Il2CppInterop.Common/XrefScans/XrefScanUtilFinder.cs +++ /dev/null @@ -1,97 +0,0 @@ -using Iced.Intel; - -namespace Il2CppInterop.Common.XrefScans; - -internal static class XrefScanUtilFinder -{ - public static IntPtr FindLastRcxReadAddressBeforeCallTo(IntPtr codeStart, IntPtr callTarget) - { - var decoder = XrefScanner.DecoderForAddress(codeStart); - var lastRcxRead = IntPtr.Zero; - - while (true) - { - decoder.Decode(out var instruction); - if (decoder.LastError == DecoderError.NoMoreBytes) return IntPtr.Zero; - - if (instruction.FlowControl == FlowControl.Return) - return IntPtr.Zero; - - if (instruction.FlowControl == FlowControl.UnconditionalBranch) - continue; - - if (instruction.Mnemonic == Mnemonic.Int || instruction.Mnemonic == Mnemonic.Int1) - return IntPtr.Zero; - - if (instruction.Mnemonic == Mnemonic.Call) - { - var target = ExtractTargetAddress(instruction); - if ((IntPtr)target == callTarget) - return lastRcxRead; - } - - if (instruction.Mnemonic == Mnemonic.Mov) - if (instruction.Op0Kind == OpKind.Register && instruction.Op0Register == Register.ECX && - instruction.Op1Kind == OpKind.Memory && instruction.IsIPRelativeMemoryOperand) - { - var movTarget = (IntPtr)instruction.IPRelativeMemoryAddress; - if (instruction.MemorySize != MemorySize.UInt32 && instruction.MemorySize != MemorySize.Int32) - continue; - - lastRcxRead = movTarget; - } - } - } - - public static IntPtr FindByteWriteTargetRightAfterCallTo(IntPtr codeStart, IntPtr callTarget) - { - var decoder = XrefScanner.DecoderForAddress(codeStart); - var seenCall = false; - - while (true) - { - decoder.Decode(out var instruction); - if (decoder.LastError == DecoderError.NoMoreBytes) return IntPtr.Zero; - - if (instruction.FlowControl == FlowControl.Return) - return IntPtr.Zero; - - if (instruction.FlowControl == FlowControl.UnconditionalBranch) - continue; - - if (instruction.Mnemonic == Mnemonic.Int || instruction.Mnemonic == Mnemonic.Int1) - return IntPtr.Zero; - - if (instruction.Mnemonic == Mnemonic.Call) - { - var target = ExtractTargetAddress(instruction); - if ((IntPtr)target == callTarget) - seenCall = true; - } - - if (instruction.Mnemonic == Mnemonic.Mov && seenCall) - if (instruction.Op0Kind == OpKind.Memory && (instruction.MemorySize == MemorySize.Int8 || - instruction.MemorySize == MemorySize.UInt8)) - return (IntPtr)instruction.IPRelativeMemoryAddress; - } - } - - private static ulong ExtractTargetAddress(in Instruction instruction) - { - switch (instruction.Op0Kind) - { - case OpKind.NearBranch16: - return instruction.NearBranch16; - case OpKind.NearBranch32: - return instruction.NearBranch32; - case OpKind.NearBranch64: - return instruction.NearBranch64; - case OpKind.FarBranch16: - return instruction.FarBranch16; - case OpKind.FarBranch32: - return instruction.FarBranch32; - default: - return 0; - } - } -} diff --git a/Il2CppInterop.Common/XrefScans/XrefScanner.cs b/Il2CppInterop.Common/XrefScans/XrefScanner.cs deleted file mode 100644 index e16c22d7..00000000 --- a/Il2CppInterop.Common/XrefScans/XrefScanner.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System.Reflection; -using Iced.Intel; -using Il2CppInterop.Common.Attributes; -using Microsoft.Extensions.Logging; - -namespace Il2CppInterop.Common.XrefScans; - -public static class XrefScanner -{ - public static unsafe IEnumerable XrefScan(MethodBase methodBase) - { - var fieldValue = Il2CppInteropUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(methodBase) - ?.GetValue(null); - if (fieldValue == null) return Enumerable.Empty(); - - CachedScanResultsAttribute? cachedAttribute = null; - try - { - cachedAttribute = methodBase.GetCustomAttribute(false); - } - catch (Exception e) - { - Logger.Instance.LogWarning("Failed to get custom attribute for {TypeName}.{MethodName}: {Error}. Falling back to scanning", methodBase.DeclaringType!.FullName, methodBase.Name, e.Message); - } - - if (cachedAttribute == null) - { - XrefScanUtil.CallMetadataInitForMethod(methodBase); - - return XrefScanImpl(DecoderForAddress(*(IntPtr*)(IntPtr)fieldValue)); - } - - if (cachedAttribute.XrefRangeStart == cachedAttribute.XrefRangeEnd) - return Enumerable.Empty(); - - XrefScanMethodDb.CallMetadataInitForMethod(cachedAttribute); - - return XrefScanMethodDb.CachedXrefScan(cachedAttribute).Where(it => - it.Type == XrefType.Method || XrefScannerManager.Impl.XrefGlobalClassFilter(it.Pointer)); - } - - public static IEnumerable UsedBy(MethodBase methodBase) - { - var cachedAttribute = methodBase.GetCustomAttribute(false); - if (cachedAttribute == null || cachedAttribute.RefRangeStart == cachedAttribute.RefRangeEnd) - return Enumerable.Empty(); - - return XrefScanMethodDb.ListUsers(cachedAttribute); - } - - internal static unsafe Decoder DecoderForAddress(IntPtr codeStart, int lengthLimit = 1000) - { - if (codeStart == IntPtr.Zero) throw new NullReferenceException(nameof(codeStart)); - - var stream = new UnmanagedMemoryStream((byte*)codeStart, lengthLimit, lengthLimit, FileAccess.Read); - var codeReader = new StreamCodeReader(stream); - var decoder = Decoder.Create(IntPtr.Size * 8, codeReader); - decoder.IP = (ulong)codeStart; - - return decoder; - } - - internal static IEnumerable XrefScanImpl(Decoder decoder, bool skipClassCheck = false) - { - while (true) - { - decoder.Decode(out var instruction); - if (decoder.LastError == DecoderError.NoMoreBytes) yield break; - - if (instruction.FlowControl == FlowControl.Return) - yield break; - - if (instruction.Mnemonic == Mnemonic.Int || instruction.Mnemonic == Mnemonic.Int1) - yield break; - - if (instruction.Mnemonic == Mnemonic.Call || instruction.Mnemonic == Mnemonic.Jmp) - { - var targetAddress = ExtractTargetAddress(instruction); - if (targetAddress != 0) - yield return new XrefInstance(XrefType.Method, (nint)targetAddress, (nint)instruction.IP); - continue; - } - - if (instruction.FlowControl == FlowControl.UnconditionalBranch) - continue; - - if (IsMoveMnemonic(instruction.Mnemonic)) - { - XrefInstance? result = null; - try - { - if (instruction.Op1Kind == OpKind.Memory && instruction.IsIPRelativeMemoryOperand) - { - var movTarget = (IntPtr)instruction.IPRelativeMemoryAddress; - if (instruction.MemorySize != MemorySize.UInt64) - continue; - - if (skipClassCheck || XrefScannerManager.Impl.XrefGlobalClassFilter(movTarget)) - result = new XrefInstance(XrefType.Global, movTarget, (IntPtr)instruction.IP); - } - } - catch (Exception ex) - { - Logger.Instance.LogError("{Error}", ex.ToString()); - } - - if (result != null) - yield return result.Value; - } - } - } - - internal static bool IsMoveMnemonic(Mnemonic mnemonic) - { - return mnemonic is Mnemonic.Mov or >= Mnemonic.Cmova and <= Mnemonic.Cmovs; - } - - internal static ulong ExtractTargetAddress(in Instruction instruction) - { - switch (instruction.Op0Kind) - { - case OpKind.NearBranch16: - return instruction.NearBranch16; - case OpKind.NearBranch32: - return instruction.NearBranch32; - case OpKind.NearBranch64: - return instruction.NearBranch64; - case OpKind.FarBranch16: - return instruction.FarBranch16; - case OpKind.FarBranch32: - return instruction.FarBranch32; - default: - return 0; - } - } -} diff --git a/Il2CppInterop.Common/XrefScans/XrefScannerManager.cs b/Il2CppInterop.Common/XrefScans/XrefScannerManager.cs deleted file mode 100644 index aa727152..00000000 --- a/Il2CppInterop.Common/XrefScans/XrefScannerManager.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Il2CppInterop.Common.Host; - -namespace Il2CppInterop.Common.XrefScans; - -internal static class XrefScannerManagerExtensions -{ - public static T AddXrefScanner(this T host) where T : BaseHost where TScanner : IXrefScannerImpl, new() - { - host.AddComponent(new XrefScannerManager(new TScanner())); - return host; - } -} - -internal class XrefScannerManager : IHostComponent -{ - private static IXrefScannerImpl? s_xrefScanner; - - public static IXrefScannerImpl Impl - { - get - { - if (s_xrefScanner == null) - { - throw new InvalidOperationException("XrefScanner is not initialized! Initialize the host before using XrefScanner!"); - } - - return s_xrefScanner; - } - } - - public XrefScannerManager(IXrefScannerImpl impl) - { - s_xrefScanner = impl; - } - - public void Dispose() - { - s_xrefScanner = null; - } - - public void Start() { } -} diff --git a/Il2CppInterop.Common/XrefScans/XrefType.cs b/Il2CppInterop.Common/XrefScans/XrefType.cs deleted file mode 100644 index 1a1501f7..00000000 --- a/Il2CppInterop.Common/XrefScans/XrefType.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Il2CppInterop.Common.XrefScans; - -public enum XrefType -{ - Global, - Method -} diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs index d8212e7a..f093f82f 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Runtime.InteropServices; using Il2CppInterop.Common; -using Il2CppInterop.Common.XrefScans; using Il2CppInterop.Runtime.Runtime; using Microsoft.Extensions.Logging; diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs index 0c09a488..cfaf6a2a 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Runtime.InteropServices; using Il2CppInterop.Common; -using Il2CppInterop.Common.XrefScans; using Il2CppInterop.Runtime.Runtime; using Microsoft.Extensions.Logging; diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs index 974bdc81..1624a6b2 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Runtime.InteropServices; using Il2CppInterop.Common; -using Il2CppInterop.Common.XrefScans; using Il2CppInterop.Runtime.Extensions; using Il2CppInterop.Runtime.Runtime; using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class; diff --git a/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs index 147aa39b..8555c81a 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Runtime.InteropServices; using Il2CppInterop.Common; -using Il2CppInterop.Common.XrefScans; using Il2CppInterop.Runtime.Runtime; using Il2CppInterop.Runtime.Startup; using Microsoft.Extensions.Logging; diff --git a/Il2CppInterop.Runtime/Injection/MemoryUtils.cs b/Il2CppInterop.Runtime/Injection/MemoryUtils.cs index cecb0322..386eb4a3 100644 --- a/Il2CppInterop.Runtime/Injection/MemoryUtils.cs +++ b/Il2CppInterop.Runtime/Injection/MemoryUtils.cs @@ -3,7 +3,6 @@ using System.Diagnostics; using System.Linq; using System.Runtime.Versioning; -using Il2CppInterop.Common.XrefScans; using TerraFX.Interop.Windows; namespace Il2CppInterop.Runtime.Injection; diff --git a/Il2CppInterop.Common/XrefScans/XrefScannerLowLevel.cs b/Il2CppInterop.Runtime/Injection/XrefScannerLowLevel.cs similarity index 71% rename from Il2CppInterop.Common/XrefScans/XrefScannerLowLevel.cs rename to Il2CppInterop.Runtime/Injection/XrefScannerLowLevel.cs index a8d44d7c..88203cdf 100644 --- a/Il2CppInterop.Common/XrefScans/XrefScannerLowLevel.cs +++ b/Il2CppInterop.Runtime/Injection/XrefScannerLowLevel.cs @@ -1,12 +1,15 @@ +using System; +using System.Collections.Generic; +using System.IO; using Iced.Intel; -namespace Il2CppInterop.Common.XrefScans; +namespace Il2CppInterop.Runtime.Injection; -public static class XrefScannerLowLevel +internal static class XrefScannerLowLevel { public static IEnumerable JumpTargets(IntPtr codeStart, bool ignoreRetn = false) { - return JumpTargetsImpl(XrefScanner.DecoderForAddress(codeStart), ignoreRetn); + return JumpTargetsImpl(DecoderForAddress(codeStart), ignoreRetn); } private static IEnumerable JumpTargetsImpl(Decoder myDecoder, bool ignoreRetn) @@ -31,8 +34,11 @@ private static IEnumerable JumpTargetsImpl(Decoder myDecoder, bool ignor // We hope and pray that the compiler didn't use short jumps for any function calls if (!instruction.IsJmpShort) { - yield return (IntPtr)ExtractTargetAddress(in instruction); - if (firstFlowControl && instruction.FlowControl == FlowControl.UnconditionalBranch) yield break; + var targetAddress = (IntPtr)ExtractTargetAddress(in instruction); + if (targetAddress != IntPtr.Zero) + yield return targetAddress; + if (firstFlowControl && instruction.FlowControl == FlowControl.UnconditionalBranch) + yield break; } } @@ -45,7 +51,7 @@ private static IEnumerable JumpTargetsImpl(Decoder myDecoder, bool ignor public static IEnumerable CallAndIndirectTargets(IntPtr pointer) { - return CallAndIndirectTargetsImpl(XrefScanner.DecoderForAddress(pointer, 1024 * 1024)); + return CallAndIndirectTargetsImpl(DecoderForAddress(pointer, 1024 * 1024)); } private static IEnumerable CallAndIndirectTargetsImpl(Decoder decoder) @@ -63,7 +69,7 @@ private static IEnumerable CallAndIndirectTargetsImpl(Decoder decoder) if (instruction.Mnemonic == Mnemonic.Call || instruction.Mnemonic == Mnemonic.Jmp) { - var targetAddress = XrefScanner.ExtractTargetAddress(instruction); + var targetAddress = ExtractTargetAddress(instruction); if (targetAddress != 0) yield return (IntPtr)targetAddress; continue; @@ -94,7 +100,20 @@ private static ulong ExtractTargetAddress(in Instruction instruction) case OpKind.FarBranch32: return instruction.FarBranch32; default: - throw new ArgumentOutOfRangeException(); + return 0; } } + + private static unsafe Decoder DecoderForAddress(IntPtr codeStart, int lengthLimit = 1000) + { + if (codeStart == IntPtr.Zero) + throw new NullReferenceException(nameof(codeStart)); + + var stream = new UnmanagedMemoryStream((byte*)codeStart, lengthLimit, lengthLimit, FileAccess.Read); + var codeReader = new StreamCodeReader(stream); + var decoder = Decoder.Create(IntPtr.Size * 8, codeReader); + decoder.IP = (ulong)codeStart; + + return decoder; + } } diff --git a/Il2CppInterop.Runtime/Startup/Il2CppInteropRuntime.cs b/Il2CppInterop.Runtime/Startup/Il2CppInteropRuntime.cs index ad3c415b..bf1167bd 100644 --- a/Il2CppInterop.Runtime/Startup/Il2CppInteropRuntime.cs +++ b/Il2CppInterop.Runtime/Startup/Il2CppInteropRuntime.cs @@ -1,9 +1,7 @@ using AssetRipper.Primitives; using Il2CppInterop.Common.Host; -using Il2CppInterop.Common.XrefScans; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.Runtime; -using Il2CppInterop.Runtime.XrefScans; namespace Il2CppInterop.Runtime.Startup; @@ -27,7 +25,6 @@ public static Il2CppInteropRuntime Create(RuntimeConfiguration configuration) DetourProvider = configuration.DetourProvider }; SetInstance(res); - res.AddXrefScanner(); return res; } diff --git a/Il2CppInterop.Runtime/XrefScans/XrefInstanceExtensions.cs b/Il2CppInterop.Runtime/XrefScans/XrefInstanceExtensions.cs deleted file mode 100644 index 220f026a..00000000 --- a/Il2CppInterop.Runtime/XrefScans/XrefInstanceExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; -using Il2CppInterop.Common.XrefScans; -using Il2CppInterop.Runtime.Runtime; -using IntPtr = System.IntPtr; -using InvalidOperationException = System.InvalidOperationException; - -namespace Il2CppInterop.Runtime.XrefScans; - -public static class XrefInstanceExtensions -{ - public static Object? ReadAsObject(this XrefInstance self) - { - if (self.Type != XrefType.Global) throw new InvalidOperationException("Can't read non-global xref as object"); - - var valueAtPointer = Marshal.ReadIntPtr(self.Pointer); - if (valueAtPointer == IntPtr.Zero) - return null; - - return Il2CppObjectPool.Get(valueAtPointer) as Object; - } - - public static MethodBase? TryResolve(this XrefInstance self) - { - if (self.Type != XrefType.Method) throw new InvalidOperationException("Can't resolve non-method xrefs"); - - return XrefScanMethodDb.TryResolvePointer(self.Pointer); - } -} diff --git a/Il2CppInterop.Runtime/XrefScans/XrefScanImpl.cs b/Il2CppInterop.Runtime/XrefScans/XrefScanImpl.cs deleted file mode 100644 index ce3d37f1..00000000 --- a/Il2CppInterop.Runtime/XrefScans/XrefScanImpl.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Linq; -using System.Runtime.InteropServices; -using Il2CppInterop.Common.XrefScans; -using Il2CppInterop.Runtime.InteropTypes.CoreLib; -using Il2CppSystem; -using Il2CppSystem.Reflection; - -namespace Il2CppInterop.Runtime.XrefScans; - -internal class XrefScanImpl : IXrefScannerImpl -{ - public unsafe (XrefScanUtil.InitMetadataForMethod, nint)? GetMetadataResolver() - { - var unityObjectCctor = AppDomainAccessor.GetAssembliesInCurrentDomain() - .Single(it => it.GetName().Name == "UnityEngine.CoreModule").GetType("UnityEngine.Object") - .GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) - .Single(); - var nativeMethodInfo = IL2CPP.il2cpp_method_get_from_reflection(unityObjectCctor.Pointer); - var ourMetadataInitForMethodPointer = XrefScannerLowLevel.JumpTargets(*(nint*)nativeMethodInfo).First(); - var ourMetadataInitForMethodDelegate = - Marshal.GetDelegateForFunctionPointer(ourMetadataInitForMethodPointer); - return (ourMetadataInitForMethodDelegate, ourMetadataInitForMethodPointer); - } - - public bool XrefGlobalClassFilter(nint movTarget) - { - var valueAtMov = (nint)Marshal.ReadInt64(movTarget); - if (valueAtMov != nint.Zero) - { - var targetClass = (nint)Marshal.ReadInt64(valueAtMov); - return targetClass == Il2CppClassPointerStore.NativeClassPointer || - targetClass == Il2CppClassPointerStore.NativeClassPointer; - } - - return false; - } -} From c4f0db35f09cf8260015c12d99b1fce967237a16 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 21:24:51 -0700 Subject: [PATCH 352/486] Move FieldAccess, Il2CppType, and RuntimeInvoke out of the InteropTypes namespace --- .../ByRefParameterOverloadProcessingLayer.cs | 1 + .../FieldAccessorProcessingLayer.cs | 1 + .../MarshallingProcessingLayer.cs | 1 - .../NativeMethodBodyProcessingLayer.cs | 2 +- .../Il2CppInteropDetour.cs | 1 - .../{InteropTypes => }/FieldAccess.cs | 2 +- .../{InteropTypes => }/Il2CppType.cs | 2 +- .../Injection/TypeInjector.cs | 1 - .../Runtime/Il2CppObjectPool.cs | 1 - .../{InteropTypes => }/RuntimeInvoke.cs | 3 ++- .../Il2CppTypeGenerator.cs | 22 +++++++++---------- 11 files changed, 18 insertions(+), 19 deletions(-) rename Il2CppInterop.Runtime/{InteropTypes => }/FieldAccess.cs (98%) rename Il2CppInterop.Runtime/{InteropTypes => }/Il2CppType.cs (99%) rename Il2CppInterop.Runtime/{InteropTypes => }/RuntimeInvoke.cs (98%) diff --git a/Il2CppInterop.Generator/ByRefParameterOverloadProcessingLayer.cs b/Il2CppInterop.Generator/ByRefParameterOverloadProcessingLayer.cs index 7d5bdef4..9d0b38b5 100644 --- a/Il2CppInterop.Generator/ByRefParameterOverloadProcessingLayer.cs +++ b/Il2CppInterop.Generator/ByRefParameterOverloadProcessingLayer.cs @@ -4,6 +4,7 @@ using Cpp2IL.Core.Model.Contexts; using Il2CppInterop.Generator.Operands; using Il2CppInterop.Generator.Visitors; +using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; namespace Il2CppInterop.Generator; diff --git a/Il2CppInterop.Generator/FieldAccessorProcessingLayer.cs b/Il2CppInterop.Generator/FieldAccessorProcessingLayer.cs index b804e75d..75da569c 100644 --- a/Il2CppInterop.Generator/FieldAccessorProcessingLayer.cs +++ b/Il2CppInterop.Generator/FieldAccessorProcessingLayer.cs @@ -5,6 +5,7 @@ using Cpp2IL.Core.Model.CustomAttributes; using Il2CppInterop.Common.Attributes; using Il2CppInterop.Generator.Operands; +using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; namespace Il2CppInterop.Generator; diff --git a/Il2CppInterop.Generator/MarshallingProcessingLayer.cs b/Il2CppInterop.Generator/MarshallingProcessingLayer.cs index 7c6de3cb..0d0c8c25 100644 --- a/Il2CppInterop.Generator/MarshallingProcessingLayer.cs +++ b/Il2CppInterop.Generator/MarshallingProcessingLayer.cs @@ -5,7 +5,6 @@ using Il2CppInterop.Common; using Il2CppInterop.Generator.Operands; using Il2CppInterop.Runtime; -using Il2CppInterop.Runtime.InteropTypes; namespace Il2CppInterop.Generator; diff --git a/Il2CppInterop.Generator/NativeMethodBodyProcessingLayer.cs b/Il2CppInterop.Generator/NativeMethodBodyProcessingLayer.cs index c20d0053..5eb214fc 100644 --- a/Il2CppInterop.Generator/NativeMethodBodyProcessingLayer.cs +++ b/Il2CppInterop.Generator/NativeMethodBodyProcessingLayer.cs @@ -2,7 +2,7 @@ using Cpp2IL.Core.Api; using Cpp2IL.Core.Model.Contexts; using Il2CppInterop.Generator.Operands; -using Il2CppInterop.Runtime.InteropTypes; +using Il2CppInterop.Runtime; namespace Il2CppInterop.Generator; diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs index dc7a5135..b39b77d4 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs @@ -4,7 +4,6 @@ using Il2CppInterop.Common; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Injection; -using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.Runtime; using Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo; using Microsoft.Extensions.Logging; diff --git a/Il2CppInterop.Runtime/InteropTypes/FieldAccess.cs b/Il2CppInterop.Runtime/FieldAccess.cs similarity index 98% rename from Il2CppInterop.Runtime/InteropTypes/FieldAccess.cs rename to Il2CppInterop.Runtime/FieldAccess.cs index ec5f77dd..da0884d9 100644 --- a/Il2CppInterop.Runtime/InteropTypes/FieldAccess.cs +++ b/Il2CppInterop.Runtime/FieldAccess.cs @@ -2,7 +2,7 @@ using System.Runtime.InteropServices; using Il2CppInterop.Common; -namespace Il2CppInterop.Runtime.InteropTypes; +namespace Il2CppInterop.Runtime; public static unsafe class FieldAccess { diff --git a/Il2CppInterop.Runtime/InteropTypes/Il2CppType.cs b/Il2CppInterop.Runtime/Il2CppType.cs similarity index 99% rename from Il2CppInterop.Runtime/InteropTypes/Il2CppType.cs rename to Il2CppInterop.Runtime/Il2CppType.cs index a3279145..506046da 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Il2CppType.cs +++ b/Il2CppInterop.Runtime/Il2CppType.cs @@ -5,7 +5,7 @@ using Il2CppInterop.Common; using Il2CppInterop.Runtime.Runtime; -namespace Il2CppInterop.Runtime.InteropTypes; +namespace Il2CppInterop.Runtime; public static class Il2CppType { diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index a6596066..94e182c1 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -9,7 +9,6 @@ using System.Runtime.InteropServices; using Il2CppInterop.Common; using Il2CppInterop.Common.Attributes; -using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.Runtime; using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class; using Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo; diff --git a/Il2CppInterop.Runtime/Runtime/Il2CppObjectPool.cs b/Il2CppInterop.Runtime/Runtime/Il2CppObjectPool.cs index 44573352..47a2cc7d 100644 --- a/Il2CppInterop.Runtime/Runtime/Il2CppObjectPool.cs +++ b/Il2CppInterop.Runtime/Runtime/Il2CppObjectPool.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Concurrent; using Il2CppInterop.Common; -using Il2CppInterop.Runtime.InteropTypes; namespace Il2CppInterop.Runtime.Runtime; diff --git a/Il2CppInterop.Runtime/InteropTypes/RuntimeInvoke.cs b/Il2CppInterop.Runtime/RuntimeInvoke.cs similarity index 98% rename from Il2CppInterop.Runtime/InteropTypes/RuntimeInvoke.cs rename to Il2CppInterop.Runtime/RuntimeInvoke.cs index 5dc12249..bcf85939 100644 --- a/Il2CppInterop.Runtime/InteropTypes/RuntimeInvoke.cs +++ b/Il2CppInterop.Runtime/RuntimeInvoke.cs @@ -5,11 +5,12 @@ using System.Runtime.CompilerServices; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Injection; +using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.Runtime; using Microsoft.Extensions.Logging; using Il2CppException = Il2CppInterop.Runtime.Exceptions.Il2CppException; -namespace Il2CppInterop.Runtime.InteropTypes; +namespace Il2CppInterop.Runtime; public static unsafe class RuntimeInvoke { diff --git a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs index bb1ed7aa..1de2328a 100644 --- a/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs +++ b/Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs @@ -183,7 +183,7 @@ private static void EmitValueTypeInstanceInterfaceMembers(IndentedTextWriter wri writer.WriteLine("readonly void global::Il2CppSystem.IValueType.WriteToSpan(global::System.Span span) =>"); writer.Indent++; - writer.WriteLine("global::Il2CppInterop.Runtime.InteropTypes.Il2CppType.WriteToSpan(this, span);"); + writer.WriteLine("global::Il2CppInterop.Runtime.Il2CppType.WriteToSpan(this, span);"); writer.Indent--; } @@ -197,8 +197,8 @@ private static void EmitStaticIl2CppProperty(IndentedTextWriter writer, MemberMo writer.WriteLine($"{accessPrefix}static partial {member.Type} {member.Name}"); writer.WriteLine("{"); writer.Indent++; - writer.WriteLine($"get => global::Il2CppInterop.Runtime.InteropTypes.FieldAccess.GetStaticFieldValue<{member.Type}>(Il2CppInternals.FieldInfoPtr_{member.Index});"); - writer.WriteLine($"set => global::Il2CppInterop.Runtime.InteropTypes.FieldAccess.SetStaticFieldValue(Il2CppInternals.FieldInfoPtr_{member.Index}, value);"); + writer.WriteLine($"get => global::Il2CppInterop.Runtime.FieldAccess.GetStaticFieldValue<{member.Type}>(Il2CppInternals.FieldInfoPtr_{member.Index});"); + writer.WriteLine($"set => global::Il2CppInterop.Runtime.FieldAccess.SetStaticFieldValue(Il2CppInternals.FieldInfoPtr_{member.Index}, value);"); writer.Indent--; writer.WriteLine("}"); } @@ -209,8 +209,8 @@ private static void EmitIl2CppProperty(IndentedTextWriter writer, MemberModel me writer.WriteLine($"{accessPrefix}partial {member.Type} {member.Name}"); writer.WriteLine("{"); writer.Indent++; - writer.WriteLine($"get => global::Il2CppInterop.Runtime.InteropTypes.FieldAccess.GetInstanceFieldValue<{member.Type}>(this, Il2CppInternals.FieldOffset_{member.Index});"); - writer.WriteLine($"set => global::Il2CppInterop.Runtime.InteropTypes.FieldAccess.SetInstanceFieldValue(this, Il2CppInternals.FieldOffset_{member.Index}, value);"); + writer.WriteLine($"get => global::Il2CppInterop.Runtime.FieldAccess.GetInstanceFieldValue<{member.Type}>(this, Il2CppInternals.FieldOffset_{member.Index});"); + writer.WriteLine($"set => global::Il2CppInterop.Runtime.FieldAccess.SetInstanceFieldValue(this, Il2CppInternals.FieldOffset_{member.Index}, value);"); writer.Indent--; writer.WriteLine("}"); } @@ -222,8 +222,8 @@ private static void EmitManagedProperty(IndentedTextWriter writer, MemberModel m writer.WriteLine($"private global::Il2CppSystem.IntPtr {member.Name}__BackingField"); writer.WriteLine("{"); writer.Indent++; - writer.WriteLine($"get => global::Il2CppInterop.Runtime.InteropTypes.FieldAccess.GetInstanceFieldValue(this, Il2CppInternals.FieldOffset_{member.Index});"); - writer.WriteLine($"set => global::Il2CppInterop.Runtime.InteropTypes.FieldAccess.SetInstanceFieldValue(this, Il2CppInternals.FieldOffset_{member.Index}, value);"); + writer.WriteLine($"get => global::Il2CppInterop.Runtime.FieldAccess.GetInstanceFieldValue(this, Il2CppInternals.FieldOffset_{member.Index});"); + writer.WriteLine($"set => global::Il2CppInterop.Runtime.FieldAccess.SetInstanceFieldValue(this, Il2CppInternals.FieldOffset_{member.Index}, value);"); writer.Indent--; writer.WriteLine("}"); @@ -329,7 +329,7 @@ private static void EmitStaticInterfaceMembers(IndentedTextWriter writer, TypeMo writer.WriteLine("{"); writer.Indent++; foreach (var member in model.Members.Where(x => !x.IsStatic)) - writer.WriteLine($"{member.Name} = global::Il2CppInterop.Runtime.InteropTypes.Il2CppType.ReadFromSpanAtOffset<{member.Type}>(span, Il2CppInternals.FieldOffset_{member.Index}),"); + writer.WriteLine($"{member.Name} = global::Il2CppInterop.Runtime.Il2CppType.ReadFromSpanAtOffset<{member.Type}>(span, Il2CppInternals.FieldOffset_{member.Index}),"); writer.Indent--; writer.WriteLine("};"); writer.WriteLine("#nullable restore"); @@ -342,7 +342,7 @@ private static void EmitStaticInterfaceMembers(IndentedTextWriter writer, TypeMo writer.WriteLine("{"); writer.Indent++; foreach (var member in model.Members.Where(x => !x.IsStatic)) - writer.WriteLine($"global::Il2CppInterop.Runtime.InteropTypes.Il2CppType.WriteToSpanAtOffset(value.{member.Name}, span, Il2CppInternals.FieldOffset_{member.Index});"); + writer.WriteLine($"global::Il2CppInterop.Runtime.Il2CppType.WriteToSpanAtOffset(value.{member.Name}, span, Il2CppInternals.FieldOffset_{member.Index});"); writer.Indent--; writer.WriteLine("}"); writer.WriteLineNoTabs(); @@ -358,7 +358,7 @@ private static void EmitStaticInterfaceMembers(IndentedTextWriter writer, TypeMo writer.WriteLine($"static {tn}? global::Il2CppInterop.Common.IIl2CppType<{tn}>.ReadFromSpan(global::System.ReadOnlySpan span)"); writer.WriteLine("{"); writer.Indent++; - writer.WriteLine($"return global::Il2CppInterop.Runtime.InteropTypes.Il2CppType.ReadReference<{tn}>(span);"); + writer.WriteLine($"return global::Il2CppInterop.Runtime.Il2CppType.ReadReference<{tn}>(span);"); writer.Indent--; writer.WriteLine("}"); writer.WriteLineNoTabs(); @@ -366,7 +366,7 @@ private static void EmitStaticInterfaceMembers(IndentedTextWriter writer, TypeMo writer.WriteLine($"static void global::Il2CppInterop.Common.IIl2CppType<{tn}>.WriteToSpan({tn}? value, global::System.Span span)"); writer.WriteLine("{"); writer.Indent++; - writer.WriteLine("global::Il2CppInterop.Runtime.InteropTypes.Il2CppType.WriteReference(value, span);"); + writer.WriteLine("global::Il2CppInterop.Runtime.Il2CppType.WriteReference(value, span);"); writer.Indent--; writer.WriteLine("}"); writer.WriteLineNoTabs(); From 91cc0e4e89a89b9ba5a69a1a9e65731e431acd79 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 21:33:54 -0700 Subject: [PATCH 353/486] Remove NativeStructUtils from public API --- Il2CppInterop.Runtime/IL2CPP.cs | 18 ++++++++++++------ .../{NativeStructUtils.cs => INativeStruct.cs} | 17 +++++------------ .../Runtime/INativeStructHandler.cs | 6 ++++++ .../Runtime/StructHandlerInterfaces.cs | 13 ------------- 4 files changed, 23 insertions(+), 31 deletions(-) rename Il2CppInterop.Runtime/Runtime/{NativeStructUtils.cs => INativeStruct.cs} (68%) create mode 100644 Il2CppInterop.Runtime/Runtime/INativeStructHandler.cs delete mode 100644 Il2CppInterop.Runtime/Runtime/StructHandlerInterfaces.cs diff --git a/Il2CppInterop.Runtime/IL2CPP.cs b/Il2CppInterop.Runtime/IL2CPP.cs index cd411e74..c5842135 100644 --- a/Il2CppInterop.Runtime/IL2CPP.cs +++ b/Il2CppInterop.Runtime/IL2CPP.cs @@ -52,7 +52,7 @@ public static int GetIl2cppValueSize(nint klass) public static nint GetIl2CppMethodByToken(nint clazz, int token) { if (clazz == nint.Zero) - return NativeStructUtils.GetMethodInfoForMissingMethod(token.ToString()); + return GetMethodInfoForMissingMethod(token.ToString()); var iter = nint.Zero; nint method; @@ -63,15 +63,14 @@ public static nint GetIl2CppMethodByToken(nint clazz, int token) var className = il2cpp_class_get_name(clazz); Logger.Instance.LogTrace("Unable to find method {ClassName}::{Token}", className, token); - return NativeStructUtils.GetMethodInfoForMissingMethod(className + "::" + token); + return GetMethodInfoForMissingMethod($"{className}::{token}"); } public static nint GetIl2CppMethod(nint clazz, bool isGeneric, string methodName, string returnTypeName, params string[] argTypes) { if (clazz == nint.Zero) - return NativeStructUtils.GetMethodInfoForMissingMethod(methodName + "(" + string.Join(", ", argTypes) + - ")"); + return GetMethodInfoForMissingMethod($"{methodName}({string.Join(", ", argTypes)})"); returnTypeName = Regex.Replace(returnTypeName, "\\`\\d+", "").Replace('/', '.').Replace('+', '.'); for (var index = 0; index < argTypes.Length; index++) @@ -164,8 +163,7 @@ public static nint GetIl2CppMethod(nint clazz, bool isGeneric, string methodName return method; } - return NativeStructUtils.GetMethodInfoForMissingMethod(className + "::" + methodName + "(" + - string.Join(", ", argTypes) + ")"); + return GetMethodInfoForMissingMethod($"{className}::{methodName}({string.Join(", ", argTypes)})"); } public static nint GetIl2CppGenericInstanceMethod(nint methodInfoPointer, nint declaringTypeClassPointer, params nint[] genericMethodArguments) @@ -232,6 +230,14 @@ static IntPtr GetNestedTypeViaReflection(nint enclosingClass, string nestedTypeN } } + private static IntPtr GetMethodInfoForMissingMethod(string methodName) + { + var methodInfo = UnityVersionHandler.NewMethod(); + methodInfo.Name = Marshal.StringToCoTaskMemUTF8(methodName); + methodInfo.Slot = ushort.MaxValue; + return methodInfo.Pointer; + } + // IL2CPP Functions [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] diff --git a/Il2CppInterop.Runtime/Runtime/NativeStructUtils.cs b/Il2CppInterop.Runtime/Runtime/INativeStruct.cs similarity index 68% rename from Il2CppInterop.Runtime/Runtime/NativeStructUtils.cs rename to Il2CppInterop.Runtime/Runtime/INativeStruct.cs index 26fefde5..c55e8059 100644 --- a/Il2CppInterop.Runtime/Runtime/NativeStructUtils.cs +++ b/Il2CppInterop.Runtime/Runtime/INativeStruct.cs @@ -1,18 +1,11 @@ -using System; -using System.Runtime.InteropServices; - namespace Il2CppInterop.Runtime.Runtime; -public static class NativeStructUtils +public interface INativeStruct +{ + nint Pointer { get; } +} +internal static class INativeStructExtensions { - public static IntPtr GetMethodInfoForMissingMethod(string methodName) - { - var methodInfo = UnityVersionHandler.NewMethod(); - methodInfo.Name = Marshal.StringToCoTaskMemUTF8(methodName); - methodInfo.Slot = ushort.MaxValue; - return methodInfo.Pointer; - } - public static unsafe bool CheckBit(this INativeStruct self, int startOffset, int bit) { var byteOffset = bit / 8; diff --git a/Il2CppInterop.Runtime/Runtime/INativeStructHandler.cs b/Il2CppInterop.Runtime/Runtime/INativeStructHandler.cs new file mode 100644 index 00000000..bb32ce3a --- /dev/null +++ b/Il2CppInterop.Runtime/Runtime/INativeStructHandler.cs @@ -0,0 +1,6 @@ +namespace Il2CppInterop.Runtime.Runtime; + +public interface INativeStructHandler +{ + public int Size(); +} diff --git a/Il2CppInterop.Runtime/Runtime/StructHandlerInterfaces.cs b/Il2CppInterop.Runtime/Runtime/StructHandlerInterfaces.cs deleted file mode 100644 index 2a079019..00000000 --- a/Il2CppInterop.Runtime/Runtime/StructHandlerInterfaces.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace Il2CppInterop.Runtime.Runtime; - -public interface INativeStructHandler -{ - public int Size(); -} - -public interface INativeStruct -{ - IntPtr Pointer { get; } -} From 81d8fea00b3a3f514b46ef4bf7b5fc518cbe4936 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 21:34:43 -0700 Subject: [PATCH 354/486] Move Il2CppToMonoDelegateReference to InteropTypes namespace --- .../{ => InteropTypes}/Il2CppToMonoDelegateReference.cs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Il2CppInterop.Runtime/{ => InteropTypes}/Il2CppToMonoDelegateReference.cs (100%) diff --git a/Il2CppInterop.Runtime/Il2CppToMonoDelegateReference.cs b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs similarity index 100% rename from Il2CppInterop.Runtime/Il2CppToMonoDelegateReference.cs rename to Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs From 5bb03ac7ebdeb3031411f5076c5386a1d9766f50 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 21:36:23 -0700 Subject: [PATCH 355/486] Fix namespace not getting changed --- Il2CppInterop.Runtime/DelegateSupport.cs | 1 + .../InteropTypes/Il2CppToMonoDelegateReference.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index 4c689bcc..185f4d20 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -7,6 +7,7 @@ using System.Text; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Injection; +using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.CoreLib; using Il2CppInterop.Runtime.Runtime; using Microsoft.Extensions.Logging; diff --git a/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs index 47f58a93..5395d4e1 100644 --- a/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs +++ b/Il2CppInterop.Runtime/InteropTypes/Il2CppToMonoDelegateReference.cs @@ -4,7 +4,7 @@ using Il2CppInterop.Common.Attributes; using Microsoft.Extensions.Logging; -namespace Il2CppInterop.Runtime; +namespace Il2CppInterop.Runtime.InteropTypes; [InjectedType(Assembly = "Assembly-CSharp.dll")] internal sealed partial class Il2CppToMonoDelegateReference : Object From 9d817183c40bda07ddb70839237597f5761a9a98 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 21:44:54 -0700 Subject: [PATCH 356/486] Minor cleanup to types in the injection namespace --- .../Injection/{DetourProvider.cs => Detour.cs} | 7 ------- .../Injection/Hooks/Class_FromName_Hook.cs | 4 ++-- Il2CppInterop.Runtime/Injection/IDetourProvider.cs | 8 ++++++++ Il2CppInterop.Runtime/Injection/InjectorHelpers.cs | 2 +- Il2CppInterop.Runtime/Injection/MemoryUtils.cs | 2 +- 5 files changed, 12 insertions(+), 11 deletions(-) rename Il2CppInterop.Runtime/Injection/{DetourProvider.cs => Detour.cs} (68%) create mode 100644 Il2CppInterop.Runtime/Injection/IDetourProvider.cs diff --git a/Il2CppInterop.Runtime/Injection/DetourProvider.cs b/Il2CppInterop.Runtime/Injection/Detour.cs similarity index 68% rename from Il2CppInterop.Runtime/Injection/DetourProvider.cs rename to Il2CppInterop.Runtime/Injection/Detour.cs index 3b6b626a..0b8592e7 100644 --- a/Il2CppInterop.Runtime/Injection/DetourProvider.cs +++ b/Il2CppInterop.Runtime/Injection/Detour.cs @@ -3,17 +3,10 @@ namespace Il2CppInterop.Runtime.Injection; - -public interface IDetourProvider -{ - IDisposable Create(nint original, TDelegate target, out TDelegate trampoline) where TDelegate : Delegate; -} - internal static class Detour { public static IDisposable Apply(nint original, T target, out T trampoline) where T : Delegate { return Il2CppInteropRuntime.Instance.DetourProvider.Create(original, target, out trampoline); - } } diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs index cfaf6a2a..a4902862 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs @@ -21,8 +21,8 @@ internal unsafe class Class_FromName_Hook : Hook(nint original, TDelegate target, out TDelegate trampoline) where TDelegate : Delegate; +} diff --git a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs index 81d256e4..7ef20413 100644 --- a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs +++ b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs @@ -64,7 +64,7 @@ internal static bool TryGetIl2CppExport(string name, out IntPtr address) return NativeLibrary.TryGetExport(Il2CppHandle, name, out address); } - internal static IntPtr GetIl2CppMethodPointer(MethodBase proxyMethod) + internal static IntPtr GetIl2CppMethodPointer(MethodBase? proxyMethod) { if (proxyMethod == null) return IntPtr.Zero; diff --git a/Il2CppInterop.Runtime/Injection/MemoryUtils.cs b/Il2CppInterop.Runtime/Injection/MemoryUtils.cs index 386eb4a3..c7d4d9eb 100644 --- a/Il2CppInterop.Runtime/Injection/MemoryUtils.cs +++ b/Il2CppInterop.Runtime/Injection/MemoryUtils.cs @@ -7,7 +7,7 @@ namespace Il2CppInterop.Runtime.Injection; -internal class MemoryUtils +internal static class MemoryUtils { public static unsafe nint FindSignatureInModule(ProcessModule module, SignatureDefinition sigDef) { From 0b4fda7782dc2bdf5e38df93503c8f1709741da6 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 21:49:30 -0700 Subject: [PATCH 357/486] Change MemoryUtils to SignatureDefinition --- .../Hooks/Class_GetFieldDefaultValue_Hook.cs | 16 ++++++++-------- .../Injection/InjectorHelpers.cs | 8 ++++---- .../{MemoryUtils.cs => SignatureDefinition.cs} | 15 ++++++--------- 3 files changed, 18 insertions(+), 21 deletions(-) rename Il2CppInterop.Runtime/Injection/{MemoryUtils.cs => SignatureDefinition.cs} (95%) diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs index 1624a6b2..4ac72163 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs @@ -32,17 +32,17 @@ internal unsafe class Class_GetFieldDefaultValue_Hook : Hook MemoryUtils.FindSignatureInModule(InjectorHelpers.Il2CppModule, s)) + .Select(s => SignatureDefinition.FindSignatureInModule(InjectorHelpers.Il2CppModule, s)) .FirstOrDefault(p => p != 0); if (classGetDefaultFieldValue == 0) diff --git a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs index 7ef20413..c3cebdca 100644 --- a/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs +++ b/Il2CppInterop.Runtime/Injection/InjectorHelpers.cs @@ -91,15 +91,15 @@ internal static IntPtr GetIl2CppMethodPointer(MethodBase? proxyMethod) internal delegate void d_ClassInit(Il2CppClass* klass); internal static d_ClassInit ClassInit; - private static readonly MemoryUtils.SignatureDefinition[] s_ClassInitSignatures = + private static readonly SignatureDefinition[] s_ClassInitSignatures = { - new MemoryUtils.SignatureDefinition + new SignatureDefinition { pattern = "\xE8\x00\x00\x00\x00\x0F\xB7\x47\x28\x83", mask = "x????xxxxx", xref = true }, - new MemoryUtils.SignatureDefinition + new SignatureDefinition { pattern = "\xE8\x00\x00\x00\x00\x0F\xB7\x47\x48\x48", mask = "x????xxxxx", @@ -131,7 +131,7 @@ static nint GetClassInitSubstitute() throw new NotSupportedException("Failed to use signature for Class::Init and a substitute cannot be found, please create an issue and report your unity version & game"); } nint pClassInit = s_ClassInitSignatures - .Select(s => MemoryUtils.FindSignatureInModule(Il2CppModule, s)) + .Select(s => SignatureDefinition.FindSignatureInModule(Il2CppModule, s)) .FirstOrDefault(p => p != 0); if (pClassInit == 0) diff --git a/Il2CppInterop.Runtime/Injection/MemoryUtils.cs b/Il2CppInterop.Runtime/Injection/SignatureDefinition.cs similarity index 95% rename from Il2CppInterop.Runtime/Injection/MemoryUtils.cs rename to Il2CppInterop.Runtime/Injection/SignatureDefinition.cs index c7d4d9eb..fb9b5378 100644 --- a/Il2CppInterop.Runtime/Injection/MemoryUtils.cs +++ b/Il2CppInterop.Runtime/Injection/SignatureDefinition.cs @@ -7,8 +7,13 @@ namespace Il2CppInterop.Runtime.Injection; -internal static class MemoryUtils +internal struct SignatureDefinition { + public string pattern; + public string mask; + public int offset; + public bool xref; + public static unsafe nint FindSignatureInModule(ProcessModule module, SignatureDefinition sigDef) { // On newer Unity (6000.x) the loaded GameAssembly maps some pages PAGE_NOACCESS / guard pages; the raw @@ -98,12 +103,4 @@ internal static unsafe List GetModuleRegions(ProcessMo return regions; } - - public struct SignatureDefinition - { - public string pattern; - public string mask; - public int offset; - public bool xref; - } } From 1cada8670c54ecb1851b502136d756d24fd50b35 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 21:53:10 -0700 Subject: [PATCH 358/486] XrefScannerLowLevel -> XrefScanner --- .../Hooks/Class_FromIl2CppType_Hook.cs | 2 +- .../Injection/Hooks/Class_FromName_Hook.cs | 2 +- .../Hooks/Class_GetFieldDefaultValue_Hook.cs | 14 ++++---- ...GetTypeInfoFromTypeDefinitionIndex_Hook.cs | 20 +++++------ .../Injection/SignatureDefinition.cs | 2 +- ...{XrefScannerLowLevel.cs => XrefScanner.cs} | 35 +++++++------------ 6 files changed, 33 insertions(+), 42 deletions(-) rename Il2CppInterop.Runtime/Injection/{XrefScannerLowLevel.cs => XrefScanner.cs} (83%) diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs index f093f82f..31a6ece0 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromIl2CppType_Hook.cs @@ -43,7 +43,7 @@ public override IntPtr FindTargetMethod() var classFromTypeAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_class_from_il2cpp_type)); Logger.Instance.LogTrace("il2cpp_class_from_il2cpp_type: 0x{ClassFromTypeApiAddress}", classFromTypeAPI.ToInt64().ToString("X2")); - return XrefScannerLowLevel.JumpTargets(classFromTypeAPI).Single(); + return XrefScanner.JumpTargets(classFromTypeAPI).Single(); } } } diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs index a4902862..cbe9c8a7 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_FromName_Hook.cs @@ -35,7 +35,7 @@ public override IntPtr FindTargetMethod() var classFromNameAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_class_from_name)); Logger.Instance.LogTrace("il2cpp_class_from_name: 0x{ClassFromNameApiAddress}", classFromNameAPI.ToInt64().ToString("X2")); - return XrefScannerLowLevel.JumpTargets(classFromNameAPI).Single(); + return XrefScanner.JumpTargets(classFromNameAPI).Single(); } } } diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs index 4ac72163..97f086c0 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs @@ -93,27 +93,27 @@ private static nint FindClassGetFieldDefaultValueXref(bool forceICallMethod = fa var monoFieldGetValueInternalThunk = InjectorHelpers.GetIl2CppMethodPointer(monoFieldType.GetMethod(nameof(Il2CppSystem.Reflection.MonoField.GetValueInternal))); Logger.Instance.LogTrace("Il2CppSystem.Reflection.MonoField::thunk_GetValueInternal: 0x{MonoFieldGetValueInternalThunkAddress}", monoFieldGetValueInternalThunk.ToInt64().ToString("X2")); - var monoFieldGetValueInternal = XrefScannerLowLevel.JumpTargets(monoFieldGetValueInternalThunk).Single(); + var monoFieldGetValueInternal = XrefScanner.JumpTargets(monoFieldGetValueInternalThunk).Single(); Logger.Instance.LogTrace("Il2CppSystem.Reflection.MonoField::GetValueInternal: 0x{MonoFieldGetValueInternalAddress}", monoFieldGetValueInternal.ToInt64().ToString("X2")); // Field::GetValueObject could be inlined with Field::GetValueObjectForThread - var fieldGetValueObject = XrefScannerLowLevel.JumpTargets(monoFieldGetValueInternal).Single(); + var fieldGetValueObject = XrefScanner.JumpTargets(monoFieldGetValueInternal).Single(); Logger.Instance.LogTrace("Field::GetValueObject: 0x{FieldGetValueObjectAddress}", fieldGetValueObject.ToInt64().ToString("X2")); - var fieldGetValueObjectForThread = XrefScannerLowLevel.JumpTargets(fieldGetValueObject).Last(); + var fieldGetValueObjectForThread = XrefScanner.JumpTargets(fieldGetValueObject).Last(); Logger.Instance.LogTrace("Field::GetValueObjectForThread: 0x{FieldGetValueObjectForThreadAddress}", fieldGetValueObjectForThread.ToInt64().ToString("X2")); - classGetDefaultFieldValue = XrefScannerLowLevel.JumpTargets(fieldGetValueObjectForThread).ElementAt(2); + classGetDefaultFieldValue = XrefScanner.JumpTargets(fieldGetValueObjectForThread).ElementAt(2); } else { var getStaticFieldValueAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_field_static_get_value)); Logger.Instance.LogTrace("il2cpp_field_static_get_value: 0x{GetStaticFieldValueApiAddress}", getStaticFieldValueAPI.ToInt64().ToString("X2")); - var getStaticFieldValue = XrefScannerLowLevel.JumpTargets(getStaticFieldValueAPI).Single(); + var getStaticFieldValue = XrefScanner.JumpTargets(getStaticFieldValueAPI).Single(); Logger.Instance.LogTrace("Field::StaticGetValue: 0x{GetStaticFieldValueAddress}", getStaticFieldValue.ToInt64().ToString("X2")); - var getStaticFieldValueTargets = XrefScannerLowLevel.JumpTargets(getStaticFieldValue).ToList(); + var getStaticFieldValueTargets = XrefScanner.JumpTargets(getStaticFieldValue).ToList(); // Sometimes the compiler can do an optimization and omit 'retn' instruction, // which then causes code following to grab wrong function pointer. A correct match should not contain more than 4 jumps @@ -125,7 +125,7 @@ private static nint FindClassGetFieldDefaultValueXref(bool forceICallMethod = fa var getStaticFieldValueInternal = getStaticFieldValueTargets[^1]; Logger.Instance.LogTrace("Field::StaticGetValueInternal: 0x{GetStaticFieldValueInternalAddress}", getStaticFieldValueInternal.ToInt64().ToString("X2")); - var getStaticFieldValueInternalTargets = XrefScannerLowLevel.JumpTargets(getStaticFieldValueInternal).ToArray(); + var getStaticFieldValueInternalTargets = XrefScanner.JumpTargets(getStaticFieldValueInternal).ToArray(); if (getStaticFieldValueInternalTargets.Length == 0) return FindClassGetFieldDefaultValueXref(true); diff --git a/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs index 8555c81a..4a03efcf 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/MetadataCache_GetTypeInfoFromTypeDefinitionIndex_Hook.cs @@ -40,30 +40,30 @@ private IntPtr FindGetTypeInfoFromTypeDefinitionIndex(bool forceICallMethod = fa ); Logger.Instance.LogTrace("Il2CppSystem.Runtime.CompilerServices.RuntimeHelpers::InitializeArray: 0x{RuntimeHelpersInitializeArrayAddress}", runtimeHelpersInitializeArray.ToInt64().ToString("X2")); - var runtimeHelpersInitializeArrayICall = XrefScannerLowLevel.JumpTargets(runtimeHelpersInitializeArray).Last(); - if (XrefScannerLowLevel.JumpTargets(runtimeHelpersInitializeArrayICall).Count() == 1) + var runtimeHelpersInitializeArrayICall = XrefScanner.JumpTargets(runtimeHelpersInitializeArray).Last(); + if (XrefScanner.JumpTargets(runtimeHelpersInitializeArrayICall).Count() == 1) { // is a thunk function Logger.Instance.LogTrace("RuntimeHelpers::thunk_InitializeArray: 0x{RuntimeHelpersInitializeArrayICallAddress}", runtimeHelpersInitializeArrayICall.ToInt64().ToString("X2")); - runtimeHelpersInitializeArrayICall = XrefScannerLowLevel.JumpTargets(runtimeHelpersInitializeArrayICall).Single(); + runtimeHelpersInitializeArrayICall = XrefScanner.JumpTargets(runtimeHelpersInitializeArrayICall).Single(); } Logger.Instance.LogTrace("RuntimeHelpers::InitializeArray: 0x{RuntimeHelpersInitializeArrayICallAddress}", runtimeHelpersInitializeArrayICall.ToInt64().ToString("X2")); - var typeGetUnderlyingType = XrefScannerLowLevel.JumpTargets(runtimeHelpersInitializeArrayICall).ElementAt(1); + var typeGetUnderlyingType = XrefScanner.JumpTargets(runtimeHelpersInitializeArrayICall).ElementAt(1); Logger.Instance.LogTrace("Type::GetUnderlyingType: 0x{TypeGetUnderlyingTypeAddress}", typeGetUnderlyingType.ToInt64().ToString("X2")); - getTypeInfoFromTypeDefinitionIndex = XrefScannerLowLevel.JumpTargets(typeGetUnderlyingType).First(); + getTypeInfoFromTypeDefinitionIndex = XrefScanner.JumpTargets(typeGetUnderlyingType).First(); } else { var imageGetClassAPI = InjectorHelpers.GetIl2CppExport(nameof(IL2CPP.il2cpp_image_get_class)); Logger.Instance.LogTrace("il2cpp_image_get_class: 0x{ImageGetClassApiAddress}", imageGetClassAPI.ToInt64().ToString("X2")); - var imageGetType = XrefScannerLowLevel.JumpTargets(imageGetClassAPI).First(); + var imageGetType = XrefScanner.JumpTargets(imageGetClassAPI).First(); Logger.Instance.LogTrace("Image::GetType: 0x{ImageGetTypeAddress}", imageGetType.ToInt64().ToString("X2")); - var imageGetTypeXrefs = XrefScannerLowLevel.JumpTargets(imageGetType).ToArray(); + var imageGetTypeXrefs = XrefScanner.JumpTargets(imageGetType).ToArray(); if (imageGetTypeXrefs.Length == 0) { @@ -89,7 +89,7 @@ private IntPtr FindGetTypeInfoFromTypeDefinitionIndex(bool forceICallMethod = fa Logger.Instance.LogTrace($"getTypeInfoFromHandle: {getTypeInfoFromHandle:X2}"); - var getTypeInfoFromHandleXrefs = XrefScannerLowLevel.JumpTargets(getTypeInfoFromHandle).ToArray(); + var getTypeInfoFromHandleXrefs = XrefScanner.JumpTargets(getTypeInfoFromHandle).ToArray(); // If getTypeInfoFromHandle xrefs is not a single call, it's the function we want, if not, we keep xrefing until we find it if (getTypeInfoFromHandleXrefs.Length != 1) @@ -102,9 +102,9 @@ private IntPtr FindGetTypeInfoFromTypeDefinitionIndex(bool forceICallMethod = fa // Two calls, second one (GetIndexForTypeDefinitionInternal) is inlined getTypeInfoFromTypeDefinitionIndex = getTypeInfoFromHandleXrefs.Single(); // Xref scanner is sometimes confused about getTypeInfoFromHandle so we walk all the thunks until we hit the big method we need - while (XrefScannerLowLevel.JumpTargets(getTypeInfoFromTypeDefinitionIndex).ToArray().Length == 1) + while (XrefScanner.JumpTargets(getTypeInfoFromTypeDefinitionIndex).ToArray().Length == 1) { - getTypeInfoFromTypeDefinitionIndex = XrefScannerLowLevel.JumpTargets(getTypeInfoFromTypeDefinitionIndex).Single(); + getTypeInfoFromTypeDefinitionIndex = XrefScanner.JumpTargets(getTypeInfoFromTypeDefinitionIndex).Single(); } } } diff --git a/Il2CppInterop.Runtime/Injection/SignatureDefinition.cs b/Il2CppInterop.Runtime/Injection/SignatureDefinition.cs index fb9b5378..5c4a384d 100644 --- a/Il2CppInterop.Runtime/Injection/SignatureDefinition.cs +++ b/Il2CppInterop.Runtime/Injection/SignatureDefinition.cs @@ -47,7 +47,7 @@ public static unsafe nint FindSignatureInModule(ProcessModule module, SignatureD } if (ptr != 0 && sigDef.xref) - ptr = XrefScannerLowLevel.JumpTargets(ptr).FirstOrDefault(); + ptr = XrefScanner.JumpTargets(ptr).FirstOrDefault(); return ptr; } diff --git a/Il2CppInterop.Runtime/Injection/XrefScannerLowLevel.cs b/Il2CppInterop.Runtime/Injection/XrefScanner.cs similarity index 83% rename from Il2CppInterop.Runtime/Injection/XrefScannerLowLevel.cs rename to Il2CppInterop.Runtime/Injection/XrefScanner.cs index 88203cdf..cd2cb1aa 100644 --- a/Il2CppInterop.Runtime/Injection/XrefScannerLowLevel.cs +++ b/Il2CppInterop.Runtime/Injection/XrefScanner.cs @@ -5,14 +5,14 @@ namespace Il2CppInterop.Runtime.Injection; -internal static class XrefScannerLowLevel +internal static class XrefScanner { - public static IEnumerable JumpTargets(IntPtr codeStart, bool ignoreRetn = false) + public static IEnumerable JumpTargets(IntPtr codeStart, bool ignoreReturn = false) { - return JumpTargetsImpl(DecoderForAddress(codeStart), ignoreRetn); + return JumpTargetsImpl(DecoderForAddress(codeStart), ignoreReturn); } - private static IEnumerable JumpTargetsImpl(Decoder myDecoder, bool ignoreRetn) + private static IEnumerable JumpTargetsImpl(Decoder myDecoder, bool ignoreReturn) { var firstFlowControl = true; @@ -25,7 +25,7 @@ private static IEnumerable JumpTargetsImpl(Decoder myDecoder, bool ignor if (instruction.Mnemonic == Mnemonic.Int3) yield break; - if (instruction.FlowControl == FlowControl.Return && !ignoreRetn) + if (instruction.FlowControl == FlowControl.Return && !ignoreReturn) yield break; if (instruction.FlowControl == FlowControl.UnconditionalBranch || @@ -85,24 +85,15 @@ private static IEnumerable CallAndIndirectTargetsImpl(Decoder decoder) } } - private static ulong ExtractTargetAddress(in Instruction instruction) + private static ulong ExtractTargetAddress(in Instruction instruction) => instruction.Op0Kind switch { - switch (instruction.Op0Kind) - { - case OpKind.NearBranch16: - return instruction.NearBranch16; - case OpKind.NearBranch32: - return instruction.NearBranch32; - case OpKind.NearBranch64: - return instruction.NearBranch64; - case OpKind.FarBranch16: - return instruction.FarBranch16; - case OpKind.FarBranch32: - return instruction.FarBranch32; - default: - return 0; - } - } + OpKind.NearBranch16 => instruction.NearBranch16, + OpKind.NearBranch32 => instruction.NearBranch32, + OpKind.NearBranch64 => instruction.NearBranch64, + OpKind.FarBranch16 => instruction.FarBranch16, + OpKind.FarBranch32 => instruction.FarBranch32, + _ => 0, + }; private static unsafe Decoder DecoderForAddress(IntPtr codeStart, int lengthLimit = 1000) { From 33591ef02a9e34c4bb32503802942cc643303826 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 22:06:51 -0700 Subject: [PATCH 359/486] Delete Il2CppInterop.Runtime.InteropTypes.CoreLib namespace --- Il2CppInterop.Runtime/DelegateSupport.cs | 13 ++++++++++- .../InteropTypes/CoreLib/AppDomainAccessor.cs | 22 ------------------- .../CoreLib/MethodBaseAccessor.cs | 18 --------------- .../InteropTypes/CoreLib/TypeAccessor.cs | 19 ---------------- 4 files changed, 12 insertions(+), 60 deletions(-) delete mode 100644 Il2CppInterop.Runtime/InteropTypes/CoreLib/AppDomainAccessor.cs delete mode 100644 Il2CppInterop.Runtime/InteropTypes/CoreLib/MethodBaseAccessor.cs delete mode 100644 Il2CppInterop.Runtime/InteropTypes/CoreLib/TypeAccessor.cs diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index 185f4d20..e50fc307 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -1,14 +1,16 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; -using Il2CppInterop.Runtime.InteropTypes.CoreLib; +using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppInterop.Runtime.Runtime; using Microsoft.Extensions.Logging; @@ -247,6 +249,15 @@ private static unsafe TNative ConvertReturnValue(TManaged? va return converted; } + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "GetParameters")] + [return: UnsafeAccessorType($"Il2CppInterop.Runtime.InteropTypes.Arrays.{nameof(Il2CppArrayRank1<>)}`1[[Il2CppSystem.Reflection.ParameterInfo, Il2Cppmscorlib]]")] + private static extern object GetParametersInternal(Il2CppSystem.Reflection.MethodBase method); + + private static IReadOnlyList GetParameters(this Il2CppSystem.Reflection.MethodBase method) + { + return (IReadOnlyList)GetParametersInternal(method); + } + internal sealed class MethodSignature : IEquatable { public readonly bool ConstructedFromNative; diff --git a/Il2CppInterop.Runtime/InteropTypes/CoreLib/AppDomainAccessor.cs b/Il2CppInterop.Runtime/InteropTypes/CoreLib/AppDomainAccessor.cs deleted file mode 100644 index 08c065e6..00000000 --- a/Il2CppInterop.Runtime/InteropTypes/CoreLib/AppDomainAccessor.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using Il2CppInterop.Runtime.InteropTypes.Arrays; -using Il2CppSystem.Reflection; - -namespace Il2CppInterop.Runtime.InteropTypes.CoreLib; - -internal static class AppDomainAccessor -{ - [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "GetAssemblies")] - [return: UnsafeAccessorType($"Il2CppInterop.Runtime.InteropTypes.Arrays.{nameof(Il2CppArrayRank1<>)}`1[[Il2CppSystem.Reflection.Assembly, Il2Cppmscorlib]]")] - public static extern object GetAssemblies([UnsafeAccessorType("Il2CppSystem.AppDomain, Il2Cppmscorlib")] object appDomain); - - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "get_CurrentDomain")] - [return: UnsafeAccessorType("Il2CppSystem.AppDomain, Il2Cppmscorlib")] - public static extern object GetCurrentDomain([UnsafeAccessorType("Il2CppSystem.AppDomain, Il2Cppmscorlib")] object? declaringType = null); - - public static IReadOnlyList GetAssembliesInCurrentDomain() - { - return (IReadOnlyList)GetAssemblies(GetCurrentDomain()); - } -} diff --git a/Il2CppInterop.Runtime/InteropTypes/CoreLib/MethodBaseAccessor.cs b/Il2CppInterop.Runtime/InteropTypes/CoreLib/MethodBaseAccessor.cs deleted file mode 100644 index 8905b9f5..00000000 --- a/Il2CppInterop.Runtime/InteropTypes/CoreLib/MethodBaseAccessor.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using Il2CppInterop.Runtime.InteropTypes.Arrays; -using Il2CppSystem.Reflection; - -namespace Il2CppInterop.Runtime.InteropTypes.CoreLib; - -internal static class MethodBaseAccessor -{ - [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "GetParameters")] - [return: UnsafeAccessorType($"Il2CppInterop.Runtime.InteropTypes.Arrays.{nameof(Il2CppArrayRank1<>)}`1[[Il2CppSystem.Reflection.ParameterInfo, Il2Cppmscorlib]]")] - private static extern object GetParametersInternal(MethodBase method); - - public static IReadOnlyList GetParameters(this MethodBase method) - { - return (IReadOnlyList)GetParametersInternal(method); - } -} diff --git a/Il2CppInterop.Runtime/InteropTypes/CoreLib/TypeAccessor.cs b/Il2CppInterop.Runtime/InteropTypes/CoreLib/TypeAccessor.cs deleted file mode 100644 index f0dc66ce..00000000 --- a/Il2CppInterop.Runtime/InteropTypes/CoreLib/TypeAccessor.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using Il2CppInterop.Runtime.InteropTypes.Arrays; -using Il2CppSystem; -using Il2CppSystem.Reflection; - -namespace Il2CppInterop.Runtime.InteropTypes.CoreLib; - -internal static class TypeAccessor -{ - [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "GetConstructors")] - [return: UnsafeAccessorType($"Il2CppInterop.Runtime.InteropTypes.Arrays.{nameof(Il2CppArrayRank1<>)}`1[[Il2CppSystem.Reflection.ConstructorInfo, Il2Cppmscorlib]]")] - private static extern object GetConstructorsInternal(Type type, BindingFlags bindingAttr); - - public static IReadOnlyList GetConstructors(this Type type, BindingFlags bindingAttr) - { - return (IReadOnlyList)GetConstructorsInternal(type, bindingAttr); - } -} From af4e8f06c7a13f7ef11f83c198182a30d2a88a4a Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 22:19:47 -0700 Subject: [PATCH 360/486] Make Logger a public class and remove InternalsVisibleTo --- .../Il2CppInterop.Common.csproj | 11 +------ Il2CppInterop.Common/Logger.cs | 32 +++++++++---------- 2 files changed, 17 insertions(+), 26 deletions(-) diff --git a/Il2CppInterop.Common/Il2CppInterop.Common.csproj b/Il2CppInterop.Common/Il2CppInterop.Common.csproj index ae750cef..80c899bc 100644 --- a/Il2CppInterop.Common/Il2CppInterop.Common.csproj +++ b/Il2CppInterop.Common/Il2CppInterop.Common.csproj @@ -1,4 +1,4 @@ - + net10.0 @@ -9,15 +9,6 @@ true - - - <_Parameter1>Il2CppInterop.HarmonySupport - - - <_Parameter1>Il2CppInterop.Runtime - - - diff --git a/Il2CppInterop.Common/Logger.cs b/Il2CppInterop.Common/Logger.cs index cc5cafe6..8c2b74a4 100644 --- a/Il2CppInterop.Common/Logger.cs +++ b/Il2CppInterop.Common/Logger.cs @@ -4,30 +4,30 @@ namespace Il2CppInterop.Common; -public static class LoggerExtensions +public static class Logger { + public static ILogger Instance { get; private set; } = NullLogger.Instance; + public static T AddLogger(this T host, ILogger logger) where T : BaseHost { - host.AddComponent(new Logger(logger)); + host.AddComponent(new LoggerComponent(logger)); return host; } -} - -internal class Logger : IHostComponent -{ - public static ILogger Instance { get; private set; } = NullLogger.Instance; - public Logger(ILogger logger) + private sealed class LoggerComponent : IHostComponent { - Instance = logger; - } + public LoggerComponent(ILogger logger) + { + Instance = logger; + } - public void Start() - { - } + public void Start() + { + } - public void Dispose() - { - Instance = NullLogger.Instance; + public void Dispose() + { + Instance = NullLogger.Instance; + } } } From 38a39e233fc8e5d8543492345a5c54ee0769b6e9 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 22:31:47 -0700 Subject: [PATCH 361/486] Move GetIl2CppMethod and GetIl2CppMethodByToken to GenerationInternals --- .../InitializationClassProcessingLayer.cs | 6 +- Il2CppInterop.Runtime/GenerationInternals.cs | 127 ++++++++++++++++++ Il2CppInterop.Runtime/IL2CPP.cs | 126 ----------------- 3 files changed, 131 insertions(+), 128 deletions(-) diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index 956339b0..50928b6b 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -38,13 +38,15 @@ public override void Process(ApplicationAnalysisContext appContext, Action { diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index dc56387c..f1db072e 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -1,7 +1,11 @@ using System; using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Exceptions; +using Il2CppInterop.Runtime.Runtime; +using Microsoft.Extensions.Logging; namespace Il2CppInterop.Runtime; @@ -65,4 +69,127 @@ public static bool Il2CppGCHandleGetTargetWasCollected(nint gchandle) var obj = IL2CPP.il2cpp_gchandle_get_target(gchandle); return obj == nint.Zero; } + + public static nint GetIl2CppMethodByToken(nint clazz, int token) + { + if (clazz == nint.Zero) + return GetMethodInfoForMissingMethod(token.ToString()); + + var iter = nint.Zero; + nint method; + while ((method = IL2CPP.il2cpp_class_get_methods(clazz, ref iter)) != nint.Zero) + if (IL2CPP.il2cpp_method_get_token(method) == token) + return method; + + var className = IL2CPP.il2cpp_class_get_name(clazz); + Logger.Instance.LogTrace("Unable to find method {ClassName}::{Token}", className, token); + + return GetMethodInfoForMissingMethod($"{className}::{token}"); + } + + public static nint GetIl2CppMethod(nint clazz, bool isGeneric, string methodName, string returnTypeName, params string[] argTypes) + { + if (clazz == nint.Zero) + return GetMethodInfoForMissingMethod($"{methodName}({string.Join(", ", argTypes)})"); + + returnTypeName = Regex.Replace(returnTypeName, "\\`\\d+", "").Replace('/', '.').Replace('+', '.'); + for (var index = 0; index < argTypes.Length; index++) + { + var argType = argTypes[index]; + argTypes[index] = Regex.Replace(argType, "\\`\\d+", "").Replace('/', '.').Replace('+', '.'); + } + + var methodsSeen = 0; + var lastMethod = nint.Zero; + var iter = nint.Zero; + nint method; + while ((method = IL2CPP.il2cpp_class_get_methods(clazz, ref iter)) != nint.Zero) + { + if (IL2CPP.il2cpp_method_get_name(method) != methodName) + continue; + + if (IL2CPP.il2cpp_method_get_param_count(method) != argTypes.Length) + continue; + + if (IL2CPP.il2cpp_method_is_generic(method) != isGeneric) + continue; + + var returnType = IL2CPP.il2cpp_method_get_return_type(method); + var returnTypeNameActual = IL2CPP.il2cpp_type_get_name(returnType); + if (returnTypeNameActual != returnTypeName) + continue; + + methodsSeen++; + lastMethod = method; + + var badType = false; + for (var i = 0; i < argTypes.Length; i++) + { + var paramType = IL2CPP.il2cpp_method_get_param(method, (uint)i); + var typeName = IL2CPP.il2cpp_type_get_name(paramType); + if (typeName != argTypes[i]) + { + badType = true; + break; + } + } + + if (badType) continue; + + return method; + } + + var className = IL2CPP.il2cpp_class_get_name(clazz); + + if (methodsSeen == 1) + { + Logger.Instance.LogTrace( + "Method {ClassName}::{MethodName} was stubbed with a random matching method of the same name", className, methodName); + Logger.Instance.LogTrace( + "Stubby return type/target: {LastMethod} / {ReturnTypeName}", IL2CPP.il2cpp_type_get_name(IL2CPP.il2cpp_method_get_return_type(lastMethod)), returnTypeName); + Logger.Instance.LogTrace("Stubby parameter types/targets follow:"); + for (var i = 0; i < argTypes.Length; i++) + { + var paramType = IL2CPP.il2cpp_method_get_param(lastMethod, (uint)i); + var typeName = IL2CPP.il2cpp_type_get_name(paramType); + Logger.Instance.LogTrace(" {TypeName} / {ArgType}", typeName, argTypes[i]); + } + + return lastMethod; + } + + Logger.Instance.LogTrace("Unable to find method {ClassName}::{MethodName}; signature follows", className, methodName); + Logger.Instance.LogTrace(" return {ReturnTypeName}", returnTypeName); + foreach (var argType in argTypes) + Logger.Instance.LogTrace(" {ArgType}", argType); + Logger.Instance.LogTrace("Available methods of this name follow:"); + iter = nint.Zero; + while ((method = IL2CPP.il2cpp_class_get_methods(clazz, ref iter)) != nint.Zero) + { + if (IL2CPP.il2cpp_method_get_name(method) != methodName) + continue; + + var nParams = IL2CPP.il2cpp_method_get_param_count(method); + Logger.Instance.LogTrace("Method starts"); + Logger.Instance.LogTrace(" return {MethodTypeName}", IL2CPP.il2cpp_type_get_name(IL2CPP.il2cpp_method_get_return_type(method))); + for (var i = 0; i < nParams; i++) + { + var paramType = IL2CPP.il2cpp_method_get_param(method, (uint)i); + var typeName = IL2CPP.il2cpp_type_get_name(paramType); + Logger.Instance.LogTrace(" {TypeName}", typeName); + } + + return method; + } + + return GetMethodInfoForMissingMethod($"{className}::{methodName}({string.Join(", ", argTypes)})"); + } + + private static IntPtr GetMethodInfoForMissingMethod(string methodName) + { + var methodInfo = UnityVersionHandler.NewMethod(); + methodInfo.Name = Marshal.StringToCoTaskMemUTF8(methodName); + methodInfo.Slot = ushort.MaxValue; + return methodInfo.Pointer; + } } diff --git a/Il2CppInterop.Runtime/IL2CPP.cs b/Il2CppInterop.Runtime/IL2CPP.cs index c5842135..d4d01e4c 100644 --- a/Il2CppInterop.Runtime/IL2CPP.cs +++ b/Il2CppInterop.Runtime/IL2CPP.cs @@ -1,7 +1,6 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Text.RegularExpressions; using Il2CppInterop.Common; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.Runtime; @@ -49,123 +48,6 @@ public static int GetIl2cppValueSize(nint klass) return il2cpp_class_value_size(klass, ref align); } - public static nint GetIl2CppMethodByToken(nint clazz, int token) - { - if (clazz == nint.Zero) - return GetMethodInfoForMissingMethod(token.ToString()); - - var iter = nint.Zero; - nint method; - while ((method = il2cpp_class_get_methods(clazz, ref iter)) != nint.Zero) - if (il2cpp_method_get_token(method) == token) - return method; - - var className = il2cpp_class_get_name(clazz); - Logger.Instance.LogTrace("Unable to find method {ClassName}::{Token}", className, token); - - return GetMethodInfoForMissingMethod($"{className}::{token}"); - } - - public static nint GetIl2CppMethod(nint clazz, bool isGeneric, string methodName, string returnTypeName, - params string[] argTypes) - { - if (clazz == nint.Zero) - return GetMethodInfoForMissingMethod($"{methodName}({string.Join(", ", argTypes)})"); - - returnTypeName = Regex.Replace(returnTypeName, "\\`\\d+", "").Replace('/', '.').Replace('+', '.'); - for (var index = 0; index < argTypes.Length; index++) - { - var argType = argTypes[index]; - argTypes[index] = Regex.Replace(argType, "\\`\\d+", "").Replace('/', '.').Replace('+', '.'); - } - - var methodsSeen = 0; - var lastMethod = nint.Zero; - var iter = nint.Zero; - nint method; - while ((method = il2cpp_class_get_methods(clazz, ref iter)) != nint.Zero) - { - if (il2cpp_method_get_name(method) != methodName) - continue; - - if (il2cpp_method_get_param_count(method) != argTypes.Length) - continue; - - if (il2cpp_method_is_generic(method) != isGeneric) - continue; - - var returnType = il2cpp_method_get_return_type(method); - var returnTypeNameActual = il2cpp_type_get_name(returnType); - if (returnTypeNameActual != returnTypeName) - continue; - - methodsSeen++; - lastMethod = method; - - var badType = false; - for (var i = 0; i < argTypes.Length; i++) - { - var paramType = il2cpp_method_get_param(method, (uint)i); - var typeName = il2cpp_type_get_name(paramType); - if (typeName != argTypes[i]) - { - badType = true; - break; - } - } - - if (badType) continue; - - return method; - } - - var className = il2cpp_class_get_name(clazz); - - if (methodsSeen == 1) - { - Logger.Instance.LogTrace( - "Method {ClassName}::{MethodName} was stubbed with a random matching method of the same name", className, methodName); - Logger.Instance.LogTrace( - "Stubby return type/target: {LastMethod} / {ReturnTypeName}", il2cpp_type_get_name(il2cpp_method_get_return_type(lastMethod)), returnTypeName); - Logger.Instance.LogTrace("Stubby parameter types/targets follow:"); - for (var i = 0; i < argTypes.Length; i++) - { - var paramType = il2cpp_method_get_param(lastMethod, (uint)i); - var typeName = il2cpp_type_get_name(paramType); - Logger.Instance.LogTrace(" {TypeName} / {ArgType}", typeName, argTypes[i]); - } - - return lastMethod; - } - - Logger.Instance.LogTrace("Unable to find method {ClassName}::{MethodName}; signature follows", className, methodName); - Logger.Instance.LogTrace(" return {ReturnTypeName}", returnTypeName); - foreach (var argType in argTypes) - Logger.Instance.LogTrace(" {ArgType}", argType); - Logger.Instance.LogTrace("Available methods of this name follow:"); - iter = nint.Zero; - while ((method = il2cpp_class_get_methods(clazz, ref iter)) != nint.Zero) - { - if (il2cpp_method_get_name(method) != methodName) - continue; - - var nParams = il2cpp_method_get_param_count(method); - Logger.Instance.LogTrace("Method starts"); - Logger.Instance.LogTrace( - " return {MethodTypeName}", il2cpp_type_get_name(il2cpp_method_get_return_type(method))); - for (var i = 0; i < nParams; i++) - { - var paramType = il2cpp_method_get_param(method, (uint)i); - var typeName = il2cpp_type_get_name(paramType); - Logger.Instance.LogTrace(" {TypeName}", typeName); - } - - return method; - } - - return GetMethodInfoForMissingMethod($"{className}::{methodName}({string.Join(", ", argTypes)})"); - } - public static nint GetIl2CppGenericInstanceMethod(nint methodInfoPointer, nint declaringTypeClassPointer, params nint[] genericMethodArguments) { // Ensure Il2CppSystem.RuntimeType is initialized before we call Il2CppSystem.Type.internal_from_handle @@ -230,14 +112,6 @@ static IntPtr GetNestedTypeViaReflection(nint enclosingClass, string nestedTypeN } } - private static IntPtr GetMethodInfoForMissingMethod(string methodName) - { - var methodInfo = UnityVersionHandler.NewMethod(); - methodInfo.Name = Marshal.StringToCoTaskMemUTF8(methodName); - methodInfo.Slot = ushort.MaxValue; - return methodInfo.Pointer; - } - // IL2CPP Functions [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] From fe5d7b79612c1c17fdcbb2e0c78998429f10f877 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 22:34:40 -0700 Subject: [PATCH 362/486] Use Regex source generation in GenerationInternals --- Il2CppInterop.Runtime/GenerationInternals.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Il2CppInterop.Runtime/GenerationInternals.cs b/Il2CppInterop.Runtime/GenerationInternals.cs index f1db072e..188c556d 100644 --- a/Il2CppInterop.Runtime/GenerationInternals.cs +++ b/Il2CppInterop.Runtime/GenerationInternals.cs @@ -13,7 +13,7 @@ namespace Il2CppInterop.Runtime; /// Do not reference this class. Everything in it is an implementation detail of the generator. Breaking changes may occur at any time without warning. /// [EditorBrowsable(EditorBrowsableState.Never)] -public static class GenerationInternals +public static partial class GenerationInternals { public static unsafe string? Il2CppStringToManaged(Il2CppSystem.String? il2CppString) { @@ -92,11 +92,11 @@ public static nint GetIl2CppMethod(nint clazz, bool isGeneric, string methodName if (clazz == nint.Zero) return GetMethodInfoForMissingMethod($"{methodName}({string.Join(", ", argTypes)})"); - returnTypeName = Regex.Replace(returnTypeName, "\\`\\d+", "").Replace('/', '.').Replace('+', '.'); + returnTypeName = GenericArityRegex.Replace(returnTypeName, "").Replace('/', '.').Replace('+', '.'); for (var index = 0; index < argTypes.Length; index++) { var argType = argTypes[index]; - argTypes[index] = Regex.Replace(argType, "\\`\\d+", "").Replace('/', '.').Replace('+', '.'); + argTypes[index] = GenericArityRegex.Replace(argType, "").Replace('/', '.').Replace('+', '.'); } var methodsSeen = 0; @@ -192,4 +192,7 @@ private static IntPtr GetMethodInfoForMissingMethod(string methodName) methodInfo.Slot = ushort.MaxValue; return methodInfo.Pointer; } + + [GeneratedRegex(@"\`\d+")] + private static partial Regex GenericArityRegex { get; } } From 636dad9a5b453e7111dd098ad1cd136271af0615 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 23:07:39 -0700 Subject: [PATCH 363/486] Fix GetIl2CppValueSize spelling --- Il2CppInterop.Generator/InitializationClassProcessingLayer.cs | 2 +- Il2CppInterop.Runtime/IL2CPP.cs | 2 +- Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs | 2 +- Il2CppInterop.SourceGenerator/Il2CppTypeGenerator.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index 50928b6b..a4b801f6 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -39,7 +39,7 @@ public override void Process(ApplicationAnalysisContext appContext, Action.NativeClassPointer);"); + writer.WriteLine($"Size = global::Il2CppInterop.Runtime.IL2CPP.GetIl2CppValueSize(global::Il2CppInterop.Runtime.Il2CppClassPointerStore<{model.TypeName}>.NativeClassPointer);"); writer.WriteLine($"global::Il2CppInterop.Runtime.Runtime.Il2CppObjectPool.RegisterValueTypeInitializer<{model.TypeName}>();"); } else if (!model.IsAbstract) From 4d7ff8133b5fbcbdd35c440ec7652790c5849b35 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 23:10:54 -0700 Subject: [PATCH 364/486] Improve TrampolineHelpers performance --- .../Injection/TrampolineHelpers.cs | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs b/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs index c9b9b265..b3a986d1 100644 --- a/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs +++ b/Il2CppInterop.Runtime/Injection/TrampolineHelpers.cs @@ -14,7 +14,7 @@ internal static class TrampolineHelpers private static ModuleBuilder? _fixedStructModuleBuilder; private static readonly Dictionary _fixedStructCache = new(); - internal static Type GetFixedSizeStructType(int size) + private static Type GetFixedSizeStructType(int size) { if (_fixedStructCache.TryGetValue(size, out var result)) { @@ -43,13 +43,19 @@ internal static Type NativeType(this Type managedType) { return managedType; } - else if (managedType.IsByRef) + else if (!managedType.IsValueType) { - throw new NotSupportedException("ByRef types are not supported in NativeType conversion."); - } - else if (managedType.IsArray || managedType.IsSZArray) - { - throw new NotSupportedException("Array types are not supported in NativeType conversion."); + if (managedType.IsByRef) + { + throw new NotSupportedException("ByRef types are not supported in NativeType conversion."); + } + else if (managedType.IsArray || managedType.IsSZArray) + { + throw new NotSupportedException("Array types are not supported in NativeType conversion."); + } + + // General reference type + return typeof(IntPtr); } else if (managedType == typeof(Il2CppSystem.Boolean)) { @@ -65,7 +71,7 @@ internal static Type NativeType(this Type managedType) { return typeof(IntPtr); } - else if (managedType.IsValueType) + else { // Struct that's passed on the stack => handle as general struct @@ -78,10 +84,5 @@ internal static Type NativeType(this Type managedType) var fixedSize = IL2CPP.GetIl2CppValueSize(nativeClassPtr); return GetFixedSizeStructType(fixedSize); } - else - { - // General reference type - return typeof(IntPtr); - } } } From 9f0ffcd3fc19957ce89db933993df8be2b0e0205 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sat, 2 May 2026 23:54:17 -0700 Subject: [PATCH 365/486] Fix array initializer syntax and use nameof for MonoField Updated s_Signatures to use correct array initializer syntax ([]). Replaced string literal "MonoField" with nameof(Il2CppSystem.Reflection.MonoField) for improved refactor safety and code clarity. --- .../Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs index 97f086c0..dc91fa54 100644 --- a/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs +++ b/Il2CppInterop.Runtime/Injection/Hooks/Class_GetFieldDefaultValue_Hook.cs @@ -33,7 +33,7 @@ internal unsafe class Class_GetFieldDefaultValue_Hook : Hook x.Name is "MonoField"); + var monoFieldType = InjectorHelpers.Il2CppMscorlib.GetTypesSafe().SingleOrDefault((x) => x.Name is nameof(Il2CppSystem.Reflection.MonoField)); if (monoFieldType == null) throw new Exception($"Unity {Il2CppInteropRuntime.Instance.UnityVersion} is not supported at the moment: MonoField isn't present in Il2Cppmscorlib.dll for unity version, unable to fetch icall"); From 9037b103357dd43aa491f4f6dc73337b453d979b Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 3 May 2026 00:32:54 -0700 Subject: [PATCH 366/486] Update class struct generation for VTable --- .../Injection/TypeInjector.cs | 32 +++++++++---------- .../VersionSpecific/Class/Class_104_0.cs | 4 +-- .../VersionSpecific/Class/Class_105_0.cs | 4 +-- .../VersionSpecific/Class/Class_16_0.cs | 4 +-- .../VersionSpecific/Class/Class_19_0.cs | 4 +-- .../VersionSpecific/Class/Class_20_0.cs | 4 +-- .../VersionSpecific/Class/Class_21_0.cs | 4 +-- .../VersionSpecific/Class/Class_21_1.cs | 4 +-- .../VersionSpecific/Class/Class_21_2.cs | 4 +-- .../VersionSpecific/Class/Class_22_0.cs | 4 +-- .../VersionSpecific/Class/Class_22_1.cs | 4 +-- .../VersionSpecific/Class/Class_23_0.cs | 4 +-- .../VersionSpecific/Class/Class_23_1.cs | 4 +-- .../VersionSpecific/Class/Class_24_0.cs | 4 +-- .../VersionSpecific/Class/Class_24_1.cs | 4 +-- .../VersionSpecific/Class/Class_24_2.cs | 4 +-- .../VersionSpecific/Class/Class_24_3.cs | 4 +-- .../VersionSpecific/Class/Class_24_4.cs | 4 +-- .../VersionSpecific/Class/Class_24_5.cs | 4 +-- .../VersionSpecific/Class/Class_24_6.cs | 4 +-- .../VersionSpecific/Class/Class_24_7.cs | 4 +-- .../VersionSpecific/Class/Class_27_0.cs | 4 +-- .../VersionSpecific/Class/Class_27_1.cs | 4 +-- .../VersionSpecific/Class/Class_27_2.cs | 4 +-- .../VersionSpecific/Class/Class_27_3.cs | 4 +-- .../VersionSpecific/Class/Class_27_4.cs | 4 +-- .../VersionSpecific/Class/Class_27_5.cs | 4 +-- .../VersionSpecific/Class/Class_29_0.cs | 4 +-- .../VersionSpecific/Class/Class_29_1.cs | 4 +-- .../VersionSpecific/Class/Class_29_2.cs | 4 +-- .../VersionSpecific/Class/Class_39_0.cs | 4 +-- .../VersionSpecific/Class/Interfaces.cs | 4 +-- .../TypeGenerators/Il2CppClassGenerator.cs | 7 ++-- 33 files changed, 82 insertions(+), 81 deletions(-) diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index 94e182c1..ee0f1207 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -299,8 +299,8 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i for (; index < lowestedInterfaceOffset; index++) { ThrowIfNotEnoughAllocated(index, vtableAllocatedSize, type); - var vtableEntry = (VirtualInvokeData*)classPointer.VTable + index; - var baseVTableEntry = (VirtualInvokeData*)baseClassPointer.VTable + index; + var vtableEntry = classPointer.VTable + index; + var baseVTableEntry = baseClassPointer.VTable + index; var baseMethodInfo = baseMap2[baseMap3[(nint)baseVTableEntry->method]]; if (baseMethodToMethodMap.TryGetValue(baseMethodInfo, out var methodInfo)) { @@ -329,7 +329,7 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i var nativeMethodInfo = map4[map1[methodInfo]]; ThrowIfNotEnoughAllocated(index, vtableAllocatedSize, type); - ((VirtualInvokeData*)classPointer.VTable)[index] = new() + classPointer.VTable[index] = new() { methodPtr = nativeMethodInfo.MethodPointer, method = nativeMethodInfo.MethodInfoPointer @@ -344,7 +344,7 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i var interfaceType = pointersToInterfaces[interfaceClassPointer.Pointer]; var baseInterfaceOffset = pair.offset; var interfaceOffset = index; - int interfaceVtableCount = interfaceClassPointer.VtableCount; + int interfaceVtableCount = interfaceClassPointer.VTableCount; interfaceOffsets.Add(new Il2CppRuntimeInterfaceOffsetPair { @@ -371,8 +371,8 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i { Debug.Assert(index == interfaceOffset + i); ThrowIfNotEnoughAllocated(index, vtableAllocatedSize, type); - var vtableEntry = (VirtualInvokeData*)classPointer.VTable + interfaceOffset + i; - var interfaceVTableEntry = (VirtualInvokeData*)interfaceClassPointer.VTable + i; + var vtableEntry = classPointer.VTable + interfaceOffset + i; + var interfaceVTableEntry = interfaceClassPointer.VTable + i; var interfaceMethodInfo = interfaceMap2[interfaceMap3[(nint)interfaceVTableEntry->method]]; if (interfaceMethodToImplementingMethod.TryGetValue(interfaceMethodInfo, out var methodInfo) && methodInfo.DeclaringType == type) { @@ -382,7 +382,7 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i } else { - var baseVTableEntry = (VirtualInvokeData*)baseClassPointer.VTable + baseInterfaceOffset + i; + var baseVTableEntry = baseClassPointer.VTable + baseInterfaceOffset + i; *vtableEntry = *baseVTableEntry; } index++; @@ -424,8 +424,8 @@ static void SetVTableAndInterfaces(Type type, INativeClassStruct classPointer, i { Debug.Assert(index == interfaceOffset + i); ThrowIfNotEnoughAllocated(index, vtableAllocatedSize, type); - var vtableEntry = (VirtualInvokeData*)classPointer.VTable + interfaceOffset + i; - var interfaceVTableEntry = (VirtualInvokeData*)interfaceClassPointer.VTable + i; + var vtableEntry = classPointer.VTable + interfaceOffset + i; + var interfaceVTableEntry = interfaceClassPointer.VTable + i; var interfaceMethodInfo = interfaceMap2[interfaceMap3[(nint)interfaceVTableEntry->method]]; var methodInfo = interfaceMethodToImplementingMethod[interfaceMethodInfo]; var nativeMethodInfo = map4[map1[methodInfo]]; @@ -536,7 +536,7 @@ static void SetFields(Type type, INativeClassStruct classPointer) private static int LowestInterfaceOffset(INativeClassStruct classPointer) { - int result = classPointer.VtableCount; + int result = classPointer.VTableCount; for (var i = classPointer.InterfaceOffsetsCount - 1; i >= 0; i--) { var offset = (classPointer.InterfaceOffsets + i)->offset; @@ -803,7 +803,7 @@ private static int CalculateVTableUpperBoundUsingReflection(Type type) } if (type.IsValueType) { - count += UnityVersionHandler.Wrap((Il2CppClass*)Il2CppClassPointerStore.NativeClassPointer).VtableCount; + count += UnityVersionHandler.Wrap((Il2CppClass*)Il2CppClassPointerStore.NativeClassPointer).VTableCount; } return int.Min(count, ushort.MaxValue); @@ -897,7 +897,7 @@ private static void RegisterEnumInIl2Cpp(Type type) InjectorHelpers.ClassInit(baseEnum.ClassPointer); - var il2cppEnum = UnityVersionHandler.NewClass(baseEnum.VtableCount); + var il2cppEnum = UnityVersionHandler.NewClass(baseEnum.VTableCount); var elementClass = UnityVersionHandler.Wrap( (Il2CppClass*)Il2CppClassPointerStore.GetNativeClassPointer(GetEnumUnderlyingType(type))); @@ -929,10 +929,10 @@ private static void RegisterEnumInIl2Cpp(Type type) il2cppEnum.Flags = (Il2CppClassAttributes)type.Attributes; - il2cppEnum.VtableCount = baseEnum.VtableCount; - var vtable = (VirtualInvokeData*)il2cppEnum.VTable; - var baseVTable = (VirtualInvokeData*)baseEnum.VTable; - for (var i = 0; i < baseEnum.VtableCount; i++) + il2cppEnum.VTableCount = baseEnum.VTableCount; + var vtable = il2cppEnum.VTable; + var baseVTable = baseEnum.VTable; + for (var i = 0; i < baseEnum.VTableCount; i++) vtable[i] = baseVTable[i]; var enumNamesAndValues = GetEnumNamesAndValues(type); diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_104_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_104_0.cs index c07927a3..07aa1b07 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_104_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_104_0.cs @@ -121,12 +121,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_104_0._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_104_0* _ => (Il2CppClass_104_0*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_104_0)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_104_0)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_105_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_105_0.cs index 1267ff11..5c20ed4a 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_105_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_105_0.cs @@ -121,12 +121,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_105_0._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_105_0* _ => (Il2CppClass_105_0*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_105_0)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_105_0)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_16_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_16_0.cs index 0f839d5a..1e351cf6 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_16_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_16_0.cs @@ -107,12 +107,12 @@ internal class NativeStructWrapper : INativeClassStruct private Il2CppClass* _klassDummy; public nint Pointer { get; } private Il2CppClass_16_0* _ => (Il2CppClass_16_0*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_16_0)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_16_0)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_19_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_19_0.cs index adc5b6f2..d7e1b251 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_19_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_19_0.cs @@ -108,12 +108,12 @@ internal class NativeStructWrapper : INativeClassStruct private Il2CppClass* _klassDummy; public nint Pointer { get; } private Il2CppClass_19_0* _ => (Il2CppClass_19_0*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_19_0)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_19_0)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_20_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_20_0.cs index fa161ea5..014d173e 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_20_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_20_0.cs @@ -110,12 +110,12 @@ internal class NativeStructWrapper : INativeClassStruct private Il2CppClass* _klassDummy; public nint Pointer { get; } private Il2CppClass_20_0* _ => (Il2CppClass_20_0*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_20_0)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_20_0)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_0.cs index 6d38f1f4..f6d518dc 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_0.cs @@ -110,12 +110,12 @@ internal class NativeStructWrapper : INativeClassStruct private Il2CppClass* _klassDummy; public nint Pointer { get; } private Il2CppClass_21_0* _ => (Il2CppClass_21_0*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_21_0)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_21_0)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_1.cs index c12b64c4..5a9e8096 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_1.cs @@ -110,12 +110,12 @@ internal class NativeStructWrapper : INativeClassStruct private Il2CppClass* _klassDummy; public nint Pointer { get; } private Il2CppClass_21_1* _ => (Il2CppClass_21_1*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_21_1)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_21_1)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_2.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_2.cs index 0c9ef6f8..09719850 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_2.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_21_2.cs @@ -111,12 +111,12 @@ internal class NativeStructWrapper : INativeClassStruct private Il2CppClass* _klassDummy; public nint Pointer { get; } private Il2CppClass_21_2* _ => (Il2CppClass_21_2*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_21_2)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_21_2)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_0.cs index d7ad3c86..c24b21ee 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_0.cs @@ -111,12 +111,12 @@ internal class NativeStructWrapper : INativeClassStruct private Il2CppClass* _klassDummy; public nint Pointer { get; } private Il2CppClass_22_0* _ => (Il2CppClass_22_0*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_22_0)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_22_0)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_1.cs index 96c93be1..df6abdca 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_22_1.cs @@ -112,12 +112,12 @@ internal class NativeStructWrapper : INativeClassStruct private Il2CppClass* _klassDummy; public nint Pointer { get; } private Il2CppClass_22_1* _ => (Il2CppClass_22_1*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_22_1)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_22_1)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_0.cs index a54e3931..45265ec5 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_0.cs @@ -112,12 +112,12 @@ internal class NativeStructWrapper : INativeClassStruct private Il2CppClass* _klassDummy; public nint Pointer { get; } private Il2CppClass_23_0* _ => (Il2CppClass_23_0*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_23_0)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_23_0)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_1.cs index 573c111a..3c579080 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_23_1.cs @@ -113,12 +113,12 @@ internal class NativeStructWrapper : INativeClassStruct private Il2CppClass* _klassDummy; public nint Pointer { get; } private Il2CppClass_23_1* _ => (Il2CppClass_23_1*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_23_1)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_23_1)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap(_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap(_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_0.cs index b1f4e29c..8329b808 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_0.cs @@ -111,12 +111,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_24_0._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_24_0* _ => (Il2CppClass_24_0*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_24_0)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_24_0)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_1.cs index 5a2ed557..aba76495 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_1.cs @@ -114,12 +114,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_24_1._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_24_1* _ => (Il2CppClass_24_1*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_24_1)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_24_1)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_2.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_2.cs index 700d2a0d..3faea67d 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_2.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_2.cs @@ -113,12 +113,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_24_2._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_24_2* _ => (Il2CppClass_24_2*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_24_2)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_24_2)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_3.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_3.cs index b51733b9..a6179610 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_3.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_3.cs @@ -115,12 +115,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_24_3._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_24_3* _ => (Il2CppClass_24_3*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_24_3)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_24_3)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_4.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_4.cs index baf485f0..4044f6ae 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_4.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_4.cs @@ -116,12 +116,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_24_4._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_24_4* _ => (Il2CppClass_24_4*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_24_4)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_24_4)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_5.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_5.cs index d00ab4d4..c62bbcfb 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_5.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_5.cs @@ -116,12 +116,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_24_5._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_24_5* _ => (Il2CppClass_24_5*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_24_5)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_24_5)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_6.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_6.cs index 3a4a45a6..27843a4a 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_6.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_6.cs @@ -117,12 +117,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_24_6._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_24_6* _ => (Il2CppClass_24_6*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_24_6)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_24_6)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_7.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_7.cs index 2b328b34..6e2da927 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_7.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_24_7.cs @@ -117,12 +117,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_24_7._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_24_7* _ => (Il2CppClass_24_7*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_24_7)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_24_7)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_0.cs index 2407f200..67b2889c 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_0.cs @@ -119,12 +119,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_27_0._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_27_0* _ => (Il2CppClass_27_0*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_27_0)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_27_0)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_1.cs index bebe271a..df69f53b 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_1.cs @@ -115,12 +115,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_27_1._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_27_1* _ => (Il2CppClass_27_1*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_27_1)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_27_1)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_2.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_2.cs index bb5f8146..579ae943 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_2.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_2.cs @@ -117,12 +117,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_27_2._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_27_2* _ => (Il2CppClass_27_2*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_27_2)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_27_2)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_3.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_3.cs index 9d0516c6..da727a74 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_3.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_3.cs @@ -117,12 +117,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_27_3._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_27_3* _ => (Il2CppClass_27_3*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_27_3)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_27_3)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_4.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_4.cs index f57e8db3..9b5e1043 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_4.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_4.cs @@ -115,12 +115,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_27_4._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_27_4* _ => (Il2CppClass_27_4*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_27_4)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_27_4)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_5.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_5.cs index cf62e742..1ef9bade 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_5.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_27_5.cs @@ -117,12 +117,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_27_5._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_27_5* _ => (Il2CppClass_27_5*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_27_5)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_27_5)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_0.cs index 115ce8eb..37fd387f 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_0.cs @@ -119,12 +119,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_29_0._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_29_0* _ => (Il2CppClass_29_0*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_29_0)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_29_0)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_1.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_1.cs index 2feb3ed5..4b05ed4a 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_1.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_1.cs @@ -119,12 +119,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_29_1._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_29_1* _ => (Il2CppClass_29_1*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_29_1)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_29_1)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_2.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_2.cs index 81a60330..fbabc678 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_2.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_29_2.cs @@ -119,12 +119,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_29_2._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_29_2* _ => (Il2CppClass_29_2*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_29_2)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_29_2)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_39_0.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_39_0.cs index 0ebfa0b1..bd8063a5 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_39_0.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Class_39_0.cs @@ -119,12 +119,12 @@ internal class NativeStructWrapper : INativeClassStruct private static int _bitfield1offset = Marshal.OffsetOf(nameof(Il2CppClass_39_0._bitfield1)).ToInt32(); public nint Pointer { get; } private Il2CppClass_39_0* _ => (Il2CppClass_39_0*)Pointer; - public nint VTable => nint.Add(Pointer, sizeof(Il2CppClass_39_0)); + public unsafe VirtualInvokeData* VTable => (VirtualInvokeData*)nint.Add(Pointer, sizeof(Il2CppClass_39_0)); public Il2CppClass* ClassPointer => (Il2CppClass*)Pointer; public INativeTypeStruct ByValArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->byval_arg); public INativeTypeStruct ThisArg => UnityVersionHandler.Wrap((Il2CppTypeStruct*)&_->this_arg); public ref uint InstanceSize => ref _->instance_size; - public ref ushort VtableCount => ref _->vtable_count; + public ref ushort VTableCount => ref _->vtable_count; public ref ushort InterfaceCount => ref _->interfaces_count; public ref ushort InterfaceOffsetsCount => ref _->interface_offsets_count; public ref byte TypeHierarchyDepth => ref _->typeHierarchyDepth; diff --git a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Interfaces.cs b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Interfaces.cs index 31bcb125..9e937179 100644 --- a/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Interfaces.cs +++ b/Il2CppInterop.Runtime/Runtime/VersionSpecific/Class/Interfaces.cs @@ -8,12 +8,12 @@ public interface INativeClassStructHandler : INativeStructHandler } public interface INativeClassStruct : INativeStruct { - nint VTable { get; } + unsafe VirtualInvokeData* VTable { get; } unsafe Il2CppClass* ClassPointer { get; } INativeTypeStruct ByValArg { get; } INativeTypeStruct ThisArg { get; } ref uint InstanceSize { get; } - ref ushort VtableCount { get; } + ref ushort VTableCount { get; } ref ushort InterfaceCount { get; } ref ushort InterfaceOffsetsCount { get; } ref byte TypeHierarchyDepth { get; } diff --git a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs index c3958dd1..a90009bc 100644 --- a/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs +++ b/Il2CppInterop.StructGenerator/TypeGenerators/Il2CppClassGenerator.cs @@ -61,9 +61,10 @@ protected override IReadOnlyList WrapperProperties byvalArg.ImmediateGet += "_->byval_arg)"; thisArg.ImmediateGet += "_->this_arg)"; return [ - new CodeGenProperty("nint", ElementProtection.Public, "VTable") + new CodeGenProperty("VirtualInvokeData*", ElementProtection.Public, "VTable") { - ImmediateGet = $"nint.Add(Pointer, sizeof({NativeStructGenerator.NativeStruct.Name}))" + ImmediateGet = $"(VirtualInvokeData*)nint.Add(Pointer, sizeof({NativeStructGenerator.NativeStruct.Name}))", + IsUnsafe = true }, new CodeGenProperty($"{NativeStub}*", ElementProtection.Public, "ClassPointer") { @@ -96,7 +97,7 @@ protected override IReadOnlyList WrapperProperties protected override IReadOnlyList ByRefWrappers => [ new ByRefWrapper("uint", "InstanceSize", ["instance_size"]), - new ByRefWrapper("ushort", "VtableCount", ["vtable_count"]), + new ByRefWrapper("ushort", "VTableCount", ["vtable_count"]), new ByRefWrapper("ushort", "InterfaceCount", ["interfaces_count"]), new ByRefWrapper("ushort", "InterfaceOffsetsCount", ["interface_offsets_count"]), new ByRefWrapper("byte", "TypeHierarchyDepth", ["typeHierarchyDepth"]), From f1c3b55f2b261418d6b63f1f023f6501bb40ef03 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 3 May 2026 00:37:50 -0700 Subject: [PATCH 367/486] Update il2cpp_class_value_size to use out instead of ref Changed il2cpp_class_value_size and its usage to use the out keyword for the align parameter instead of ref, reflecting that the value is only assigned within the method and not used by the caller. --- Il2CppInterop.Runtime/IL2CPP.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Il2CppInterop.Runtime/IL2CPP.cs b/Il2CppInterop.Runtime/IL2CPP.cs index 1d690d02..98c5559f 100644 --- a/Il2CppInterop.Runtime/IL2CPP.cs +++ b/Il2CppInterop.Runtime/IL2CPP.cs @@ -44,8 +44,7 @@ public static int GetIl2CppValueSize(nint klass) { if (klass == nint.Zero) return 0; - uint align = 0; - return il2cpp_class_value_size(klass, ref align); + return il2cpp_class_value_size(klass, out _); } public static nint GetIl2CppGenericInstanceMethod(nint methodInfoPointer, nint declaringTypeClassPointer, params nint[] genericMethodArguments) @@ -327,7 +326,7 @@ static IntPtr GetNestedTypeViaReflection(nint enclosingClass, string nestedTypeN [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] - public static partial int il2cpp_class_value_size(nint klass, ref uint align); + public static partial int il2cpp_class_value_size(nint klass, out uint align); [LibraryImport("GameAssembly")] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] From 38ad4c734b14d1854a2166bae7c48c656b881c64 Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 3 May 2026 00:39:58 -0700 Subject: [PATCH 368/486] Fix bug in previous commit --- Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs | 3 +-- Il2CppInterop.Runtime/Injection/TypeInjector.cs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs index b39b77d4..3ba9303b 100644 --- a/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs +++ b/Il2CppInterop.HarmonySupport/Il2CppInteropDetour.cs @@ -223,8 +223,7 @@ private DynamicMethodDefinition GenerateNativeToManagedThunk() var isReturnValueType = managedReturnType.IsValueType; if (isReturnValueType) { - uint align = 0; - returnSize = IL2CPP.il2cpp_class_value_size(Il2CppClassPointerStore.GetNativeClassPointer(managedReturnType), ref align); + returnSize = IL2CPP.GetIl2CppValueSize(Il2CppClassPointerStore.GetNativeClassPointer(managedReturnType)); } var hasReturnBuffer = isReturnValueType && IsReturnBufferNeeded(returnSize); diff --git a/Il2CppInterop.Runtime/Injection/TypeInjector.cs b/Il2CppInterop.Runtime/Injection/TypeInjector.cs index ee0f1207..966d7048 100644 --- a/Il2CppInterop.Runtime/Injection/TypeInjector.cs +++ b/Il2CppInterop.Runtime/Injection/TypeInjector.cs @@ -513,8 +513,7 @@ static void SetFields(Type type, INativeClassStruct classPointer) fieldInfo.Offset = fieldOffset; if (IL2CPP.il2cpp_class_is_valuetype(fieldInfoClass)) { - uint _align = 0; - var fieldSize = IL2CPP.il2cpp_class_value_size(fieldInfoClass, ref _align); + var fieldSize = IL2CPP.GetIl2CppValueSize(fieldInfoClass); fieldOffset += fieldSize; } else From 68b258c5153f84f44b8734253094c96b283f602d Mon Sep 17 00:00:00 2001 From: ds5678 <49847914+ds5678@users.noreply.github.com> Date: Sun, 3 May 2026 00:54:13 -0700 Subject: [PATCH 369/486] Initial generic class inflation --- .../InitializationClassProcessingLayer.cs | 2 +- Il2CppInterop.Runtime/DelegateSupport.cs | 3 +- .../Extensions/Il2CppSystemTypeExtensions.cs | 45 ++++++++++++ Il2CppInterop.Runtime/GenerationInternals.cs | 35 ++++++++-- Il2CppInterop.Runtime/IL2CPP.cs | 26 ++----- .../Injection/GenericTypeInflater.cs | 70 +++++++++++++++++++ .../Injection/TypeInjector.cs | 5 +- Il2CppInterop.Runtime/InteropTypes/Pointer.cs | 5 +- 8 files changed, 158 insertions(+), 33 deletions(-) create mode 100644 Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs create mode 100644 Il2CppInterop.Runtime/Injection/GenericTypeInflater.cs diff --git a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs index a4b801f6..3dbafb5e 100644 --- a/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs +++ b/Il2CppInterop.Generator/InitializationClassProcessingLayer.cs @@ -34,7 +34,6 @@ public override void Process(ApplicationAnalysisContext appContext, Action diff --git a/Il2CppInterop.Runtime/DelegateSupport.cs b/Il2CppInterop.Runtime/DelegateSupport.cs index e50fc307..c286b6e5 100644 --- a/Il2CppInterop.Runtime/DelegateSupport.cs +++ b/Il2CppInterop.Runtime/DelegateSupport.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using System.Text; using Il2CppInterop.Common; +using Il2CppInterop.Runtime.Extensions; using Il2CppInterop.Runtime.Injection; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; @@ -199,7 +200,7 @@ private static unsafe TNative ConvertReturnValue(TManaged? va if (classTypePtr == IntPtr.Zero) throw new ArgumentException($"Type {typeof(TIl2Cpp)} has uninitialized class pointer"); - var il2CppDelegateType = Il2CppSystem.Type.internal_from_handle(IL2CPP.il2cpp_class_get_type(classTypePtr)); + var il2CppDelegateType = Il2CppSystem.Type.FromClassPointer(classTypePtr); var nativeDelegateInvokeMethod = il2CppDelegateType.GetMethod("Invoke"); var nativeParameters = nativeDelegateInvokeMethod.GetParameters(); diff --git a/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs new file mode 100644 index 00000000..03f2223b --- /dev/null +++ b/Il2CppInterop.Runtime/Extensions/Il2CppSystemTypeExtensions.cs @@ -0,0 +1,45 @@ +using System.Runtime.CompilerServices; +using Il2CppSystem; + +namespace Il2CppInterop.Runtime.Extensions; + +internal static class Il2CppSystemTypeExtensions +{ + extension(Type type) + { + public static Type FromTypePointer(nint typePointer) + { + // Ensure Il2CppSystem.RuntimeType is initialized before we call Il2CppSystem.Type.internal_from_handle + RuntimeHelpers.RunClassConstructor(typeof(RuntimeType).TypeHandle); + + return Type.internal_from_handle(typePointer); + } + + public static Type FromClassPointer(nint classPointer) + { + var il2CppType = IL2CPP.il2cpp_class_get_type(classPointer); + if (il2CppType == default) + { + throw new System.ArgumentException($"Class pointer {classPointer} does not have a corresponding IL2CPP type pointer", nameof(classPointer)); + } + return Type.FromTypePointer(il2CppType); + } + + public nint ToTypePointer() + { + return type.TypeHandle.value; + } + + ///