From c5ead42adefd77c5f734ec9d150a1bee287b7d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E9=93=AE?= <834207172@qq.com> Date: Mon, 31 Mar 2025 14:55:24 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B000?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EventKit/EventSystem/EnumEventSystem.cs | 34 +- .../Runtime/Utility/RemoteServices.cs | 24 - .../Runtime/Utility/RemoteServices.cs.meta | 3 - .../Runtime/Utility/RemoteServicesWithAuth.cs | 51 - .../Utility/RemoteServicesWithAuth.cs.meta | 3 - .../Runtime/Utility/UnityAsyncExtensions.cs | 67 ++ .../Utility/UnityAsyncExtensions.cs.meta | 3 + .../Runtime/Utility/WebRequestSystem.cs | 10 +- Assets/00.StaryEvo/package.json | 2 +- Assets/00.StaryEvo/~Samples.meta | 8 + .../Data~/NetStandard/netstandard2.0.dll | Bin 0 -> 84992 bytes .../Data~/NetStandard/netstandard2.1.dll | Bin 0 -> 90112 bytes .../Data~/hybridclr_version.json | 19 + .../com.code-philosophy.hybridclr/Editor.meta | 8 + .../Editor/3rds.meta | 8 + .../Editor/3rds/UnityHook.meta | 8 + .../Editor/3rds/UnityHook/CodePatcher.cs | 320 +++++++ .../Editor/3rds/UnityHook/CodePatcher.cs.meta | 11 + .../Editor/3rds/UnityHook/HookPool.cs | 74 ++ .../Editor/3rds/UnityHook/HookPool.cs.meta | 11 + .../Editor/3rds/UnityHook/HookUtils.cs | 272 ++++++ .../Editor/3rds/UnityHook/HookUtils.cs.meta | 11 + .../Editor/3rds/UnityHook/HookUtils_OSX.cs | 102 ++ .../3rds/UnityHook/HookUtils_OSX.cs.meta | 11 + .../Editor/3rds/UnityHook/HybridCLRHooks.meta | 8 + .../CopyStrippedAOTAssembliesHook.cs | 67 ++ .../CopyStrippedAOTAssembliesHook.cs.meta | 11 + .../HybridCLRHooks/GetIl2CppFolderHook.cs | 56 ++ .../GetIl2CppFolderHook.cs.meta | 11 + .../PatchScriptingAssembliesJsonHook.cs | 57 ++ .../PatchScriptingAssembliesJsonHook.cs.meta | 11 + .../Editor/3rds/UnityHook/LDasm.cs | 903 ++++++++++++++++++ .../Editor/3rds/UnityHook/LDasm.cs.meta | 11 + .../Editor/3rds/UnityHook/MethodHook.cs | 381 ++++++++ .../Editor/3rds/UnityHook/MethodHook.cs.meta | 11 + .../Editor/3rds/UnityHook/Plugins.meta | 8 + .../Editor/3rds/UnityHook/Plugins/Utils.cpp | 23 + .../3rds/UnityHook/Plugins/Utils.cpp.meta | 81 ++ .../build_libMonoHookUtils_OSX.dylib.sh | 4 + .../build_libMonoHookUtils_OSX.dylib.sh.meta | 7 + .../3rds/UnityHook/Plugins/silicon.meta | 8 + .../silicon/libMonoHookUtils_OSX.dylib | Bin 0 -> 33543 bytes .../silicon/libMonoHookUtils_OSX.dylib.meta | 81 ++ .../Editor/3rds/UnityHook/Plugins/x86_64.meta | 8 + .../Plugins/x86_64/libMonoHookUtils_OSX.dylib | Bin 0 -> 166928 bytes .../x86_64/libMonoHookUtils_OSX.dylib.meta | 81 ++ .../Editor/ABI.meta | 8 + .../Editor/ABI/ABIUtil.cs | 23 + .../Editor/ABI/ABIUtil.cs.meta | 11 + .../Editor/ABI/MethodDesc.cs | 77 ++ .../Editor/ABI/MethodDesc.cs.meta | 11 + .../Editor/ABI/ParamInfo.cs | 30 + .../Editor/ABI/ParamInfo.cs.meta | 11 + .../Editor/ABI/ParamOrReturnType.cs | 27 + .../Editor/ABI/ParamOrReturnType.cs.meta | 11 + .../Editor/ABI/PlatformABI.cs | 10 + .../Editor/ABI/PlatformABI.cs.meta | 11 + .../Editor/ABI/TypeCreator.cs | 102 ++ .../Editor/ABI/TypeCreator.cs.meta | 11 + .../Editor/ABI/TypeInfo.cs | 116 +++ .../Editor/ABI/TypeInfo.cs.meta | 11 + .../ABI/ValueTypeSizeAligmentCalculator.cs | 181 ++++ .../ValueTypeSizeAligmentCalculator.cs.meta | 11 + .../Editor/AOT.meta | 8 + .../Editor/AOT/Analyzer.cs | 208 ++++ .../Editor/AOT/Analyzer.cs.meta | 11 + .../Editor/AOT/ConstraintContext.cs | 73 ++ .../Editor/AOT/ConstraintContext.cs.meta | 11 + .../Editor/AOT/GenericReferenceWriter.cs | 139 +++ .../Editor/AOT/GenericReferenceWriter.cs.meta | 11 + .../Editor/BuildProcessors.meta | 8 + ...Lil2cppSourceCodeToXcodeproj2021OrOlder.cs | 254 +++++ ...ppSourceCodeToXcodeproj2021OrOlder.cs.meta | 11 + ...Lil2cppSourceCodeToXcodeproj2022OrNewer.cs | 57 ++ ...ppSourceCodeToXcodeproj2022OrNewer.cs.meta | 11 + .../Editor/BuildProcessors/CheckSettings.cs | 72 ++ .../BuildProcessors/CheckSettings.cs.meta | 11 + .../CopyStrippedAOTAssemblies.cs | 107 +++ .../CopyStrippedAOTAssemblies.cs.meta | 11 + .../BuildProcessors/FilterHotFixAssemblies.cs | 68 ++ .../FilterHotFixAssemblies.cs.meta | 11 + .../BuildProcessors/MsvcStdextWorkaround.cs | 32 + .../MsvcStdextWorkaround.cs.meta | 11 + .../PatchScriptingAssemblyList.cs | 117 +++ .../PatchScriptingAssemblyList.cs.meta | 11 + .../ScriptingAssembliesJsonPatcher.cs | 50 + .../ScriptingAssembliesJsonPatcher.cs.meta | 11 + .../Editor/Commands.meta | 8 + .../Commands/AOTReferenceGeneratorCommand.cs | 46 + .../AOTReferenceGeneratorCommand.cs.meta | 11 + .../Editor/Commands/CompileDllCommand.cs | 90 ++ .../Editor/Commands/CompileDllCommand.cs.meta | 11 + .../Commands/Il2CppDefGeneratorCommand.cs | 30 + .../Il2CppDefGeneratorCommand.cs.meta | 11 + .../Editor/Commands/LinkGeneratorCommand.cs | 39 + .../Commands/LinkGeneratorCommand.cs.meta | 11 + .../Commands/MethodBridgeGeneratorCommand.cs | 81 ++ .../MethodBridgeGeneratorCommand.cs.meta | 11 + .../Editor/Commands/PrebuildCommand.cs | 34 + .../Editor/Commands/PrebuildCommand.cs.meta | 11 + .../ReversePInvokeWrapperGeneratorCommand.cs | 49 + ...ersePInvokeWrapperGeneratorCommand.cs.meta | 11 + .../Editor/Commands/StripAOTDllCommand.cs | 162 ++++ .../Commands/StripAOTDllCommand.cs.meta | 11 + .../Editor/HashUtil.cs | 28 + .../Editor/HashUtil.cs.meta | 11 + .../Editor/HybridCLR.Editor.asmdef | 18 + .../Editor/HybridCLR.Editor.asmdef.meta | 7 + .../Editor/Il2CppDef.meta | 8 + .../Editor/Il2CppDef/Il2CppDefGenerator.cs | 86 ++ .../Il2CppDef/Il2CppDefGenerator.cs.meta | 11 + .../Editor/Installer.meta | 8 + .../Editor/Installer/BashUtil.cs | 143 +++ .../Editor/Installer/BashUtil.cs.meta | 11 + .../Editor/Installer/InstallerController.cs | 270 ++++++ .../Installer/InstallerController.cs.meta | 11 + .../Editor/Installer/InstallerWindow.cs | 113 +++ .../Editor/Installer/InstallerWindow.cs.meta | 11 + .../Editor/Link.meta | 8 + .../Editor/Link/Analyzer.cs | 47 + .../Editor/Link/Analyzer.cs.meta | 11 + .../Editor/Link/LinkXmlWriter.cs | 47 + .../Editor/Link/LinkXmlWriter.cs.meta | 11 + .../Editor/Meta.meta | 8 + .../Editor/Meta/AssemblyCache.cs | 20 + .../Editor/Meta/AssemblyCache.cs.meta | 11 + .../Editor/Meta/AssemblyCacheBase.cs | 107 +++ .../Editor/Meta/AssemblyCacheBase.cs.meta | 11 + .../Meta/AssemblyReferenceDeepCollector.cs | 50 + .../AssemblyReferenceDeepCollector.cs.meta | 11 + .../Editor/Meta/AssemblyResolverBase.cs | 33 + .../Editor/Meta/AssemblyResolverBase.cs.meta | 11 + .../Editor/Meta/CombinedAssemblyResolver.cs | 33 + .../Meta/CombinedAssemblyResolver.cs.meta | 11 + .../Editor/Meta/FixedSetAssemblyResolver.cs | 37 + .../Meta/FixedSetAssemblyResolver.cs.meta | 11 + .../Editor/Meta/GenericArgumentContext.cs | 104 ++ .../Meta/GenericArgumentContext.cs.meta | 11 + .../Editor/Meta/GenericClass.cs | 74 ++ .../Editor/Meta/GenericClass.cs.meta | 11 + .../Editor/Meta/GenericMethod.cs | 109 +++ .../Editor/Meta/GenericMethod.cs.meta | 11 + .../Editor/Meta/IAssemblyResolver.cs | 13 + .../Editor/Meta/IAssemblyResolver.cs.meta | 11 + .../Editor/Meta/MetaUtil.cs | 193 ++++ .../Editor/Meta/MetaUtil.cs.meta | 11 + .../Editor/Meta/MethodReferenceAnalyzer.cs | 79 ++ .../Meta/MethodReferenceAnalyzer.cs.meta | 11 + .../Editor/Meta/PathAssemblyResolver.cs | 35 + .../Editor/Meta/PathAssemblyResolver.cs.meta | 11 + .../Editor/MethodBridge.meta | 8 + .../Editor/MethodBridge/Analyzer.cs | 204 ++++ .../Editor/MethodBridge/Analyzer.cs.meta | 11 + .../Editor/MethodBridge/Generator.cs | 828 ++++++++++++++++ .../Editor/MethodBridge/Generator.cs.meta | 11 + .../Editor/ReversePInvokeWrap.meta | 8 + .../Editor/ReversePInvokeWrap/Analyzer.cs | 108 +++ .../ReversePInvokeWrap/Analyzer.cs.meta | 11 + .../Editor/ReversePInvokeWrap/Generator.cs | 59 ++ .../ReversePInvokeWrap/Generator.cs.meta | 11 + .../Editor/Settings.meta | 8 + .../Editor/Settings/EditorStatusWatcher.cs | 32 + .../Settings/EditorStatusWatcher.cs.meta | 11 + .../Settings/HybridCLRSettingProvider.cs | 178 ++++ .../Settings/HybridCLRSettingProvider.cs.meta | 11 + .../Editor/Settings/HybridCLRSettings.cs | 54 ++ .../Editor/Settings/HybridCLRSettings.cs.meta | 11 + .../Editor/Settings/MenuProvider.cs | 39 + .../Editor/Settings/MenuProvider.cs.meta | 11 + .../Editor/Settings/ScriptableSignleton.cs | 89 ++ .../Settings/ScriptableSignleton.cs.meta | 11 + .../Editor/Settings/SettingsPresetReceiver.cs | 39 + .../Settings/SettingsPresetReceiver.cs.meta | 11 + .../Editor/SettingsUtil.cs | 115 +++ .../Editor/SettingsUtil.cs.meta | 11 + .../Editor/Template.meta | 8 + .../Editor/Template/FileRegionReplace.cs | 74 ++ .../Editor/Template/FileRegionReplace.cs.meta | 11 + .../com.code-philosophy.hybridclr/LICENSE | 21 + .../LICENSE.meta | 7 + .../Plugins.meta | 8 + .../Plugins/dnlib.dll | Bin 0 -> 1162752 bytes .../Plugins/dnlib.dll.meta | 87 ++ .../com.code-philosophy.hybridclr/README.md | 91 ++ .../README.md.meta | 7 + .../README_zh.md | 91 ++ .../README_zh.md.meta | 7 + .../RELEASELOG.md | 436 +++++++++ .../RELEASELOG.md.meta | 7 + .../Runtime.meta | 8 + .../Runtime/HomologousImageMode.cs | 10 + .../Runtime/HomologousImageMode.cs.meta | 11 + .../Runtime/HybridCLR.Runtime.asmdef | 14 + .../Runtime/HybridCLR.Runtime.asmdef.meta | 7 + .../Runtime/LoadImageErrorCode.cs | 15 + .../Runtime/LoadImageErrorCode.cs.meta | 11 + ...eversePInvokeWrapperGenerationAttribute.cs | 19 + ...ePInvokeWrapperGenerationAttribute.cs.meta | 11 + .../Runtime/RuntimeApi.cs | 95 ++ .../Runtime/RuntimeApi.cs.meta | 11 + .../Runtime/RuntimeOptionId.cs | 9 + .../Runtime/RuntimeOptionId.cs.meta | 11 + .../package.json | 22 + .../package.json.meta | 7 + Packages/manifest.json | 12 +- Packages/packages-lock.json | 25 + ProjectSettings/PackageManagerSettings.asset | 14 +- 207 files changed, 10338 insertions(+), 108 deletions(-) delete mode 100644 Assets/00.StaryEvo/Runtime/Utility/RemoteServices.cs delete mode 100644 Assets/00.StaryEvo/Runtime/Utility/RemoteServices.cs.meta delete mode 100644 Assets/00.StaryEvo/Runtime/Utility/RemoteServicesWithAuth.cs delete mode 100644 Assets/00.StaryEvo/Runtime/Utility/RemoteServicesWithAuth.cs.meta create mode 100644 Assets/00.StaryEvo/Runtime/Utility/UnityAsyncExtensions.cs create mode 100644 Assets/00.StaryEvo/Runtime/Utility/UnityAsyncExtensions.cs.meta create mode 100644 Assets/00.StaryEvo/~Samples.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Data~/NetStandard/netstandard2.0.dll create mode 100644 Packages/com.code-philosophy.hybridclr/Data~/NetStandard/netstandard2.1.dll create mode 100644 Packages/com.code-philosophy.hybridclr/Data~/hybridclr_version.json create mode 100644 Packages/com.code-philosophy.hybridclr/Editor.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/CodePatcher.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/CodePatcher.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookPool.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookPool.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils_OSX.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils_OSX.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/LDasm.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/LDasm.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/MethodHook.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/MethodHook.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/Utils.cpp create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/Utils.cpp.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/build_libMonoHookUtils_OSX.dylib.sh create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/build_libMonoHookUtils_OSX.dylib.sh.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/silicon.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/silicon/libMonoHookUtils_OSX.dylib create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/silicon/libMonoHookUtils_OSX.dylib.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/x86_64.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/x86_64/libMonoHookUtils_OSX.dylib create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/x86_64/libMonoHookUtils_OSX.dylib.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/ABIUtil.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/ABIUtil.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/MethodDesc.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/MethodDesc.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamInfo.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamInfo.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamOrReturnType.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamOrReturnType.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/PlatformABI.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/PlatformABI.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeCreator.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeCreator.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeInfo.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeInfo.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/ValueTypeSizeAligmentCalculator.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ABI/ValueTypeSizeAligmentCalculator.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/AOT.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/AOT/Analyzer.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/AOT/Analyzer.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/AOT/ConstraintContext.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/AOT/ConstraintContext.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/AOT/GenericReferenceWriter.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/AOT/GenericReferenceWriter.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CheckSettings.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CheckSettings.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/FilterHotFixAssemblies.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/FilterHotFixAssemblies.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/MsvcStdextWorkaround.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/MsvcStdextWorkaround.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/PatchScriptingAssemblyList.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/PatchScriptingAssemblyList.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/ScriptingAssembliesJsonPatcher.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/ScriptingAssembliesJsonPatcher.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/AOTReferenceGeneratorCommand.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/AOTReferenceGeneratorCommand.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/CompileDllCommand.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/CompileDllCommand.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/Il2CppDefGeneratorCommand.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/Il2CppDefGeneratorCommand.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/LinkGeneratorCommand.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/LinkGeneratorCommand.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/MethodBridgeGeneratorCommand.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/MethodBridgeGeneratorCommand.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/PrebuildCommand.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/PrebuildCommand.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/StripAOTDllCommand.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Commands/StripAOTDllCommand.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/HashUtil.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/HashUtil.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/HybridCLR.Editor.asmdef create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/HybridCLR.Editor.asmdef.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Il2CppDef.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Il2CppDef/Il2CppDefGenerator.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Il2CppDef/Il2CppDefGenerator.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Installer.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Installer/BashUtil.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Installer/BashUtil.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerController.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerController.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerWindow.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerWindow.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Link.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Link/Analyzer.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Link/Analyzer.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Link/LinkXmlWriter.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Link/LinkXmlWriter.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCache.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCache.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCacheBase.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCacheBase.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyReferenceDeepCollector.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyReferenceDeepCollector.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyResolverBase.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyResolverBase.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/CombinedAssemblyResolver.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/CombinedAssemblyResolver.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/FixedSetAssemblyResolver.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/FixedSetAssemblyResolver.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericArgumentContext.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericArgumentContext.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericClass.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericClass.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericMethod.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericMethod.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/IAssemblyResolver.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/IAssemblyResolver.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/MetaUtil.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/MetaUtil.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/MethodReferenceAnalyzer.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/MethodReferenceAnalyzer.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/PathAssemblyResolver.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Meta/PathAssemblyResolver.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/MethodBridge.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Analyzer.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Analyzer.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Generator.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Generator.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Analyzer.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Analyzer.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Generator.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Generator.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings/EditorStatusWatcher.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings/EditorStatusWatcher.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettingProvider.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettingProvider.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettings.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettings.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings/MenuProvider.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings/MenuProvider.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings/ScriptableSignleton.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings/ScriptableSignleton.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings/SettingsPresetReceiver.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Settings/SettingsPresetReceiver.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/SettingsUtil.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/SettingsUtil.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Template.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Template/FileRegionReplace.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Editor/Template/FileRegionReplace.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/LICENSE create mode 100644 Packages/com.code-philosophy.hybridclr/LICENSE.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Plugins.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Plugins/dnlib.dll create mode 100644 Packages/com.code-philosophy.hybridclr/Plugins/dnlib.dll.meta create mode 100644 Packages/com.code-philosophy.hybridclr/README.md create mode 100644 Packages/com.code-philosophy.hybridclr/README.md.meta create mode 100644 Packages/com.code-philosophy.hybridclr/README_zh.md create mode 100644 Packages/com.code-philosophy.hybridclr/README_zh.md.meta create mode 100644 Packages/com.code-philosophy.hybridclr/RELEASELOG.md create mode 100644 Packages/com.code-philosophy.hybridclr/RELEASELOG.md.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime/HomologousImageMode.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime/HomologousImageMode.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime/HybridCLR.Runtime.asmdef create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime/HybridCLR.Runtime.asmdef.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime/LoadImageErrorCode.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime/LoadImageErrorCode.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime/ReversePInvokeWrapperGenerationAttribute.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime/ReversePInvokeWrapperGenerationAttribute.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime/RuntimeApi.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime/RuntimeApi.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime/RuntimeOptionId.cs create mode 100644 Packages/com.code-philosophy.hybridclr/Runtime/RuntimeOptionId.cs.meta create mode 100644 Packages/com.code-philosophy.hybridclr/package.json create mode 100644 Packages/com.code-philosophy.hybridclr/package.json.meta diff --git a/Assets/00.StaryEvo/Runtime/Tool/EventKit/EventSystem/EnumEventSystem.cs b/Assets/00.StaryEvo/Runtime/Tool/EventKit/EventSystem/EnumEventSystem.cs index 66482f1..77a89a4 100644 --- a/Assets/00.StaryEvo/Runtime/Tool/EventKit/EventSystem/EnumEventSystem.cs +++ b/Assets/00.StaryEvo/Runtime/Tool/EventKit/EventSystem/EnumEventSystem.cs @@ -8,7 +8,7 @@ namespace Stary.Evo { public static readonly EnumEventSystem Global = new EnumEventSystem(); - private readonly Dictionary mEvents = new Dictionary(50); + private readonly Dictionary mEvents = new Dictionary(50); public EnumEventSystem(){} @@ -16,7 +16,7 @@ namespace Stary.Evo public IUnRegister Register(T key, Action onEvent)where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { var easyEvent = e.As(); @@ -31,7 +31,7 @@ namespace Stary.Evo } public IUnRegister Register(T key, Action onEvent)where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { var easyEvent = e.As>(); @@ -46,7 +46,7 @@ namespace Stary.Evo } public IUnRegister Register(T key, Action onEvent)where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { var easyEvent = e.As>(); @@ -61,7 +61,7 @@ namespace Stary.Evo } public IUnRegister Register(T key, Action onEvent) where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { @@ -77,7 +77,7 @@ namespace Stary.Evo } public IUnRegister Register(T key, Action onEvent) where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { @@ -93,7 +93,7 @@ namespace Stary.Evo } public void UnRegister(T key, Action onEvent) where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { @@ -102,7 +102,7 @@ namespace Stary.Evo } public void UnRegister(T key, Action onEvent) where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { @@ -111,7 +111,7 @@ namespace Stary.Evo } public void UnRegister(T key, Action onEvent) where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { @@ -120,7 +120,7 @@ namespace Stary.Evo } public void UnRegister(T key, Action onEvent) where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { @@ -129,7 +129,7 @@ namespace Stary.Evo } public void UnRegister(T key, Action onEvent) where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { @@ -145,7 +145,7 @@ namespace Stary.Evo } public void Send(T key) where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { @@ -154,7 +154,7 @@ namespace Stary.Evo } public void Send(T key, T1 t1) where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { @@ -163,7 +163,7 @@ namespace Stary.Evo } public void Send(T key, T1 t1,T2 t2) where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { @@ -172,7 +172,7 @@ namespace Stary.Evo } public void Send(T key, T1 t1,T2 t2 ,T3 t3) where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { @@ -181,11 +181,11 @@ namespace Stary.Evo } public void Send(T key, params object[] args) where T : IConvertible { - var kv = key.ToInt32(null); + var kv = typeof(T).ToString()+ key.ToInt32(null); if (mEvents.TryGetValue(kv, out var e)) { - e.As>().Trigger(kv,args); + e.As>().Trigger(kv,args); } } diff --git a/Assets/00.StaryEvo/Runtime/Utility/RemoteServices.cs b/Assets/00.StaryEvo/Runtime/Utility/RemoteServices.cs deleted file mode 100644 index 7494e70..0000000 --- a/Assets/00.StaryEvo/Runtime/Utility/RemoteServices.cs +++ /dev/null @@ -1,24 +0,0 @@ -using YooAsset; - -namespace Stary.Evo -{ - public class RemoteServices : IRemoteServices - { - private readonly string _defaultHostServer; - private readonly string _fallbackHostServer; - - public RemoteServices(string defaultHostServer, string fallbackHostServer) - { - _defaultHostServer = defaultHostServer; - _fallbackHostServer = fallbackHostServer; - } - string IRemoteServices.GetRemoteMainURL(string fileName) - { - return $"{_defaultHostServer}/{fileName}"; - } - string IRemoteServices.GetRemoteFallbackURL(string fileName) - { - return $"{_fallbackHostServer}/{fileName}"; - } - } -} \ No newline at end of file diff --git a/Assets/00.StaryEvo/Runtime/Utility/RemoteServices.cs.meta b/Assets/00.StaryEvo/Runtime/Utility/RemoteServices.cs.meta deleted file mode 100644 index c1c1d57..0000000 --- a/Assets/00.StaryEvo/Runtime/Utility/RemoteServices.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 24f14ead8b7e46eaa0eddd6e68db8d56 -timeCreated: 1741248220 \ No newline at end of file diff --git a/Assets/00.StaryEvo/Runtime/Utility/RemoteServicesWithAuth.cs b/Assets/00.StaryEvo/Runtime/Utility/RemoteServicesWithAuth.cs deleted file mode 100644 index 5de6214..0000000 --- a/Assets/00.StaryEvo/Runtime/Utility/RemoteServicesWithAuth.cs +++ /dev/null @@ -1,51 +0,0 @@ -using YooAsset; -using System.Collections; -using Stary.Evo; -using UnityEngine.Networking; - -public class RemoteServicesWithAuth : IRemoteServices -{ - private readonly string _defaultHostServer; - private readonly string _fallbackHostServer; - private string _authToken; - private string _authServiceUrl; - - public string CurrentToken { get; private set; } - - public RemoteServicesWithAuth(string defaultHostServer, - string fallbackHostServer, - string authToken, - string authServiceUrl) - { - _defaultHostServer = defaultHostServer; - _fallbackHostServer = fallbackHostServer; - _authToken = authToken; - _authServiceUrl = authServiceUrl; - RefreshToken(); - } - - private void RefreshToken() - { - // 这里实现具体的token刷新逻辑 - CurrentToken = _authToken; // 简单示例直接使用初始token - // 实际项目应该通过authServiceUrl获取新token - } - - string IRemoteServices.GetRemoteMainURL(string fileName) - { - // 在原始URL后附加鉴权参数 - return $"{_defaultHostServer}/{fileName}?token={CurrentToken}"; - } - - public string GetRemoteFallbackURL(string fileName) - { - return $"{_fallbackHostServer}/{fileName}?token={CurrentToken}"; - } - - // UnityWebRequest CreateRequest(string url) - // { - // var request = base.CreateRequest(url); - // request.SetRequestHeader("Authorization", $"Bearer {CurrentToken}"); - // return request; - // } -} diff --git a/Assets/00.StaryEvo/Runtime/Utility/RemoteServicesWithAuth.cs.meta b/Assets/00.StaryEvo/Runtime/Utility/RemoteServicesWithAuth.cs.meta deleted file mode 100644 index cdc26a3..0000000 --- a/Assets/00.StaryEvo/Runtime/Utility/RemoteServicesWithAuth.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 6dc545bfe9be45789ff05152e3679e20 -timeCreated: 1741319247 \ No newline at end of file diff --git a/Assets/00.StaryEvo/Runtime/Utility/UnityAsyncExtensions.cs b/Assets/00.StaryEvo/Runtime/Utility/UnityAsyncExtensions.cs new file mode 100644 index 0000000..260f773 --- /dev/null +++ b/Assets/00.StaryEvo/Runtime/Utility/UnityAsyncExtensions.cs @@ -0,0 +1,67 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +using System; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using UnityEngine; +#if ENABLE_UNITYWEBREQUEST && (!UNITY_2019_1_OR_NEWER || UNITASK_WEBREQUEST_SUPPORT) +using UnityEngine.Networking; +#endif + +namespace Stary.Evo +{ + public static partial class UnityAsyncExtensions + { + + +#if !UNITY_2023_1_OR_NEWER + // from Unity2023.1.0a15, AsyncOperationAwaitableExtensions.GetAwaiter is defined in UnityEngine. + public static AsyncOperationAwaiter GetAwaiter(this AsyncOperation asyncOperation) + { + return new AsyncOperationAwaiter(asyncOperation); + } +#endif + + + public struct AsyncOperationAwaiter : ICriticalNotifyCompletion + { + AsyncOperation asyncOperation; + Action continuationAction; + + public AsyncOperationAwaiter(AsyncOperation asyncOperation) + { + this.asyncOperation = asyncOperation; + this.continuationAction = null; + } + + public bool IsCompleted => asyncOperation.isDone; + + public void GetResult() + { + if (continuationAction != null) + { + asyncOperation.completed -= continuationAction; + continuationAction = null; + asyncOperation = null; + } + else + { + asyncOperation = null; + } + } + + public void OnCompleted(Action continuation) + { + UnsafeOnCompleted(continuation); + } + + public void UnsafeOnCompleted(Action continuation) + { + + } + } + + + } +} \ No newline at end of file diff --git a/Assets/00.StaryEvo/Runtime/Utility/UnityAsyncExtensions.cs.meta b/Assets/00.StaryEvo/Runtime/Utility/UnityAsyncExtensions.cs.meta new file mode 100644 index 0000000..3e053f9 --- /dev/null +++ b/Assets/00.StaryEvo/Runtime/Utility/UnityAsyncExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a42a4edb452e470b87e698b7d7b7db4a +timeCreated: 1743403227 \ No newline at end of file diff --git a/Assets/00.StaryEvo/Runtime/Utility/WebRequestSystem.cs b/Assets/00.StaryEvo/Runtime/Utility/WebRequestSystem.cs index f2eddba..bd6bfa7 100644 --- a/Assets/00.StaryEvo/Runtime/Utility/WebRequestSystem.cs +++ b/Assets/00.StaryEvo/Runtime/Utility/WebRequestSystem.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using Cysharp.Threading.Tasks; +using System.Threading.Tasks; using UnityEngine; using UnityEngine.Networking; @@ -8,8 +8,8 @@ namespace Stary.Evo { public interface IWebRequestSystem { - UniTask Post(string url, string postData); - UniTask Get(string url, string token=null); + Task Post(string url, string postData); + Task Get(string url, string token=null); } @@ -21,7 +21,7 @@ namespace Stary.Evo /// 获取Token值的服务URL地址(很重要) /// 传入请求的参数,此处参数为JOSN格式 /// - public async UniTask Post(string url, string postData) + public async Task Post(string url, string postData) { using (UnityWebRequest webRequest = UnityWebRequest.Post(url, postData)) //第二种写法此行注释 { @@ -51,7 +51,7 @@ namespace Stary.Evo /// 请求数据的URL地址 /// token验证的参数,此处为authorization /// - public async UniTask Get(string url, string token=null) + public async Task Get(string url, string token=null) { try { diff --git a/Assets/00.StaryEvo/package.json b/Assets/00.StaryEvo/package.json index 9771a97..5713360 100644 --- a/Assets/00.StaryEvo/package.json +++ b/Assets/00.StaryEvo/package.json @@ -1,6 +1,6 @@ { "name": "com.staryevo.main", - "version": "1.0.0", + "version": "1.0.1", "displayName": "00.StaryEvo", "description": "This is an Framework package", "unity": "2021.3", diff --git a/Assets/00.StaryEvo/~Samples.meta b/Assets/00.StaryEvo/~Samples.meta new file mode 100644 index 0000000..a304446 --- /dev/null +++ b/Assets/00.StaryEvo/~Samples.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 50c0b79ec6a68a24cb577c05cefb670d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Data~/NetStandard/netstandard2.0.dll b/Packages/com.code-philosophy.hybridclr/Data~/NetStandard/netstandard2.0.dll new file mode 100644 index 0000000000000000000000000000000000000000..250cf817385cd5d2ea5cb8e72f00c5f5cab50ee6 GIT binary patch literal 84992 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 D+Hv%0 literal 0 HcmV?d00001 diff --git a/Packages/com.code-philosophy.hybridclr/Data~/hybridclr_version.json b/Packages/com.code-philosophy.hybridclr/Data~/hybridclr_version.json new file mode 100644 index 0000000..6a1e92e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Data~/hybridclr_version.json @@ -0,0 +1,19 @@ +{ + "versions": [ + { + "unity_version":"2020", + "hybridclr" : { "branch":"v4.0.10"}, + "il2cpp_plus": { "branch":"v2020-4.0.8"} + }, + { + "unity_version":"2021", + "hybridclr" : { "branch":"v4.0.10"}, + "il2cpp_plus": { "branch":"v2021-4.0.8"} + }, + { + "unity_version":"2022", + "hybridclr" : { "branch":"v4.0.10"}, + "il2cpp_plus": { "branch":"v2022-4.0.8"} + } + ] +} \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Editor.meta b/Packages/com.code-philosophy.hybridclr/Editor.meta new file mode 100644 index 0000000..003696a --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c3fabc41cf17c444995fc01a76c5dbe6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds.meta new file mode 100644 index 0000000..5f5d553 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: daa1e09af240aae4da0741843cb2b3f3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook.meta new file mode 100644 index 0000000..4fab614 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 13fe0cab0b357464d889de45c8d98850 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/CodePatcher.cs b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/CodePatcher.cs new file mode 100644 index 0000000..6ec2fa7 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/CodePatcher.cs @@ -0,0 +1,320 @@ +using DotNetDetour; +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using System.Linq; + +namespace MonoHook +{ + public unsafe abstract class CodePatcher + { + public bool isValid { get; protected set; } + + protected void* _pTarget, _pReplace, _pProxy; + protected int _jmpCodeSize; + protected byte[] _targetHeaderBackup; + + public CodePatcher(IntPtr target, IntPtr replace, IntPtr proxy, int jmpCodeSize) + { + _pTarget = target.ToPointer(); + _pReplace = replace.ToPointer(); + _pProxy = proxy.ToPointer(); + _jmpCodeSize = jmpCodeSize; + } + + public void ApplyPatch() + { + BackupHeader(); + EnableAddrModifiable(); + PatchTargetMethod(); + PatchProxyMethod(); + FlushICache(); + } + + public void RemovePatch() + { + if (_targetHeaderBackup == null) + return; + + EnableAddrModifiable(); + RestoreHeader(); + FlushICache(); + } + + protected void BackupHeader() + { + if (_targetHeaderBackup != null) + return; + + uint requireSize = LDasm.SizeofMinNumByte(_pTarget, _jmpCodeSize); + _targetHeaderBackup = new byte[requireSize]; + + fixed (void* ptr = _targetHeaderBackup) + HookUtils.MemCpy(ptr, _pTarget, _targetHeaderBackup.Length); + } + + protected void RestoreHeader() + { + if (_targetHeaderBackup == null) + return; + + HookUtils.MemCpy_Jit(_pTarget, _targetHeaderBackup); + } + + protected void PatchTargetMethod() + { + byte[] buff = GenJmpCode(_pTarget, _pReplace); + HookUtils.MemCpy_Jit(_pTarget, buff); + } + protected void PatchProxyMethod() + { + if (_pProxy == null) + return; + + // copy target's code to proxy + HookUtils.MemCpy_Jit(_pProxy, _targetHeaderBackup); + + // jmp to target's new position + long jmpFrom = (long)_pProxy + _targetHeaderBackup.Length; + long jmpTo = (long)_pTarget + _targetHeaderBackup.Length; + + byte[] buff = GenJmpCode((void*)jmpFrom, (void*)jmpTo); + HookUtils.MemCpy_Jit((void*)jmpFrom, buff); + } + + protected void FlushICache() + { + HookUtils.FlushICache(_pTarget, _targetHeaderBackup.Length); + HookUtils.FlushICache(_pProxy, _targetHeaderBackup.Length * 2); + } + protected abstract byte[] GenJmpCode(void* jmpFrom, void* jmpTo); + +#if ENABLE_HOOK_DEBUG + protected string PrintAddrs() + { + if (IntPtr.Size == 4) + return $"target:0x{(uint)_pTarget:x}, replace:0x{(uint)_pReplace:x}, proxy:0x{(uint)_pProxy:x}"; + else + return $"target:0x{(ulong)_pTarget:x}, replace:0x{(ulong)_pReplace:x}, proxy:0x{(ulong)_pProxy:x}"; + } +#endif + + private void EnableAddrModifiable() + { + HookUtils.SetAddrFlagsToRWX(new IntPtr(_pTarget), _targetHeaderBackup.Length); + HookUtils.SetAddrFlagsToRWX(new IntPtr(_pProxy), _targetHeaderBackup.Length + _jmpCodeSize); + } + } + + public unsafe class CodePatcher_x86 : CodePatcher + { + protected static readonly byte[] s_jmpCode = new byte[] // 5 bytes + { + 0xE9, 0x00, 0x00, 0x00, 0x00, // jmp $val ; $val = $dst - $src - 5 + }; + + public CodePatcher_x86(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length) { } + + protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo) + { + byte[] ret = new byte[s_jmpCode.Length]; + int val = (int)jmpTo - (int)jmpFrom - 5; + + fixed(void * p = &ret[0]) + { + byte* ptr = (byte*)p; + *ptr = 0xE9; + int* pOffset = (int*)(ptr + 1); + *pOffset = val; + } + return ret; + } + } + + /// + /// x64下2G 内的跳转 + /// + public unsafe class CodePatcher_x64_near : CodePatcher_x86 // x64_near pathcer code is same to x86 + { + public CodePatcher_x64_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy) { } + } + + /// + /// x64下距离超过2G的跳转 + /// + public unsafe class CodePatcher_x64_far : CodePatcher + { + protected static readonly byte[] s_jmpCode = new byte[] // 12 bytes + { + // 由于 rax 会被函数作为返回值修改,并且不会被做为参数使用,因此修改是安全的 + 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, + 0x50, // push rax + 0xC3 // ret + }; + + //protected static readonly byte[] s_jmpCode2 = new byte[] // 14 bytes + //{ + // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // + // 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF // jmp [rip - 0xe] + //}; + + public CodePatcher_x64_far(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length) { } + protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo) + { + byte[] ret = new byte[s_jmpCode.Length]; + + fixed (void* p = &ret[0]) + { + byte* ptr = (byte*)p; + *ptr++ = 0x48; + *ptr++ = 0xB8; + *(long*)ptr = (long)jmpTo; + ptr += 8; + *ptr++ = 0x50; + *ptr++ = 0xC3; + } + return ret; + } + } + + public unsafe class CodePatcher_arm32_near : CodePatcher + { + private static readonly byte[] s_jmpCode = new byte[] // 4 bytes + { + 0x00, 0x00, 0x00, 0xEA, // B $val ; $val = (($dst - $src) / 4 - 2) & 0x1FFFFFF + }; + + public CodePatcher_arm32_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length) + { + if (Math.Abs((long)target - (long)replace) >= ((1 << 25) - 1)) + throw new ArgumentException("address offset of target and replace must less than ((1 << 25) - 1)"); + +#if ENABLE_HOOK_DEBUG + Debug.Log($"CodePatcher_arm32_near: {PrintAddrs()}"); +#endif + } + + protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo) + { + byte[] ret = new byte[s_jmpCode.Length]; + int val = ((int)jmpTo - (int)jmpFrom) / 4 - 2; + + fixed (void* p = &ret[0]) + { + byte* ptr = (byte*)p; + *ptr++ = (byte)val; + *ptr++ = (byte)(val >> 8); + *ptr++ = (byte)(val >> 16); + *ptr++ = 0xEA; + } + return ret; + } + } + + public unsafe class CodePatcher_arm32_far : CodePatcher + { + private static readonly byte[] s_jmpCode = new byte[] // 8 bytes + { + 0x04, 0xF0, 0x1F, 0xE5, // LDR PC, [PC, #-4] + 0x00, 0x00, 0x00, 0x00, // $val + }; + + public CodePatcher_arm32_far(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length) + { + if (Math.Abs((long)target - (long)replace) < ((1 << 25) - 1)) + throw new ArgumentException("address offset of target and replace must larger than ((1 << 25) - 1), please use InstructionModifier_arm32_near instead"); + +#if ENABLE_HOOK_DEBUG + Debug.Log($"CodePatcher_arm32_far: {PrintAddrs()}"); +#endif + } + + protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo) + { + byte[] ret = new byte[s_jmpCode.Length]; + + fixed (void* p = &ret[0]) + { + uint* ptr = (uint*)p; + *ptr++ = 0xE51FF004; + *ptr = (uint)jmpTo; + } + return ret; + } + } + + /// + /// arm64 下 ±128MB 范围内的跳转 + /// + public unsafe class CodePatcher_arm64_near : CodePatcher + { + private static readonly byte[] s_jmpCode = new byte[] // 4 bytes + { + /* + * from 0x14 to 0x17 is B opcode + * offset bits is 26 + * https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/B--Branch- + */ + 0x00, 0x00, 0x00, 0x14, // B $val ; $val = (($dst - $src)/4) & 7FFFFFF + }; + + public CodePatcher_arm64_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length) + { + if (Math.Abs((long)target - (long)replace) >= ((1 << 26) - 1) * 4) + throw new ArgumentException("address offset of target and replace must less than (1 << 26) - 1) * 4"); + +#if ENABLE_HOOK_DEBUG + Debug.Log($"CodePatcher_arm64: {PrintAddrs()}"); +#endif + } + + protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo) + { + byte[] ret = new byte[s_jmpCode.Length]; + int val = (int)((long)jmpTo - (long)jmpFrom) / 4; + + fixed (void* p = &ret[0]) + { + byte* ptr = (byte*)p; + *ptr++ = (byte)val; + *ptr++ = (byte)(val >> 8); + *ptr++ = (byte)(val >> 16); + + byte last = (byte)(val >> 24); + last &= 0b11; + last |= 0x14; + + *ptr = last; + } + return ret; + } + } + + /// + /// arm64 远距离跳转 + /// + public unsafe class CodePatcher_arm64_far : CodePatcher + { + private static readonly byte[] s_jmpCode = new byte[] // 20 bytes(字节数过多,太危险了,不建议使用) + { + /* + * ADR: https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/ADR--Form-PC-relative-address- + * BR: https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/BR--Branch-to-Register- + */ + 0x6A, 0x00, 0x00, 0x10, // ADR X10, #C + 0x4A, 0x01, 0x40, 0xF9, // LDR X10, [X10,#0] + 0x40, 0x01, 0x1F, 0xD6, // BR X10 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // $dst + }; + + public CodePatcher_arm64_far(IntPtr target, IntPtr replace, IntPtr proxy, int jmpCodeSize) : base(target, replace, proxy, jmpCodeSize) + { + } + + protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/CodePatcher.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/CodePatcher.cs.meta new file mode 100644 index 0000000..f745350 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/CodePatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 97cc0d26f72fc4148b8370b2252d1585 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookPool.cs b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookPool.cs new file mode 100644 index 0000000..34a0599 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookPool.cs @@ -0,0 +1,74 @@ +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using System.Linq; +using System.IO; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace MonoHook +{ + /// + /// Hook 池,防止重复 Hook + /// + public static class HookPool + { + private static Dictionary _hooks = new Dictionary(); + + public static void AddHook(MethodBase method, MethodHook hook) + { + MethodHook preHook; + if (_hooks.TryGetValue(method, out preHook)) + { + preHook.Uninstall(); + _hooks[method] = hook; + } + else + _hooks.Add(method, hook); + } + + public static MethodHook GetHook(MethodBase method) + { + if (method == null) return null; + + MethodHook hook; + if (_hooks.TryGetValue(method, out hook)) + return hook; + return null; + } + + public static void RemoveHooker(MethodBase method) + { + if (method == null) return; + + _hooks.Remove(method); + } + + public static void UninstallAll() + { + var list = _hooks.Values.ToList(); + foreach (var hook in list) + hook.Uninstall(); + + _hooks.Clear(); + } + + public static void UninstallByTag(string tag) + { + var list = _hooks.Values.ToList(); + foreach (var hook in list) + { + if(hook.tag == tag) + hook.Uninstall(); + } + } + + public static List GetAllHooks() + { + return _hooks.Values.ToList(); + } + } + +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookPool.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookPool.cs.meta new file mode 100644 index 0000000..7503859 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6b7421e47f0ae1e4ebb72bf18d1d7d48 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils.cs b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils.cs new file mode 100644 index 0000000..7acd8c9 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils.cs @@ -0,0 +1,272 @@ +#if !(UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX) +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using UnityEngine; + +namespace MonoHook +{ + public static unsafe class HookUtils + { + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + delegate void DelegateFlushICache(void* code, int size); // delegate * unmanaged[Cdecl] native_flush_cache_fun_ptr; // unsupported at C# 8.0 + + static DelegateFlushICache flush_icache; + private static readonly long _Pagesize; + + static HookUtils() + { + PropertyInfo p_SystemPageSize = typeof(Environment).GetProperty("SystemPageSize"); + if (p_SystemPageSize == null) + throw new NotSupportedException("Unsupported runtime"); + _Pagesize = (int)p_SystemPageSize.GetValue(null, new object[0]); + SetupFlushICacheFunc(); + } + + public static void MemCpy(void* pDst, void* pSrc, int len) + { + byte* pDst_ = (byte*)pDst; + byte* pSrc_ = (byte*)pSrc; + + for (int i = 0; i < len; i++) + *pDst_++ = *pSrc_++; + } + + public static void MemCpy_Jit(void* pDst, byte[] src) + { + fixed (void* p = &src[0]) + { + MemCpy(pDst, p, src.Length); + } + } + + /// + /// set flags of address to `read write execute` + /// + public static void SetAddrFlagsToRWX(IntPtr ptr, int size) + { + if (ptr == IntPtr.Zero) + return; + +#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN + uint oldProtect; + bool ret = VirtualProtect(ptr, (uint)size, Protection.PAGE_EXECUTE_READWRITE, out oldProtect); + UnityEngine.Debug.Assert(ret); +#else + SetMemPerms(ptr,(ulong)size,MmapProts.PROT_READ | MmapProts.PROT_WRITE | MmapProts.PROT_EXEC); +#endif + } + + public static void FlushICache(void* code, int size) + { + if (code == null) + return; + + flush_icache?.Invoke(code, size); + +#if ENABLE_HOOK_DEBUG + Debug.Log($"flush icache at 0x{(IntPtr.Size == 4 ? (uint)code : (ulong)code):x}, size:{size}"); +#endif + } + + public static KeyValuePair GetPageAlignedAddr(long code, int size) + { + long pagesize = _Pagesize; + long startPage = (code) & ~(pagesize - 1); + long endPage = (code + size + pagesize - 1) & ~(pagesize - 1); + return new KeyValuePair(startPage, endPage); + } + + + const int PRINT_SPLIT = 4; + const int PRINT_COL_SIZE = PRINT_SPLIT * 4; + public static string HexToString(void* ptr, int size, int offset = 0) + { + Func formatAddr = (IntPtr addr__) => IntPtr.Size == 4 ? $"0x{(uint)addr__:x}" : $"0x{(ulong)addr__:x}"; + + byte* addr = (byte*)ptr; + + StringBuilder sb = new StringBuilder(1024); + sb.AppendLine($"addr:{formatAddr(new IntPtr(addr))}"); + + addr += offset; + size += Math.Abs(offset); + + int count = 0; + while (true) + { + sb.Append($"\r\n{formatAddr(new IntPtr(addr + count))}: "); + for (int i = 1; i < PRINT_COL_SIZE + 1; i++) + { + if (count >= size) + goto END; + + sb.Append($"{*(addr + count):x2}"); + if (i % PRINT_SPLIT == 0) + sb.Append(" "); + + count++; + } + } + END:; + return sb.ToString(); + } + + static void SetupFlushICacheFunc() + { + string processorType = SystemInfo.processorType; + if (processorType.Contains("Intel") || processorType.Contains("AMD")) + return; + + if (IntPtr.Size == 4) + { + // never release, so save GCHandle is unnecessary + s_ptr_flush_icache_arm32 = GCHandle.Alloc(s_flush_icache_arm32, GCHandleType.Pinned).AddrOfPinnedObject().ToPointer(); + SetAddrFlagsToRWX(new IntPtr(s_ptr_flush_icache_arm32), s_flush_icache_arm32.Length); + flush_icache = Marshal.GetDelegateForFunctionPointer(new IntPtr(s_ptr_flush_icache_arm32)); + } + else + { + s_ptr_flush_icache_arm64 = GCHandle.Alloc(s_flush_icache_arm64, GCHandleType.Pinned).AddrOfPinnedObject().ToPointer(); + SetAddrFlagsToRWX(new IntPtr(s_ptr_flush_icache_arm64), s_flush_icache_arm64.Length); + flush_icache = Marshal.GetDelegateForFunctionPointer(new IntPtr(s_ptr_flush_icache_arm64)); + } + +#if ENABLE_HOOK_DEBUG + Debug.Log($"flush_icache delegate is {((flush_icache != null) ? "not " : "")}null"); +#endif + } + + + static void* s_ptr_flush_icache_arm32, s_ptr_flush_icache_arm64; + private static byte[] s_flush_icache_arm32 = new byte[] + { + // void cdecl mono_arch_flush_icache (guint8 *code, gint size) + 0x00, 0x48, 0x2D, 0xE9, // PUSH {R11,LR} + 0x0D, 0xB0, 0xA0, 0xE1, // MOV R11, SP + 0x08, 0xD0, 0x4D, 0xE2, // SUB SP, SP, #8 + 0x04, 0x00, 0x8D, 0xE5, // STR R0, [SP,#8+var_4] + 0x00, 0x10, 0x8D, 0xE5, // STR R1, [SP,#8+var_8] + 0x04, 0x00, 0x9D, 0xE5, // LDR R0, [SP,#8+var_4] + 0x04, 0x10, 0x9D, 0xE5, // LDR R1, [SP,#8+var_4] + 0x00, 0x20, 0x9D, 0xE5, // LDR R2, [SP,#8+var_8] + 0x02, 0x10, 0x81, 0xE0, // ADD R1, R1, R2 + 0x01, 0x00, 0x00, 0xEB, // BL __clear_cache + 0x0B, 0xD0, 0xA0, 0xE1, // MOV SP, R11 + 0x00, 0x88, 0xBD, 0xE8, // POP {R11,PC} + + // __clear_cache ; CODE XREF: j___clear_cache+8↑j + 0x80, 0x00, 0x2D, 0xE9, // PUSH { R7 } + 0x02, 0x70, 0x00, 0xE3, 0x0F, 0x70, 0x40, 0xE3, // MOV R7, #0xF0002 + 0x00, 0x20, 0xA0, 0xE3, // MOV R2, #0 + 0x00, 0x00, 0x00, 0xEF, // SVC 0 + 0x80, 0x00, 0xBD, 0xE8, // POP {R7} + 0x1E, 0xFF, 0x2F, 0xE1, // BX LR + }; + + private static byte[] s_flush_icache_arm64 = new byte[] // X0: code, W1: size + { + // void cdecl mono_arch_flush_icache (guint8 *code, gint size) + 0xFF, 0xC3, 0x00, 0xD1, // SUB SP, SP, #0x30 + 0xE8, 0x03, 0x7E, 0xB2, // MOV X8, #4 + 0xE0, 0x17, 0x00, 0xF9, // STR X0, [SP,#0x30+var_8] + 0xE1, 0x27, 0x00, 0xB9, // STR W1, [SP,#0x30+var_C] + 0xE0, 0x17, 0x40, 0xF9, // LDR X0, [SP,#0x30+var_8] + 0xE9, 0x27, 0x80, 0xB9, // LDRSW X9, [SP,#0x30+var_C] + 0x09, 0x00, 0x09, 0x8B, // ADD X9, X0, X9 + 0xE9, 0x0F, 0x00, 0xF9, // STR X9, [SP,#0x30+var_18] + 0xE8, 0x07, 0x00, 0xF9, // STR X8, [SP,#0x30+var_28] + 0xE8, 0x03, 0x00, 0xF9, // STR X8, [SP,#0x30+var_30] + 0xE8, 0x17, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_8] + 0x08, 0xF5, 0x7E, 0x92, // AND X8, X8, #0xFFFFFFFFFFFFFFFC + 0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20] + + // loc_590 ; CODE XREF: mono_arch_flush_icache(uchar*, int)+58↓j + 0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20] + 0xE9, 0x0F, 0x40, 0xF9, // LDR X9, [SP,#0x30+var_18] + 0x1F, 0x01, 0x09, 0xEB, // CMP X8, X9 + 0xE2, 0x00, 0x00, 0x54, // B.CS loc_5B8 + 0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20] + 0x28, 0x7E, 0x0B, 0xD5, // SYS #3, c7, c14, #1, X8 + 0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20] + 0x08, 0x11, 0x00, 0x91, // ADD X8, X8, #4 + 0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20] + 0xF7, 0xFF, 0xFF, 0x17, // B loc_590 + // ; --------------------------------------------------------------------------- + + // loc_5B8 ; CODE XREF: mono_arch_flush_icache(uchar *, int)+40↑j + 0x9F, 0x3B, 0x03, 0xD5, // DSB ISH + 0xE8, 0x17, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_8] + 0x08, 0xF5, 0x7E, 0x92, // AND X8, X8, #0xFFFFFFFFFFFFFFFC + 0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20] + + // loc_5C8 ; CODE XREF: mono_arch_flush_icache(uchar *, int)+90↓j + 0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20] + 0xE9, 0x0F, 0x40, 0xF9, // LDR X9, [SP,#0x30+var_18] + 0x1F, 0x01, 0x09, 0xEB, // CMP X8, X9 + 0xE2, 0x00, 0x00, 0x54, // B.CS loc_5F0 + 0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20] + 0x28, 0x75, 0x0B, 0xD5, // SYS #3, c7, c5, #1, X8 + 0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20] + 0x08, 0x11, 0x00, 0x91, // ADD X8, X8, #4 + 0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20] + 0xF7, 0xFF, 0xFF, 0x17, // B loc_5C8 + // ; --------------------------------------------------------------------------- + + // loc_5F0 ; CODE XREF: mono_arch_flush_icache(uchar *, int)+78↑j + 0x9F, 0x3B, 0x03, 0xD5, // DSB ISH + 0xDF, 0x3F, 0x03, 0xD5, // ISB + 0xFF, 0xC3, 0x00, 0x91, // ADD SP, SP, #0x30 ; '0' + 0xC0, 0x03, 0x5F, 0xD6, // RET + }; + + +#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN + [Flags] + public enum Protection + { + PAGE_NOACCESS = 0x01, + PAGE_READONLY = 0x02, + PAGE_READWRITE = 0x04, + PAGE_WRITECOPY = 0x08, + PAGE_EXECUTE = 0x10, + PAGE_EXECUTE_READ = 0x20, + PAGE_EXECUTE_READWRITE = 0x40, + PAGE_EXECUTE_WRITECOPY = 0x80, + PAGE_GUARD = 0x100, + PAGE_NOCACHE = 0x200, + PAGE_WRITECOMBINE = 0x400 + } + + [DllImport("kernel32")] + public static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, Protection flNewProtect, out uint lpflOldProtect); + +#else + [Flags] + public enum MmapProts : int { + PROT_READ = 0x1, + PROT_WRITE = 0x2, + PROT_EXEC = 0x4, + PROT_NONE = 0x0, + PROT_GROWSDOWN = 0x01000000, + PROT_GROWSUP = 0x02000000, + } + + [DllImport("libc", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + private static extern int mprotect(IntPtr start, IntPtr len, MmapProts prot); + + public static unsafe void SetMemPerms(IntPtr start, ulong len, MmapProts prot) { + var requiredAddr = GetPageAlignedAddr(start.ToInt64(), (int)len); + long startPage = requiredAddr.Key; + long endPage = requiredAddr.Value; + + if (mprotect((IntPtr) startPage, (IntPtr) (endPage - startPage), prot) != 0) + throw new Exception($"mprotect with prot:{prot} fail!"); + } +#endif + } +} + +#endif \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils.cs.meta new file mode 100644 index 0000000..8ec4cb3 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e84139b42a6164e4c93ce4df1be6dcfb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils_OSX.cs b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils_OSX.cs new file mode 100644 index 0000000..8e4a126 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils_OSX.cs @@ -0,0 +1,102 @@ +#if (UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX) +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using UnityEngine; + +namespace MonoHook +{ + public static unsafe class HookUtils + { + static bool jit_write_protect_supported; + private static readonly long _Pagesize; + + + static HookUtils() + { + jit_write_protect_supported = pthread_jit_write_protect_supported_np() != 0; + + PropertyInfo p_SystemPageSize = typeof(Environment).GetProperty("SystemPageSize"); + if (p_SystemPageSize == null) + throw new NotSupportedException("Unsupported runtime"); + _Pagesize = (int)p_SystemPageSize.GetValue(null, new object[0]); + } + + public static void MemCpy(void* pDst, void* pSrc, int len) + { + byte* pDst_ = (byte*)pDst; + byte* pSrc_ = (byte*)pSrc; + + for (int i = 0; i < len; i++) + *pDst_++ = *pSrc_++; + } + + public static void MemCpy_Jit(void* pDst, byte[] src) + { + fixed(void * p = &src[0]) + { + memcpy_jit(new IntPtr(pDst), new IntPtr(p), src.Length); + } + } + + /// + /// set flags of address to `read write execute` + /// + public static void SetAddrFlagsToRWX(IntPtr ptr, int size) { } + + public static void FlushICache(void* code, int size) { } + + public static KeyValuePair GetPageAlignedAddr(long code, int size) + { + long pagesize = _Pagesize; + long startPage = (code) & ~(pagesize - 1); + long endPage = (code + size + pagesize - 1) & ~(pagesize - 1); + return new KeyValuePair(startPage, endPage); + } + + + const int PRINT_SPLIT = 4; + const int PRINT_COL_SIZE = PRINT_SPLIT * 4; + public static string HexToString(void* ptr, int size, int offset = 0) + { + Func formatAddr = (IntPtr addr__) => IntPtr.Size == 4 ? $"0x{(uint)addr__:x}" : $"0x{(ulong)addr__:x}"; + + byte* addr = (byte*)ptr; + + StringBuilder sb = new StringBuilder(1024); + sb.AppendLine($"addr:{formatAddr(new IntPtr(addr))}"); + + addr += offset; + size += Math.Abs(offset); + + int count = 0; + while (true) + { + sb.Append($"\r\n{formatAddr(new IntPtr(addr + count))}: "); + for (int i = 1; i < PRINT_COL_SIZE + 1; i++) + { + if (count >= size) + goto END; + + sb.Append($"{*(addr + count):x2}"); + if (i % PRINT_SPLIT == 0) + sb.Append(" "); + + count++; + } + } + END:; + return sb.ToString(); + } + + [DllImport("pthread", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + private static extern int pthread_jit_write_protect_supported_np(); + + [DllImport("libMonoHookUtils_OSX", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr memcpy_jit(IntPtr dst, IntPtr src, int len); + } +} + +#endif \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils_OSX.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils_OSX.cs.meta new file mode 100644 index 0000000..6ecee49 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HookUtils_OSX.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: efda6e010e5c6594081c4a62861d469f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks.meta new file mode 100644 index 0000000..8169f8d --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d796fc01daee1964586621890988a5ae +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs new file mode 100644 index 0000000..7e3373d --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs @@ -0,0 +1,67 @@ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using UnityEditor; +using System.Runtime.CompilerServices; +using MonoHook; +using HybridCLR.Editor.BuildProcessors; +using System.IO; + +namespace HybridCLR.MonoHook +{ +#if UNITY_2021_1_OR_NEWER + [InitializeOnLoad] + public class CopyStrippedAOTAssembliesHook + { + private static MethodHook _hook; + + static CopyStrippedAOTAssembliesHook() + { + if (_hook == null) + { + Type type = typeof(UnityEditor.EditorApplication).Assembly.GetType("UnityEditorInternal.AssemblyStripper"); + MethodInfo miTarget = type.GetMethod("StripAssembliesTo", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + + MethodInfo miReplacement = new StripAssembliesDel(OverrideStripAssembliesTo).Method; + MethodInfo miProxy = new StripAssembliesDel(StripAssembliesToProxy).Method; + + _hook = new MethodHook(miTarget, miReplacement, miProxy); + _hook.Install(); + } + } + + private delegate bool StripAssembliesDel(string outputFolder, out string output, out string error, IEnumerable linkXmlFiles, object runInformation); + + private static bool OverrideStripAssembliesTo(string outputFolder, out string output, out string error, IEnumerable linkXmlFiles, object runInformation) + { + bool result = StripAssembliesToProxy(outputFolder, out output, out error, linkXmlFiles, runInformation); + if (!result) + { + return false; + } + UnityEngine.Debug.Log($"== StripAssembliesTo outputDir:{outputFolder}"); + string outputStrippedDir = HybridCLR.Editor.SettingsUtil.GetAssembliesPostIl2CppStripDir(EditorUserBuildSettings.activeBuildTarget); + Directory.CreateDirectory(outputStrippedDir); + foreach (var aotDll in Directory.GetFiles(outputFolder, "*.dll")) + { + string dstFile = $"{outputStrippedDir}/{Path.GetFileName(aotDll)}"; + Debug.Log($"[RunAssemblyStripper] copy aot dll {aotDll} -> {dstFile}"); + File.Copy(aotDll, dstFile, true); + } + return result; + } + + [MethodImpl(MethodImplOptions.NoOptimization)] + private static bool StripAssembliesToProxy(string outputFolder, out string output, out string error, IEnumerable linkXmlFiles, object runInformation) + { + Debug.LogError("== StripAssembliesToProxy =="); + output = ""; + error = ""; + return true; + } + } +#endif +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs.meta new file mode 100644 index 0000000..18542c3 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/CopyStrippedAOTAssembliesHook.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cf42c4f20b8a1b94baa04a1a5c6b8beb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs new file mode 100644 index 0000000..c3ce1f5 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs @@ -0,0 +1,56 @@ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using UnityEditor; +using System.Runtime.CompilerServices; +using MonoHook; +using HybridCLR.Editor.BuildProcessors; +using System.IO; + +namespace HybridCLR.MonoHook +{ +#if UNITY_2022 + [InitializeOnLoad] + public class GetIl2CppFolderHook + { + private static MethodHook _hook; + + static GetIl2CppFolderHook() + { + if (_hook == null) + { + Type type = typeof(UnityEditor.EditorApplication).Assembly.GetType("UnityEditorInternal.IL2CPPUtils"); + MethodInfo miTarget = type.GetMethod("GetIl2CppFolder", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, + new Type[] { typeof(bool).MakeByRefType() }, null); + + MethodInfo miReplacement = new StripAssembliesDel(OverrideMethod).Method; + MethodInfo miProxy = new StripAssembliesDel(PlaceHolderMethod).Method; + + _hook = new MethodHook(miTarget, miReplacement, miProxy); + _hook.Install(); + } + } + + private delegate string StripAssembliesDel(out bool isDevelopmentLocation); + + private static string OverrideMethod(out bool isDevelopmentLocation) + { + //Debug.Log("[GetIl2CppFolderHook] OverrideMethod"); + string result = PlaceHolderMethod(out isDevelopmentLocation); + isDevelopmentLocation = false; + return result; + } + + [MethodImpl(MethodImplOptions.NoOptimization)] + private static string PlaceHolderMethod(out bool isDevelopmentLocation) + { + Debug.LogError("[GetIl2CppFolderHook] PlaceHolderMethod"); + isDevelopmentLocation = false; + return null; + } + } +#endif +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs.meta new file mode 100644 index 0000000..bcde7d8 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/GetIl2CppFolderHook.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 96c2bc28db69e1644892219abef3d4b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs new file mode 100644 index 0000000..169d766 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs @@ -0,0 +1,57 @@ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using UnityEditor; +using System.Runtime.CompilerServices; +using MonoHook; +using HybridCLR.Editor.BuildProcessors; +using System.IO; + +namespace HybridCLR.MonoHook +{ +#if UNITY_2021_1_OR_NEWER && UNITY_WEBGL + [InitializeOnLoad] + public class PatchScriptingAssembliesJsonHook + { + private static MethodHook _hook; + + static PatchScriptingAssembliesJsonHook() + { + if (_hook == null) + { + Type type = typeof(UnityEditor.EditorApplication); + MethodInfo miTarget = type.GetMethod("BuildMainWindowTitle", BindingFlags.Static | BindingFlags.NonPublic); + + MethodInfo miReplacement = new Func(BuildMainWindowTitle).Method; + MethodInfo miProxy = new Func(BuildMainWindowTitleProxy).Method; + + _hook = new MethodHook(miTarget, miReplacement, miProxy); + _hook.Install(); + } + } + + private static string BuildMainWindowTitle() + { + string tempJsonPath = $"{Application.dataPath}/../Library/PlayerDataCache/WebGL/Data/ScriptingAssemblies.json"; + if (File.Exists(tempJsonPath)) + { + var patcher = new PatchScriptingAssemblyList(); + patcher.PathScriptingAssembilesFile(Path.GetDirectoryName(tempJsonPath)); + } + string newTitle = BuildMainWindowTitleProxy(); + return newTitle; + } + + [MethodImpl(MethodImplOptions.NoOptimization)] + private static string BuildMainWindowTitleProxy() + { + // 为满足MonoHook要求的最小代码长度而特地加入的无用填充代码, + UnityEngine.Debug.Log(12345.ToString()); + return string.Empty; + } + } +#endif +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs.meta new file mode 100644 index 0000000..ccf939f --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cc89a9041ab48ac41975fbd1e00b9b98 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/LDasm.cs b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/LDasm.cs new file mode 100644 index 0000000..d87ab91 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/LDasm.cs @@ -0,0 +1,903 @@ +using System; +using System.Runtime.InteropServices; + +namespace DotNetDetour +{ + /// + /// 用于计算汇编指令长度,使用的是BlackBone的LDasm.c中的算法,我把他翻译成C#了 + /// + public unsafe class LDasm + { + const int F_INVALID = 0x01; + const int F_PREFIX = 0x02; + const int F_REX = 0x04; + const int F_MODRM = 0x08; + const int F_SIB = 0x10; + const int F_DISP = 0x20; + const int F_IMM = 0x40; + const int F_RELATIVE = 0x80; + + const int OP_NONE = 0x00; + const int OP_INVALID = 0x80; + + const int OP_DATA_I8 = 0x01; + const int OP_DATA_I16 = 0x02; + const int OP_DATA_I16_I32 = 0x04; + const int OP_DATA_I16_I32_I64 = 0x08; + const int OP_EXTENDED = 0x10; + const int OP_RELATIVE = 0x20; + const int OP_MODRM = 0x40; + const int OP_PREFIX = 0x80; + + struct ldasm_data + { + public byte flags; + public byte rex; + public byte modrm; + public byte sib; + public byte opcd_offset; + public byte opcd_size; + public byte disp_offset; + public byte disp_size; + public byte imm_offset; + public byte imm_size; + } + + static byte[] flags_table = + { + /* 00 */ OP_MODRM, + /* 01 */ OP_MODRM, + /* 02 */ OP_MODRM, + /* 03 */ OP_MODRM, + /* 04 */ OP_DATA_I8, + /* 05 */ OP_DATA_I16_I32, + /* 06 */ OP_NONE, + /* 07 */ OP_NONE, + /* 08 */ OP_MODRM, + /* 09 */ OP_MODRM, + /* 0A */ OP_MODRM, + /* 0B */ OP_MODRM, + /* 0C */ OP_DATA_I8, + /* 0D */ OP_DATA_I16_I32, + /* 0E */ OP_NONE, + /* 0F */ OP_NONE, + + /* 10 */ OP_MODRM, + /* 11 */ OP_MODRM, + /* 12 */ OP_MODRM, + /* 13 */ OP_MODRM, + /* 14 */ OP_DATA_I8, + /* 15 */ OP_DATA_I16_I32, + /* 16 */ OP_NONE, + /* 17 */ OP_NONE, + /* 18 */ OP_MODRM, + /* 19 */ OP_MODRM, + /* 1A */ OP_MODRM, + /* 1B */ OP_MODRM, + /* 1C */ OP_DATA_I8, + /* 1D */ OP_DATA_I16_I32, + /* 1E */ OP_NONE, + /* 1F */ OP_NONE, + + /* 20 */ OP_MODRM, + /* 21 */ OP_MODRM, + /* 22 */ OP_MODRM, + /* 23 */ OP_MODRM, + /* 24 */ OP_DATA_I8, + /* 25 */ OP_DATA_I16_I32, + /* 26 */ OP_PREFIX, + /* 27 */ OP_NONE, + /* 28 */ OP_MODRM, + /* 29 */ OP_MODRM, + /* 2A */ OP_MODRM, + /* 2B */ OP_MODRM, + /* 2C */ OP_DATA_I8, + /* 2D */ OP_DATA_I16_I32, + /* 2E */ OP_PREFIX, + /* 2F */ OP_NONE, + + /* 30 */ OP_MODRM, + /* 31 */ OP_MODRM, + /* 32 */ OP_MODRM, + /* 33 */ OP_MODRM, + /* 34 */ OP_DATA_I8, + /* 35 */ OP_DATA_I16_I32, + /* 36 */ OP_PREFIX, + /* 37 */ OP_NONE, + /* 38 */ OP_MODRM, + /* 39 */ OP_MODRM, + /* 3A */ OP_MODRM, + /* 3B */ OP_MODRM, + /* 3C */ OP_DATA_I8, + /* 3D */ OP_DATA_I16_I32, + /* 3E */ OP_PREFIX, + /* 3F */ OP_NONE, + + /* 40 */ OP_NONE, + /* 41 */ OP_NONE, + /* 42 */ OP_NONE, + /* 43 */ OP_NONE, + /* 44 */ OP_NONE, + /* 45 */ OP_NONE, + /* 46 */ OP_NONE, + /* 47 */ OP_NONE, + /* 48 */ OP_NONE, + /* 49 */ OP_NONE, + /* 4A */ OP_NONE, + /* 4B */ OP_NONE, + /* 4C */ OP_NONE, + /* 4D */ OP_NONE, + /* 4E */ OP_NONE, + /* 4F */ OP_NONE, + + /* 50 */ OP_NONE, + /* 51 */ OP_NONE, + /* 52 */ OP_NONE, + /* 53 */ OP_NONE, + /* 54 */ OP_NONE, + /* 55 */ OP_NONE, + /* 56 */ OP_NONE, + /* 57 */ OP_NONE, + /* 58 */ OP_NONE, + /* 59 */ OP_NONE, + /* 5A */ OP_NONE, + /* 5B */ OP_NONE, + /* 5C */ OP_NONE, + /* 5D */ OP_NONE, + /* 5E */ OP_NONE, + /* 5F */ OP_NONE, + /* 60 */ OP_NONE, + + /* 61 */ OP_NONE, + /* 62 */ OP_MODRM, + /* 63 */ OP_MODRM, + /* 64 */ OP_PREFIX, + /* 65 */ OP_PREFIX, + /* 66 */ OP_PREFIX, + /* 67 */ OP_PREFIX, + /* 68 */ OP_DATA_I16_I32, + /* 69 */ OP_MODRM | OP_DATA_I16_I32, + /* 6A */ OP_DATA_I8, + /* 6B */ OP_MODRM | OP_DATA_I8, + /* 6C */ OP_NONE, + /* 6D */ OP_NONE, + /* 6E */ OP_NONE, + /* 6F */ OP_NONE, + + /* 70 */ OP_RELATIVE | OP_DATA_I8, + /* 71 */ OP_RELATIVE | OP_DATA_I8, + /* 72 */ OP_RELATIVE | OP_DATA_I8, + /* 73 */ OP_RELATIVE | OP_DATA_I8, + /* 74 */ OP_RELATIVE | OP_DATA_I8, + /* 75 */ OP_RELATIVE | OP_DATA_I8, + /* 76 */ OP_RELATIVE | OP_DATA_I8, + /* 77 */ OP_RELATIVE | OP_DATA_I8, + /* 78 */ OP_RELATIVE | OP_DATA_I8, + /* 79 */ OP_RELATIVE | OP_DATA_I8, + /* 7A */ OP_RELATIVE | OP_DATA_I8, + /* 7B */ OP_RELATIVE | OP_DATA_I8, + /* 7C */ OP_RELATIVE | OP_DATA_I8, + /* 7D */ OP_RELATIVE | OP_DATA_I8, + /* 7E */ OP_RELATIVE | OP_DATA_I8, + /* 7F */ OP_RELATIVE | OP_DATA_I8, + + /* 80 */ OP_MODRM | OP_DATA_I8, + /* 81 */ OP_MODRM | OP_DATA_I16_I32, + /* 82 */ OP_MODRM | OP_DATA_I8, + /* 83 */ OP_MODRM | OP_DATA_I8, + /* 84 */ OP_MODRM, + /* 85 */ OP_MODRM, + /* 86 */ OP_MODRM, + /* 87 */ OP_MODRM, + /* 88 */ OP_MODRM, + /* 89 */ OP_MODRM, + /* 8A */ OP_MODRM, + /* 8B */ OP_MODRM, + /* 8C */ OP_MODRM, + /* 8D */ OP_MODRM, + /* 8E */ OP_MODRM, + /* 8F */ OP_MODRM, + + /* 90 */ OP_NONE, + /* 91 */ OP_NONE, + /* 92 */ OP_NONE, + /* 93 */ OP_NONE, + /* 94 */ OP_NONE, + /* 95 */ OP_NONE, + /* 96 */ OP_NONE, + /* 97 */ OP_NONE, + /* 98 */ OP_NONE, + /* 99 */ OP_NONE, + /* 9A */ OP_DATA_I16 | OP_DATA_I16_I32, + /* 9B */ OP_NONE, + /* 9C */ OP_NONE, + /* 9D */ OP_NONE, + /* 9E */ OP_NONE, + /* 9F */ OP_NONE, + + /* A0 */ OP_DATA_I8, + /* A1 */ OP_DATA_I16_I32_I64, + /* A2 */ OP_DATA_I8, + /* A3 */ OP_DATA_I16_I32_I64, + /* A4 */ OP_NONE, + /* A5 */ OP_NONE, + /* A6 */ OP_NONE, + /* A7 */ OP_NONE, + /* A8 */ OP_DATA_I8, + /* A9 */ OP_DATA_I16_I32, + /* AA */ OP_NONE, + /* AB */ OP_NONE, + /* AC */ OP_NONE, + /* AD */ OP_NONE, + /* AE */ OP_NONE, + /* AF */ OP_NONE, + + /* B0 */ OP_DATA_I8, + /* B1 */ OP_DATA_I8, + /* B2 */ OP_DATA_I8, + /* B3 */ OP_DATA_I8, + /* B4 */ OP_DATA_I8, + /* B5 */ OP_DATA_I8, + /* B6 */ OP_DATA_I8, + /* B7 */ OP_DATA_I8, + /* B8 */ OP_DATA_I16_I32_I64, + /* B9 */ OP_DATA_I16_I32_I64, + /* BA */ OP_DATA_I16_I32_I64, + /* BB */ OP_DATA_I16_I32_I64, + /* BC */ OP_DATA_I16_I32_I64, + /* BD */ OP_DATA_I16_I32_I64, + /* BE */ OP_DATA_I16_I32_I64, + /* BF */ OP_DATA_I16_I32_I64, + + /* C0 */ OP_MODRM | OP_DATA_I8, + /* C1 */ OP_MODRM | OP_DATA_I8, + /* C2 */ OP_DATA_I16, + /* C3 */ OP_NONE, + /* C4 */ OP_MODRM, + /* C5 */ OP_MODRM, + /* C6 */ OP_MODRM | OP_DATA_I8, + /* C7 */ OP_MODRM | OP_DATA_I16_I32, + /* C8 */ OP_DATA_I8 | OP_DATA_I16, + /* C9 */ OP_NONE, + /* CA */ OP_DATA_I16, + /* CB */ OP_NONE, + /* CC */ OP_NONE, + /* CD */ OP_DATA_I8, + /* CE */ OP_NONE, + /* CF */ OP_NONE, + + /* D0 */ OP_MODRM, + /* D1 */ OP_MODRM, + /* D2 */ OP_MODRM, + /* D3 */ OP_MODRM, + /* D4 */ OP_DATA_I8, + /* D5 */ OP_DATA_I8, + /* D6 */ OP_NONE, + /* D7 */ OP_NONE, + /* D8 */ OP_MODRM, + /* D9 */ OP_MODRM, + /* DA */ OP_MODRM, + /* DB */ OP_MODRM, + /* DC */ OP_MODRM, + /* DD */ OP_MODRM, + /* DE */ OP_MODRM, + /* DF */ OP_MODRM, + + /* E0 */ OP_RELATIVE | OP_DATA_I8, + /* E1 */ OP_RELATIVE | OP_DATA_I8, + /* E2 */ OP_RELATIVE | OP_DATA_I8, + /* E3 */ OP_RELATIVE | OP_DATA_I8, + /* E4 */ OP_DATA_I8, + /* E5 */ OP_DATA_I8, + /* E6 */ OP_DATA_I8, + /* E7 */ OP_DATA_I8, + /* E8 */ OP_RELATIVE | OP_DATA_I16_I32, + /* E9 */ OP_RELATIVE | OP_DATA_I16_I32, + /* EA */ OP_DATA_I16 | OP_DATA_I16_I32, + /* EB */ OP_RELATIVE | OP_DATA_I8, + /* EC */ OP_NONE, + /* ED */ OP_NONE, + /* EE */ OP_NONE, + /* EF */ OP_NONE, + + /* F0 */ OP_PREFIX, + /* F1 */ OP_NONE, + /* F2 */ OP_PREFIX, + /* F3 */ OP_PREFIX, + /* F4 */ OP_NONE, + /* F5 */ OP_NONE, + /* F6 */ OP_MODRM, + /* F7 */ OP_MODRM, + /* F8 */ OP_NONE, + /* F9 */ OP_NONE, + /* FA */ OP_NONE, + /* FB */ OP_NONE, + /* FC */ OP_NONE, + /* FD */ OP_NONE, + /* FE */ OP_MODRM, + /* FF */ OP_MODRM + }; + + static byte[] flags_table_ex = + { + /* 0F00 */ OP_MODRM, + /* 0F01 */ OP_MODRM, + /* 0F02 */ OP_MODRM, + /* 0F03 */ OP_MODRM, + /* 0F04 */ OP_INVALID, + /* 0F05 */ OP_NONE, + /* 0F06 */ OP_NONE, + /* 0F07 */ OP_NONE, + /* 0F08 */ OP_NONE, + /* 0F09 */ OP_NONE, + /* 0F0A */ OP_INVALID, + /* 0F0B */ OP_NONE, + /* 0F0C */ OP_INVALID, + /* 0F0D */ OP_MODRM, + /* 0F0E */ OP_INVALID, + /* 0F0F */ OP_MODRM | OP_DATA_I8, //3Dnow + + /* 0F10 */ OP_MODRM, + /* 0F11 */ OP_MODRM, + /* 0F12 */ OP_MODRM, + /* 0F13 */ OP_MODRM, + /* 0F14 */ OP_MODRM, + /* 0F15 */ OP_MODRM, + /* 0F16 */ OP_MODRM, + /* 0F17 */ OP_MODRM, + /* 0F18 */ OP_MODRM, + /* 0F19 */ OP_INVALID, + /* 0F1A */ OP_INVALID, + /* 0F1B */ OP_INVALID, + /* 0F1C */ OP_INVALID, + /* 0F1D */ OP_INVALID, + /* 0F1E */ OP_INVALID, + /* 0F1F */ OP_NONE, + + /* 0F20 */ OP_MODRM, + /* 0F21 */ OP_MODRM, + /* 0F22 */ OP_MODRM, + /* 0F23 */ OP_MODRM, + /* 0F24 */ OP_MODRM | OP_EXTENDED, //SSE5 + /* 0F25 */ OP_INVALID, + /* 0F26 */ OP_MODRM, + /* 0F27 */ OP_INVALID, + /* 0F28 */ OP_MODRM, + /* 0F29 */ OP_MODRM, + /* 0F2A */ OP_MODRM, + /* 0F2B */ OP_MODRM, + /* 0F2C */ OP_MODRM, + /* 0F2D */ OP_MODRM, + /* 0F2E */ OP_MODRM, + /* 0F2F */ OP_MODRM, + + /* 0F30 */ OP_NONE, + /* 0F31 */ OP_NONE, + /* 0F32 */ OP_NONE, + /* 0F33 */ OP_NONE, + /* 0F34 */ OP_NONE, + /* 0F35 */ OP_NONE, + /* 0F36 */ OP_INVALID, + /* 0F37 */ OP_NONE, + /* 0F38 */ OP_MODRM | OP_EXTENDED, + /* 0F39 */ OP_INVALID, + /* 0F3A */ OP_MODRM | OP_EXTENDED | OP_DATA_I8, + /* 0F3B */ OP_INVALID, + /* 0F3C */ OP_INVALID, + /* 0F3D */ OP_INVALID, + /* 0F3E */ OP_INVALID, + /* 0F3F */ OP_INVALID, + + /* 0F40 */ OP_MODRM, + /* 0F41 */ OP_MODRM, + /* 0F42 */ OP_MODRM, + /* 0F43 */ OP_MODRM, + /* 0F44 */ OP_MODRM, + /* 0F45 */ OP_MODRM, + /* 0F46 */ OP_MODRM, + /* 0F47 */ OP_MODRM, + /* 0F48 */ OP_MODRM, + /* 0F49 */ OP_MODRM, + /* 0F4A */ OP_MODRM, + /* 0F4B */ OP_MODRM, + /* 0F4C */ OP_MODRM, + /* 0F4D */ OP_MODRM, + /* 0F4E */ OP_MODRM, + /* 0F4F */ OP_MODRM, + + /* 0F50 */ OP_MODRM, + /* 0F51 */ OP_MODRM, + /* 0F52 */ OP_MODRM, + /* 0F53 */ OP_MODRM, + /* 0F54 */ OP_MODRM, + /* 0F55 */ OP_MODRM, + /* 0F56 */ OP_MODRM, + /* 0F57 */ OP_MODRM, + /* 0F58 */ OP_MODRM, + /* 0F59 */ OP_MODRM, + /* 0F5A */ OP_MODRM, + /* 0F5B */ OP_MODRM, + /* 0F5C */ OP_MODRM, + /* 0F5D */ OP_MODRM, + /* 0F5E */ OP_MODRM, + /* 0F5F */ OP_MODRM, + + /* 0F60 */ OP_MODRM, + /* 0F61 */ OP_MODRM, + /* 0F62 */ OP_MODRM, + /* 0F63 */ OP_MODRM, + /* 0F64 */ OP_MODRM, + /* 0F65 */ OP_MODRM, + /* 0F66 */ OP_MODRM, + /* 0F67 */ OP_MODRM, + /* 0F68 */ OP_MODRM, + /* 0F69 */ OP_MODRM, + /* 0F6A */ OP_MODRM, + /* 0F6B */ OP_MODRM, + /* 0F6C */ OP_MODRM, + /* 0F6D */ OP_MODRM, + /* 0F6E */ OP_MODRM, + /* 0F6F */ OP_MODRM, + + /* 0F70 */ OP_MODRM | OP_DATA_I8, + /* 0F71 */ OP_MODRM | OP_DATA_I8, + /* 0F72 */ OP_MODRM | OP_DATA_I8, + /* 0F73 */ OP_MODRM | OP_DATA_I8, + /* 0F74 */ OP_MODRM, + /* 0F75 */ OP_MODRM, + /* 0F76 */ OP_MODRM, + /* 0F77 */ OP_NONE, + /* 0F78 */ OP_MODRM, + /* 0F79 */ OP_MODRM, + /* 0F7A */ OP_INVALID, + /* 0F7B */ OP_INVALID, + /* 0F7C */ OP_MODRM, + /* 0F7D */ OP_MODRM, + /* 0F7E */ OP_MODRM, + /* 0F7F */ OP_MODRM, + + /* 0F80 */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F81 */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F82 */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F83 */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F84 */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F85 */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F86 */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F87 */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F88 */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F89 */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F8A */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F8B */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F8C */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F8D */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F8E */ OP_RELATIVE | OP_DATA_I16_I32, + /* 0F8F */ OP_RELATIVE | OP_DATA_I16_I32, + + /* 0F90 */ OP_MODRM, + /* 0F91 */ OP_MODRM, + /* 0F92 */ OP_MODRM, + /* 0F93 */ OP_MODRM, + /* 0F94 */ OP_MODRM, + /* 0F95 */ OP_MODRM, + /* 0F96 */ OP_MODRM, + /* 0F97 */ OP_MODRM, + /* 0F98 */ OP_MODRM, + /* 0F99 */ OP_MODRM, + /* 0F9A */ OP_MODRM, + /* 0F9B */ OP_MODRM, + /* 0F9C */ OP_MODRM, + /* 0F9D */ OP_MODRM, + /* 0F9E */ OP_MODRM, + /* 0F9F */ OP_MODRM, + + /* 0FA0 */ OP_NONE, + /* 0FA1 */ OP_NONE, + /* 0FA2 */ OP_NONE, + /* 0FA3 */ OP_MODRM, + /* 0FA4 */ OP_MODRM | OP_DATA_I8, + /* 0FA5 */ OP_MODRM, + /* 0FA6 */ OP_INVALID, + /* 0FA7 */ OP_INVALID, + /* 0FA8 */ OP_NONE, + /* 0FA9 */ OP_NONE, + /* 0FAA */ OP_NONE, + /* 0FAB */ OP_MODRM, + /* 0FAC */ OP_MODRM | OP_DATA_I8, + /* 0FAD */ OP_MODRM, + /* 0FAE */ OP_MODRM, + /* 0FAF */ OP_MODRM, + + /* 0FB0 */ OP_MODRM, + /* 0FB1 */ OP_MODRM, + /* 0FB2 */ OP_MODRM, + /* 0FB3 */ OP_MODRM, + /* 0FB4 */ OP_MODRM, + /* 0FB5 */ OP_MODRM, + /* 0FB6 */ OP_MODRM, + /* 0FB7 */ OP_MODRM, + /* 0FB8 */ OP_MODRM, + /* 0FB9 */ OP_MODRM, + /* 0FBA */ OP_MODRM | OP_DATA_I8, + /* 0FBB */ OP_MODRM, + /* 0FBC */ OP_MODRM, + /* 0FBD */ OP_MODRM, + /* 0FBE */ OP_MODRM, + /* 0FBF */ OP_MODRM, + + /* 0FC0 */ OP_MODRM, + /* 0FC1 */ OP_MODRM, + /* 0FC2 */ OP_MODRM | OP_DATA_I8, + /* 0FC3 */ OP_MODRM, + /* 0FC4 */ OP_MODRM | OP_DATA_I8, + /* 0FC5 */ OP_MODRM | OP_DATA_I8, + /* 0FC6 */ OP_MODRM | OP_DATA_I8, + /* 0FC7 */ OP_MODRM, + /* 0FC8 */ OP_NONE, + /* 0FC9 */ OP_NONE, + /* 0FCA */ OP_NONE, + /* 0FCB */ OP_NONE, + /* 0FCC */ OP_NONE, + /* 0FCD */ OP_NONE, + /* 0FCE */ OP_NONE, + /* 0FCF */ OP_NONE, + + /* 0FD0 */ OP_MODRM, + /* 0FD1 */ OP_MODRM, + /* 0FD2 */ OP_MODRM, + /* 0FD3 */ OP_MODRM, + /* 0FD4 */ OP_MODRM, + /* 0FD5 */ OP_MODRM, + /* 0FD6 */ OP_MODRM, + /* 0FD7 */ OP_MODRM, + /* 0FD8 */ OP_MODRM, + /* 0FD9 */ OP_MODRM, + /* 0FDA */ OP_MODRM, + /* 0FDB */ OP_MODRM, + /* 0FDC */ OP_MODRM, + /* 0FDD */ OP_MODRM, + /* 0FDE */ OP_MODRM, + /* 0FDF */ OP_MODRM, + + /* 0FE0 */ OP_MODRM, + /* 0FE1 */ OP_MODRM, + /* 0FE2 */ OP_MODRM, + /* 0FE3 */ OP_MODRM, + /* 0FE4 */ OP_MODRM, + /* 0FE5 */ OP_MODRM, + /* 0FE6 */ OP_MODRM, + /* 0FE7 */ OP_MODRM, + /* 0FE8 */ OP_MODRM, + /* 0FE9 */ OP_MODRM, + /* 0FEA */ OP_MODRM, + /* 0FEB */ OP_MODRM, + /* 0FEC */ OP_MODRM, + /* 0FED */ OP_MODRM, + /* 0FEE */ OP_MODRM, + /* 0FEF */ OP_MODRM, + + /* 0FF0 */ OP_MODRM, + /* 0FF1 */ OP_MODRM, + /* 0FF2 */ OP_MODRM, + /* 0FF3 */ OP_MODRM, + /* 0FF4 */ OP_MODRM, + /* 0FF5 */ OP_MODRM, + /* 0FF6 */ OP_MODRM, + /* 0FF7 */ OP_MODRM, + /* 0FF8 */ OP_MODRM, + /* 0FF9 */ OP_MODRM, + /* 0FFA */ OP_MODRM, + /* 0FFB */ OP_MODRM, + /* 0FFC */ OP_MODRM, + /* 0FFD */ OP_MODRM, + /* 0FFE */ OP_MODRM, + /* 0FFF */ OP_INVALID, + }; + + static byte cflags(byte op) + { + return flags_table[op]; + } + + static byte cflags_ex(byte op) + { + return flags_table_ex[op]; + } + + /// + /// 计算大于等于 size 字节的最少指令的长度 + /// + /// + /// + public static uint SizeofMinNumByte(void* code, int size) + { + if (IsARM()) + return (uint)((size + 3) / 4) * 4; // 此为 jit 模式下的长度,不再支持 thumb + + uint Length; + byte* pOpcode; + uint Result = 0; + ldasm_data data = new ldasm_data(); + bool is64 = IntPtr.Size == 8; + do + { + Length = ldasm(code, data, is64); + + pOpcode = (byte*)code + data.opcd_offset; + Result += Length; + if (Result >= size) + break; + if ((Length == 1) && (*pOpcode == 0xCC)) + break; + + code = (void*)((ulong)code + Length); + + } while (Length>0); + + return Result; + } + + static bool? s_isArm; + public static bool IsARM() + { + if(s_isArm.HasValue) + return s_isArm.Value; + + var arch = RuntimeInformation.ProcessArchitecture; + s_isArm = arch == Architecture.Arm || arch == Architecture.Arm64; + + return s_isArm.Value; + } + + public static bool IsArm32() + { + return IsARM() && IntPtr.Size == 4; + } + + public static bool IsArm64() + { + return IsARM() && IntPtr.Size == 8; + } + + static bool? s_isiOS; + public static bool IsiOS() + { + if(s_isiOS.HasValue) + return s_isiOS.Value; + + s_isiOS = UnityEngine.SystemInfo.operatingSystem.ToLower().Contains("ios"); + return s_isiOS.Value; + } + + static bool? s_isIL2CPP; + public static bool IsIL2CPP() + { + if (s_isIL2CPP.HasValue) + return s_isIL2CPP.Value; + + try + { + byte[] ilBody = typeof(LDasm).GetMethod("IsIL2CPP").GetMethodBody().GetILAsByteArray(); + if (ilBody == null || ilBody.Length == 0) + s_isIL2CPP = true; + else + s_isIL2CPP = false; + } + catch + { + s_isIL2CPP = true; + } + + return s_isIL2CPP.Value; + } + + public static bool IsThumb(IntPtr code) + { + return IsArm32() && ((long)code & 0x1) == 0x1; + } + + /// + /// 计算 thumb 指令长度 + /// + /// + /// + /// + public static uint CalcARMThumbMinLen(void* code, int size) + { + uint len = 0; + + ushort* ins = (ushort*)code; + while (true) + { + if (len >= size) + return len; + + if (((*ins >> 13) & 3) == 3) + { + ins += 2; + len += 4; + } + else + { + ins++; + len += 2; + } + } + } + + static uint ldasm(void* code, ldasm_data ld, bool is64) + { + byte* p = (byte*)code; + byte s, op, f; + byte rexw, pr_66, pr_67; + + s = rexw = pr_66 = pr_67 = 0; + + /* dummy check */ + if ((int)code==0) + return 0; + + /* init output data */ + //memset(ld, 0, sizeof(ldasm_data)); + + /* phase 1: parse prefixies */ + while ((cflags(*p) & OP_PREFIX)!=0) + { + if (*p == 0x66) + pr_66 = 1; + if (*p == 0x67) + pr_67 = 1; + p++; s++; + ld.flags |= F_PREFIX; + if (s == 15) + { + ld.flags |= F_INVALID; + return s; + } + } + + /* parse REX prefix */ + if (is64 && *p >> 4 == 4) + { + ld.rex = *p; + rexw = (byte)((ld.rex >> 3) & 1); + ld.flags |= F_REX; + p++; s++; + } + + /* can be only one REX prefix */ + if (is64 && *p >> 4 == 4) + { + ld.flags |= F_INVALID; + s++; + return s; + } + + /* phase 2: parse opcode */ + ld.opcd_offset = (byte)(p - (byte*)code); + ld.opcd_size = 1; + op = *p++; s++; + + /* is 2 byte opcode? */ + if (op == 0x0F) + { + op = *p++; s++; + ld.opcd_size++; + f = cflags_ex(op); + if ((f & OP_INVALID)!=0) + { + ld.flags |= F_INVALID; + return s; + } + /* for SSE instructions */ + if ((f & OP_EXTENDED)!=0) + { + op = *p++; s++; + ld.opcd_size++; + } + } + else { + f = cflags(op); + /* pr_66 = pr_67 for opcodes A0-A3 */ + if (op >= 0xA0 && op <= 0xA3) + pr_66 = pr_67; + } + + /* phase 3: parse ModR/M, SIB and DISP */ + if ((f & OP_MODRM)!=0) + { + byte mod = (byte)(*p >> 6); + byte ro = (byte)((*p & 0x38) >> 3); + byte rm = (byte)(*p & 7); + + ld.modrm = *p++; s++; + ld.flags |= F_MODRM; + + /* in F6,F7 opcodes immediate data present if R/O == 0 */ + if (op == 0xF6 && (ro == 0 || ro == 1)) + f |= OP_DATA_I8; + if (op == 0xF7 && (ro == 0 || ro == 1)) + f |= OP_DATA_I16_I32_I64; + + /* is SIB byte exist? */ + if (mod != 3 && rm == 4 && !(!is64 && pr_67!=0)) + { + ld.sib = *p++; s++; + ld.flags |= F_SIB; + + /* if base == 5 and mod == 0 */ + if ((ld.sib & 7) == 5 && mod == 0) + { + ld.disp_size = 4; + } + } + + switch (mod) + { + case 0: + if (is64) + { + if (rm == 5) + { + ld.disp_size = 4; + if (is64) + ld.flags |= F_RELATIVE; + } + } + else if (pr_67!=0) + { + if (rm == 6) + ld.disp_size = 2; + } + else { + if (rm == 5) + ld.disp_size = 4; + } + break; + case 1: + ld.disp_size = 1; + break; + case 2: + if (is64) + ld.disp_size = 4; + else if (pr_67!=0) + ld.disp_size = 2; + else + ld.disp_size = 4; + break; + } + + if (ld.disp_size>0) + { + ld.disp_offset = (byte)(p - (byte*)code); + p += ld.disp_size; + s += ld.disp_size; + ld.flags |= F_DISP; + } + } + + /* phase 4: parse immediate data */ + if (rexw!=0 && (f & OP_DATA_I16_I32_I64)!=0) + ld.imm_size = 8; + else if ((f & OP_DATA_I16_I32)!=0 || (f & OP_DATA_I16_I32_I64)!=0) + ld.imm_size = (byte)(4 - (pr_66 << 1)); + + /* if exist, add OP_DATA_I16 and OP_DATA_I8 size */ + ld.imm_size += (byte)(f & 3); + + if ((ld.imm_size)!=0) + { + s += ld.imm_size; + ld.imm_offset = (byte)(p - (byte*)code); + ld.flags |= F_IMM; + if ((f & OP_RELATIVE)!=0) + ld.flags |= F_RELATIVE; + } + + /* instruction is too long */ + if (s > 15) + ld.flags |= F_INVALID; + + return s; + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/LDasm.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/LDasm.cs.meta new file mode 100644 index 0000000..969a5a1 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/LDasm.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c561c9729c367e4fbef63f4ec56f268 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/MethodHook.cs b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/MethodHook.cs new file mode 100644 index 0000000..2c7c862 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/MethodHook.cs @@ -0,0 +1,381 @@ +/* + Desc: 一个可以运行时 Hook Mono 方法的工具,让你可以无需修改 UnityEditor.dll 等文件就可以重写其函数功能 + Author: Misaka Mikoto + Github: https://github.com/Misaka-Mikoto-Tech/MonoHook + */ + +using DotNetDetour; +using System; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.InteropServices; +using Unity.Collections.LowLevel.Unsafe; +#if UNITY_EDITOR +using UnityEditor; +#endif +using UnityEngine; +using System.Runtime.CompilerServices; + + +/* +>>>>>>> 原始 UnityEditor.LogEntries.Clear 一型(.net 4.x) +0000000000403A00 < | 55 | push rbp | +0000000000403A01 | 48 8B EC | mov rbp,rsp | +0000000000403A04 | 48 81 EC 80 00 00 00 | sub rsp,80 | +0000000000403A0B | 48 89 65 B0 | mov qword ptr ss:[rbp-50],rsp | +0000000000403A0F | 48 89 6D A8 | mov qword ptr ss:[rbp-58],rbp | +0000000000403A13 | 48 89 5D C8 | mov qword ptr ss:[rbp-38],rbx | << +0000000000403A17 | 48 89 75 D0 | mov qword ptr ss:[rbp-30],rsi | +0000000000403A1B | 48 89 7D D8 | mov qword ptr ss:[rbp-28],rdi | +0000000000403A1F | 4C 89 65 E0 | mov qword ptr ss:[rbp-20],r12 | +0000000000403A23 | 4C 89 6D E8 | mov qword ptr ss:[rbp-18],r13 | +0000000000403A27 | 4C 89 75 F0 | mov qword ptr ss:[rbp-10],r14 | +0000000000403A2B | 4C 89 7D F8 | mov qword ptr ss:[rbp-8],r15 | +0000000000403A2F | 49 BB 00 2D 1E 1A FE 7F 00 00 | mov r11,7FFE1A1E2D00 | +0000000000403A39 | 4C 89 5D B8 | mov qword ptr ss:[rbp-48],r11 | +0000000000403A3D | 49 BB 08 2D 1E 1A FE 7F 00 00 | mov r11,7FFE1A1E2D08 | + + +>>>>>>> 二型(.net 2.x) +0000000000403E8F | 55 | push rbp | +0000000000403E90 | 48 8B EC | mov rbp,rsp | +0000000000403E93 | 48 83 EC 70 | sub rsp,70 | +0000000000403E97 | 48 89 65 C8 | mov qword ptr ss:[rbp-38],rsp | +0000000000403E9B | 48 89 5D B8 | mov qword ptr ss:[rbp-48],rbx | +0000000000403E9F | 48 89 6D C0 | mov qword ptr ss:[rbp-40],rbp | <<(16) +0000000000403EA3 | 48 89 75 F8 | mov qword ptr ss:[rbp-8],rsi | +0000000000403EA7 | 48 89 7D F0 | mov qword ptr ss:[rbp-10],rdi | +0000000000403EAB | 4C 89 65 D0 | mov qword ptr ss:[rbp-30],r12 | +0000000000403EAF | 4C 89 6D D8 | mov qword ptr ss:[rbp-28],r13 | +0000000000403EB3 | 4C 89 75 E0 | mov qword ptr ss:[rbp-20],r14 | +0000000000403EB7 | 4C 89 7D E8 | mov qword ptr ss:[rbp-18],r15 | +0000000000403EBB | 48 83 EC 20 | sub rsp,20 | +0000000000403EBF | 49 BB 18 3F 15 13 FE 7F 00 00 | mov r11,7FFE13153F18 | +0000000000403EC9 | 41 FF D3 | call r11 | +0000000000403ECC | 48 83 C4 20 | add rsp,20 | + +>>>>>>>>> arm64 +il2cpp:00000000003DE714 F5 0F 1D F8 STR X21, [SP,#-0x10+var_20]! | << absolute safe +il2cpp:00000000003DE718 F4 4F 01 A9 STP X20, X19, [SP,#0x20+var_10] | << may be safe +il2cpp:00000000003DE71C FD 7B 02 A9 STP X29, X30, [SP,#0x20+var_s0] | +il2cpp:00000000003DE720 FD 83 00 91 ADD X29, SP, #0x20 | +il2cpp:00000000003DE724 B5 30 00 B0 ADRP X21, #_ZZ62GameObject_SetActive_mCF1EEF2A314F3AE | << dangerous: relative instruction, can not be overwritten +il2cpp:00000000003DE728 A2 56 47 F9 LDR method, [X21,#_ZZ62GameObject_SetActive_mCF] ; | +il2cpp:00000000003DE72C F3 03 01 2A MOV W19, W1 | + */ + +namespace MonoHook +{ + /// + /// Hook 类,用来 Hook 某个 C# 方法 + /// + public unsafe class MethodHook + { + public string tag; + public bool isHooked { get; private set; } + public bool isPlayModeHook { get; private set; } + + public MethodBase targetMethod { get; private set; } // 需要被hook的目标方法 + public MethodBase replacementMethod { get; private set; } // 被hook后的替代方法 + public MethodBase proxyMethod { get; private set; } // 目标方法的代理方法(可以通过此方法调用被hook后的原方法) + + private IntPtr _targetPtr; // 目标方法被 jit 后的地址指针 + private IntPtr _replacementPtr; + private IntPtr _proxyPtr; + + private CodePatcher _codePatcher; + +#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER + /// + /// call `MethodInfo.MethodHandle.GetFunctionPointer()` + /// will visit static class `UnityEditor.IMGUI.Controls.TreeViewGUI.Styles` and invoke its static constructor, + /// and init static filed `foldout`, but `GUISKin.current` is null now, + /// so we should wait until `GUISKin.current` has a valid value + /// + private static FieldInfo s_fi_GUISkin_current; +#endif + + static MethodHook() + { +#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER + s_fi_GUISkin_current = typeof(GUISkin).GetField("current", BindingFlags.Static | BindingFlags.NonPublic); +#endif + } + + /// + /// 创建一个 Hook + /// + /// 需要替换的目标方法 + /// 准备好的替换方法 + /// 如果还需要调用原始目标方法,可以通过此参数的方法调用,如果不需要可以填 null + public MethodHook(MethodBase targetMethod, MethodBase replacementMethod, MethodBase proxyMethod, string data = "") + { + this.targetMethod = targetMethod; + this.replacementMethod = replacementMethod; + this.proxyMethod = proxyMethod; + this.tag = data; + + CheckMethod(); + } + + public void Install() + { + if (LDasm.IsiOS()) // iOS 不支持修改 code 所在区域 page + return; + + if (isHooked) + return; + +#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER + if (s_fi_GUISkin_current.GetValue(null) != null) + DoInstall(); + else + EditorApplication.update += OnEditorUpdate; +#else + DoInstall(); +#endif + isPlayModeHook = Application.isPlaying; + } + + public void Uninstall() + { + if (!isHooked) + return; + + _codePatcher.RemovePatch(); + + isHooked = false; + HookPool.RemoveHooker(targetMethod); + } + + #region private + private void DoInstall() + { + if (targetMethod == null || replacementMethod == null) + throw new Exception("none of methods targetMethod or replacementMethod can be null"); + + HookPool.AddHook(targetMethod, this); + + if (_codePatcher == null) + { + if (GetFunctionAddr()) + { +#if ENABLE_HOOK_DEBUG + UnityEngine.Debug.Log($"Original [{targetMethod.DeclaringType.Name}.{targetMethod.Name}]: {HookUtils.HexToString(_targetPtr.ToPointer(), 64, -16)}"); + UnityEngine.Debug.Log($"Original [{replacementMethod.DeclaringType.Name}.{replacementMethod.Name}]: {HookUtils.HexToString(_replacementPtr.ToPointer(), 64, -16)}"); + if(proxyMethod != null) + UnityEngine.Debug.Log($"Original [{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}]: {HookUtils.HexToString(_proxyPtr.ToPointer(), 64, -16)}"); +#endif + + CreateCodePatcher(); + _codePatcher.ApplyPatch(); + +#if ENABLE_HOOK_DEBUG + UnityEngine.Debug.Log($"New [{targetMethod.DeclaringType.Name}.{targetMethod.Name}]: {HookUtils.HexToString(_targetPtr.ToPointer(), 64, -16)}"); + UnityEngine.Debug.Log($"New [{replacementMethod.DeclaringType.Name}.{replacementMethod.Name}]: {HookUtils.HexToString(_replacementPtr.ToPointer(), 64, -16)}"); + if(proxyMethod != null) + UnityEngine.Debug.Log($"New [{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}]: {HookUtils.HexToString(_proxyPtr.ToPointer(), 64, -16)}"); +#endif + } + } + + isHooked = true; + } + + private void CheckMethod() + { + if (targetMethod == null || replacementMethod == null) + throw new Exception("MethodHook:targetMethod and replacementMethod and proxyMethod can not be null"); + + string methodName = $"{targetMethod.DeclaringType.Name}.{targetMethod.Name}"; + if (targetMethod.IsAbstract) + throw new Exception($"WRANING: you can not hook abstract method [{methodName}]"); + +#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER + int minMethodBodySize = 10; + + { + if ((targetMethod.MethodImplementationFlags & MethodImplAttributes.InternalCall) != MethodImplAttributes.InternalCall) + { + int codeSize = targetMethod.GetMethodBody().GetILAsByteArray().Length; // GetMethodBody can not call on il2cpp + if (codeSize < minMethodBodySize) + UnityEngine.Debug.LogWarning($"WRANING: you can not hook method [{methodName}], cause its method body is too short({codeSize}), will random crash on IL2CPP release mode"); + } + } + + if(proxyMethod != null) + { + methodName = $"{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}"; + int codeSize = proxyMethod.GetMethodBody().GetILAsByteArray().Length; + if (codeSize < minMethodBodySize) + UnityEngine.Debug.LogWarning($"WRANING: size of method body[{methodName}] is too short({codeSize}), will random crash on IL2CPP release mode, please fill some dummy code inside"); + + if ((proxyMethod.MethodImplementationFlags & MethodImplAttributes.NoOptimization) != MethodImplAttributes.NoOptimization) + throw new Exception($"WRANING: method [{methodName}] must has a Attribute `MethodImpl(MethodImplOptions.NoOptimization)` to prevent code call to this optimized by compiler(pass args by shared stack)"); + } +#endif + } + + private void CreateCodePatcher() + { + long addrOffset = Math.Abs(_targetPtr.ToInt64() - _proxyPtr.ToInt64()); + + if(_proxyPtr != IntPtr.Zero) + addrOffset = Math.Max(addrOffset, Math.Abs(_targetPtr.ToInt64() - _proxyPtr.ToInt64())); + + if (LDasm.IsARM()) + { + if (IntPtr.Size == 8) + _codePatcher = new CodePatcher_arm64_near(_targetPtr, _replacementPtr, _proxyPtr); + else if (addrOffset < ((1 << 25) - 1)) + _codePatcher = new CodePatcher_arm32_near(_targetPtr, _replacementPtr, _proxyPtr); + else if (addrOffset < ((1 << 27) - 1)) + _codePatcher = new CodePatcher_arm32_far(_targetPtr, _replacementPtr, _proxyPtr); + else + throw new Exception("address of target method and replacement method are too far, can not hook"); + } + else + { + if (IntPtr.Size == 8) + { + if(addrOffset < 0x7fffffff) // 2G + _codePatcher = new CodePatcher_x64_near(_targetPtr, _replacementPtr, _proxyPtr); + else + _codePatcher = new CodePatcher_x64_far(_targetPtr, _replacementPtr, _proxyPtr); + } + else + _codePatcher = new CodePatcher_x86(_targetPtr, _replacementPtr, _proxyPtr); + } + } + + /// + /// 获取对应函数jit后的native code的地址 + /// + private bool GetFunctionAddr() + { + _targetPtr = GetFunctionAddr(targetMethod); + _replacementPtr = GetFunctionAddr(replacementMethod); + _proxyPtr = GetFunctionAddr(proxyMethod); + + if (_targetPtr == IntPtr.Zero || _replacementPtr == IntPtr.Zero) + return false; + + if (proxyMethod != null && _proxyPtr == null) + return false; + + if(_replacementPtr == _targetPtr) + { + throw new Exception($"the addresses of target method {targetMethod.Name} and replacement method {replacementMethod.Name} can not be same"); + } + + if (LDasm.IsThumb(_targetPtr) || LDasm.IsThumb(_replacementPtr)) + { + throw new Exception("does not support thumb arch"); + } + + return true; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] // 好像在 IL2CPP 里无效 + private struct __ForCopy + { + public long __dummy; + public MethodBase method; + } + /// + /// 获取方法指令地址 + /// + /// + /// + private IntPtr GetFunctionAddr(MethodBase method) + { + if (method == null) + return IntPtr.Zero; + + if (!LDasm.IsIL2CPP()) + return method.MethodHandle.GetFunctionPointer(); + else + { + /* + // System.Reflection.MonoMethod + typedef struct Il2CppReflectionMethod + { + Il2CppObject object; + const MethodInfo *method; + Il2CppString *name; + Il2CppReflectionType *reftype; + } Il2CppReflectionMethod; + + typedef Il2CppClass Il2CppVTable; + typedef struct Il2CppObject + { + union + { + Il2CppClass *klass; + Il2CppVTable *vtable; + }; + MonitorData *monitor; + } Il2CppObject; + + typedef struct MethodInfo + { + Il2CppMethodPointer methodPointer; // this is the pointer to native code of method + InvokerMethod invoker_method; + const char* name; + Il2CppClass *klass; + const Il2CppType *return_type; + const ParameterInfo* parameters; + // ... + } + */ + + __ForCopy __forCopy = new __ForCopy() { method = method }; + + long* ptr = &__forCopy.__dummy; + ptr++; // addr of _forCopy.method + + IntPtr methodAddr = IntPtr.Zero; + if (sizeof(IntPtr) == 8) + { + long methodDataAddr = *(long*)ptr; + byte* ptrData = (byte*)methodDataAddr + sizeof(IntPtr) * 2; // offset of Il2CppReflectionMethod::const MethodInfo *method; + + long methodPtr = 0; + methodPtr = *(long*)ptrData; + methodAddr = new IntPtr(*(long*)methodPtr); // MethodInfo::Il2CppMethodPointer methodPointer; + } + else + { + int methodDataAddr = *(int*)ptr; + byte* ptrData = (byte*)methodDataAddr + sizeof(IntPtr) * 2; // offset of Il2CppReflectionMethod::const MethodInfo *method; + + int methodPtr = 0; + methodPtr = *(int*)ptrData; + methodAddr = new IntPtr(*(int*)methodPtr); + } + return methodAddr; + } + } + +#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER + private void OnEditorUpdate() + { + if (s_fi_GUISkin_current.GetValue(null) != null) + { + try + { + DoInstall(); + } + finally + { + EditorApplication.update -= OnEditorUpdate; + } + } + } +#endif + + #endregion + } + +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/MethodHook.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/MethodHook.cs.meta new file mode 100644 index 0000000..007e62c --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/MethodHook.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bd0b8071cf434d6498160259e3829980 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins.meta new file mode 100644 index 0000000..1f7f284 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 16b9dc031f67b4fe5ad79c230f75768c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/Utils.cpp b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/Utils.cpp new file mode 100644 index 0000000..106d990 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/Utils.cpp @@ -0,0 +1,23 @@ +// +// Utils.cpp +// MonoHookUtils_OSX +// +// Created by Misaka-Mikoto on 2022/8/31. +// +#include +#include +#include +#include +#include + +extern "C"{ + +void* memcpy_jit(void* dst, void* src, int32_t size) +{ + pthread_jit_write_protect_np(0); + void* ret = memcpy(dst, src, size); + pthread_jit_write_protect_np(1); + sys_icache_invalidate (dst, size); + return ret; +} +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/Utils.cpp.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/Utils.cpp.meta new file mode 100644 index 0000000..447c3db --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/Utils.cpp.meta @@ -0,0 +1,81 @@ +fileFormatVersion: 2 +guid: 56b28b5583a184c669dcb968d175544c +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 0 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: OSX + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: ARM64 + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/build_libMonoHookUtils_OSX.dylib.sh b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/build_libMonoHookUtils_OSX.dylib.sh new file mode 100644 index 0000000..8de985c --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/build_libMonoHookUtils_OSX.dylib.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +clang -shared -undefined dynamic_lookup -o libMonoHookUtils_OSX.dylib Utils.cpp + diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/build_libMonoHookUtils_OSX.dylib.sh.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/build_libMonoHookUtils_OSX.dylib.sh.meta new file mode 100644 index 0000000..ed9f26d --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/build_libMonoHookUtils_OSX.dylib.sh.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 69eeb734e262a0a4fbe0887249198f73 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/silicon.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/silicon.meta new file mode 100644 index 0000000..2e09562 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/silicon.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7adba4475cf0bdc4fa7995c0d748f480 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/silicon/libMonoHookUtils_OSX.dylib b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/silicon/libMonoHookUtils_OSX.dylib new file mode 100644 index 0000000000000000000000000000000000000000..edabc8a37ed744ceabe53717d4bb64b6076800e1 GIT binary patch literal 33543 zcmeI*UuYaf90%~ZyIhkrF*!6ugW4QY3XPg#TQD!;UjIl!Z7!Iry$9_iy}Pz+a<}1j z(>A8q3nicl2*nf&{-F_TIINI{DkrE!Dk`O*hhVir$&1x)8_ z{Z!47hO&c{R^qUw3Y3(OxA{@0tw(j?vRCEpq(WreMJY{daId*iRX*N?8gH%Y!DaV& zRcbt1yB(w)OdZlwajB>F8B|j~UQUhIuKIJ?J)WvwN!aZqMJcz1A|bgo+}Z8uX{yT& zQugA=FNEKKl=}@A+YQINi~8C@``4Vy{7y^nfXh5DUW1g6cXaO9zOAG5PBT==L9?%- zq+O|Q=K0tkiE6%$(l(0xTz7rHzIUgQGTIHJZkBztaJ)RutZ5 zC%?*-U+v_1OYl8vUhb6lPxIb++GlOY6KdZ&mw68}?`96D-OW_wE!GqQ8E1=eAj9`l z$kgc?(L)F6DXsP~C;&)F?1vCoOGrw8-D z4mi|Nq~gld8_UZ4{{weBcjSK^l-66y2TPN;pL^>IS-es^OHZD19#2;x8mNx7UJ_pV z{est?hDr5NyH$v4Ax3(FUi)ZyRrOzqw$eyP&F?f)M!RA3?XvWKQ--^v>dg6;Z@MlY z4gdaKXnAdN|KL}jJou15fBL73Pk-O=e%EJv&iwe!(K9nqc4j6 z+>vKTFMl}R{=x%OH*0VC_Qk~y(!`7wHHGeIUHJII$mjX#w;MX{e6wlYpVjkYAI;rt{9A4JJoZ%akAr_Lj8!i*dPbWf W7q^(>zs7#K@7+hlmBR)9j(-4!MS4E~ literal 0 HcmV?d00001 diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/silicon/libMonoHookUtils_OSX.dylib.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/silicon/libMonoHookUtils_OSX.dylib.meta new file mode 100644 index 0000000..3045ab9 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/silicon/libMonoHookUtils_OSX.dylib.meta @@ -0,0 +1,81 @@ +fileFormatVersion: 2 +guid: e092a73910a69894daea44290d7292f6 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 0 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + CPU: ARM64 + DefaultValueInitialized: true + OS: OSX + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: x86 + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: x86_64 + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/x86_64.meta b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/x86_64.meta new file mode 100644 index 0000000..d4267c3 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/x86_64.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 31f6a810e38e66f4c832b135770a04bb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/x86_64/libMonoHookUtils_OSX.dylib b/Packages/com.code-philosophy.hybridclr/Editor/3rds/UnityHook/Plugins/x86_64/libMonoHookUtils_OSX.dylib new file mode 100644 index 0000000000000000000000000000000000000000..07f9063d92b36f9dbcdc9e518b52ea85f4516eb7 GIT binary patch literal 166928 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 + { + public string Sig { get; private set; } + + public MethodDef MethodDef { get; set; } + + public ReturnInfo ReturnInfo { get; set; } + + public List ParamInfos { get; set; } + + public void Init() + { + for(int i = 0; i < ParamInfos.Count; i++) + { + ParamInfos[i].Index = i; + } + Sig = CreateCallSigName(); + } + + public void TransfromSigTypes(Func transformer) + { + ReturnInfo.Type = transformer(ReturnInfo.Type, true); + foreach(var paramType in ParamInfos) + { + paramType.Type = transformer(paramType.Type, false); + } + } + + public string CreateCallSigName() + { + var n = new StringBuilder(); + n.Append(ReturnInfo.Type.CreateSigName()); + foreach(var param in ParamInfos) + { + n.Append(param.Type.CreateSigName()); + } + return n.ToString(); + } + + public string CreateInvokeSigName() + { + var n = new StringBuilder(); + n.Append(ReturnInfo.Type.CreateSigName()); + foreach (var param in ParamInfos) + { + n.Append(param.Type.CreateSigName()); + } + return n.ToString(); + } + + public override bool Equals(object obj) + { + return Equals((MethodDesc)obj); + } + + public bool Equals(MethodDesc other) + { + return Sig == other.Sig; + } + + public override int GetHashCode() + { + return Sig.GetHashCode(); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/MethodDesc.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/ABI/MethodDesc.cs.meta new file mode 100644 index 0000000..0a0a97a --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/MethodDesc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 28e06667d06f37b4990b16f54f903a35 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamInfo.cs b/Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamInfo.cs new file mode 100644 index 0000000..fc2cc7f --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamInfo.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.ABI +{ + + public class ParamInfo + { + public TypeInfo Type { get; set; } + + public int Index { get; set; } + + } + + public class ReturnInfo + { + public TypeInfo Type { get; set; } + + public bool IsVoid => Type.PorType == ParamOrReturnType.VOID; + + public override string ToString() + { + return Type.GetTypeName(); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamInfo.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamInfo.cs.meta new file mode 100644 index 0000000..6b4174e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f2ba16cf4bf82374c814789b6ced3abd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamOrReturnType.cs b/Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamOrReturnType.cs new file mode 100644 index 0000000..f8a478c --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamOrReturnType.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.ABI +{ + public enum ParamOrReturnType + { + VOID, + I1, + U1, + I2, + U2, + I4, + U4, + I8, + U8, + R4, + R8, + I, + U, + TYPEDBYREF, + STRUCT, + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamOrReturnType.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamOrReturnType.cs.meta new file mode 100644 index 0000000..12ffd4b --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/ParamOrReturnType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80682e47c38a2f04f8af94d356688cf0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/PlatformABI.cs b/Packages/com.code-philosophy.hybridclr/Editor/ABI/PlatformABI.cs new file mode 100644 index 0000000..62fdb16 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/PlatformABI.cs @@ -0,0 +1,10 @@ +namespace HybridCLR.Editor.ABI +{ + public enum PlatformABI + { + Universal32, + Universal64, + Arm64, + WebGL32, + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/PlatformABI.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/ABI/PlatformABI.cs.meta new file mode 100644 index 0000000..bea367c --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/PlatformABI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b9f06ff0612105b4ea20e0309e759e24 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeCreator.cs b/Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeCreator.cs new file mode 100644 index 0000000..12af7ae --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeCreator.cs @@ -0,0 +1,102 @@ +using dnlib.DotNet; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.ABI +{ + public class TypeCreator + { + private readonly Dictionary _typeInfoCache = new Dictionary(TypeEqualityComparer.Instance); + + private int _nextStructId = 0; + + public TypeInfo CreateTypeInfo(TypeSig type) + { + type = type.RemovePinnedAndModifiers(); + if (!_typeInfoCache.TryGetValue(type, out var typeInfo)) + { + typeInfo = CreateTypeInfo0(type); + _typeInfoCache.Add(type, typeInfo); + } + return typeInfo; + } + + TypeInfo CreateTypeInfo0(TypeSig type) + { + type = type.RemovePinnedAndModifiers(); + if (type.IsByRef) + { + return TypeInfo.s_u; + } + switch (type.ElementType) + { + case ElementType.Void: return TypeInfo.s_void; + case ElementType.Boolean: return TypeInfo.s_u1; + case ElementType.I1: return TypeInfo.s_i1; + case ElementType.U1: return TypeInfo.s_u1; + case ElementType.I2: return TypeInfo.s_i2; + case ElementType.Char: + case ElementType.U2: return TypeInfo.s_u2; + case ElementType.I4: return TypeInfo.s_i4; + case ElementType.U4: return TypeInfo.s_u4; + case ElementType.I8: return TypeInfo.s_i8; + case ElementType.U8: return TypeInfo.s_u8; + case ElementType.R4: return TypeInfo.s_r4; + case ElementType.R8: return TypeInfo.s_r8; + case ElementType.I: return TypeInfo.s_i; + case ElementType.U: + case ElementType.String: + case ElementType.Ptr: + case ElementType.ByRef: + case ElementType.Class: + case ElementType.Array: + case ElementType.SZArray: + case ElementType.FnPtr: + case ElementType.Object: + case ElementType.Module: + case ElementType.Var: + case ElementType.MVar: + return TypeInfo.s_u; + case ElementType.TypedByRef: return TypeInfo.s_typedByRef; + case ElementType.ValueType: + { + TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDef(); + if (typeDef == null) + { + throw new Exception($"type:{type} definition could not be found. Please try `HybridCLR/Genergate/LinkXml`, then Build once to generate the AOT dll, and then regenerate the bridge function"); + } + if (typeDef.IsEnum) + { + return CreateTypeInfo(typeDef.GetEnumUnderlyingType()); + } + return CreateValueType(type); + } + case ElementType.GenericInst: + { + GenericInstSig gis = (GenericInstSig)type; + if (!gis.GenericType.IsValueType) + { + return TypeInfo.s_u; + } + TypeDef typeDef = gis.GenericType.ToTypeDefOrRef().ResolveTypeDef(); + if (typeDef.IsEnum) + { + return CreateTypeInfo(typeDef.GetEnumUnderlyingType()); + } + return CreateValueType(type); + } + default: throw new NotSupportedException($"{type.ElementType}"); + } + } + + protected TypeInfo CreateValueType(TypeSig type) + { + return new TypeInfo(ParamOrReturnType.STRUCT, type, _nextStructId++); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeCreator.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeCreator.cs.meta new file mode 100644 index 0000000..7452840 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeCreator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0b1df5760b488fa43a68843c46fda63a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeInfo.cs b/Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeInfo.cs new file mode 100644 index 0000000..6d0b404 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeInfo.cs @@ -0,0 +1,116 @@ +using dnlib.DotNet; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; + +namespace HybridCLR.Editor.ABI +{ + public class TypeInfo : IEquatable + { + + public static readonly TypeInfo s_void = new TypeInfo(ParamOrReturnType.VOID); + public static readonly TypeInfo s_i1 = new TypeInfo(ParamOrReturnType.I1); + public static readonly TypeInfo s_u1 = new TypeInfo(ParamOrReturnType.U1); + public static readonly TypeInfo s_i2 = new TypeInfo(ParamOrReturnType.I2); + public static readonly TypeInfo s_u2 = new TypeInfo(ParamOrReturnType.U2); + public static readonly TypeInfo s_i4 = new TypeInfo(ParamOrReturnType.I4); + public static readonly TypeInfo s_u4 = new TypeInfo(ParamOrReturnType.U4); + public static readonly TypeInfo s_i8 = new TypeInfo(ParamOrReturnType.I8); + public static readonly TypeInfo s_u8 = new TypeInfo(ParamOrReturnType.U8); + public static readonly TypeInfo s_r4 = new TypeInfo(ParamOrReturnType.R4); + public static readonly TypeInfo s_r8 = new TypeInfo(ParamOrReturnType.R8); + public static readonly TypeInfo s_i = new TypeInfo(ParamOrReturnType.I); + public static readonly TypeInfo s_u = new TypeInfo(ParamOrReturnType.U); + public static readonly TypeInfo s_typedByRef = new TypeInfo(ParamOrReturnType.TYPEDBYREF); + + public const string strTypedByRef = "typedbyref"; + + public TypeInfo(ParamOrReturnType portype, TypeSig klass = null, int typeId = 0) + { + PorType = portype; + Klass = klass; + _typeId = typeId; + } + + public ParamOrReturnType PorType { get; } + + public TypeSig Klass { get; } + + public bool IsStruct => PorType == ParamOrReturnType.STRUCT; + + public bool IsPrimitiveType => PorType <= ParamOrReturnType.U; + + private readonly int _typeId; + + public int TypeId => _typeId; + + public bool Equals(TypeInfo other) + { + return PorType == other.PorType && TypeEqualityComparer.Instance.Equals(Klass, other.Klass); + } + + public override bool Equals(object obj) + { + return Equals((TypeInfo)obj); + } + + public override int GetHashCode() + { + return (int)PorType * 23 + (Klass != null ? TypeEqualityComparer.Instance.GetHashCode(Klass) : 0); + } + + public bool NeedExpandValue() + { + return PorType >= ParamOrReturnType.I1 && PorType <= ParamOrReturnType.U2; + } + + public string CreateSigName() + { + switch (PorType) + { + case ParamOrReturnType.VOID: return "v"; + case ParamOrReturnType.I1: return "i1"; + case ParamOrReturnType.U1: return "u1"; + case ParamOrReturnType.I2: return "i2"; + case ParamOrReturnType.U2: return "u2"; + case ParamOrReturnType.I4: return "i4"; + case ParamOrReturnType.U4: return "u4"; + case ParamOrReturnType.I8: return "i8"; + case ParamOrReturnType.U8: return "u8"; + case ParamOrReturnType.R4: return "r4"; + case ParamOrReturnType.R8: return "r8"; + case ParamOrReturnType.I: return "i"; + case ParamOrReturnType.U: return "u"; + case ParamOrReturnType.TYPEDBYREF: return strTypedByRef; + case ParamOrReturnType.STRUCT: return $"s{_typeId}"; + default: throw new NotSupportedException(PorType.ToString()); + }; + } + + public string GetTypeName() + { + switch (PorType) + { + case ParamOrReturnType.VOID: return "void"; + case ParamOrReturnType.I1: return "int8_t"; + case ParamOrReturnType.U1: return "uint8_t"; + case ParamOrReturnType.I2: return "int16_t"; + case ParamOrReturnType.U2: return "uint16_t"; + case ParamOrReturnType.I4: return "int32_t"; + case ParamOrReturnType.U4: return "uint32_t"; + case ParamOrReturnType.I8: return "int64_t"; + case ParamOrReturnType.U8: return "uint64_t"; + case ParamOrReturnType.R4: return "float"; + case ParamOrReturnType.R8: return "double"; + case ParamOrReturnType.I: return "intptr_t"; + case ParamOrReturnType.U: return "uintptr_t"; + case ParamOrReturnType.TYPEDBYREF: return "Il2CppTypedRef"; + case ParamOrReturnType.STRUCT: return $"__struct_{_typeId}__"; + default: throw new NotImplementedException(PorType.ToString()); + }; + } + + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeInfo.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeInfo.cs.meta new file mode 100644 index 0000000..5df8577 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/TypeInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ffafce7f1f0bf614d95b48ca39385377 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/ValueTypeSizeAligmentCalculator.cs b/Packages/com.code-philosophy.hybridclr/Editor/ABI/ValueTypeSizeAligmentCalculator.cs new file mode 100644 index 0000000..a97dd02 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/ValueTypeSizeAligmentCalculator.cs @@ -0,0 +1,181 @@ +using dnlib.DotNet; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.ABI +{ + public class ValueTypeSizeAligmentCalculator + { + public static ValueTypeSizeAligmentCalculator Caculator64 { get; } = new ValueTypeSizeAligmentCalculator(false); + + public static ValueTypeSizeAligmentCalculator Caculator32 { get; } = new ValueTypeSizeAligmentCalculator(true); + + public ValueTypeSizeAligmentCalculator(bool arch32) + { + _referenceSize = arch32 ? 4 : 8; + } + + private readonly int _referenceSize; + + private static bool IsIgnoreField(FieldDef field) + { + var ignoreAttr = field.CustomAttributes.Where(a => a.AttributeType.FullName == "UnityEngine.Bindings.IgnoreAttribute").FirstOrDefault(); + if (ignoreAttr == null) + { + return false; + } + CANamedArgument arg = ignoreAttr.GetProperty("DoesNotContributeToSize"); + if(arg != null && (bool)arg.Value) + { + //Debug.Log($"IgnoreField.DoesNotContributeToSize = true:{field}"); + return true; + } + return false; + } + + private (int Size, int Aligment) SizeAndAligmentOfStruct(TypeSig type) + { + int totalSize = 0; + int packAligment = 8; + int maxAligment = 1; + + TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow(); + + List klassInst = type.ToGenericInstSig()?.GenericArguments?.ToList(); + GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null; + + ClassLayout sa = typeDef.ClassLayout; + if (sa != null && sa.PackingSize > 0) + { + packAligment = sa.PackingSize; + } + bool useSLSize = true; + foreach (FieldDef field in typeDef.Fields) + { + if (field.IsStatic) + { + continue; + } + TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType; + var (fs, fa) = SizeAndAligmentOf(fieldType); + fa = Math.Min(fa, packAligment); + if (fa > maxAligment) + { + maxAligment = fa; + } + if (IsIgnoreField(field)) + { + continue; + } + if (typeDef.Layout.HasFlag(dnlib.DotNet.TypeAttributes.ExplicitLayout)) + { + int offset = (int)field.FieldOffset.Value; + totalSize = Math.Max(totalSize, offset + fs); + if (sa != null && offset > sa.ClassSize) + { + useSLSize = false; + } + } + else + { + if (totalSize % fa != 0) + { + totalSize = (totalSize + fa - 1) / fa * fa; + } + totalSize += fs; + if (sa != null && totalSize > sa.ClassSize) + { + useSLSize = false; + } + } + } + if (totalSize == 0) + { + totalSize = maxAligment; + } + if (totalSize % maxAligment != 0) + { + totalSize = (totalSize + maxAligment - 1) / maxAligment * maxAligment; + } + if (sa != null && sa.ClassSize > 0) + { + if (/*sa.Value == LayoutKind.Explicit &&*/ useSLSize) + { + totalSize = (int)sa.ClassSize; + while(totalSize % maxAligment != 0) + { + maxAligment /= 2; + } + } + } + return (totalSize, maxAligment); + } + + public (int Size, int Aligment) SizeAndAligmentOf(TypeSig type) + { + type = type.RemovePinnedAndModifiers(); + if (type.IsByRef || !type.IsValueType || type.IsArray) + return (_referenceSize, _referenceSize); + + switch (type.ElementType) + { + case ElementType.Void: throw new NotSupportedException(type.ToString()); + case ElementType.Boolean: + case ElementType.I1: + case ElementType.U1: return (1, 1); + case ElementType.Char: + case ElementType.I2: + case ElementType.U2: return (2, 2); + case ElementType.I4: + case ElementType.U4: return (4, 4); + case ElementType.I8: + case ElementType.U8: return (8, 8); + case ElementType.R4: return (4, 4); + case ElementType.R8: return (8, 8); + case ElementType.I: + case ElementType.U: + case ElementType.String: + case ElementType.Ptr: + case ElementType.ByRef: + case ElementType.Class: + case ElementType.Array: + case ElementType.SZArray: + case ElementType.FnPtr: + case ElementType.Object: + case ElementType.Module: return (_referenceSize, _referenceSize); + case ElementType.TypedByRef: return SizeAndAligmentOfStruct(type); + case ElementType.ValueType: + { + TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDef(); + if (typeDef.IsEnum) + { + return SizeAndAligmentOf(typeDef.GetEnumUnderlyingType()); + } + return SizeAndAligmentOfStruct(type); + } + case ElementType.GenericInst: + { + GenericInstSig gis = (GenericInstSig)type; + if (!gis.GenericType.IsValueType) + { + return (_referenceSize, _referenceSize); + } + TypeDef typeDef = gis.GenericType.ToTypeDefOrRef().ResolveTypeDef(); + if (typeDef.IsEnum) + { + return SizeAndAligmentOf(typeDef.GetEnumUnderlyingType()); + } + return SizeAndAligmentOfStruct(type); + } + default: throw new NotSupportedException(type.ToString()); + } + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ABI/ValueTypeSizeAligmentCalculator.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/ABI/ValueTypeSizeAligmentCalculator.cs.meta new file mode 100644 index 0000000..4b83d63 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ABI/ValueTypeSizeAligmentCalculator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7af32bdf1cf55c42bfc449820d401cb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/AOT.meta b/Packages/com.code-philosophy.hybridclr/Editor/AOT.meta new file mode 100644 index 0000000..9b9539f --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/AOT.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b4071bf66ac9c544487ae88b5ee9b20a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/AOT/Analyzer.cs b/Packages/com.code-philosophy.hybridclr/Editor/AOT/Analyzer.cs new file mode 100644 index 0000000..5d9c475 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/AOT/Analyzer.cs @@ -0,0 +1,208 @@ +using dnlib.DotNet; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.AOT +{ + + public class Analyzer + { + public class Options + { + public AssemblyReferenceDeepCollector Collector { get; set; } + + public int MaxIterationCount { get; set; } + } + + private readonly int _maxInterationCount; + + private readonly AssemblyReferenceDeepCollector _assemblyCollector; + + private readonly HashSet _genericTypes = new HashSet(); + private readonly HashSet _genericMethods = new HashSet(); + + private List _processingMethods = new List(); + private List _newMethods = new List(); + + public IReadOnlyCollection GenericTypes => _genericTypes; + + public IReadOnlyCollection GenericMethods => _genericMethods; + + private readonly MethodReferenceAnalyzer _methodReferenceAnalyzer; + + private readonly HashSet _hotUpdateAssemblyFiles; + + public ConstraintContext ConstraintContext { get; } = new ConstraintContext(); + + public List AotGenericTypes { get; } = new List(); + + public List AotGenericMethods { get; } = new List(); + + public Analyzer(Options options) + { + _assemblyCollector = options.Collector; + _maxInterationCount = options.MaxIterationCount; + _methodReferenceAnalyzer = new MethodReferenceAnalyzer(this.OnNewMethod); + _hotUpdateAssemblyFiles = new HashSet(options.Collector.GetRootAssemblyNames().Select(assName => assName + ".dll")); + } + + private void TryAddAndWalkGenericType(GenericClass gc) + { + if (gc == null) + { + return; + } + gc = gc.ToGenericShare(); + if (_genericTypes.Add(gc) && NeedWalk(null, gc.Type)) + { + WalkType(gc); + } + } + + private bool NeedWalk(MethodDef callFrom, TypeDef type) + { + return _hotUpdateAssemblyFiles.Contains(type.Module.Name) || callFrom == null || callFrom.HasGenericParameters; + } + + private bool IsAotType(TypeDef type) + { + return !_hotUpdateAssemblyFiles.Contains(type.Module.Name); + } + + private bool IsAotGenericMethod(MethodDef method) + { + return IsAotType(method.DeclaringType) && method.HasGenericParameters; + } + + private void OnNewMethod(MethodDef methodDef, List klassGenericInst, List methodGenericInst, GenericMethod method) + { + if(method == null) + { + return; + } + if (NeedWalk(methodDef, method.Method.DeclaringType) && _genericMethods.Add(method)) + { + _newMethods.Add(method); + } + if (method.KlassInst != null) + { + TryAddAndWalkGenericType(new GenericClass(method.Method.DeclaringType, method.KlassInst)); + } + } + + private void TryAddMethodNotWalkType(GenericMethod method) + { + if (method == null) + { + return; + } + if (NeedWalk(null, method.Method.DeclaringType) && _genericMethods.Add(method)) + { + _newMethods.Add(method); + } + } + + private void WalkType(GenericClass gc) + { + //Debug.Log($"typespec:{sig} {sig.GenericType} {sig.GenericType.TypeDefOrRef.ResolveTypeDef()}"); + //Debug.Log($"== walk generic type:{new GenericInstSig(gc.Type.ToTypeSig().ToClassOrValueTypeSig(), gc.KlassInst)}"); + ITypeDefOrRef baseType = gc.Type.BaseType; + if (baseType != null && baseType.TryGetGenericInstSig() != null) + { + GenericClass parentType = GenericClass.ResolveClass((TypeSpec)baseType, new GenericArgumentContext(gc.KlassInst, null)); + TryAddAndWalkGenericType(parentType); + } + foreach (var method in gc.Type.Methods) + { + if (method.HasGenericParameters || !method.HasBody || method.Body.Instructions == null) + { + continue; + } + var gm = new GenericMethod(method, gc.KlassInst, null).ToGenericShare(); + //Debug.Log($"add method:{gm.Method} {gm.KlassInst}"); + TryAddMethodNotWalkType(gm); + } + } + + private void WalkType(TypeDef typeDef) + { + if (typeDef.HasGenericParameters) + { + return; + } + ITypeDefOrRef baseType = typeDef.BaseType; + if (baseType != null && baseType.TryGetGenericInstSig() != null) + { + GenericClass gc = GenericClass.ResolveClass((TypeSpec)baseType, null); + TryAddAndWalkGenericType(gc); + } + } + + private void Prepare() + { + // 将所有非泛型函数全部加入函数列表,同时立马walk这些method。 + // 后续迭代中将只遍历MethodSpec + foreach (var ass in _assemblyCollector.GetLoadedModulesOfRootAssemblies()) + { + foreach (TypeDef typeDef in ass.GetTypes()) + { + WalkType(typeDef); + } + + for (uint rid = 1, n = ass.Metadata.TablesStream.TypeSpecTable.Rows; rid <= n; rid++) + { + var ts = ass.ResolveTypeSpec(rid); + var cs = GenericClass.ResolveClass(ts, null)?.ToGenericShare(); + if (cs != null) + { + TryAddAndWalkGenericType(cs); + } + } + + for (uint rid = 1, n = ass.Metadata.TablesStream.MethodSpecTable.Rows; rid <= n; rid++) + { + var ms = ass.ResolveMethodSpec(rid); + var gm = GenericMethod.ResolveMethod(ms, null)?.ToGenericShare(); + TryAddMethodNotWalkType(gm); + } + } + Debug.Log($"PostPrepare genericTypes:{_genericTypes.Count} genericMethods:{_genericMethods.Count} newMethods:{_newMethods.Count}"); + } + + private void RecursiveCollect() + { + for (int i = 0; i < _maxInterationCount && _newMethods.Count > 0; i++) + { + var temp = _processingMethods; + _processingMethods = _newMethods; + _newMethods = temp; + _newMethods.Clear(); + + foreach (var method in _processingMethods) + { + _methodReferenceAnalyzer.WalkMethod(method.Method, method.KlassInst, method.MethodInst); + } + Debug.Log($"iteration:[{i}] genericClass:{_genericTypes.Count} genericMethods:{_genericMethods.Count} newMethods:{_newMethods.Count}"); + } + } + + private void FilterAOTGenericTypeAndMethods() + { + ConstraintContext cc = this.ConstraintContext; + AotGenericTypes.AddRange(_genericTypes.Where(type => IsAotType(type.Type)).Select(gc => cc.ApplyConstraints(gc))); + AotGenericMethods.AddRange(_genericMethods.Where(method => IsAotGenericMethod(method.Method)).Select(gm => cc.ApplyConstraints(gm))); + } + + public void Run() + { + Prepare(); + RecursiveCollect(); + FilterAOTGenericTypeAndMethods(); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/AOT/Analyzer.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/AOT/Analyzer.cs.meta new file mode 100644 index 0000000..2e573fc --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/AOT/Analyzer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 30bbf4a80a6cf3a43b3f489747d9dd6a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/AOT/ConstraintContext.cs b/Packages/com.code-philosophy.hybridclr/Editor/AOT/ConstraintContext.cs new file mode 100644 index 0000000..4a9cd3c --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/AOT/ConstraintContext.cs @@ -0,0 +1,73 @@ +using dnlib.DotNet; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.AOT +{ + + public class ConstraintContext + { + public class ImplType + { + public TypeSig BaseType { get; } + + public List Interfaces { get; } + + public bool ValueType { get; } + + private readonly int _hash; + + public ImplType(TypeSig baseType, List interfaces, bool valueType) + { + BaseType = baseType; + Interfaces = interfaces; + ValueType = valueType; + _hash = ComputHash(); + } + + public override bool Equals(object obj) + { + ImplType o = (ImplType)obj; + return MetaUtil.EqualsTypeSig(this.BaseType, o.BaseType) + && MetaUtil.EqualsTypeSigArray(this.Interfaces, o.Interfaces) + && this.ValueType == o.ValueType; + } + + public override int GetHashCode() + { + return _hash; + } + + private int ComputHash() + { + int hash = 0; + if (BaseType != null) + { + hash = HashUtil.CombineHash(hash, TypeEqualityComparer.Instance.GetHashCode(BaseType)); + } + if (Interfaces.Count > 0) + { + hash = HashUtil.CombineHash(hash, HashUtil.ComputHash(Interfaces)); + } + + return hash; + } + } + + public HashSet ImplTypes { get; } = new HashSet(); + + public GenericClass ApplyConstraints(GenericClass gc) + { + return gc; + } + + public GenericMethod ApplyConstraints(GenericMethod gm) + { + return gm; + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/AOT/ConstraintContext.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/AOT/ConstraintContext.cs.meta new file mode 100644 index 0000000..3e99cab --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/AOT/ConstraintContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 812d81a75b690394bbe16ef5f0bcbc46 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/AOT/GenericReferenceWriter.cs b/Packages/com.code-philosophy.hybridclr/Editor/AOT/GenericReferenceWriter.cs new file mode 100644 index 0000000..20612c4 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/AOT/GenericReferenceWriter.cs @@ -0,0 +1,139 @@ +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.AOT +{ + public class GenericReferenceWriter + { + private static readonly Dictionary _typeNameMapping = new Dictionary + { + {typeof(bool), "bool" }, + {typeof(byte), "byte" }, + {typeof(sbyte), "sbyte" }, + {typeof(short), "short" }, + {typeof(ushort), "ushort" }, + {typeof(int), "int" }, + {typeof(uint), "uint" }, + {typeof(long), "long" }, + {typeof(ulong), "ulong" }, + {typeof(float), "float" }, + {typeof(double), "double" }, + {typeof(object), "object" }, + {typeof(string), "string" }, + }; + + private readonly Dictionary _typeSimpleNameMapping = new Dictionary(); + private readonly Regex _systemTypePattern; + private readonly Regex _genericPattern = new Regex(@"`\d+"); + + public GenericReferenceWriter() + { + foreach (var e in _typeNameMapping) + { + _typeSimpleNameMapping.Add(e.Key.FullName, e.Value); + } + _systemTypePattern = new Regex(string.Join("|", _typeSimpleNameMapping.Keys.Select (k => $@"\b{k}\b"))); + } + + public string PrettifyTypeSig(string typeSig) + { + string s = _genericPattern.Replace(typeSig, "").Replace('/', '.'); + return _systemTypePattern.Replace(s, m => _typeSimpleNameMapping[m.Groups[0].Value]); + } + + public string PrettifyMethodSig(string methodSig) + { + string s = PrettifyTypeSig(methodSig).Replace("::", "."); + if (s.Contains(".ctor(")) + { + s = "new " + s.Replace(".ctor(", "("); + } + return s; + } + + public void Write(List types, List methods, string outputFile) + { + string parentDir = Directory.GetParent(outputFile).FullName; + Directory.CreateDirectory(parentDir); + + List codes = new List(); + codes.Add("using System.Collections.Generic;"); + codes.Add("public class AOTGenericReferences : UnityEngine.MonoBehaviour"); + codes.Add("{"); + + codes.Add(""); + codes.Add("\t// {{ AOT assemblies"); + codes.Add("\tpublic static readonly IReadOnlyList PatchedAOTAssemblyList = new List"); + codes.Add("\t{"); + List modules = new HashSet( + types.Select(t => t.Type.Module).Concat(methods.Select(m => m.Method.Module))).ToList(); + modules.Sort((a, b) => a.Name.CompareTo(b.Name)); + foreach (dnlib.DotNet.ModuleDef module in modules) + { + codes.Add($"\t\t\"{module.Name}\","); + } + codes.Add("\t};"); + codes.Add("\t// }}"); + + + codes.Add(""); + codes.Add("\t// {{ constraint implement type"); + + codes.Add("\t// }} "); + + codes.Add(""); + codes.Add("\t// {{ AOT generic types"); + + List typeNames = types.Select(t => PrettifyTypeSig(t.ToTypeSig().ToString())).ToList(); + typeNames.Sort(string.CompareOrdinal); + foreach(var typeName in typeNames) + { + codes.Add($"\t// {typeName}"); + } + + codes.Add("\t// }}"); + + codes.Add(""); + codes.Add("\tpublic void RefMethods()"); + codes.Add("\t{"); + + List<(string, string, string)> methodTypeAndNames = methods.Select(m => + (PrettifyTypeSig(m.Method.DeclaringType.ToString()), PrettifyMethodSig(m.Method.Name), PrettifyMethodSig(m.ToMethodSpec().ToString()))) + .ToList(); + methodTypeAndNames.Sort((a, b) => + { + int c = String.Compare(a.Item1, b.Item1, StringComparison.Ordinal); + if (c != 0) + { + return c; + } + + c = String.Compare(a.Item2, b.Item2, StringComparison.Ordinal); + if (c != 0) + { + return c; + } + return String.Compare(a.Item3, b.Item3, StringComparison.Ordinal); + }); + foreach(var method in methodTypeAndNames) + { + codes.Add($"\t\t// {PrettifyMethodSig(method.Item3)}"); + } + codes.Add("\t}"); + + codes.Add("}"); + + + var utf8WithoutBom = new System.Text.UTF8Encoding(false); + File.WriteAllText(outputFile, string.Join("\n", codes), utf8WithoutBom); + Debug.Log($"[GenericReferenceWriter] write {outputFile}"); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/AOT/GenericReferenceWriter.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/AOT/GenericReferenceWriter.cs.meta new file mode 100644 index 0000000..9fc1497 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/AOT/GenericReferenceWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d1243cf04685361478972f93b5ca868a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors.meta b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors.meta new file mode 100644 index 0000000..428a0a1 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f80d2287f01c89642a74b0a60f7a3305 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs new file mode 100644 index 0000000..b0788aa --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs @@ -0,0 +1,254 @@ +using System; +using HybridCLR.Editor.Installer; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using UnityEditor; +using System.Reflection; +using HybridCLR.Editor.Settings; +#if (UNITY_2020 || UNITY_2021) && UNITY_IOS +using UnityEditor.Build; +using UnityEditor.Callbacks; +using UnityEditor.iOS.Xcode; +using UnityEngine; + +namespace HybridCLR.Editor.BuildProcessors +{ + public static class AddLil2cppSourceCodeToXcodeproj2021OrOlder + { + //[MenuItem("Test/GenProj")] + //public static void Modify() + //{ + // OnPostProcessBuild(BuildTarget.iOS, $"{SettingsUtil.ProjectDir}/Build-iOS"); + //} + + //[MenuItem("Test/CreateLumps")] + //public static void CreateLumpsCmd() + //{ + // CreateLumps($"{SettingsUtil.LocalIl2CppDir}/libil2cpp", $"{SettingsUtil.HybridCLRDataDir}/lumps"); + //} + + [PostProcessBuild] + public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject) + { + if (target != BuildTarget.iOS || !HybridCLRSettings.Instance.enable) + return; + /* + * 1. 生成lump,并且添加到工程 + 3. 将libil2cpp目录复制到 Library/. 删除旧的. search paths里修改 libil2cpp/include为libil2cpp + 3. Libraries/bdwgc/include -> Libraries/external/bdwgc/include + 4. 将external目录复制到 Library/external。删除旧目录 + 5. 将Library/external/baselib/Platforms/OSX改名为 IOS 全大写 + 6. 将 external/zlib下c 文件添加到工程 + 7. 移除libil2cpp.a + 8. Include path add libil2cpp/os/ClassLibraryPAL/brotli/include + 9. add external/xxHash + */ + + string pbxprojFile = $"{pathToBuiltProject}/Unity-iPhone.xcodeproj/project.pbxproj"; + string srcLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp"; + string dstLibil2cppDir = $"{pathToBuiltProject}/Libraries/libil2cpp"; + string lumpDir = $"{pathToBuiltProject}/Libraries/lumps"; + string srcExternalDir = $"{SettingsUtil.LocalIl2CppDir}/external"; + string dstExternalDir = $"{pathToBuiltProject}/Libraries/external"; + //RemoveExternalLibil2cppOption(srcExternalDir, dstExternalDir); + CopyLibil2cppToXcodeProj(srcLibil2cppDir, dstLibil2cppDir); + CopyExternalToXcodeProj(srcExternalDir, dstExternalDir); + var lumpFiles = CreateLumps(dstLibil2cppDir, lumpDir); + var extraSources = GetExtraSourceFiles(dstExternalDir, dstLibil2cppDir); + var cflags = new List() + { + "-DIL2CPP_MONO_DEBUGGER_DISABLED", + }; + ModifyPBXProject(pathToBuiltProject, pbxprojFile, lumpFiles, extraSources, cflags); + } + + private static string GetRelativePathFromProj(string path) + { + return path.Substring(path.IndexOf("Libraries", StringComparison.Ordinal)).Replace('\\', '/'); + } + + private static void ModifyPBXProject(string pathToBuiltProject, string pbxprojFile, List lumpFiles, List extraFiles, List cflags) + { + var proj = new PBXProject(); + proj.ReadFromFile(pbxprojFile); + string targetGUID = proj.GetUnityFrameworkTargetGuid(); + // 移除旧的libil2cpp.a + var libil2cppGUID = proj.FindFileGuidByProjectPath("Libraries/libil2cpp.a"); + if (!string.IsNullOrEmpty(libil2cppGUID)) + { + proj.RemoveFileFromBuild(targetGUID, libil2cppGUID); + proj.RemoveFile(libil2cppGUID); + File.Delete(Path.Combine(pathToBuiltProject, "Libraries", "libil2cpp.a")); + } + + //var lumpGroupGuid = proj.AddFile("Lumps", $"Classes/Lumps", PBXSourceTree.Group); + + foreach (var lumpFile in lumpFiles) + { + string lumpFileName = Path.GetFileName(lumpFile.lumpFile); + string projPathOfFile = $"Classes/Lumps/{lumpFileName}"; + string relativePathOfFile = GetRelativePathFromProj(lumpFile.lumpFile); + string lumpGuid = proj.FindFileGuidByProjectPath(projPathOfFile); + if (!string.IsNullOrEmpty(lumpGuid)) + { + proj.RemoveFileFromBuild(targetGUID, lumpGuid); + proj.RemoveFile(lumpGuid); + } + lumpGuid = proj.AddFile(relativePathOfFile, projPathOfFile, PBXSourceTree.Source); + proj.AddFileToBuild(targetGUID, lumpGuid); + } + + foreach (var extraFile in extraFiles) + { + string projPathOfFile = $"Classes/Extrals/{Path.GetFileName(extraFile)}"; + string extraFileGuid = proj.FindFileGuidByProjectPath(projPathOfFile); + if (!string.IsNullOrEmpty(extraFileGuid)) + { + proj.RemoveFileFromBuild(targetGUID, extraFileGuid); + proj.RemoveFile(extraFileGuid); + //Debug.LogWarning($"remove exist extra file:{projPathOfFile} guid:{extraFileGuid}"); + } + var lumpGuid = proj.AddFile(GetRelativePathFromProj(extraFile), projPathOfFile, PBXSourceTree.Source); + proj.AddFileToBuild(targetGUID, lumpGuid); + } + + foreach(var configName in proj.BuildConfigNames()) + { + //Debug.Log($"build config:{bcn}"); + string configGuid = proj.BuildConfigByName(targetGUID, configName); + string headerSearchPaths = "HEADER_SEARCH_PATHS"; + string hspProp = proj.GetBuildPropertyForConfig(configGuid, headerSearchPaths); + //Debug.Log($"config guid:{configGuid} prop:{hspProp}"); + string newPro = hspProp.Replace("libil2cpp/include", "libil2cpp") + .Replace("Libraries/bdwgc", "Libraries/external/bdwgc"); + + if (!newPro.Contains("Libraries/libil2cpp/os/ClassLibraryPAL/brotli/include")) + { + newPro += " $(SRCROOT)/Libraries/libil2cpp/os/ClassLibraryPAL/brotli/include"; + } + if (!newPro.Contains("Libraries/external/xxHash")) + { + newPro += " $(SRCROOT)/Libraries/external/xxHash"; + } + //Debug.Log($"config:{bcn} new prop:{newPro}"); + proj.SetBuildPropertyForConfig(configGuid, headerSearchPaths, newPro); + + string cflagKey = "OTHER_CFLAGS"; + string cfProp = proj.GetBuildPropertyForConfig(configGuid, cflagKey); + foreach (var flag in cflags) + { + if (!cfProp.Contains(flag)) + { + cfProp += " " + flag; + } + } + if (configName.Contains("Debug") && !cfProp.Contains("-DIL2CPP_DEBUG=")) + { + cfProp += " -DIL2CPP_DEBUG=1 -DDEBUG=1"; + } + proj.SetBuildPropertyForConfig(configGuid, cflagKey, cfProp); + + } + proj.WriteToFile(pbxprojFile); + } + + private static void CopyLibil2cppToXcodeProj(string srcLibil2cppDir, string dstLibil2cppDir) + { + BashUtil.RemoveDir(dstLibil2cppDir); + BashUtil.CopyDir(srcLibil2cppDir, dstLibil2cppDir, true); + } + + + private static void CopyExternalToXcodeProj(string srcExternalDir, string dstExternalDir) + { + BashUtil.RemoveDir(dstExternalDir); + BashUtil.CopyDir(srcExternalDir, dstExternalDir, true); + + string baselibPlatfromsDir = $"{dstExternalDir}/baselib/Platforms"; + BashUtil.RemoveDir($"{baselibPlatfromsDir}/IOS"); + BashUtil.CopyDir($"{baselibPlatfromsDir}/OSX", $"{baselibPlatfromsDir}/IOS", true); + } + + class LumpFile + { + public List cppFiles = new List(); + + public readonly string lumpFile; + + public readonly string il2cppConfigFile; + + public LumpFile(string lumpFile, string il2cppConfigFile) + { + this.lumpFile = lumpFile; + this.il2cppConfigFile = il2cppConfigFile; + this.cppFiles.Add(il2cppConfigFile); + } + + public void SaveFile() + { + var lumpFileContent = new List(); + foreach (var file in cppFiles) + { + lumpFileContent.Add($"#include \"{GetRelativePathFromProj(file)}\""); + } + File.WriteAllLines(lumpFile, lumpFileContent, Encoding.UTF8); + Debug.Log($"create lump file:{lumpFile}"); + } + } + + private static List CreateLumps(string libil2cppDir, string outputDir) + { + BashUtil.RecreateDir(outputDir); + + string il2cppConfigFile = $"{libil2cppDir}/il2cpp-config.h"; + var lumpFiles = new List(); + int lumpFileIndex = 0; + foreach (var cppDir in Directory.GetDirectories(libil2cppDir, "*", SearchOption.AllDirectories).Concat(new string[] {libil2cppDir})) + { + var lumpFile = new LumpFile($"{outputDir}/lump_{Path.GetFileName(cppDir)}_{lumpFileIndex}.cpp", il2cppConfigFile); + foreach (var file in Directory.GetFiles(cppDir, "*.cpp", SearchOption.TopDirectoryOnly)) + { + lumpFile.cppFiles.Add(file); + } + lumpFile.SaveFile(); + lumpFiles.Add(lumpFile); + ++lumpFileIndex; + } + + var mmFiles = Directory.GetFiles(libil2cppDir, "*.mm", SearchOption.AllDirectories); + if (mmFiles.Length > 0) + { + var lumpFile = new LumpFile($"{outputDir}/lump_mm.mm", il2cppConfigFile); + foreach (var file in mmFiles) + { + lumpFile.cppFiles.Add(file); + } + lumpFile.SaveFile(); + lumpFiles.Add(lumpFile); + } + return lumpFiles; + } + + private static List GetExtraSourceFiles(string externalDir, string libil2cppDir) + { + var files = new List(); + foreach (string extraDir in new string[] + { + $"{externalDir}/zlib", + $"{externalDir}/xxHash", + $"{libil2cppDir}/os/ClassLibraryPAL/brotli", + }) + { + if (!Directory.Exists(extraDir)) + { + continue; + } + files.AddRange(Directory.GetFiles(extraDir, "*.c", SearchOption.AllDirectories)); + } + return files; + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs.meta new file mode 100644 index 0000000..7eba538 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2021OrOlder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 61948fcb1bc40ba47b8c10b0ae801ebb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs new file mode 100644 index 0000000..e1cdd9e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs @@ -0,0 +1,57 @@ +using HybridCLR.Editor.Installer; +using HybridCLR.Editor.Settings; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Callbacks; +using UnityEngine; + +#if UNITY_2022_2_OR_NEWER && UNITY_IOS + +namespace HybridCLR.Editor.BuildProcessors +{ + public static class AddLil2cppSourceCodeToXcodeproj2022OrNewer + { + //[MenuItem("HybridCLR/Modfiyxcode")] + //public static void Modify() + //{ + // OnPostProcessBuild(BuildTarget.iOS, $"{SettingsUtil.ProjectDir}/Build-iOS"); + //} + + [PostProcessBuild] + public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject) + { + if (target != BuildTarget.iOS || !HybridCLRSettings.Instance.enable) + return; + + string pbxprojFile = $"{pathToBuiltProject}/Unity-iPhone.xcodeproj/project.pbxproj"; + RemoveExternalLibil2cppOption(pbxprojFile); + CopyLibil2cppToXcodeProj(pathToBuiltProject); + } + + private static void RemoveExternalLibil2cppOption(string pbxprojFile) + { + string pbxprojContent = File.ReadAllText(pbxprojFile, Encoding.UTF8); + string removeBuildOption = @"--external-lib-il2-cpp=\""$PROJECT_DIR/Libraries/libil2cpp.a\"""; + if (!pbxprojContent.Contains(removeBuildOption)) + { + //throw new BuildFailedException("modified project.pbxproj fail"); + Debug.LogError("[AddLil2cppSourceCodeToXcodeproj] modified project.pbxproj fail"); + return; + } + pbxprojContent = pbxprojContent.Replace(removeBuildOption, ""); + File.WriteAllText(pbxprojFile, pbxprojContent, Encoding.UTF8); + Debug.Log($"[AddLil2cppSourceCodeToXcodeproj] remove il2cpp build option '{removeBuildOption}' from file '{pbxprojFile}'"); + } + + private static void CopyLibil2cppToXcodeProj(string pathToBuiltProject) + { + string srcLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp"; + string destLibil2cppDir = $"{pathToBuiltProject}/Il2CppOutputProject/IL2CPP/libil2cpp"; + BashUtil.RemoveDir(destLibil2cppDir); + BashUtil.CopyDir(srcLibil2cppDir, destLibil2cppDir, true); + } + } +} +#endif \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs.meta new file mode 100644 index 0000000..e71a765 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/AddLil2cppSourceCodeToXcodeproj2022OrNewer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4ce072f7e4a17248a3d9ebfd011356b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CheckSettings.cs b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CheckSettings.cs new file mode 100644 index 0000000..a5840bc --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CheckSettings.cs @@ -0,0 +1,72 @@ +using HybridCLR.Editor.Settings; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEngine; +using static UnityEngine.GraphicsBuffer; + +namespace HybridCLR.Editor.BuildProcessors +{ + internal class CheckSettings : IPreprocessBuildWithReport + { + public int callbackOrder => 0; + + public void OnPreprocessBuild(BuildReport report) + { + HybridCLRSettings globalSettings = SettingsUtil.HybridCLRSettings; + if (!globalSettings.enable || globalSettings.useGlobalIl2cpp) + { + string oldIl2cppPath = Environment.GetEnvironmentVariable("UNITY_IL2CPP_PATH"); + if (!string.IsNullOrEmpty(oldIl2cppPath)) + { + Environment.SetEnvironmentVariable("UNITY_IL2CPP_PATH", ""); + Debug.Log($"[CheckSettings] clean process environment variable: UNITY_IL2CPP_PATH, old vlaue:'{oldIl2cppPath}'"); + } + } + else + { + string curIl2cppPath = Environment.GetEnvironmentVariable("UNITY_IL2CPP_PATH"); + if (curIl2cppPath != SettingsUtil.LocalIl2CppDir) + { + Environment.SetEnvironmentVariable("UNITY_IL2CPP_PATH", SettingsUtil.LocalIl2CppDir); + Debug.Log($"[CheckSettings] UNITY_IL2CPP_PATH old value:'{curIl2cppPath}', new value:'{SettingsUtil.LocalIl2CppDir}'"); + } + } + if (!globalSettings.enable) + { + return; + } + BuildTargetGroup buildTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget); + ScriptingImplementation curScriptingImplementation = PlayerSettings.GetScriptingBackend(buildTargetGroup); + ScriptingImplementation targetScriptingImplementation = ScriptingImplementation.IL2CPP; + if (curScriptingImplementation != targetScriptingImplementation) + { + Debug.LogError($"[CheckSettings] current ScriptingBackend:{curScriptingImplementation},have been switched to:{targetScriptingImplementation} automatically"); + PlayerSettings.SetScriptingBackend(buildTargetGroup, targetScriptingImplementation); + } + + var installer = new Installer.InstallerController(); + if (!installer.HasInstalledHybridCLR()) + { + throw new BuildFailedException($"You have not initialized HybridCLR, please install it via menu 'HybridCLR/Installer'"); + } + + if (installer.PackageVersion != installer.InstalledLibil2cppVersion) + { + throw new BuildFailedException($"You must run `HybridCLR/Installer` after upgrading package"); + } + + HybridCLRSettings gs = SettingsUtil.HybridCLRSettings; + if (((gs.hotUpdateAssemblies?.Length + gs.hotUpdateAssemblyDefinitions?.Length) ?? 0) == 0) + { + Debug.LogWarning("[CheckSettings] No hot update modules configured in HybridCLRSettings"); + } + + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CheckSettings.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CheckSettings.cs.meta new file mode 100644 index 0000000..0cc3643 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CheckSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb4ba063068b17247b2d0233420aa5f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs new file mode 100644 index 0000000..1d3259e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs @@ -0,0 +1,107 @@ +using HybridCLR.Editor.Installer; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEditor.Il2Cpp; +using UnityEditor.UnityLinker; +using UnityEngine; + +namespace HybridCLR.Editor.BuildProcessors +{ + internal class CopyStrippedAOTAssemblies : IPostprocessBuildWithReport, IPreprocessBuildWithReport +#if !UNITY_2021_1_OR_NEWER + , IIl2CppProcessor +#endif + { + + public int callbackOrder => 0; + +#if UNITY_2021_1_OR_NEWER + public static string GetStripAssembliesDir2021(BuildTarget target) + { + string projectDir = SettingsUtil.ProjectDir; + switch (target) + { + case BuildTarget.StandaloneWindows: + case BuildTarget.StandaloneWindows64: + return $"{projectDir}/Library/Bee/artifacts/WinPlayerBuildProgram/ManagedStripped"; + case BuildTarget.StandaloneLinux64: + return $"{projectDir}/Library/Bee/artifacts/LinuxPlayerBuildProgram/ManagedStripped"; + case BuildTarget.Android: + return $"{projectDir}/Library/Bee/artifacts/Android/ManagedStripped"; + case BuildTarget.iOS: + return $"{projectDir}/Library/Bee/artifacts/iOS/ManagedStripped"; + case BuildTarget.WebGL: + return $"{projectDir}/Library/Bee/artifacts/WebGL/ManagedStripped"; + case BuildTarget.StandaloneOSX: + return $"{projectDir}/Library/Bee/artifacts/MacStandalonePlayerBuildProgram/ManagedStripped"; + case BuildTarget.PS4: + return $"{projectDir}/Library/Bee/artifacts/PS4PlayerBuildProgram/ManagedStripped"; + case BuildTarget.PS5: + return $"{projectDir}/Library/Bee/artifacts/PS5PlayerBuildProgram/ManagedStripped"; + default: return ""; + } + } +#else + private string GetStripAssembliesDir2020(BuildTarget target) + { + string subPath = target == BuildTarget.Android ? + "assets/bin/Data/Managed" : + "Data/Managed/"; + return $"{SettingsUtil.ProjectDir}/Temp/StagingArea/{subPath}"; + } + + public void OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data) + { + // 此回调只在 2020中调用 + CopyStripDlls(GetStripAssembliesDir2020(data.target), data.target); + } +#endif + + public static void CopyStripDlls(string srcStripDllPath, BuildTarget target) + { + if (!SettingsUtil.Enable) + { + Debug.Log($"[CopyStrippedAOTAssemblies] disabled"); + return; + } + Debug.Log($"[CopyStrippedAOTAssemblies] CopyScripDlls. src:{srcStripDllPath} target:{target}"); + + var dstPath = SettingsUtil.GetAssembliesPostIl2CppStripDir(target); + + Directory.CreateDirectory(dstPath); + + foreach (var fileFullPath in Directory.GetFiles(srcStripDllPath, "*.dll")) + { + var file = Path.GetFileName(fileFullPath); + Debug.Log($"[CopyStrippedAOTAssemblies] copy strip dll {fileFullPath} ==> {dstPath}/{file}"); + File.Copy($"{fileFullPath}", $"{dstPath}/{file}", true); + } + } + + public void OnPostprocessBuild(BuildReport report) + { +#if UNITY_2021_1_OR_NEWER + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + string srcStripDllPath = GetStripAssembliesDir2021(target); + if (!string.IsNullOrEmpty(srcStripDllPath) && Directory.Exists(srcStripDllPath)) + { + CopyStripDlls(srcStripDllPath, target); + } +#endif + } + + public void OnPreprocessBuild(BuildReport report) + { + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + var dstPath = SettingsUtil.GetAssembliesPostIl2CppStripDir(target); + BashUtil.RecreateDir(dstPath); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs.meta new file mode 100644 index 0000000..3ebc0e1 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/CopyStrippedAOTAssemblies.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7884710ec2f8e545b3fe9aa05def5a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/FilterHotFixAssemblies.cs b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/FilterHotFixAssemblies.cs new file mode 100644 index 0000000..1cb56b6 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/FilterHotFixAssemblies.cs @@ -0,0 +1,68 @@ +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEditor.Build; +using UnityEngine; + +namespace HybridCLR.Editor.BuildProcessors +{ + /// + /// 将热更新dll从Build过程中过滤,防止打包到主工程中 + /// + internal class FilterHotFixAssemblies : IFilterBuildAssemblies + { + public int callbackOrder => 0; + + public string[] OnFilterAssemblies(BuildOptions buildOptions, string[] assemblies) + { + if (!SettingsUtil.Enable) + { + Debug.Log($"[FilterHotFixAssemblies] disabled"); + return assemblies; + } + List allHotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; + + // 检查是否重复填写 + var hotUpdateDllSet = new HashSet(); + foreach(var hotUpdateDll in allHotUpdateDllNames) + { + if (string.IsNullOrWhiteSpace(hotUpdateDll)) + { + throw new BuildFailedException($"hot update assembly name cann't be empty"); + } + if (!hotUpdateDllSet.Add(hotUpdateDll)) + { + throw new BuildFailedException($"hot update assembly:{hotUpdateDll} is duplicated"); + } + } + + var assResolver = MetaUtil.CreateHotUpdateAssemblyResolver(EditorUserBuildSettings.activeBuildTarget, allHotUpdateDllNames); + // 检查是否填写了正确的dll名称 + foreach (var hotUpdateDllName in allHotUpdateDllNames) + { + if (assemblies.Select(Path.GetFileNameWithoutExtension).All(ass => ass != hotUpdateDllName) + && string.IsNullOrEmpty(assResolver.ResolveAssembly(hotUpdateDllName, false))) + { + throw new BuildFailedException($"hot update assembly:{hotUpdateDllName} doesn't exist"); + } + } + + // 将热更dll从打包列表中移除 + return assemblies.Where(ass => + { + string assName = Path.GetFileNameWithoutExtension(ass); + bool reserved = allHotUpdateDllNames.All(dll => !assName.Equals(dll, StringComparison.Ordinal)); + if (!reserved) + { + Debug.Log($"[FilterHotFixAssemblies] filter assembly:{assName}"); + } + return reserved; + }).ToArray(); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/FilterHotFixAssemblies.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/FilterHotFixAssemblies.cs.meta new file mode 100644 index 0000000..2ab4ba5 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/FilterHotFixAssemblies.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9dec2922e3df5464aa047b636eb19e0d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/MsvcStdextWorkaround.cs b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/MsvcStdextWorkaround.cs new file mode 100644 index 0000000..f01a4dc --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/MsvcStdextWorkaround.cs @@ -0,0 +1,32 @@ +#if UNITY_EDITOR +using System; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; + +namespace HybridCLR.Editor.BuildProcessors +{ + + public class MsvcStdextWorkaround : IPreprocessBuildWithReport + { + const string kWorkaroundFlag = "/D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS"; + + public int callbackOrder => 0; + + public void OnPreprocessBuild(BuildReport report) + { + var clEnv = Environment.GetEnvironmentVariable("_CL_"); + + if (string.IsNullOrEmpty(clEnv)) + { + Environment.SetEnvironmentVariable("_CL_", kWorkaroundFlag); + } + else if (!clEnv.Contains(kWorkaroundFlag)) + { + clEnv += " " + kWorkaroundFlag; + Environment.SetEnvironmentVariable("_CL_", clEnv); + } + } + } +} + +#endif // UNITY_EDITOR diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/MsvcStdextWorkaround.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/MsvcStdextWorkaround.cs.meta new file mode 100644 index 0000000..ef28c51 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/MsvcStdextWorkaround.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8bff6cadf0b8db54b87ba51b24d080f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/PatchScriptingAssemblyList.cs b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/PatchScriptingAssemblyList.cs new file mode 100644 index 0000000..ee21b9b --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/PatchScriptingAssemblyList.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEditor.Android; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEditor.Il2Cpp; +using UnityEditor.UnityLinker; +using UnityEngine; + +namespace HybridCLR.Editor.BuildProcessors +{ + public class PatchScriptingAssemblyList : +#if UNITY_ANDROID + IPostGenerateGradleAndroidProject, +#endif + IPostprocessBuildWithReport +#if !UNITY_2021_1_OR_NEWER && UNITY_WEBGL + , IIl2CppProcessor +#endif + +#if UNITY_PS5 + , IUnityLinkerProcessor +#endif + + { + public int callbackOrder => 0; + + public void OnPostGenerateGradleAndroidProject(string path) + { + // 如果直接打包apk,没有机会在PostprocessBuild中修改ScriptingAssemblies.json。 + // 因此需要在这个时机处理 + // Unity有bug,偶然情况下会传入apk的路径,导致替换失败 + if (Directory.Exists(path)) + { + PathScriptingAssembilesFile(path); + } + else + { + PathScriptingAssembilesFile($"{SettingsUtil.ProjectDir}/Library"); + } + } + + public void OnPostprocessBuild(BuildReport report) + { + // 如果target为Android,由于已经在OnPostGenerateGradelAndroidProject中处理过, + // 这里不再重复处理 +#if !UNITY_ANDROID && !UNITY_WEBGL + PathScriptingAssembilesFile(report.summary.outputPath); +#endif + } + +#if UNITY_PS5 + /// + /// 打包模式如果是 Package 需要在这个阶段提前处理 .json , PC Hosted 和 GP5 模式不受影响 + /// + + public string GenerateAdditionalLinkXmlFile(UnityEditor.Build.Reporting.BuildReport report, UnityEditor.UnityLinker.UnityLinkerBuildPipelineData data) + { + string path = $"{SettingsUtil.ProjectDir}/Library/PlayerDataCache/PS5/Data"; + PathScriptingAssembilesFile(path); + return null; + } +#endif + public void PathScriptingAssembilesFile(string path) + { + if (!SettingsUtil.Enable) + { + Debug.Log($"[PatchScriptingAssemblyList] disabled"); + return; + } + Debug.Log($"[PatchScriptingAssemblyList]. path:{path}"); + if (!Directory.Exists(path)) + { + path = Path.GetDirectoryName(path); + Debug.Log($"[PatchScriptingAssemblyList] get path parent:{path}"); + } + AddHotFixAssembliesToScriptingAssembliesJson(path); + } + + private void AddHotFixAssembliesToScriptingAssembliesJson(string path) + { + Debug.Log($"[PatchScriptingAssemblyList]. path:{path}"); + /* + * ScriptingAssemblies.json 文件中记录了所有的dll名称,此列表在游戏启动时自动加载, + * 不在此列表中的dll在资源反序列化时无法被找到其类型 + * 因此 OnFilterAssemblies 中移除的条目需要再加回来 + */ + string[] jsonFiles = Directory.GetFiles(path, SettingsUtil.ScriptingAssembliesJsonFile, SearchOption.AllDirectories); + + if (jsonFiles.Length == 0) + { + Debug.LogWarning($"can not find file {SettingsUtil.ScriptingAssembliesJsonFile}"); + return; + } + + foreach (string file in jsonFiles) + { + var patcher = new ScriptingAssembliesJsonPatcher(); + patcher.Load(file); + patcher.AddScriptingAssemblies(SettingsUtil.HotUpdateAssemblyFilesIncludePreserved); + patcher.Save(file); + } + } + +#if UNITY_WEBGL + public void OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data) + { + PathScriptingAssembilesFile($"{SettingsUtil.ProjectDir}/Temp/StagingArea/Data"); + } +#endif + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/PatchScriptingAssemblyList.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/PatchScriptingAssemblyList.cs.meta new file mode 100644 index 0000000..0affdc7 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/PatchScriptingAssemblyList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9bb6e2908d8948648979c9ff6bb7937d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/ScriptingAssembliesJsonPatcher.cs b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/ScriptingAssembliesJsonPatcher.cs new file mode 100644 index 0000000..a124e34 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/ScriptingAssembliesJsonPatcher.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.BuildProcessors +{ + public class ScriptingAssembliesJsonPatcher + { + [Serializable] + private class ScriptingAssemblies + { + public List names; + public List types; + } + + private string _file; + ScriptingAssemblies _scriptingAssemblies; + + public void Load(string file) + { + _file = file; + string content = File.ReadAllText(file); + _scriptingAssemblies = JsonUtility.FromJson(content); + } + + public void AddScriptingAssemblies(List assemblies) + { + foreach (string name in assemblies) + { + if (!_scriptingAssemblies.names.Contains(name)) + { + _scriptingAssemblies.names.Add(name); + _scriptingAssemblies.types.Add(16); // user dll type + Debug.Log($"[PatchScriptAssembliesJson] add hotfix assembly:{name} to {_file}"); + } + } + } + + public void Save(string jsonFile) + { + string content = JsonUtility.ToJson(_scriptingAssemblies); + + File.WriteAllText(jsonFile, content); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/ScriptingAssembliesJsonPatcher.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/ScriptingAssembliesJsonPatcher.cs.meta new file mode 100644 index 0000000..c4c07e0 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/BuildProcessors/ScriptingAssembliesJsonPatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4455f7304f8678f408dd6cf21734f55e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands.meta b/Packages/com.code-philosophy.hybridclr/Editor/Commands.meta new file mode 100644 index 0000000..c61c778 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 92f51c069d2607447ae2f61de80540fb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/AOTReferenceGeneratorCommand.cs b/Packages/com.code-philosophy.hybridclr/Editor/Commands/AOTReferenceGeneratorCommand.cs new file mode 100644 index 0000000..c426f1d --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/AOTReferenceGeneratorCommand.cs @@ -0,0 +1,46 @@ +using HybridCLR.Editor.AOT; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEngine; + +namespace HybridCLR.Editor.Commands +{ + using Analyzer = HybridCLR.Editor.AOT.Analyzer; + public static class AOTReferenceGeneratorCommand + { + + [MenuItem("HybridCLR/Generate/AOTGenericReference", priority = 102)] + public static void CompileAndGenerateAOTGenericReference() + { + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + CompileDllCommand.CompileDll(target); + GenerateAOTGenericReference(target); + } + + public static void GenerateAOTGenericReference(BuildTarget target) + { + var gs = SettingsUtil.HybridCLRSettings; + List hotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; + + using (AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames), hotUpdateDllNames)) + { + var analyzer = new Analyzer(new Analyzer.Options + { + MaxIterationCount = Math.Min(20, gs.maxGenericReferenceIteration), + Collector = collector, + }); + + analyzer.Run(); + + var writer = new GenericReferenceWriter(); + writer.Write(analyzer.AotGenericTypes.ToList(), analyzer.AotGenericMethods.ToList(), $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}"); + AssetDatabase.Refresh(); + } + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/AOTReferenceGeneratorCommand.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Commands/AOTReferenceGeneratorCommand.cs.meta new file mode 100644 index 0000000..39760e8 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/AOTReferenceGeneratorCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2b464872c07f6ba4f9a4e4a02ca9a28c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/CompileDllCommand.cs b/Packages/com.code-philosophy.hybridclr/Editor/Commands/CompileDllCommand.cs new file mode 100644 index 0000000..a26b97d --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/CompileDllCommand.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEditor.Build.Player; +using UnityEngine; + +namespace HybridCLR.Editor.Commands +{ + public class CompileDllCommand + { + public static void CompileDll(string buildDir, BuildTarget target, bool developmentBuild) + { + var group = BuildPipeline.GetBuildTargetGroup(target); + + ScriptCompilationSettings scriptCompilationSettings = new ScriptCompilationSettings(); + scriptCompilationSettings.group = group; + scriptCompilationSettings.target = target; + scriptCompilationSettings.options = developmentBuild ? ScriptCompilationOptions.DevelopmentBuild : ScriptCompilationOptions.None; + Directory.CreateDirectory(buildDir); + ScriptCompilationResult scriptCompilationResult = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, buildDir); +#if UNITY_2022 + UnityEditor.EditorUtility.ClearProgressBar(); +#endif + Debug.Log("compile finish!!!"); + } + + public static void CompileDll(BuildTarget target, bool developmentBuild = false) + { + CompileDll(SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target), target, developmentBuild); + } + + [MenuItem("HybridCLR/CompileDll/ActiveBuildTarget", priority = 100)] + public static void CompileDllActiveBuildTarget() + { + CompileDll(EditorUserBuildSettings.activeBuildTarget); + } + + [MenuItem("HybridCLR/CompileDll/ActiveBuildTarget_Development", priority = 101)] + public static void CompileDllActiveBuildTargetDevelopment() + { + CompileDll(EditorUserBuildSettings.activeBuildTarget, true); + } + + [MenuItem("HybridCLR/CompileDll/Win32", priority = 200)] + public static void CompileDllWin32() + { + CompileDll(BuildTarget.StandaloneWindows); + } + + [MenuItem("HybridCLR/CompileDll/Win64", priority = 201)] + public static void CompileDllWin64() + { + CompileDll(BuildTarget.StandaloneWindows64); + } + + [MenuItem("HybridCLR/CompileDll/MacOS", priority = 202)] + public static void CompileDllMacOS() + { + CompileDll(BuildTarget.StandaloneOSX); + } + + [MenuItem("HybridCLR/CompileDll/Linux", priority = 203)] + public static void CompileDllLinux() + { + CompileDll(BuildTarget.StandaloneLinux64); + } + + [MenuItem("HybridCLR/CompileDll/Android", priority = 210)] + public static void CompileDllAndroid() + { + CompileDll(BuildTarget.Android); + } + + [MenuItem("HybridCLR/CompileDll/IOS", priority = 220)] + public static void CompileDllIOS() + { + CompileDll(BuildTarget.iOS); + } + + [MenuItem("HybridCLR/CompileDll/WebGL", priority = 230)] + public static void CompileDllWebGL() + { + CompileDll(BuildTarget.WebGL); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/CompileDllCommand.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Commands/CompileDllCommand.cs.meta new file mode 100644 index 0000000..88b2e30 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/CompileDllCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bf11b6c8bbc5afd4cb4a11921e5bd81e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/Il2CppDefGeneratorCommand.cs b/Packages/com.code-philosophy.hybridclr/Editor/Commands/Il2CppDefGeneratorCommand.cs new file mode 100644 index 0000000..a56c2b0 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/Il2CppDefGeneratorCommand.cs @@ -0,0 +1,30 @@ +using HybridCLR.Editor.Link; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace HybridCLR.Editor.Commands +{ + + public static class Il2CppDefGeneratorCommand + { + + [MenuItem("HybridCLR/Generate/Il2CppDef", priority = 104)] + public static void GenerateIl2CppDef() + { + var options = new Il2CppDef.Il2CppDefGenerator.Options() + { + UnityVersion = Application.unityVersion, + HotUpdateAssemblies = SettingsUtil.HotUpdateAssemblyNamesIncludePreserved, + OutputFile = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/generated/UnityVersion.h", + OutputFile2 = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/generated/AssemblyManifest.cpp", + }; + + var g = new Il2CppDef.Il2CppDefGenerator(options); + g.Generate(); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/Il2CppDefGeneratorCommand.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Commands/Il2CppDefGeneratorCommand.cs.meta new file mode 100644 index 0000000..21f9427 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/Il2CppDefGeneratorCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5165a065d05497c43a2fff885f31ed07 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/LinkGeneratorCommand.cs b/Packages/com.code-philosophy.hybridclr/Editor/Commands/LinkGeneratorCommand.cs new file mode 100644 index 0000000..c545ff5 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/LinkGeneratorCommand.cs @@ -0,0 +1,39 @@ +using HybridCLR.Editor.Link; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace HybridCLR.Editor.Commands +{ + using Analyzer = HybridCLR.Editor.Link.Analyzer; + + public static class LinkGeneratorCommand + { + + [MenuItem("HybridCLR/Generate/LinkXml", priority = 100)] + public static void GenerateLinkXml() + { + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + CompileDllCommand.CompileDll(target); + GenerateLinkXml(target); + } + + public static void GenerateLinkXml(BuildTarget target) + { + var ls = SettingsUtil.HybridCLRSettings; + + List hotfixAssemblies = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; + + var analyzer = new Analyzer(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotfixAssemblies)); + var refTypes = analyzer.CollectRefs(hotfixAssemblies); + + Debug.Log($"[LinkGeneratorCommand] hotfix assembly count:{hotfixAssemblies.Count}, ref type count:{refTypes.Count} output:{Application.dataPath}/{ls.outputLinkFile}"); + var linkXmlWriter = new LinkXmlWriter(); + linkXmlWriter.Write($"{Application.dataPath}/{ls.outputLinkFile}", refTypes); + AssetDatabase.Refresh(); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/LinkGeneratorCommand.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Commands/LinkGeneratorCommand.cs.meta new file mode 100644 index 0000000..0eeba1f --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/LinkGeneratorCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f5b96abdbc4c424eb1bc3bc34b3a1a4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/MethodBridgeGeneratorCommand.cs b/Packages/com.code-philosophy.hybridclr/Editor/Commands/MethodBridgeGeneratorCommand.cs new file mode 100644 index 0000000..fde1084 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/MethodBridgeGeneratorCommand.cs @@ -0,0 +1,81 @@ +using HybridCLR.Editor; +using HybridCLR.Editor.ABI; +using HybridCLR.Editor.Meta; +using HybridCLR.Editor.MethodBridge; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEditor.Build; +using UnityEngine; + +namespace HybridCLR.Editor.Commands +{ + using Analyzer = HybridCLR.Editor.MethodBridge.Analyzer; + public class MethodBridgeGeneratorCommand + { + + public static void CleanIl2CppBuildCache() + { + string il2cppBuildCachePath = SettingsUtil.Il2CppBuildCacheDir; + if (!Directory.Exists(il2cppBuildCachePath)) + { + return; + } + Debug.Log($"clean il2cpp build cache:{il2cppBuildCachePath}"); + Directory.Delete(il2cppBuildCachePath, true); + } + + private static void GenerateMethodBridgeCppFile(Analyzer analyzer, string outputFile) + { + string templateCode = File.ReadAllText(outputFile, Encoding.UTF8); + var g = new Generator(new Generator.Options() + { + TemplateCode = templateCode, + OutputFile = outputFile, + GenericMethods = analyzer.GenericMethods, + }); + + g.PrepareMethods(); + g.Generate(); + Debug.LogFormat("[MethodBridgeGeneratorCommand] output:{0}", outputFile); + } + + [MenuItem("HybridCLR/Generate/MethodBridge", priority = 101)] + public static void CompileAndGenerateMethodBridge() + { + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + GenerateMethodBridge(target); + } + + public static void GenerateMethodBridge(BuildTarget target) + { + string aotDllDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target); + List aotAssemblyNames = Directory.Exists(aotDllDir) ? + Directory.GetFiles(aotDllDir, "*.dll", SearchOption.TopDirectoryOnly).Select(Path.GetFileNameWithoutExtension).ToList() + : new List(); + if (aotAssemblyNames.Count == 0) + { + throw new Exception($"no aot assembly found. please run `HybridCLR/Generate/All` or `HybridCLR/Generate/AotDlls` to generate aot dlls before runing `HybridCLR/Generate/MethodBridge`"); + } + using (AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateAOTAssemblyResolver(target), aotAssemblyNames)) + { + var analyzer = new Analyzer(new Analyzer.Options + { + MaxIterationCount = Math.Min(20, SettingsUtil.HybridCLRSettings.maxMethodBridgeGenericIteration), + Collector = collector, + }); + + analyzer.Run(); + string outputFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge.cpp"; + GenerateMethodBridgeCppFile(analyzer, outputFile); + } + + CleanIl2CppBuildCache(); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/MethodBridgeGeneratorCommand.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Commands/MethodBridgeGeneratorCommand.cs.meta new file mode 100644 index 0000000..9827997 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/MethodBridgeGeneratorCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 46bc62d5236f5e941850776c435a9560 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/PrebuildCommand.cs b/Packages/com.code-philosophy.hybridclr/Editor/Commands/PrebuildCommand.cs new file mode 100644 index 0000000..8fe2a46 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/PrebuildCommand.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; + +namespace HybridCLR.Editor.Commands +{ + public static class PrebuildCommand + { + /// + /// 按照必要的顺序,执行所有生成操作,适合打包前操作 + /// + [MenuItem("HybridCLR/Generate/All", priority = 200)] + public static void GenerateAll() + { + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + CompileDllCommand.CompileDll(target); + Il2CppDefGeneratorCommand.GenerateIl2CppDef(); + + // 这几个生成依赖HotUpdateDlls + LinkGeneratorCommand.GenerateLinkXml(target); + + // 生成裁剪后的aot dll + StripAOTDllCommand.GenerateStripedAOTDlls(target); + + // 桥接函数生成依赖于AOT dll,必须保证已经build过,生成AOT dll + MethodBridgeGeneratorCommand.GenerateMethodBridge(target); + ReversePInvokeWrapperGeneratorCommand.GenerateReversePInvokeWrapper(target); + AOTReferenceGeneratorCommand.GenerateAOTGenericReference(target); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/PrebuildCommand.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Commands/PrebuildCommand.cs.meta new file mode 100644 index 0000000..a27aea2 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/PrebuildCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c20f09bfbe3f32143aae872d3813d9e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs b/Packages/com.code-philosophy.hybridclr/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs new file mode 100644 index 0000000..706e748 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs @@ -0,0 +1,49 @@ +using HybridCLR.Editor.ABI; +using HybridCLR.Editor.Link; +using HybridCLR.Editor.Meta; +using HybridCLR.Editor.ReversePInvokeWrap; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEngine; + +namespace HybridCLR.Editor.Commands +{ + + public static class ReversePInvokeWrapperGeneratorCommand + { + + [MenuItem("HybridCLR/Generate/ReversePInvokeWrapper", priority = 103)] + + public static void CompileAndGenerateReversePInvokeWrapper() + { + BuildTarget target = EditorUserBuildSettings.activeBuildTarget; + CompileDllCommand.CompileDll(target); + GenerateReversePInvokeWrapper(target); + } + + public static void GenerateReversePInvokeWrapper(BuildTarget target) + { + List hotUpdateDlls = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; + using (var cache = new AssemblyCache(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDlls))) + { + var analyzer = new ReversePInvokeWrap.Analyzer(cache, hotUpdateDlls); + analyzer.Run(); + + string outputFile = $"{SettingsUtil.GeneratedCppDir}/ReversePInvokeMethodStub.cpp"; + + List methods = analyzer.BuildABIMethods(); + Debug.Log($"GenerateReversePInvokeWrapper. wraperCount:{methods.Sum(m => m.Count)} output:{outputFile}"); + var generator = new Generator(); + generator.Generate(methods, outputFile); + Debug.LogFormat("[ReversePInvokeWrapperGeneratorCommand] output:{0}", outputFile); + } + MethodBridgeGeneratorCommand.CleanIl2CppBuildCache(); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs.meta new file mode 100644 index 0000000..79fb3d8 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7db18e1736f593c4089c85d764cf8620 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/StripAOTDllCommand.cs b/Packages/com.code-philosophy.hybridclr/Editor/Commands/StripAOTDllCommand.cs new file mode 100644 index 0000000..f340c1e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/StripAOTDllCommand.cs @@ -0,0 +1,162 @@ +using HybridCLR.Editor.Installer; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEngine; +using static UnityEngine.Networking.UnityWebRequest; + +namespace HybridCLR.Editor.Commands +{ + public static class StripAOTDllCommand + { + [MenuItem("HybridCLR/Generate/AOTDlls", priority = 105)] + public static void GenerateStripedAOTDlls() + { + GenerateStripedAOTDlls(EditorUserBuildSettings.activeBuildTarget); + } + + static BuildOptions GetBuildPlayerOptions(BuildTarget buildTarget) + { + BuildOptions options = BuildOptions.None; + bool development = EditorUserBuildSettings.development; + if (development) + { + options |= BuildOptions.Development; + } + + if (EditorUserBuildSettings.allowDebugging && development) + { + options |= BuildOptions.AllowDebugging; + } + + if (EditorUserBuildSettings.connectProfiler && (development || buildTarget == BuildTarget.WSAPlayer)) + { + options |= BuildOptions.ConnectWithProfiler; + } + + if (EditorUserBuildSettings.buildWithDeepProfilingSupport && development) + { + options |= BuildOptions.EnableDeepProfilingSupport; + } + +#if UNITY_2021_2_OR_NEWER + options |= BuildOptions.CleanBuildCache; +#endif + + return options; + } + + private static string GetLocationPathName(string buildDir, BuildTarget target) + { + switch(target) + { + case BuildTarget.StandaloneWindows: + case BuildTarget.StandaloneWindows64: return $"{buildDir}/{target}"; + case BuildTarget.StandaloneOSX: return buildDir; + case BuildTarget.iOS: return buildDir; + case BuildTarget.Android: return buildDir; + case BuildTarget.StandaloneLinux64: return buildDir; + default: return buildDir; + } + } + + public static void GenerateStripedAOTDlls(BuildTarget target) + { + string outputPath = $"{SettingsUtil.HybridCLRDataDir}/StrippedAOTDllsTempProj/{target}"; + BashUtil.RemoveDir(outputPath); + + var buildOptions = GetBuildPlayerOptions(target); +#if UNITY_2021_2_OR_NEWER + buildOptions |= BuildOptions.CleanBuildCache; +#endif + + bool oldExportAndroidProj = EditorUserBuildSettings.exportAsGoogleAndroidProject; +#if UNITY_EDITOR_OSX + bool oldCreateSolution = UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject; +#elif UNITY_EDITOR_WIN + bool oldCreateSolution = UnityEditor.WindowsStandalone.UserBuildSettings.createSolution; +#endif + bool oldBuildScriptsOnly = EditorUserBuildSettings.buildScriptsOnly; + EditorUserBuildSettings.buildScriptsOnly = true; + + string location = GetLocationPathName(outputPath, target); + string oldBuildLocation = EditorUserBuildSettings.GetBuildLocation(target); + EditorUserBuildSettings.SetBuildLocation(target, location); + + switch (target) + { + case BuildTarget.StandaloneWindows: + case BuildTarget.StandaloneWindows64: + { +#if UNITY_EDITOR_WIN + UnityEditor.WindowsStandalone.UserBuildSettings.createSolution = true; +#endif + break; + } + case BuildTarget.StandaloneOSX: + { +#if UNITY_EDITOR_OSX + UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject = true; +#endif + break; + } + case BuildTarget.Android: + { + EditorUserBuildSettings.exportAsGoogleAndroidProject = true; + break; + } + } + + Debug.Log($"GenerateStripedAOTDlls build option:{buildOptions}"); + + BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions() + { + scenes = EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray(), + locationPathName = location, + options = buildOptions, + target = target, + targetGroup = BuildPipeline.GetBuildTargetGroup(target), + }; + + var report = BuildPipeline.BuildPlayer(buildPlayerOptions); + + EditorUserBuildSettings.buildScriptsOnly = oldBuildScriptsOnly; + EditorUserBuildSettings.SetBuildLocation(target, oldBuildLocation); + + switch (target) + { + case BuildTarget.StandaloneWindows: + case BuildTarget.StandaloneWindows64: + { +#if UNITY_EDITOR_WIN + UnityEditor.WindowsStandalone.UserBuildSettings.createSolution = oldCreateSolution; +#endif + break; + } + case BuildTarget.StandaloneOSX: + { +#if UNITY_EDITOR_OSX + UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject = oldCreateSolution; +#endif + break; + } + case BuildTarget.Android: + { + EditorUserBuildSettings.exportAsGoogleAndroidProject = oldExportAndroidProj; + break; + } + } + + if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded) + { + throw new Exception("GenerateStripedAOTDlls failed"); + } + Debug.Log($"GenerateStripedAOTDlls target:{target} path:{outputPath}"); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Commands/StripAOTDllCommand.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Commands/StripAOTDllCommand.cs.meta new file mode 100644 index 0000000..3979b80 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Commands/StripAOTDllCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21fb0a02f23185141a4a3df67fe61789 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/HashUtil.cs b/Packages/com.code-philosophy.hybridclr/Editor/HashUtil.cs new file mode 100644 index 0000000..38e83e3 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/HashUtil.cs @@ -0,0 +1,28 @@ +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor +{ + public static class HashUtil + { + public static int CombineHash(int hash1, int hash2) + { + return hash1 * 1566083941 + hash2; + } + + public static int ComputHash(List sigs) + { + int hash = 135781321; + TypeEqualityComparer tc = TypeEqualityComparer.Instance; + foreach (var sig in sigs) + { + hash = hash * 1566083941 + tc.GetHashCode(sig); + } + return hash; + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/HashUtil.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/HashUtil.cs.meta new file mode 100644 index 0000000..9cdce22 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/HashUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d4ae4a5c0bba49469c525887d812717 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/HybridCLR.Editor.asmdef b/Packages/com.code-philosophy.hybridclr/Editor/HybridCLR.Editor.asmdef new file mode 100644 index 0000000..4612a6d --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/HybridCLR.Editor.asmdef @@ -0,0 +1,18 @@ +{ + "name": "HybridCLR.Editor", + "rootNamespace": "", + "references": [ + "HybridCLR.Runtime" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Editor/HybridCLR.Editor.asmdef.meta b/Packages/com.code-philosophy.hybridclr/Editor/HybridCLR.Editor.asmdef.meta new file mode 100644 index 0000000..be1417b --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/HybridCLR.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2373f786d14518f44b0f475db77ba4de +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Il2CppDef.meta b/Packages/com.code-philosophy.hybridclr/Editor/Il2CppDef.meta new file mode 100644 index 0000000..dc951ca --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Il2CppDef.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: da46bc9f1a4dece41a5c193166be9a30 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Il2CppDef/Il2CppDefGenerator.cs b/Packages/com.code-philosophy.hybridclr/Editor/Il2CppDef/Il2CppDefGenerator.cs new file mode 100644 index 0000000..8728c65 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Il2CppDef/Il2CppDefGenerator.cs @@ -0,0 +1,86 @@ +using HybridCLR.Editor.ABI; +using HybridCLR.Editor.Template; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.Il2CppDef +{ + public class Il2CppDefGenerator + { + public class Options + { + public List HotUpdateAssemblies { get; set; } + + public string OutputFile { get; set; } + + public string OutputFile2 { get; set; } + + public string UnityVersion { get; set; } + } + + private readonly Options _options; + public Il2CppDefGenerator(Options options) + { + _options = options; + } + + + private static readonly Regex s_unityVersionPat = new Regex(@"(\d+)\.(\d+)\.(\d+)"); + + public void Generate() + { + GenerateIl2CppConfig(); + GeneratePlaceHolderAssemblies(); + } + + private void GenerateIl2CppConfig() + { + var frr = new FileRegionReplace(File.ReadAllText(_options.OutputFile)); + + List lines = new List(); + + var match = s_unityVersionPat.Matches(_options.UnityVersion)[0]; + int majorVer = int.Parse(match.Groups[1].Value); + int minorVer1 = int.Parse(match.Groups[2].Value); + int minorVer2 = int.Parse(match.Groups[3].Value); + + lines.Add($"#define HYBRIDCLR_UNITY_VERSION {majorVer}{minorVer1.ToString("D2")}{minorVer2.ToString("D2")}"); + lines.Add($"#define HYBRIDCLR_UNITY_{majorVer} 1"); + for (int ver = 2019; ver <= 2024; ver++) + { + if (majorVer >= ver) + { + lines.Add($"#define HYBRIDCLR_UNITY_{ver}_OR_NEW 1"); + } + } + + frr.Replace("UNITY_VERSION", string.Join("\n", lines)); + + frr.Commit(_options.OutputFile); + Debug.Log($"[HybridCLR.Editor.Il2CppDef.Generator] output:{_options.OutputFile}"); + } + + private void GeneratePlaceHolderAssemblies() + { + var frr = new FileRegionReplace(File.ReadAllText(_options.OutputFile2)); + + List lines = new List(); + + foreach (var ass in _options.HotUpdateAssemblies) + { + lines.Add($"\t\t\"{ass}\","); + } + + frr.Replace("PLACE_HOLDER", string.Join("\n", lines)); + + frr.Commit(_options.OutputFile2); + Debug.Log($"[HybridCLR.Editor.Il2CppDef.Generator] output:{_options.OutputFile2}"); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Il2CppDef/Il2CppDefGenerator.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Il2CppDef/Il2CppDefGenerator.cs.meta new file mode 100644 index 0000000..b7fe9d7 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Il2CppDef/Il2CppDefGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 590419ee7e82ac24cbac9b8a48891fe0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Installer.meta b/Packages/com.code-philosophy.hybridclr/Editor/Installer.meta new file mode 100644 index 0000000..b27774d --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Installer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a2c8f84b297371d4cbcd5ca655bf360d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Installer/BashUtil.cs b/Packages/com.code-philosophy.hybridclr/Editor/Installer/BashUtil.cs new file mode 100644 index 0000000..555f3ca --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Installer/BashUtil.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.Installer +{ + public static class BashUtil + { + public static int RunCommand(string workingDir, string program, string[] args, bool log = true) + { + using (Process p = new Process()) + { + p.StartInfo.WorkingDirectory = workingDir; + p.StartInfo.FileName = program; + p.StartInfo.UseShellExecute = false; + p.StartInfo.CreateNoWindow = true; + string argsStr = string.Join(" ", args.Select(arg => "\"" + arg + "\"")); + p.StartInfo.Arguments = argsStr; + if (log) + { + UnityEngine.Debug.Log($"[BashUtil] run => {program} {argsStr}"); + } + p.Start(); + p.WaitForExit(); + return p.ExitCode; + } + } + + + public static (int ExitCode, string StdOut, string StdErr) RunCommand2(string workingDir, string program, string[] args, bool log = true) + { + using (Process p = new Process()) + { + p.StartInfo.WorkingDirectory = workingDir; + p.StartInfo.FileName = program; + p.StartInfo.UseShellExecute = false; + p.StartInfo.CreateNoWindow = true; + p.StartInfo.RedirectStandardOutput = true; + p.StartInfo.RedirectStandardError = true; + string argsStr = string.Join(" ", args); + p.StartInfo.Arguments = argsStr; + if (log) + { + UnityEngine.Debug.Log($"[BashUtil] run => {program} {argsStr}"); + } + p.Start(); + p.WaitForExit(); + + string stdOut = p.StandardOutput.ReadToEnd(); + string stdErr = p.StandardError.ReadToEnd(); + return (p.ExitCode, stdOut, stdErr); + } + } + + + public static void RemoveDir(string dir, bool log = false) + { + if (log) + { + UnityEngine.Debug.Log($"[BashUtil] RemoveDir dir:{dir}"); + } + + int maxTryCount = 5; + for (int i = 0; i < maxTryCount; ++i) + { + try + { + if (!Directory.Exists(dir)) + { + return; + } + foreach (var file in Directory.GetFiles(dir)) + { + File.SetAttributes(file, FileAttributes.Normal); + File.Delete(file); + } + foreach (var subDir in Directory.GetDirectories(dir)) + { + RemoveDir(subDir); + } + Directory.Delete(dir); + break; + } + catch (Exception e) + { + UnityEngine.Debug.LogError($"[BashUtil] RemoveDir:{dir} with exception:{e}. try count:{i}"); + Thread.Sleep(100); + } + } + } + + public static void RecreateDir(string dir) + { + if(Directory.Exists(dir)) + { + RemoveDir(dir, true); + } + Directory.CreateDirectory(dir); + } + + private static void CopyWithCheckLongFile(string srcFile, string dstFile) + { + var maxPathLength = 255; +#if UNITY_EDITOR_OSX + maxPathLength = 1024; +#endif + if (srcFile.Length > maxPathLength) + { + UnityEngine.Debug.LogError($"srcFile:{srcFile} path is too long. copy ignore!"); + return; + } + if (dstFile.Length > maxPathLength) + { + UnityEngine.Debug.LogError($"dstFile:{dstFile} path is too long. copy ignore!"); + return; + } + File.Copy(srcFile, dstFile); + } + + public static void CopyDir(string src, string dst, bool log = false) + { + if (log) + { + UnityEngine.Debug.Log($"[BashUtil] CopyDir {src} => {dst}"); + } + RemoveDir(dst); + Directory.CreateDirectory(dst); + foreach(var file in Directory.GetFiles(src)) + { + CopyWithCheckLongFile(file, $"{dst}/{Path.GetFileName(file)}"); + } + foreach(var subDir in Directory.GetDirectories(src)) + { + CopyDir(subDir, $"{dst}/{Path.GetFileName(subDir)}"); + } + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Installer/BashUtil.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Installer/BashUtil.cs.meta new file mode 100644 index 0000000..ef7e11d --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Installer/BashUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 960a0257c3a17f64b810193308ce1558 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerController.cs b/Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerController.cs new file mode 100644 index 0000000..1118994 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerController.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using UnityEditor; +using UnityEngine; +using Debug = UnityEngine.Debug; +using System.Text.RegularExpressions; +using System.Linq; +using HybridCLR.Editor.Settings; + +namespace HybridCLR.Editor.Installer +{ + + public class InstallerController + { + private const string hybridclr_repo_path = "hybridclr_repo"; + + private const string il2cpp_plus_repo_path = "il2cpp_plus_repo"; + + public int MajorVersion => _curVersion.major; + + private readonly UnityVersion _curVersion; + + private readonly HybridclrVersionManifest _versionManifest; + private readonly HybridclrVersionInfo _curDefaultVersion; + + public string PackageVersion { get; private set; } + + public string InstalledLibil2cppVersion { get; private set; } + + public InstallerController() + { + _curVersion = ParseUnityVersion(Application.unityVersion); + _versionManifest = GetHybridCLRVersionManifest(); + _curDefaultVersion = _versionManifest.versions.FirstOrDefault(v => v.unity_version == _curVersion.major.ToString()); + PackageVersion = LoadPackageInfo().version; + InstalledLibil2cppVersion = ReadLocalVersion(); + } + + private HybridclrVersionManifest GetHybridCLRVersionManifest() + { + string versionFile = $"{SettingsUtil.ProjectDir}/{SettingsUtil.HybridCLRDataPathInPackage}/hybridclr_version.json"; + return JsonUtility.FromJson(File.ReadAllText(versionFile, Encoding.UTF8)); + } + + private PackageInfo LoadPackageInfo() + { + string packageJson = $"{SettingsUtil.ProjectDir}/Packages/{SettingsUtil.PackageName}/package.json"; + return JsonUtility.FromJson(File.ReadAllText(packageJson, Encoding.UTF8)); + } + + + [Serializable] + class PackageInfo + { + public string name; + + public string version; + } + + [Serializable] + class VersionDesc + { + public string branch; + + //public string hash; + } + + [Serializable] + class HybridclrVersionInfo + { + public string unity_version; + + public VersionDesc hybridclr; + + public VersionDesc il2cpp_plus; + } + + [Serializable] + class HybridclrVersionManifest + { + public List versions; + } + + private class UnityVersion + { + public int major; + public int minor1; + public int minor2; + + public override string ToString() + { + return $"{major}.{minor1}.{minor2}"; + } + } + + private static readonly Regex s_unityVersionPat = new Regex(@"(\d+)\.(\d+)\.(\d+)"); + + private UnityVersion ParseUnityVersion(string versionStr) + { + var matches = s_unityVersionPat.Matches(versionStr); + if (matches.Count == 0) + { + return null; + } + Match match = matches[matches.Count - 1]; + int major = int.Parse(match.Groups[1].Value); + int minor1 = int.Parse(match.Groups[2].Value); + int minor2 = int.Parse(match.Groups[3].Value); + return new UnityVersion { major = major, minor1 = minor1, minor2 = minor2 }; + } + + public string GetCurrentUnityVersionMinCompatibleVersionStr() + { + return GetMinCompatibleVersion(MajorVersion); + } + + public string GetMinCompatibleVersion(int majorVersion) + { + switch(majorVersion) + { + case 2020: return $"2020.3.0"; + case 2021: return $"2021.3.0"; + case 2022: return $"2022.3.0"; + default: return $"2020.3.0"; + } + } + + public enum CompatibleType + { + Compatible, + MaybeIncompatible, + Incompatible, + } + + public CompatibleType GetCompatibleType() + { + UnityVersion version = _curVersion; + if (version == null) + { + return CompatibleType.Incompatible; + } + if (version.minor1 != 3) + { + return CompatibleType.MaybeIncompatible; + } + return CompatibleType.Compatible; + } + + public string HybridclrLocalVersion => _curDefaultVersion?.hybridclr?.branch; + + public string Il2cppPlusLocalVersion => _curDefaultVersion?.il2cpp_plus?.branch; + + + private string GetIl2CppPathByContentPath(string contentPath) + { + return $"{contentPath}/il2cpp"; + } + + public string ApplicationIl2cppPath => GetIl2CppPathByContentPath(EditorApplication.applicationContentsPath); + + public string LocalVersionFile => $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/generated/libil2cpp-version.txt"; + + private string ReadLocalVersion() + { + if (!File.Exists(LocalVersionFile)) + { + return null; + } + return File.ReadAllText(LocalVersionFile, Encoding.UTF8); + } + + public void WriteLocalVersion() + { + InstalledLibil2cppVersion = PackageVersion; + File.WriteAllText(LocalVersionFile, PackageVersion, Encoding.UTF8); + Debug.Log($"Write installed version:'{PackageVersion}' to {LocalVersionFile}"); + } + + public void InstallDefaultHybridCLR() + { + InstallFromLocal(PrepareLibil2cppWithHybridclrFromGitRepo()); + } + + public bool HasInstalledHybridCLR() + { + return Directory.Exists($"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr"); + } + + void CloneBranch(string workDir, string repoUrl, string branch, string repoDir) + { + BashUtil.RemoveDir(repoDir); + BashUtil.RunCommand(workDir, "git", new string[] {"clone", "-b", branch, "--depth", "1", repoUrl, repoDir}); + } + + private string PrepareLibil2cppWithHybridclrFromGitRepo() + { + string workDir = SettingsUtil.HybridCLRDataDir; + Directory.CreateDirectory(workDir); + //BashUtil.RecreateDir(workDir); + + // clone hybridclr + string hybridclrRepoURL = HybridCLRSettings.Instance.hybridclrRepoURL; + string hybridclrRepoDir = $"{workDir}/{hybridclr_repo_path}"; + CloneBranch(workDir, hybridclrRepoURL, _curDefaultVersion.hybridclr.branch, hybridclrRepoDir); + + if (!Directory.Exists(hybridclrRepoDir)) + { + throw new Exception($"clone hybridclr fail. url: {hybridclrRepoURL}"); + } + + // clone il2cpp_plus + string il2cppPlusRepoURL = HybridCLRSettings.Instance.il2cppPlusRepoURL; + string il2cppPlusRepoDir = $"{workDir}/{il2cpp_plus_repo_path}"; + CloneBranch(workDir, il2cppPlusRepoURL, _curDefaultVersion.il2cpp_plus.branch, il2cppPlusRepoDir); + + if (!Directory.Exists(il2cppPlusRepoDir)) + { + throw new Exception($"clone il2cpp_plus fail. url: {il2cppPlusRepoDir}"); + } + + Directory.Move($"{hybridclrRepoDir}/hybridclr", $"{il2cppPlusRepoDir}/libil2cpp/hybridclr"); + return $"{il2cppPlusRepoDir}/libil2cpp"; + } + + public void InstallFromLocal(string libil2cppWithHybridclrSourceDir) + { + RunInitLocalIl2CppData(ApplicationIl2cppPath, libil2cppWithHybridclrSourceDir, _curVersion); + } + + private void RunInitLocalIl2CppData(string editorIl2cppPath, string libil2cppWithHybridclrSourceDir, UnityVersion version) + { + if (GetCompatibleType() == CompatibleType.Incompatible) + { + Debug.LogError($"Incompatible with current version, minimum compatible version: {GetCurrentUnityVersionMinCompatibleVersionStr()}"); + return; + } + string workDir = SettingsUtil.HybridCLRDataDir; + Directory.CreateDirectory(workDir); + + // create LocalIl2Cpp + string localUnityDataDir = SettingsUtil.LocalUnityDataDir; + BashUtil.RecreateDir(localUnityDataDir); + + // copy MonoBleedingEdge + BashUtil.CopyDir($"{Directory.GetParent(editorIl2cppPath)}/MonoBleedingEdge", $"{localUnityDataDir}/MonoBleedingEdge", true); + + // copy il2cpp + BashUtil.CopyDir(editorIl2cppPath, SettingsUtil.LocalIl2CppDir, true); + + // replace libil2cpp + string dstLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp"; + BashUtil.CopyDir($"{libil2cppWithHybridclrSourceDir}", dstLibil2cppDir, true); + + // clean Il2cppBuildCache + BashUtil.RemoveDir($"{SettingsUtil.ProjectDir}/Library/Il2cppBuildCache", true); + + if (HasInstalledHybridCLR()) + { + WriteLocalVersion(); + Debug.Log("Install Sucessfully"); + } + else + { + Debug.LogError("Installation failed!"); + } + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerController.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerController.cs.meta new file mode 100644 index 0000000..6b30944 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 44c8627d126b30d4e9560b1f738264ca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerWindow.cs b/Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerWindow.cs new file mode 100644 index 0000000..676fe6e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerWindow.cs @@ -0,0 +1,113 @@ +using System; +using System.IO; +using System.Reflection; +using UnityEditor; +using UnityEngine; + + +namespace HybridCLR.Editor.Installer +{ + public class InstallerWindow : EditorWindow + { + private InstallerController _controller; + + private bool _installFromDir; + + private string _installLibil2cppWithHybridclrSourceDir; + + private void OnEnable() + { + _controller = new InstallerController(); + } + + private void OnGUI() + { + var rect = new Rect + { + x = EditorGUIUtility.currentViewWidth - 24, + y = 5, + width = 24, + height = 24 + }; + var content = EditorGUIUtility.IconContent("Settings"); + content.tooltip = "HybridCLR Settings"; + if (GUI.Button(rect, content, GUI.skin.GetStyle("IconButton"))) + { + SettingsService.OpenProjectSettings("Project/HybridCLR Settings"); + } + + bool hasInstall = _controller.HasInstalledHybridCLR(); + + GUILayout.Space(10f); + + EditorGUILayout.BeginVertical("box"); + EditorGUILayout.LabelField($"Installed: {hasInstall}", EditorStyles.boldLabel); + GUILayout.Space(10f); + + EditorGUILayout.LabelField($"Package Version: v{_controller.PackageVersion}"); + GUILayout.Space(5f); + EditorGUILayout.LabelField($"Installed Version: {_controller.InstalledLibil2cppVersion ?? "Unknown"}"); + GUILayout.Space(5f); + + GUILayout.Space(10f); + + InstallerController.CompatibleType compatibleType = _controller.GetCompatibleType(); + if (compatibleType != InstallerController.CompatibleType.Incompatible) + { + if (compatibleType == InstallerController.CompatibleType.MaybeIncompatible) + { + EditorGUILayout.HelpBox($"Maybe incompatible with current version, recommend minimum compatible version:{_controller.GetCurrentUnityVersionMinCompatibleVersionStr()}", MessageType.Warning); + } + + EditorGUILayout.BeginHorizontal(); + _installFromDir = EditorGUILayout.Toggle("Copy libil2cpp from local", _installFromDir, GUILayout.MinWidth(100)); + EditorGUI.BeginDisabledGroup(!_installFromDir); + EditorGUILayout.TextField(_installLibil2cppWithHybridclrSourceDir, GUILayout.Width(400)); + if (GUILayout.Button("Choose", GUILayout.Width(100))) + { + _installLibil2cppWithHybridclrSourceDir = EditorUtility.OpenFolderPanel("Select libil2cpp", Application.dataPath, "libil2cpp"); + } + EditorGUI.EndDisabledGroup(); + EditorGUILayout.EndHorizontal(); + + GUILayout.Space(20f); + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Install", GUILayout.Width(100))) + { + InstallLocalHybridCLR(); + GUIUtility.ExitGUI(); + } + EditorGUILayout.EndHorizontal(); + } + else + { + EditorGUILayout.HelpBox($"Incompatible with current version, minimum compatible version:{_controller.GetCurrentUnityVersionMinCompatibleVersionStr()}", MessageType.Error); + } + + EditorGUILayout.EndVertical(); + } + + private void InstallLocalHybridCLR() + { + if (_installFromDir) + { + if (!Directory.Exists(_installLibil2cppWithHybridclrSourceDir)) + { + Debug.LogError($"Source libil2cpp:'{_installLibil2cppWithHybridclrSourceDir}' doesn't exist."); + return; + } + if (!File.Exists($"{_installLibil2cppWithHybridclrSourceDir}/il2cpp-config.h") || !File.Exists($"{_installLibil2cppWithHybridclrSourceDir}/hybridclr/RuntimeApi.cpp")) + { + Debug.LogError($"Source libil2cpp:' {_installLibil2cppWithHybridclrSourceDir} ' is invalid"); + return; + } + _controller.InstallFromLocal(_installLibil2cppWithHybridclrSourceDir); + } + else + { + _controller.InstallDefaultHybridCLR(); + } + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerWindow.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerWindow.cs.meta new file mode 100644 index 0000000..f404c28 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Installer/InstallerWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 959fbf0bb06629542969354505189240 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Link.meta b/Packages/com.code-philosophy.hybridclr/Editor/Link.meta new file mode 100644 index 0000000..1cad1b3 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Link.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5186a137e0258034cb3832bdf6b16a70 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Link/Analyzer.cs b/Packages/com.code-philosophy.hybridclr/Editor/Link/Analyzer.cs new file mode 100644 index 0000000..b54d5f3 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Link/Analyzer.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using dnlib.DotNet; +using HybridCLR.Editor.Meta; +using UnityEditor; +using IAssemblyResolver = HybridCLR.Editor.Meta.IAssemblyResolver; + +namespace HybridCLR.Editor.Link +{ + public class Analyzer + { + private readonly IAssemblyResolver _resolver; + + public Analyzer(IAssemblyResolver resolver) + { + _resolver = resolver; + } + + public HashSet CollectRefs(List rootAssemblies) + { + using (var assCollector = new AssemblyCache(_resolver)) + { + var rootAssemblyNames = new HashSet(rootAssemblies); + + var typeRefs = new HashSet(TypeEqualityComparer.Instance); + foreach (var rootAss in rootAssemblies) + { + var dnAss = assCollector.LoadModule(rootAss, false); + foreach (var type in dnAss.GetTypeRefs()) + { + if (!rootAssemblyNames.Contains(type.DefinitionAssembly.Name.ToString())) + { + typeRefs.Add(type); + } + } + } + + assCollector.Dispose(); + return typeRefs; + } + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Link/Analyzer.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Link/Analyzer.cs.meta new file mode 100644 index 0000000..0c6fa90 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Link/Analyzer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd3dd4871efd10e46947cb61c13797fd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Link/LinkXmlWriter.cs b/Packages/com.code-philosophy.hybridclr/Editor/Link/LinkXmlWriter.cs new file mode 100644 index 0000000..0ede314 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Link/LinkXmlWriter.cs @@ -0,0 +1,47 @@ +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.Link +{ + internal class LinkXmlWriter + { + public void Write(string outputLinkXmlFile, HashSet refTypes) + { + string parentDir = Directory.GetParent(outputLinkXmlFile).FullName; + Directory.CreateDirectory(parentDir); + var writer = System.Xml.XmlWriter.Create(outputLinkXmlFile, + new System.Xml.XmlWriterSettings { Encoding = Encoding.UTF8, Indent = true}); + + writer.WriteStartDocument(); + writer.WriteStartElement("linker"); + + var typesByAssembly = refTypes.GroupBy(t => t.DefinitionAssembly.Name.String).ToList(); + typesByAssembly.Sort((a, b) => String.Compare(a.Key, b.Key, StringComparison.Ordinal)); + + foreach(var assembly in typesByAssembly) + { + writer.WriteStartElement("assembly"); + writer.WriteAttributeString("fullname", assembly.Key); + List assTypeNames = assembly.Select(t => t.FullName).ToList(); + assTypeNames.Sort(string.CompareOrdinal); + foreach(var typeName in assTypeNames) + { + writer.WriteStartElement("type"); + writer.WriteAttributeString("fullname", typeName); + writer.WriteAttributeString("preserve", "all"); + writer.WriteEndElement(); + } + writer.WriteEndElement(); + } + writer.WriteEndElement(); + writer.WriteEndDocument(); + writer.Close(); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Link/LinkXmlWriter.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Link/LinkXmlWriter.cs.meta new file mode 100644 index 0000000..4c6c61c --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Link/LinkXmlWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d5cc4ae4adc319b4bb1e115567d7613e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta.meta new file mode 100644 index 0000000..3291c30 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3787c7d8b775c754aa4ae06bf78e96ea +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCache.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCache.cs new file mode 100644 index 0000000..7fed930 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCache.cs @@ -0,0 +1,20 @@ +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.Meta +{ + public class AssemblyCache : AssemblyCacheBase + { + + public AssemblyCache(IAssemblyResolver assemblyResolver) : base(assemblyResolver) + { + + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCache.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCache.cs.meta new file mode 100644 index 0000000..a99c3b2 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCache.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa4650e79a52228488aa85e0690ca52c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCacheBase.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCacheBase.cs new file mode 100644 index 0000000..82fb007 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCacheBase.cs @@ -0,0 +1,107 @@ +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.Meta +{ + public abstract class AssemblyCacheBase : IDisposable + { + private readonly IAssemblyResolver _assemblyPathResolver; + private readonly ModuleContext _modCtx; + private readonly AssemblyResolver _asmResolver; + private bool disposedValue; + private bool _loadedNetstandard; + + public Dictionary LoadedModules { get; } = new Dictionary(); + + private readonly List _loadedModulesIncludeNetstandard = new List(); + + protected AssemblyCacheBase(IAssemblyResolver assemblyResolver) + { + _assemblyPathResolver = assemblyResolver; + _modCtx = ModuleDef.CreateModuleContext(); + _asmResolver = (AssemblyResolver)_modCtx.AssemblyResolver; + _asmResolver.EnableTypeDefCache = true; + _asmResolver.UseGAC = false; + } + + public ModuleDefMD LoadModule(string moduleName, bool loadReferenceAssemblies = true) + { + // Debug.Log($"load module:{moduleName}"); + if (LoadedModules.TryGetValue(moduleName, out var mod)) + { + return mod; + } + if (moduleName == "netstandard") + { + if (!_loadedNetstandard) + { + LoadNetStandard(); + } + return null; + } + mod = DoLoadModule(_assemblyPathResolver.ResolveAssembly(moduleName, true)); + LoadedModules.Add(moduleName, mod); + + if (loadReferenceAssemblies) + { + foreach (var refAsm in mod.GetAssemblyRefs()) + { + LoadModule(refAsm.Name); + } + } + + return mod; + } + + private void LoadNetStandard() + { + string netstandardDllPath = _assemblyPathResolver.ResolveAssembly("netstandard", false); + if (!string.IsNullOrEmpty(netstandardDllPath)) + { + DoLoadModule(netstandardDllPath); + } + else + { + DoLoadModule(MetaUtil.ResolveNetStandardAssemblyPath("netstandard2.0")); + DoLoadModule(MetaUtil.ResolveNetStandardAssemblyPath("netstandard2.1")); + } + _loadedNetstandard = true; + } + + private ModuleDefMD DoLoadModule(string dllPath) + { + //Debug.Log($"do load module:{dllPath}"); + ModuleDefMD mod = ModuleDefMD.Load(dllPath, _modCtx); + _asmResolver.AddToCache(mod); + _loadedModulesIncludeNetstandard.Add(mod); + return mod; + } + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + foreach (var mod in _loadedModulesIncludeNetstandard) + { + mod.Dispose(); + } + _loadedModulesIncludeNetstandard.Clear(); + LoadedModules.Clear(); + } + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCacheBase.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCacheBase.cs.meta new file mode 100644 index 0000000..5c02171 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyCacheBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b01fa99119e72141bfee5628c0ffce1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyReferenceDeepCollector.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyReferenceDeepCollector.cs new file mode 100644 index 0000000..44c1c71 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyReferenceDeepCollector.cs @@ -0,0 +1,50 @@ +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.Meta +{ + public class AssemblyReferenceDeepCollector : AssemblyCacheBase + { + private readonly List _rootAssemblies; + + public IReadOnlyList GetRootAssemblyNames() + { + return _rootAssemblies; + } + + public List GetLoadedModulesExcludeRootAssemblies() + { + return LoadedModules.Where(e => !_rootAssemblies.Contains(e.Key)).Select(e => e.Value).ToList(); + } + + public List GetLoadedModules() + { + return LoadedModules.Select(e => e.Value).ToList(); + } + + public List GetLoadedModulesOfRootAssemblies() + { + return _rootAssemblies.Select(ass => LoadedModules[ass]).ToList(); + } + + public AssemblyReferenceDeepCollector(IAssemblyResolver assemblyResolver, List rootAssemblies) : base(assemblyResolver) + { + _rootAssemblies = rootAssemblies; + LoadAllAssembiles(); + } + + private void LoadAllAssembiles() + { + foreach (var asm in _rootAssemblies) + { + LoadModule(asm); + } + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyReferenceDeepCollector.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyReferenceDeepCollector.cs.meta new file mode 100644 index 0000000..e93354f --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyReferenceDeepCollector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0342c7d8575fdea49896260c77285286 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyResolverBase.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyResolverBase.cs new file mode 100644 index 0000000..973619a --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyResolverBase.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.Meta +{ + public abstract class AssemblyResolverBase : IAssemblyResolver + { + public string ResolveAssembly(string assemblyName, bool throwExIfNotFind) + { + if (TryResolveAssembly(assemblyName, out string assemblyPath)) + { + return assemblyPath; + } + if (throwExIfNotFind) + { + if (SettingsUtil.HotUpdateAssemblyNamesIncludePreserved.Contains(assemblyName)) + { + throw new Exception($"resolve Hot update dll:{assemblyName} failed! Please make sure that this hot update dll exists or the search path is configured in the external hot update path."); + } + else + { + throw new Exception($"resolve AOT dll:{assemblyName} failed! Please make sure that the AOT project has referenced the dll and generated the trimmed AOT dll correctly."); + } + } + return null; + } + + protected abstract bool TryResolveAssembly(string assemblyName, out string assemblyPath); + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyResolverBase.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyResolverBase.cs.meta new file mode 100644 index 0000000..e153d4e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/AssemblyResolverBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f8d48774b790364cbd36f1f68fd6614 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/CombinedAssemblyResolver.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/CombinedAssemblyResolver.cs new file mode 100644 index 0000000..31a0c51 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/CombinedAssemblyResolver.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.Meta +{ + public class CombinedAssemblyResolver : AssemblyResolverBase + { + private readonly IAssemblyResolver[] _resolvers; + + public CombinedAssemblyResolver(params IAssemblyResolver[] resolvers) + { + _resolvers = resolvers; + } + + protected override bool TryResolveAssembly(string assemblyName, out string assemblyPath) + { + foreach(var resolver in _resolvers) + { + var assembly = resolver.ResolveAssembly(assemblyName, false); + if (assembly != null) + { + assemblyPath = assembly; + return true; + } + } + assemblyPath = null; + return false; + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/CombinedAssemblyResolver.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/CombinedAssemblyResolver.cs.meta new file mode 100644 index 0000000..81b443c --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/CombinedAssemblyResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 89b83906438c52d4b9af4aaef055f177 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/FixedSetAssemblyResolver.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/FixedSetAssemblyResolver.cs new file mode 100644 index 0000000..5bee4e4 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/FixedSetAssemblyResolver.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.Meta +{ + public class FixedSetAssemblyResolver : AssemblyResolverBase + { + private readonly string _rootDir; + private readonly HashSet _fileNames; + + public FixedSetAssemblyResolver(string rootDir, IEnumerable fileNameNotExts) + { + _rootDir = rootDir; + _fileNames = new HashSet(fileNameNotExts); + } + + protected override bool TryResolveAssembly(string assemblyName, out string assemblyPath) + { + if (_fileNames.Contains(assemblyName)) + { + assemblyPath = $"{_rootDir}/{assemblyName}.dll"; + if (File.Exists(assemblyPath)) + { + Debug.Log($"[FixedSetAssemblyResolver] resolve:{assemblyName} path:{assemblyPath}"); + return true; + } + } + assemblyPath = null; + return false; + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/FixedSetAssemblyResolver.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/FixedSetAssemblyResolver.cs.meta new file mode 100644 index 0000000..cc4fb61 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/FixedSetAssemblyResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f135accd10f42c64b9735c3aa8cb1e77 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericArgumentContext.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericArgumentContext.cs new file mode 100644 index 0000000..47883f5 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericArgumentContext.cs @@ -0,0 +1,104 @@ +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.Meta +{ + /// + /// Replaces generic type/method var with its generic argument + /// + public sealed class GenericArgumentContext + { + List typeArgsStack = new List(); + List methodArgsStack = new List(); + + public GenericArgumentContext(List typeArgsStack, List methodArgsStack) + { + this.typeArgsStack = typeArgsStack; + this.methodArgsStack = methodArgsStack; + } + + + + /// + /// Replaces a generic type/method var with its generic argument (if any). If + /// isn't a generic type/method var or if it can't + /// be resolved, it itself is returned. Else the resolved type is returned. + /// + /// Type signature + /// New which is never null unless + /// is null + public TypeSig Resolve(TypeSig typeSig) + { + if (!typeSig.ContainsGenericParameter) + { + return typeSig; + } + typeSig = typeSig.RemovePinnedAndModifiers(); + switch (typeSig.ElementType) + { + case ElementType.Ptr: return new PtrSig(Resolve(typeSig.Next)); + case ElementType.ByRef: return new PtrSig(Resolve(typeSig.Next)); + + case ElementType.SZArray: return new PtrSig(Resolve(typeSig.Next)); + case ElementType.Array: + { + var ara = (ArraySig)typeSig; + return new ArraySig(Resolve(typeSig.Next), ara.Rank, ara.Sizes, ara.LowerBounds); + } + + case ElementType.Var: + { + GenericVar genericVar = (GenericVar)typeSig; + var newSig = Resolve(typeArgsStack, genericVar.Number, true); + if (newSig == null) + { + throw new Exception(); + } + return newSig; + } + + case ElementType.MVar: + { + GenericMVar genericVar = (GenericMVar)typeSig; + var newSig = Resolve(methodArgsStack, genericVar.Number, true); + if (newSig == null) + { + throw new Exception(); + } + return newSig; + } + case ElementType.GenericInst: + { + var gia = (GenericInstSig)typeSig; + return new GenericInstSig(gia.GenericType, gia.GenericArguments.Select(ga => Resolve(ga)).ToList()); + } + + case ElementType.FnPtr: + { + throw new NotSupportedException(typeSig.ToString()); + } + + case ElementType.ValueArray: + { + var vas = (ValueArraySig)typeSig; + return new ValueArraySig(Resolve(vas.Next), vas.Size); + } + default: return typeSig; + } + } + + private TypeSig Resolve(List args, uint number, bool isTypeVar) + { + var typeSig = args[(int)number]; + var gvar = typeSig as GenericSig; + if (gvar is null || gvar.IsTypeVar != isTypeVar) + return typeSig; + return gvar; + } + } + +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericArgumentContext.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericArgumentContext.cs.meta new file mode 100644 index 0000000..acb9355 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericArgumentContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 07595a9b5b2f54c44a67022ae3e077d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericClass.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericClass.cs new file mode 100644 index 0000000..0479f6f --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericClass.cs @@ -0,0 +1,74 @@ +using dnlib.DotNet; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace HybridCLR.Editor.Meta +{ + public class GenericClass + { + public TypeDef Type { get; } + + public List KlassInst { get; } + + private readonly int _hashCode; + + public GenericClass(TypeDef type, List classInst) + { + Type = type; + KlassInst = classInst; + _hashCode = ComputHashCode(); + } + + public GenericClass ToGenericShare() + { + return new GenericClass(Type, MetaUtil.ToShareTypeSigs(Type.Module.CorLibTypes, KlassInst)); + } + + public override bool Equals(object obj) + { + if (obj is GenericClass gc) + { + return Type == gc.Type && MetaUtil.EqualsTypeSigArray(KlassInst, gc.KlassInst); + } + return false; + } + + public override int GetHashCode() + { + return _hashCode; + } + + private int ComputHashCode() + { + int hash = TypeEqualityComparer.Instance.GetHashCode(Type); + if (KlassInst != null) + { + hash = HashUtil.CombineHash(hash, HashUtil.ComputHash(KlassInst)); + } + return hash; + } + + public TypeSig ToTypeSig() + { + return new GenericInstSig(this.Type.ToTypeSig().ToClassOrValueTypeSig(), this.KlassInst); + } + + public static GenericClass ResolveClass(TypeSpec type, GenericArgumentContext ctx) + { + var sig = type.TypeSig.ToGenericInstSig(); + if (sig == null) + { + return null; + } + TypeDef def = type.ResolveTypeDef(); + if (def == null) + { + Debug.LogWarning($"type:{type} ResolveTypeDef() == null"); + return null; + } + var klassInst = ctx != null ? sig.GenericArguments.Select(ga => MetaUtil.Inflate(ga, ctx)).ToList() : sig.GenericArguments.ToList(); + return new GenericClass(def, klassInst); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericClass.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericClass.cs.meta new file mode 100644 index 0000000..438a1a3 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericClass.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c95ff173013909548bd9e2008812f9ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericMethod.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericMethod.cs new file mode 100644 index 0000000..96252fc --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericMethod.cs @@ -0,0 +1,109 @@ +using dnlib.DotNet; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace HybridCLR.Editor.Meta +{ + public class GenericMethod + { + public MethodDef Method { get; } + + public List KlassInst { get; } + + public List MethodInst { get; } + + private readonly int _hashCode; + + public GenericMethod(MethodDef method, List classInst, List methodInst) + { + Method = method; + KlassInst = classInst; + MethodInst = methodInst; + _hashCode = ComputHashCode(); + } + + public GenericMethod ToGenericShare() + { + ICorLibTypes corLibTypes = Method.Module.CorLibTypes; + return new GenericMethod(Method, MetaUtil.ToShareTypeSigs(corLibTypes, KlassInst), MetaUtil.ToShareTypeSigs(corLibTypes, MethodInst)); + } + + public override bool Equals(object obj) + { + GenericMethod o = (GenericMethod)obj; + return Method == o.Method + && MetaUtil.EqualsTypeSigArray(KlassInst, o.KlassInst) + && MetaUtil.EqualsTypeSigArray(MethodInst, o.MethodInst); + } + + public override int GetHashCode() + { + return _hashCode; + } + + public override string ToString() + { + return $"{Method}|{string.Join(",", (IEnumerable)KlassInst ?? Array.Empty())}|{string.Join(",", (IEnumerable)MethodInst ?? Array.Empty())}"; + } + + private int ComputHashCode() + { + int hash = MethodEqualityComparer.CompareDeclaringTypes.GetHashCode(Method); + if (KlassInst != null) + { + hash = HashUtil.CombineHash(hash, HashUtil.ComputHash(KlassInst)); + } + if (MethodInst != null) + { + hash = HashUtil.CombineHash(hash, HashUtil.ComputHash(MethodInst)); + } + return hash; + } + + public MethodSpec ToMethodSpec() + { + IMethodDefOrRef mt = KlassInst != null ? + (IMethodDefOrRef)new MemberRefUser(this.Method.Module, Method.Name, Method.MethodSig, new TypeSpecUser(new GenericInstSig(this.Method.DeclaringType.ToTypeSig().ToClassOrValueTypeSig(), this.KlassInst))) + : this.Method; + return new MethodSpecUser(mt, new GenericInstMethodSig(MethodInst)); + } + + public static GenericMethod ResolveMethod(IMethod method, GenericArgumentContext ctx) + { + //Debug.Log($"== resolve method:{method}"); + TypeDef typeDef = null; + List klassInst = null; + List methodInst = null; + + MethodDef methodDef = null; + + + var decalringType = method.DeclaringType; + typeDef = decalringType.ResolveTypeDef(); + if (typeDef == null) + { + return null; + } + GenericInstSig gis = decalringType.TryGetGenericInstSig(); + if (gis != null) + { + klassInst = ctx != null ? gis.GenericArguments.Select(ga => MetaUtil.Inflate(ga, ctx)).ToList() : gis.GenericArguments.ToList(); + } + methodDef = method.ResolveMethodDef(); + if (methodDef == null) + { + Debug.LogWarning($"method:{method} ResolveMethodDef() == null"); + return null; + } + if (method is MethodSpec methodSpec) + { + methodInst = ctx != null ? methodSpec.GenericInstMethodSig.GenericArguments.Select(ga => MetaUtil.Inflate(ga, ctx)).ToList() + : methodSpec.GenericInstMethodSig.GenericArguments.ToList(); + } + return new GenericMethod(methodDef, klassInst, methodInst); + } + + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericMethod.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericMethod.cs.meta new file mode 100644 index 0000000..ef15a5c --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/GenericMethod.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88ecf3d52ec393b4cac142518944e487 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/IAssemblyResolver.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/IAssemblyResolver.cs new file mode 100644 index 0000000..25a6d42 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/IAssemblyResolver.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.Meta +{ + public interface IAssemblyResolver + { + string ResolveAssembly(string assemblyName, bool throwExIfNotFind); + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/IAssemblyResolver.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/IAssemblyResolver.cs.meta new file mode 100644 index 0000000..d56059d --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/IAssemblyResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f962a018018dbb945a19f82d2e098686 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/MetaUtil.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/MetaUtil.cs new file mode 100644 index 0000000..eb95a7a --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/MetaUtil.cs @@ -0,0 +1,193 @@ +using dnlib.DotNet; +using HybridCLR.Editor.Meta; +using HybridCLR.Editor.Settings; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; + +namespace HybridCLR.Editor.Meta +{ + public static class MetaUtil + { + + public static bool EqualsTypeSig(TypeSig a, TypeSig b) + { + if (a == b) + { + return true; + } + if (a != null && b != null) + { + return TypeEqualityComparer.Instance.Equals(a, b); + } + return false; + } + + public static bool EqualsTypeSigArray(List a, List b) + { + if (a == b) + { + return true; + } + if (a != null && b != null) + { + if (a.Count != b.Count) + { + return false; + } + for (int i = 0; i < a.Count; i++) + { + if (!TypeEqualityComparer.Instance.Equals(a[i], b[i])) + { + return false; + } + } + return true; + } + return false; + } + + public static TypeSig Inflate(TypeSig sig, GenericArgumentContext ctx) + { + if (!sig.ContainsGenericParameter) + { + return sig; + } + return ctx.Resolve(sig); + } + + public static TypeSig ToShareTypeSig(ICorLibTypes corTypes, TypeSig typeSig) + { + var a = typeSig.RemovePinnedAndModifiers(); + switch (a.ElementType) + { + case ElementType.Void: return corTypes.Void; + case ElementType.Boolean: return corTypes.Byte; + case ElementType.Char: return corTypes.UInt16; + case ElementType.I1: return corTypes.SByte; + case ElementType.U1:return corTypes.Byte; + case ElementType.I2: return corTypes.Int16; + case ElementType.U2: return corTypes.UInt16; + case ElementType.I4: return corTypes.Int32; + case ElementType.U4: return corTypes.UInt32; + case ElementType.I8: return corTypes.Int64; + case ElementType.U8: return corTypes.UInt64; + case ElementType.R4: return corTypes.Single; + case ElementType.R8: return corTypes.Double; + case ElementType.String: return corTypes.Object; + case ElementType.TypedByRef: return corTypes.TypedReference; + case ElementType.I: return corTypes.IntPtr; + case ElementType.U: return corTypes.UIntPtr; + case ElementType.Object: return corTypes.Object; + case ElementType.Sentinel: return typeSig; + case ElementType.Ptr: return corTypes.UIntPtr; + case ElementType.ByRef: return corTypes.UIntPtr; + case ElementType.SZArray: return corTypes.Object; + case ElementType.Array: return corTypes.Object; + case ElementType.ValueType: + { + TypeDef typeDef = a.ToTypeDefOrRef().ResolveTypeDef(); + if (typeDef == null) + { + throw new Exception($"type:{a} definition could not be found"); + } + if (typeDef.IsEnum) + { + return ToShareTypeSig(corTypes, typeDef.GetEnumUnderlyingType()); + } + return typeSig; + } + case ElementType.Var: + case ElementType.MVar: + case ElementType.Class: return corTypes.Object; + case ElementType.GenericInst: + { + var gia = (GenericInstSig)a; + TypeDef typeDef = gia.GenericType.ToTypeDefOrRef().ResolveTypeDef(); + if (typeDef == null) + { + throw new Exception($"type:{a} definition could not be found"); + } + if (typeDef.IsEnum) + { + return ToShareTypeSig(corTypes, typeDef.GetEnumUnderlyingType()); + } + if (!typeDef.IsValueType) + { + return corTypes.Object; + } + return new GenericInstSig(gia.GenericType, gia.GenericArguments.Select(ga => ToShareTypeSig(corTypes, ga)).ToList()); + } + case ElementType.FnPtr: return corTypes.IntPtr; + case ElementType.ValueArray: return typeSig; + case ElementType.Module: return typeSig; + default: + throw new NotSupportedException(typeSig.ToString()); + } + } + + public static List ToShareTypeSigs(ICorLibTypes corTypes, IList typeSigs) + { + if (typeSigs == null) + { + return null; + } + return typeSigs.Select(s => ToShareTypeSig(corTypes, s)).ToList(); + } + + public static IAssemblyResolver CreateHotUpdateAssemblyResolver(BuildTarget target, List hotUpdateDlls) + { + var externalDirs = HybridCLRSettings.Instance.externalHotUpdateAssembliyDirs; + var defaultHotUpdateOutputDir = SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target); + IAssemblyResolver defaultHotUpdateResolver = new FixedSetAssemblyResolver(defaultHotUpdateOutputDir, hotUpdateDlls); + if (externalDirs == null || externalDirs.Length == 0) + { + return defaultHotUpdateResolver; + } + else + { + var resolvers = new List(); + foreach (var dir in externalDirs) + { + resolvers.Add(new FixedSetAssemblyResolver($"{dir}/{target}", hotUpdateDlls)); + resolvers.Add(new FixedSetAssemblyResolver(dir, hotUpdateDlls)); + } + resolvers.Add(defaultHotUpdateResolver); + return new CombinedAssemblyResolver(resolvers.ToArray()); + } + } + + public static IAssemblyResolver CreateAOTAssemblyResolver(BuildTarget target) + { + return new PathAssemblyResolver(SettingsUtil.GetAssembliesPostIl2CppStripDir(target)); + } + + public static IAssemblyResolver CreateHotUpdateAndAOTAssemblyResolver(BuildTarget target, List hotUpdateDlls) + { + return new CombinedAssemblyResolver( + CreateHotUpdateAssemblyResolver(target, hotUpdateDlls), + CreateAOTAssemblyResolver(target) + ); + } + + public static string ResolveNetStandardAssemblyPath(string assemblyName) + { + return $"{SettingsUtil.HybridCLRDataPathInPackage}/NetStandard/{assemblyName}.dll"; + } + + + public static List CreateDefaultGenericParams(ModuleDef module, int genericParamCount) + { + var methodGenericParams = new List(); + for (int i = 0; i < genericParamCount; i++) + { + methodGenericParams.Add(module.CorLibTypes.Object); + } + return methodGenericParams; + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/MetaUtil.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/MetaUtil.cs.meta new file mode 100644 index 0000000..d9342a4 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/MetaUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f3dbfe2e8b6a92742b18e287c5d281dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/MethodReferenceAnalyzer.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/MethodReferenceAnalyzer.cs new file mode 100644 index 0000000..bb36692 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/MethodReferenceAnalyzer.cs @@ -0,0 +1,79 @@ +using dnlib.DotNet; +using HybridCLR.Editor.ABI; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.Meta +{ + public class MethodReferenceAnalyzer + { + private readonly Action, List, GenericMethod> _onNewMethod; + + private readonly ConcurrentDictionary> _methodEffectInsts = new ConcurrentDictionary>(); + + public MethodReferenceAnalyzer(Action, List, GenericMethod> onNewMethod) + { + _onNewMethod = onNewMethod; + } + + public void WalkMethod(MethodDef method, List klassGenericInst, List methodGenericInst) + { + var ctx = new GenericArgumentContext(klassGenericInst, methodGenericInst); + + if (_methodEffectInsts.TryGetValue(method, out var effectInsts)) + { + foreach (var met in effectInsts) + { + var resolveMet = GenericMethod.ResolveMethod(met, ctx)?.ToGenericShare(); + _onNewMethod(method, klassGenericInst, methodGenericInst, resolveMet); + } + return; + } + + var body = method.Body; + if (body == null || !body.HasInstructions) + { + return; + } + + effectInsts = new List(); + foreach (var inst in body.Instructions) + { + if (inst.Operand == null) + { + continue; + } + switch (inst.Operand) + { + case IMethod met: + { + if (!met.IsMethod) + { + continue; + } + var resolveMet = GenericMethod.ResolveMethod(met, ctx)?.ToGenericShare(); + if (resolveMet == null) + { + continue; + } + effectInsts.Add(met); + _onNewMethod(method, klassGenericInst, methodGenericInst, resolveMet); + break; + } + case ITokenOperand token: + { + //GenericParamContext paramContext = method.HasGenericParameters || method.DeclaringType.HasGenericParameters ? + // new GenericParamContext(method.DeclaringType, method) : default; + //method.Module.ResolveToken(token.MDToken, paramContext); + break; + } + } + } + _methodEffectInsts.TryAdd(method, effectInsts); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/MethodReferenceAnalyzer.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/MethodReferenceAnalyzer.cs.meta new file mode 100644 index 0000000..7554a58 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/MethodReferenceAnalyzer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1c644b0c018fb87498d69c3202439d21 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/PathAssemblyResolver.cs b/Packages/com.code-philosophy.hybridclr/Editor/Meta/PathAssemblyResolver.cs new file mode 100644 index 0000000..a356117 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/PathAssemblyResolver.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.Meta +{ + public class PathAssemblyResolver : AssemblyResolverBase + { + private readonly string[] _searchPaths; + public PathAssemblyResolver(params string[] searchPaths) + { + _searchPaths = searchPaths; + } + + protected override bool TryResolveAssembly(string assemblyName, out string assemblyPath) + { + foreach(var path in _searchPaths) + { + string assPath = Path.Combine(path, assemblyName + ".dll"); + if (File.Exists(assPath)) + { + Debug.Log($"resolve {assemblyName} at {assPath}"); + assemblyPath = assPath; + return true; + } + } + assemblyPath = null; + return false; + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Meta/PathAssemblyResolver.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Meta/PathAssemblyResolver.cs.meta new file mode 100644 index 0000000..af02cb8 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Meta/PathAssemblyResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 121d574bf01969444aa6619a8f6dbb4c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge.meta b/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge.meta new file mode 100644 index 0000000..5ff8e80 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0c2444f09010bce41a52d951b7100c49 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Analyzer.cs b/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Analyzer.cs new file mode 100644 index 0000000..59e2dd7 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Analyzer.cs @@ -0,0 +1,204 @@ +using dnlib.DotNet; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.MethodBridge +{ + + public class Analyzer + { + public class Options + { + public AssemblyReferenceDeepCollector Collector { get; set; } + + public int MaxIterationCount { get; set; } + } + + private readonly int _maxInterationCount; + private readonly AssemblyReferenceDeepCollector _assemblyCollector; + + private readonly object _lock = new object(); + + private readonly List _typeDefs = new List(); + + private readonly HashSet _genericTypes = new HashSet(); + private readonly HashSet _genericMethods = new HashSet(); + + private List _processingMethods = new List(); + private List _newMethods = new List(); + + public IReadOnlyList TypeDefs => _typeDefs; + + public IReadOnlyCollection GenericTypes => _genericTypes; + + public IReadOnlyCollection GenericMethods => _genericMethods; + + + private readonly MethodReferenceAnalyzer _methodReferenceAnalyzer; + + public Analyzer(Options options) + { + _maxInterationCount = options.MaxIterationCount; + _assemblyCollector = options.Collector; + _methodReferenceAnalyzer = new MethodReferenceAnalyzer(this.OnNewMethod); + } + + private void TryAddAndWalkGenericType(GenericClass gc) + { + if (gc == null) + { + return; + } + lock(_lock) + { + gc = StandardizeClass(gc); + if (_genericTypes.Add(gc)) + { + WalkType(gc); + } + } + } + + private GenericClass StandardizeClass(GenericClass gc) + { + TypeDef typeDef = gc.Type; + ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes; + List klassGenericParams = gc.KlassInst != null ? MetaUtil.ToShareTypeSigs(corLibTypes, gc.KlassInst) : (typeDef.GenericParameters.Count > 0 ? MetaUtil.CreateDefaultGenericParams(typeDef.Module, typeDef.GenericParameters.Count) : null); + return new GenericClass(typeDef, klassGenericParams); + } + + private GenericMethod StandardizeMethod(GenericMethod gm) + { + TypeDef typeDef = gm.Method.DeclaringType; + ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes; + List klassGenericParams = gm.KlassInst != null ? MetaUtil.ToShareTypeSigs(corLibTypes, gm.KlassInst) : (typeDef.GenericParameters.Count > 0 ? MetaUtil.CreateDefaultGenericParams(typeDef.Module, typeDef.GenericParameters.Count) : null); + List methodGenericParams = gm.MethodInst != null ? MetaUtil.ToShareTypeSigs(corLibTypes, gm.MethodInst) : (gm.Method.GenericParameters.Count > 0 ? MetaUtil.CreateDefaultGenericParams(typeDef.Module, gm.Method.GenericParameters.Count) : null); + return new GenericMethod(gm.Method, klassGenericParams, methodGenericParams); + } + + private void OnNewMethod(MethodDef methodDef, List klassGenericInst, List methodGenericInst, GenericMethod method) + { + lock(_lock) + { + method = StandardizeMethod(method); + if (_genericMethods.Add(method)) + { + _newMethods.Add(method); + } + if (method.KlassInst != null) + { + TryAddAndWalkGenericType(new GenericClass(method.Method.DeclaringType, method.KlassInst)); + } + } + } + + private void WalkType(GenericClass gc) + { + //Debug.Log($"typespec:{sig} {sig.GenericType} {sig.GenericType.TypeDefOrRef.ResolveTypeDef()}"); + //Debug.Log($"== walk generic type:{new GenericInstSig(gc.Type.ToTypeSig().ToClassOrValueTypeSig(), gc.KlassInst)}"); + ITypeDefOrRef baseType = gc.Type.BaseType; + if (baseType != null && baseType.TryGetGenericInstSig() != null) + { + GenericClass parentType = GenericClass.ResolveClass((TypeSpec)baseType, new GenericArgumentContext(gc.KlassInst, null)); + TryAddAndWalkGenericType(parentType); + } + foreach (var method in gc.Type.Methods) + { + var gm = StandardizeMethod(new GenericMethod(method, gc.KlassInst, null)); + //Debug.Log($"add method:{gm.Method} {gm.KlassInst}"); + + if (_genericMethods.Add(gm)) + { + if (method.HasBody && method.Body.Instructions != null) + { + _newMethods.Add(gm); + } + } + } + } + + private void WalkType(TypeDef typeDef) + { + _typeDefs.Add(typeDef); + ITypeDefOrRef baseType = typeDef.BaseType; + if (baseType != null && baseType.TryGetGenericInstSig() != null) + { + GenericClass gc = GenericClass.ResolveClass((TypeSpec)baseType, null); + TryAddAndWalkGenericType(gc); + } + foreach (var method in typeDef.Methods) + { + // 对于带泛型的参数,统一泛型共享为object + var gm = StandardizeMethod(new GenericMethod(method, null, null)); + _genericMethods.Add(gm); + } + } + + private void Prepare() + { + // 将所有非泛型函数全部加入函数列表,同时立马walk这些method。 + // 后续迭代中将只遍历MethodSpec + foreach (var ass in _assemblyCollector.GetLoadedModules()) + { + foreach (TypeDef typeDef in ass.GetTypes()) + { + WalkType(typeDef); + } + + for (uint rid = 1, n = ass.Metadata.TablesStream.TypeSpecTable.Rows; rid <= n; rid++) + { + var ts = ass.ResolveTypeSpec(rid); + var cs = GenericClass.ResolveClass(ts, null); + if (cs != null) + { + TryAddAndWalkGenericType(cs); + } + } + + for (uint rid = 1, n = ass.Metadata.TablesStream.MethodSpecTable.Rows; rid <= n; rid++) + { + var ms = ass.ResolveMethodSpec(rid); + var gm = GenericMethod.ResolveMethod(ms, null)?.ToGenericShare(); + if (gm == null) + { + continue; + } + gm = StandardizeMethod(gm); + if (_genericMethods.Add(gm)) + { + _newMethods.Add(gm); + } + } + } + Debug.Log($"PostPrepare allMethods:{_genericMethods.Count} newMethods:{_newMethods.Count}"); + } + + private void RecursiveCollect() + { + for (int i = 0; i < _maxInterationCount && _newMethods.Count > 0; i++) + { + var temp = _processingMethods; + _processingMethods = _newMethods; + _newMethods = temp; + _newMethods.Clear(); + + Task.WaitAll(_processingMethods.Select(method => Task.Run(() => + { + _methodReferenceAnalyzer.WalkMethod(method.Method, method.KlassInst, method.MethodInst); + })).ToArray()); + Debug.Log($"iteration:[{i}] genericClass:{_genericTypes.Count} genericMethods:{_genericMethods.Count} newMethods:{_newMethods.Count}"); + } + } + + public void Run() + { + Prepare(); + RecursiveCollect(); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Analyzer.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Analyzer.cs.meta new file mode 100644 index 0000000..4fd796f --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Analyzer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ee1ec106190e514489c7ba32bc7bc2e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Generator.cs b/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Generator.cs new file mode 100644 index 0000000..bb9f56e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Generator.cs @@ -0,0 +1,828 @@ +using dnlib.DotNet; +using HybridCLR.Editor.ABI; +using HybridCLR.Editor.Meta; +using HybridCLR.Editor.Template; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using UnityEditor; +using UnityEngine; +using TypeInfo = HybridCLR.Editor.ABI.TypeInfo; + +namespace HybridCLR.Editor.MethodBridge +{ + public class Generator + { + public class Options + { + public string TemplateCode { get; set; } + + public string OutputFile { get; set; } + + public IReadOnlyCollection GenericMethods { get; set; } + } + + private readonly List _genericMethods; + + private readonly string _templateCode; + + private readonly string _outputFile; + + private readonly TypeCreator _typeCreator; + + private readonly HashSet _managed2nativeMethodSet = new HashSet(); + + private readonly HashSet _native2managedMethodSet = new HashSet(); + + private readonly HashSet _adjustThunkMethodSet = new HashSet(); + + public Generator(Options options) + { + List<(GenericMethod, string)> genericMethodInfo = options.GenericMethods.Select(m => (m, m.ToString())).ToList(); + genericMethodInfo.Sort((a, b) => string.CompareOrdinal(a.Item2, b.Item2)); + _genericMethods = genericMethodInfo.Select(m => m.Item1).ToList(); + + _templateCode = options.TemplateCode; + _outputFile = options.OutputFile; + _typeCreator = new TypeCreator(); + } + + private readonly Dictionary _sig2Types = new Dictionary(); + + private TypeInfo GetSharedTypeInfo(TypeSig type) + { + var typeInfo = _typeCreator.CreateTypeInfo(type); + if (!typeInfo.IsStruct) + { + return typeInfo; + } + string sigName = ToFullName(typeInfo.Klass); + if (!_sig2Types.TryGetValue(sigName, out var sharedTypeInfo)) + { + sharedTypeInfo = typeInfo; + _sig2Types.Add(sigName, sharedTypeInfo); + } + return sharedTypeInfo; + } + + private MethodDesc CreateMethodDesc(MethodDef methodDef, bool forceRemoveThis, TypeSig returnType, List parameters) + { + var paramInfos = new List(); + if (forceRemoveThis && !methodDef.IsStatic) + { + parameters.RemoveAt(0); + } + if (returnType.ContainsGenericParameter) + { + throw new Exception($"[PreservedMethod] method:{methodDef} has generic parameters"); + } + foreach (var paramInfo in parameters) + { + if (paramInfo.ContainsGenericParameter) + { + throw new Exception($"[PreservedMethod] method:{methodDef} has generic parameters"); + } + paramInfos.Add(new ParamInfo() { Type = GetSharedTypeInfo(paramInfo) }); + } + var mbs = new MethodDesc() + { + MethodDef = methodDef, + ReturnInfo = new ReturnInfo() { Type = returnType != null ? GetSharedTypeInfo(returnType) : TypeInfo.s_void }, + ParamInfos = paramInfos, + }; + return mbs; + } + + private void AddManaged2NativeMethod(MethodDesc method) + { + method.Init(); + _managed2nativeMethodSet.Add(method); + } + + private void AddNative2ManagedMethod(MethodDesc method) + { + method.Init(); + _native2managedMethodSet.Add(method); + } + + private void AddAdjustThunkMethod(MethodDesc method) + { + method.Init(); + _adjustThunkMethodSet.Add(method); + } + + private void ProcessMethod(MethodDef method, List klassInst, List methodInst) + { + if (method.IsPrivate || (method.IsAssembly && !method.IsPublic && !method.IsFamily)) + { + if (klassInst == null && methodInst == null) + { + return; + } + else + { + //Debug.Log($"[PreservedMethod] method:{method}"); + } + } + ICorLibTypes corLibTypes = method.Module.CorLibTypes; + TypeSig returnType; + List parameters; + if (klassInst == null && methodInst == null) + { + if (method.HasGenericParameters) + { + throw new Exception($"[PreservedMethod] method:{method} has generic parameters"); + } + returnType = MetaUtil.ToShareTypeSig(corLibTypes, method.ReturnType); + parameters = method.Parameters.Select(p => MetaUtil.ToShareTypeSig(corLibTypes, p.Type)).ToList(); + } + else + { + var gc = new GenericArgumentContext(klassInst, methodInst); + returnType = MetaUtil.ToShareTypeSig(corLibTypes, MetaUtil.Inflate(method.ReturnType, gc)); + parameters = method.Parameters.Select(p => MetaUtil.ToShareTypeSig(corLibTypes, MetaUtil.Inflate(p.Type, gc))).ToList(); + } + + var m2nMethod = CreateMethodDesc(method, false, returnType, parameters); + AddManaged2NativeMethod(m2nMethod); + + if (method.IsVirtual) + { + if (method.DeclaringType.IsInterface) + { + AddAdjustThunkMethod(m2nMethod); + } + //var adjustThunkMethod = CreateMethodDesc(method, true, returnType, parameters); + AddNative2ManagedMethod(m2nMethod); + } + if (method.Name == "Invoke" && method.DeclaringType.IsDelegate) + { + var openMethod = CreateMethodDesc(method, true, returnType, parameters); + AddNative2ManagedMethod(openMethod); + } + } + + public void PrepareMethods() + { + foreach(var method in _genericMethods) + { + ProcessMethod(method.Method, method.KlassInst, method.MethodInst); + } + } + + static void CheckUnique(IEnumerable names) + { + var set = new HashSet(); + foreach (var name in names) + { + if (!set.Add(name)) + { + throw new Exception($"[CheckUnique] duplicate name:{name}"); + } + } + } + + + private List _managed2NativeMethodList0; + private List _native2ManagedMethodList0; + private List _adjustThunkMethodList0; + + private List _structTypes0; + + private void CollectTypesAndMethods() + { + _managed2NativeMethodList0 = _managed2nativeMethodSet.ToList(); + _managed2NativeMethodList0.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig)); + + _native2ManagedMethodList0 = _native2managedMethodSet.ToList(); + _native2ManagedMethodList0.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig)); + + _adjustThunkMethodList0 = _adjustThunkMethodSet.ToList(); + _adjustThunkMethodList0.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig)); + + + var structTypeSet = new HashSet(); + CollectStructDefs(_managed2NativeMethodList0, structTypeSet); + CollectStructDefs(_native2ManagedMethodList0, structTypeSet); + CollectStructDefs(_adjustThunkMethodList0, structTypeSet); + _structTypes0 = structTypeSet.ToList(); + _structTypes0.Sort((a, b) => a.TypeId - b.TypeId); + + CheckUnique(_structTypes0.Select(t => ToFullName(t.Klass))); + CheckUnique(_structTypes0.Select(t => t.CreateSigName())); + + Debug.LogFormat("== before optimization struct:{3} managed2native:{0} native2managed:{1} adjustThunk:{2}", + _managed2NativeMethodList0.Count, _native2ManagedMethodList0.Count, _adjustThunkMethodList0.Count, _structTypes0.Count); + } + + private class AnalyzeTypeInfo + { + public TypeInfo toSharedType; + public List fields; + public string signature; + } + + private readonly Dictionary _analyzeTypeInfos = new Dictionary(); + + private readonly Dictionary _signature2Type = new Dictionary(); + + private AnalyzeTypeInfo CalculateAnalyzeTypeInfoBasic(TypeInfo typeInfo) + { + TypeSig type = typeInfo.Klass; + TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow(); + + List klassInst = type.ToGenericInstSig()?.GenericArguments?.ToList(); + GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null; + + ClassLayout sa = typeDef.ClassLayout; + var analyzeTypeInfo = new AnalyzeTypeInfo(); + + // don't share type with explicit layout + if (sa != null) + { + analyzeTypeInfo.toSharedType = typeInfo; + analyzeTypeInfo.signature = typeInfo.CreateSigName(); + _signature2Type.Add(analyzeTypeInfo.signature, typeInfo); + return analyzeTypeInfo; + } + + var fields = analyzeTypeInfo.fields = new List(); + + foreach (FieldDef field in typeDef.Fields) + { + if (field.IsStatic) + { + continue; + } + TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType; + fields.Add(GetSharedTypeInfo(fieldType)); + } + return analyzeTypeInfo; + } + + private string GetOrCalculateTypeInfoSignature(TypeInfo typeInfo) + { + if (!typeInfo.IsStruct) + { + return typeInfo.CreateSigName(); + } + + var ati = _analyzeTypeInfos[typeInfo]; + + //if (_analyzeTypeInfos.TryGetValue(typeInfo, out var ati)) + //{ + // return ati.signature; + //} + //ati = CalculateAnalyzeTypeInfoBasic(typeInfo); + //_analyzeTypeInfos.Add(typeInfo, ati); + if (ati.signature != null) + { + return ati.signature; + } + + var sigBuf = new StringBuilder(); + foreach (var field in ati.fields) + { + sigBuf.Append(GetOrCalculateTypeInfoSignature(ToIsomorphicType(field))); + } + return ati.signature = sigBuf.ToString(); + } + + private TypeInfo ToIsomorphicType(TypeInfo type) + { + if (!type.IsStruct) + { + return type; + } + if (!_analyzeTypeInfos.TryGetValue(type, out var ati)) + { + ati = CalculateAnalyzeTypeInfoBasic(type); + _analyzeTypeInfos.Add(type, ati); + } + if (ati.toSharedType == null) + { + string signature = GetOrCalculateTypeInfoSignature(type); + Debug.Assert(signature == ati.signature); + if (_signature2Type.TryGetValue(signature, out var sharedType)) + { + // Debug.Log($"[ToIsomorphicType] type:{type.Klass} ==> sharedType:{sharedType.Klass} signature:{signature} "); + ati.toSharedType = sharedType; + } + else + { + ati.toSharedType = type; + _signature2Type.Add(signature, type); + } + } + return ati.toSharedType; + } + + private MethodDesc ToIsomorphicMethod(MethodDesc method) + { + var paramInfos = new List(); + foreach (var paramInfo in method.ParamInfos) + { + paramInfos.Add(new ParamInfo() { Type = ToIsomorphicType(paramInfo.Type) }); + } + var mbs = new MethodDesc() + { + MethodDef = method.MethodDef, + ReturnInfo = new ReturnInfo() { Type = ToIsomorphicType(method.ReturnInfo.Type) }, + ParamInfos = paramInfos, + }; + mbs.Init(); + return mbs; + } + + private List _managed2NativeMethodList; + private List _native2ManagedMethodList; + private List _adjustThunkMethodList; + + private List structTypes; + + private void BuildAnalyzeTypeInfos() + { + foreach (var type in _structTypes0) + { + ToIsomorphicType(type); + } + structTypes = _signature2Type.Values.ToList(); + structTypes.Sort((a, b) => a.TypeId - b.TypeId); + } + + private List ToUniqueOrderedList(List methods) + { + var methodMap = new SortedDictionary(); + foreach (var method in methods) + { + var sharedMethod = ToIsomorphicMethod(method); + var sig = sharedMethod.Sig; + if (!methodMap.TryGetValue(sig, out var _)) + { + methodMap.Add(sig, sharedMethod); + } + } + return methodMap.Values.ToList(); + } + + private void BuildOptimizedMethods() + { + _managed2NativeMethodList = ToUniqueOrderedList(_managed2NativeMethodList0); + _native2ManagedMethodList = ToUniqueOrderedList(_native2ManagedMethodList0); + _adjustThunkMethodList = ToUniqueOrderedList(_adjustThunkMethodList0); + } + + private void OptimizationTypesAndMethods() + { + BuildAnalyzeTypeInfos(); + BuildOptimizedMethods(); + Debug.LogFormat("== after optimization struct:{3} managed2native:{0} native2managed:{1} adjustThunk:{2}", + _managed2NativeMethodList.Count, _native2ManagedMethodList.Count, _adjustThunkMethodList.Count, structTypes.Count); + } + + private void GenerateCode() + { + var frr = new FileRegionReplace(_templateCode); + + List lines = new List(20_0000); + + var classInfos = new List(); + var classTypeSet = new HashSet(); + foreach (var type in structTypes) + { + GenerateClassInfo(type, classTypeSet, classInfos); + } + + GenerateStructDefines(classInfos, lines); + + // use structTypes0 to generate signature + GenerateStructureSignatureStub(_structTypes0, lines); + + foreach (var method in _managed2NativeMethodList) + { + GenerateManaged2NativeMethod(method, lines); + } + + GenerateManaged2NativeStub(_managed2NativeMethodList, lines); + + foreach (var method in _native2ManagedMethodList) + { + GenerateNative2ManagedMethod(method, lines); + } + + GenerateNative2ManagedStub(_native2ManagedMethodList, lines); + + foreach (var method in _adjustThunkMethodList) + { + GenerateAdjustThunkMethod(method, lines); + } + + GenerateAdjustThunkStub(_adjustThunkMethodList, lines); + + frr.Replace("CODE", string.Join("\n", lines)); + + Directory.CreateDirectory(Path.GetDirectoryName(_outputFile)); + + frr.Commit(_outputFile); + } + + public void Generate() + { + CollectTypesAndMethods(); + OptimizationTypesAndMethods(); + GenerateCode(); + } + + private void CollectStructDefs(List methods, HashSet structTypes) + { + foreach (var method in methods) + { + foreach(var paramInfo in method.ParamInfos) + { + if (paramInfo.Type.IsStruct) + { + structTypes.Add(paramInfo.Type); + if (paramInfo.Type.Klass.ContainsGenericParameter) + { + throw new Exception($"[CollectStructDefs] method:{method.MethodDef} type:{paramInfo.Type.Klass} contains generic parameter"); + } + } + + } + if (method.ReturnInfo.Type.IsStruct) + { + structTypes.Add(method.ReturnInfo.Type); + if (method.ReturnInfo.Type.Klass.ContainsGenericParameter) + { + throw new Exception($"[CollectStructDefs] method:{method.MethodDef} type:{method.ReturnInfo.Type.Klass} contains generic parameter"); + } + } + } + + } + + class FieldInfo + { + public FieldDef field; + public TypeInfo type; + } + + class ClassInfo + { + public TypeInfo type; + + public TypeDef typeDef; + + public List fields = new List(); + + public ClassLayout layout; + } + + private void GenerateClassInfo(TypeInfo type, HashSet typeSet, List classInfos) + { + if (!typeSet.Add(type)) + { + return; + } + TypeSig typeSig = type.Klass; + var fields = new List(); + + TypeDef typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow(); + + List klassInst = typeSig.ToGenericInstSig()?.GenericArguments?.ToList(); + GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null; + + ClassLayout sa = typeDef.ClassLayout; + + ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes; + foreach (FieldDef field in typeDef.Fields) + { + if (field.IsStatic) + { + continue; + } + TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType; + fieldType = MetaUtil.ToShareTypeSig(corLibTypes, fieldType); + var fieldTypeInfo = ToIsomorphicType(_typeCreator.CreateTypeInfo(fieldType)); + if (fieldTypeInfo.IsStruct) + { + GenerateClassInfo(fieldTypeInfo, typeSet, classInfos); + } + fields.Add(new FieldInfo { field = field, type = fieldTypeInfo }); + } + classInfos.Add(new ClassInfo() { type = type, typeDef = typeDef, fields = fields, layout = sa }); + } + + private void GenerateStructDefines(List classInfos, List lines) + { + foreach (var ci in classInfos) + { + lines.Add($"// {ci.type.Klass}"); + uint packingSize = ci.layout?.PackingSize ?? 0; + if (packingSize != 0) + { + lines.Add($"#pragma pack(push, {packingSize})"); + } + uint classSize = ci.layout?.ClassSize ?? 0; + + if (ci.typeDef.IsExplicitLayout) + { + lines.Add($"union {ci.type.GetTypeName()} {{"); + if (classSize > 0) + { + lines.Add($"\tstruct {{ char __fieldSize_offsetPadding[{classSize}];}};"); + } + int index = 0; + foreach (var field in ci.fields) + { + uint offset = field.field.FieldOffset.Value; + string fieldName = $"__{index}"; + string commentFieldName = $"{field.field.Name}"; + lines.Add("\t#pragma pack(push, 1)"); + lines.Add($"\tstruct {{ {(offset > 0 ? $"char {fieldName}_offsetPadding[{offset}];" : "")} {field.type.GetTypeName()} {fieldName};}}; // {commentFieldName}"); + lines.Add($"\t#pragma pack(pop)"); + lines.Add($"\tstruct {{ {field.type.GetTypeName()} {fieldName}_forAlignmentOnly;}}; // {commentFieldName}"); + ++index; + } + } + else + { + lines.Add($"{(classSize > 0 ? "union" : "struct")} {ci.type.GetTypeName()} {{"); + if (classSize > 0) + { + lines.Add($"\tstruct {{ char __fieldSize_offsetPadding[{classSize}];}};"); + lines.Add("\tstruct {"); + } + int index = 0; + foreach (var field in ci.fields) + { + string fieldName = $"__{index}"; + string commentFieldName = $"{field.field.Name}"; + lines.Add($"\t{field.type.GetTypeName()} {fieldName}; // {commentFieldName}"); + ++index; + } + if (classSize > 0) + { + lines.Add("\t};"); + } + } + lines.Add("};"); + if (packingSize != 0) + { + lines.Add($"#pragma pack(pop)"); + } + } + } + + public const string SigOfObj = "u"; + + public static string ToFullName(TypeSig type) + { + type = type.RemovePinnedAndModifiers(); + switch (type.ElementType) + { + case ElementType.Void: return "v"; + case ElementType.Boolean: return "u1"; + case ElementType.I1: return "i1"; + case ElementType.U1: return "u1"; + case ElementType.I2: return "i2"; + case ElementType.Char: + case ElementType.U2: return "u2"; + case ElementType.I4: return "i4"; + case ElementType.U4: return "u4"; + case ElementType.I8: return "i8"; + case ElementType.U8: return "u8"; + case ElementType.R4: return "r4"; + case ElementType.R8: return "r8"; + case ElementType.I: return "i"; + case ElementType.U: + case ElementType.String: + case ElementType.Ptr: + case ElementType.ByRef: + case ElementType.Class: + case ElementType.Array: + case ElementType.SZArray: + case ElementType.FnPtr: + case ElementType.Object: + return SigOfObj; + case ElementType.Module: + case ElementType.Var: + case ElementType.MVar: + throw new NotSupportedException($"ToFullName type:{type}"); + case ElementType.TypedByRef: return TypeInfo.strTypedByRef; + case ElementType.ValueType: + { + TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDef(); + if (typeDef == null) + { + throw new Exception($"type:{type} definition could not be found. Please try `HybridCLR/Genergate/LinkXml`, then Build once to generate the AOT dll, and then regenerate the bridge function"); + } + if (typeDef.IsEnum) + { + return ToFullName(typeDef.GetEnumUnderlyingType()); + } + return ToValueTypeFullName((ClassOrValueTypeSig)type); + } + case ElementType.GenericInst: + { + GenericInstSig gis = (GenericInstSig)type; + if (!gis.GenericType.IsValueType) + { + return SigOfObj; + } + TypeDef typeDef = gis.GenericType.ToTypeDefOrRef().ResolveTypeDef(); + if (typeDef.IsEnum) + { + return ToFullName(typeDef.GetEnumUnderlyingType()); + } + return $"{ToValueTypeFullName(gis.GenericType)}<{string.Join(",", gis.GenericArguments.Select(a => ToFullName(a)))}>"; + } + default: throw new NotSupportedException($"{type.ElementType}"); + } + } + + private static bool IsSystemOrUnityAssembly(ModuleDef module) + { + if (module.IsCoreLibraryModule == true) + { + return true; + } + string assName = module.Assembly.Name.String; + return assName.StartsWith("System.") || assName.StartsWith("UnityEngine."); + } + + private static string ToValueTypeFullName(ClassOrValueTypeSig type) + { + TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDef(); + if (typeDef == null) + { + throw new Exception($"type:{type} resolve fail"); + } + + if (typeDef.DeclaringType != null) + { + return $"{ToValueTypeFullName((ClassOrValueTypeSig)typeDef.DeclaringType.ToTypeSig())}/{typeDef.Name}"; + } + + if (IsSystemOrUnityAssembly(typeDef.Module)) + { + return type.FullName; + } + return $"{Path.GetFileNameWithoutExtension(typeDef.Module.Name)}:{typeDef.FullName}"; + } + + public void GenerateStructureSignatureStub(List types, List lines) + { + lines.Add("FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {"); + foreach (var type in types) + { + TypeInfo isoType = ToIsomorphicType(type); + lines.Add($"\t{{\"{ToFullName(type.Klass)}\", \"{isoType.CreateSigName()}\"}},"); + } + lines.Add("\t{ nullptr, nullptr},"); + lines.Add("};"); + } + + public void GenerateManaged2NativeStub(List methods, List lines) + { + lines.Add($@" +Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] = +{{ +"); + + foreach (var method in methods) + { + lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", __M2N_{method.CreateInvokeSigName()}}},"); + } + + lines.Add($"\t{{nullptr, nullptr}},"); + lines.Add("};"); + } + + public void GenerateNative2ManagedStub(List methods, List lines) + { + lines.Add($@" +Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] = +{{ +"); + + foreach (var method in methods) + { + lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", (Il2CppMethodPointer)__N2M_{method.CreateInvokeSigName()}}},"); + } + + lines.Add($"\t{{nullptr, nullptr}},"); + lines.Add("};"); + } + + public void GenerateAdjustThunkStub(List methods, List lines) + { + lines.Add($@" +NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] = +{{ +"); + + foreach (var method in methods) + { + lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", (Il2CppMethodPointer)__N2M_AdjustorThunk_{method.CreateCallSigName()}}},"); + } + + lines.Add($"\t{{nullptr, nullptr}},"); + lines.Add("};"); + } + + private string GetManaged2NativePassParam(TypeInfo type, string varName) + { + return $"M2NFromValueOrAddress<{type.GetTypeName()}>({varName})"; + } + + private string GetNative2ManagedPassParam(TypeInfo type, string varName) + { + return type.NeedExpandValue() ? $"(uint64_t)({varName})" : $"N2MAsUint64ValueOrAddress<{type.GetTypeName()}>({varName})"; + } + + public void GenerateManaged2NativeMethod(MethodDesc method, List lines) + { + string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" })); + string paramNameListStr = string.Join(", ", method.ParamInfos.Select(p => GetManaged2NativePassParam(p.Type, $"localVarBase+argVarIndexs[{p.Index}]")).Concat(new string[] { "method" })); + + lines.Add($@" +static void __M2N_{method.CreateCallSigName()}(const MethodInfo* method, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret) +{{ + typedef {method.ReturnInfo.Type.GetTypeName()} (*NativeMethod)({paramListStr}); + {(!method.ReturnInfo.IsVoid ? $"*({method.ReturnInfo.Type.GetTypeName()}*)ret = " : "")}((NativeMethod)(method->methodPointerCallByInterp))({paramNameListStr}); +}} +"); + } + + public string GenerateArgumentSizeAndOffset(List paramInfos) + { + StringBuilder s = new StringBuilder(); + int index = 0; + foreach (var param in paramInfos) + { + s.AppendLine($"\tconstexpr int __ARG_OFFSET_{index}__ = {(index > 0 ? $"__ARG_OFFSET_{index - 1}__ + __ARG_SIZE_{index-1}__" : "0")};"); + s.AppendLine($"\tconstexpr int __ARG_SIZE_{index}__ = (sizeof(__arg{index}) + 7)/8;"); + index++; + } + s.AppendLine($"\tconstexpr int __TOTAL_ARG_SIZE__ = {(paramInfos.Count > 0 ? $"__ARG_OFFSET_{index-1}__ + __ARG_SIZE_{index-1}__" : "1")};"); + return s.ToString(); + } + + public string GenerateCopyArgumentToInterpreterStack(List paramInfos) + { + StringBuilder s = new StringBuilder(); + int index = 0; + foreach (var param in paramInfos) + { + if (param.Type.IsPrimitiveType) + { + if (param.Type.NeedExpandValue()) + { + s.AppendLine($"\targs[__ARG_OFFSET_{index}__].u64 = __arg{index};"); + } + else + { + s.AppendLine($"\t*({param.Type.GetTypeName()}*)(args + __ARG_OFFSET_{index}__) = __arg{index};"); + } + } + else + { + s.AppendLine($"\t*({param.Type.GetTypeName()}*)(args + __ARG_OFFSET_{index}__) = __arg{index};"); + } + index++; + } + return s.ToString(); + } + + private void GenerateNative2ManagedMethod0(MethodDesc method, bool adjustorThunk, List lines) + { + string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" })); + lines.Add($@" +static {method.ReturnInfo.Type.GetTypeName()} __N2M_{(adjustorThunk ? "AdjustorThunk_" : "")}{method.CreateCallSigName()}({paramListStr}) +{{ + {(adjustorThunk ? "__arg0 += sizeof(Il2CppObject);" : "")} +{GenerateArgumentSizeAndOffset(method.ParamInfos)} + StackObject args[__TOTAL_ARG_SIZE__]; +{GenerateCopyArgumentToInterpreterStack(method.ParamInfos)} + {(method.ReturnInfo.IsVoid ? "Interpreter::Execute(method, args, nullptr);" : $"{method.ReturnInfo.Type.GetTypeName()} ret; Interpreter::Execute(method, args, &ret); return ret;")} +}} +"); + } + + public void GenerateNative2ManagedMethod(MethodDesc method, List lines) + { + GenerateNative2ManagedMethod0(method, false, lines); + } + + public void GenerateAdjustThunkMethod(MethodDesc method, List lines) + { + GenerateNative2ManagedMethod0(method, true, lines); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Generator.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Generator.cs.meta new file mode 100644 index 0000000..914508e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/MethodBridge/Generator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e42a0f3bcbc5ddf438a85ae16c1b3116 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap.meta b/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap.meta new file mode 100644 index 0000000..234a1bc --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 259c1cb7fe681f74eb435ab8f268890d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Analyzer.cs b/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Analyzer.cs new file mode 100644 index 0000000..e089c5b --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Analyzer.cs @@ -0,0 +1,108 @@ +using dnlib.DotNet; +using HybridCLR.Editor.ABI; +using HybridCLR.Editor.Meta; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace HybridCLR.Editor.ReversePInvokeWrap +{ + public class RawReversePInvokeMethodInfo + { + public MethodDef Method { get; set; } + + public CustomAttribute GenerationAttribute { get; set; } + } + + public class ABIReversePInvokeMethodInfo + { + public MethodDesc Method { get; set; } + + public int Count { get; set; } + } + + public class Analyzer + { + + private readonly List _rootModules = new List(); + + private readonly List _reversePInvokeMethods = new List(); + + public Analyzer(AssemblyCache cache, List assemblyNames) + { + foreach (var assemblyName in assemblyNames) + { + _rootModules.Add(cache.LoadModule(assemblyName)); + } + } + + private void CollectReversePInvokeMethods() + { + foreach (var mod in _rootModules) + { + Debug.Log($"ass:{mod.FullName} methodcount:{mod.Metadata.TablesStream.MethodTable.Rows}"); + for (uint rid = 1, n = mod.Metadata.TablesStream.MethodTable.Rows; rid <= n; rid++) + { + var method = mod.ResolveMethod(rid); + //Debug.Log($"method:{method}"); + if (!method.IsStatic || !method.HasCustomAttributes) + { + continue; + } + CustomAttribute wa = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.Name == "MonoPInvokeCallbackAttribute"); + if (wa == null) + { + continue; + } + //foreach (var ca in method.CustomAttributes) + //{ + // Debug.Log($"{ca.AttributeType.FullName} {ca.TypeFullName}"); + //} + _reversePInvokeMethods.Add(new RawReversePInvokeMethodInfo() + { + Method = method, + GenerationAttribute = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "HybridCLR.ReversePInvokeWrapperGenerationAttribute"), + }); + } + } + } + + public List BuildABIMethods() + { + var methodsBySig = new Dictionary(); + var typeCreator = new TypeCreator(); + foreach(var method in _reversePInvokeMethods) + { + MethodDesc desc = new MethodDesc + { + MethodDef = method.Method, + ReturnInfo = new ReturnInfo { Type = typeCreator.CreateTypeInfo(method.Method.ReturnType)}, + ParamInfos = method.Method.Parameters.Select(p => new ParamInfo { Type = typeCreator.CreateTypeInfo(p.Type)}).ToList(), + }; + desc.Init(); + if (!methodsBySig.TryGetValue(desc.Sig, out var arm)) + { + arm = new ABIReversePInvokeMethodInfo() + { + Method = desc, + Count = 0, + }; + methodsBySig.Add(desc.Sig, arm); + } + int preserveCount = method.GenerationAttribute != null ? (int)method.GenerationAttribute.ConstructorArguments[0].Value : 1; + arm.Count += preserveCount; + } + var methods = methodsBySig.Values.ToList(); + methods.Sort((a, b) => String.CompareOrdinal(a.Method.Sig, b.Method.Sig)); + return methods; + } + + public void Run() + { + CollectReversePInvokeMethods(); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Analyzer.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Analyzer.cs.meta new file mode 100644 index 0000000..792b5b5 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Analyzer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c172068b408c0e349b2ceee4c4635085 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Generator.cs b/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Generator.cs new file mode 100644 index 0000000..fdf6df5 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Generator.cs @@ -0,0 +1,59 @@ +using HybridCLR.Editor.ABI; +using HybridCLR.Editor.Template; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace HybridCLR.Editor.ReversePInvokeWrap +{ + public class Generator + { + public void Generate(List methods, string outputFile) + { + string template = File.ReadAllText(outputFile, Encoding.UTF8); + var frr = new FileRegionReplace(template); + var codes = new List(); + + int methodIndex = 0; + var stubCodes = new List(); + foreach(var methodInfo in methods) + { + MethodDesc method = methodInfo.Method; + string paramDeclaringListWithoutMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}")); + string paramNameListWithoutMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"__arg{p.Index}").Concat(new string[] { "method" })); + string paramTypeListWithMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()}").Concat(new string[] { "const MethodInfo*" })); + string methodTypeDef = $"typedef {method.ReturnInfo.Type.GetTypeName()} (*Callback)({paramTypeListWithMethodInfoStr})"; + for (int i = 0; i < methodInfo.Count; i++, methodIndex++) + { + codes.Add($@" + {method.ReturnInfo.Type.GetTypeName()} __ReversePInvokeMethod_{methodIndex}({paramDeclaringListWithoutMethodInfoStr}) + {{ + const MethodInfo* method = MetadataModule::GetMethodInfoByReversePInvokeWrapperIndex({methodIndex}); + {methodTypeDef}; + {(method.ReturnInfo.IsVoid ? "" : "return ")}((Callback)(method->methodPointerCallByInterp))({paramNameListWithoutMethodInfoStr}); + }} +"); + stubCodes.Add($"\t\t{{\"{method.Sig}\", (Il2CppMethodPointer)__ReversePInvokeMethod_{methodIndex}}},\n"); + } + Debug.Log($"[ReversePInvokeWrap.Generator] method:{method.MethodDef} wrapperCount:{methodInfo.Count}"); + } + + codes.Add(@" + ReversePInvokeMethodData g_reversePInvokeMethodStub[] + { +"); + codes.AddRange(stubCodes); + + codes.Add(@" + {nullptr, nullptr}, + }; +"); + + frr.Replace("CODE", string.Join("", codes)); + frr.Commit(outputFile); + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Generator.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Generator.cs.meta new file mode 100644 index 0000000..36a7c55 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/ReversePInvokeWrap/Generator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d883f182f206fa4db31f4085ce0ecdc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings.meta b/Packages/com.code-philosophy.hybridclr/Editor/Settings.meta new file mode 100644 index 0000000..f73ef75 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3708ee1d4035cb14abaa4d64a8ec8148 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings/EditorStatusWatcher.cs b/Packages/com.code-philosophy.hybridclr/Editor/Settings/EditorStatusWatcher.cs new file mode 100644 index 0000000..0c3865e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings/EditorStatusWatcher.cs @@ -0,0 +1,32 @@ +using HybridCLR.Editor; +using System; +using UnityEditor; +using UnityEditorInternal; + +namespace HybridCLR.Editor.Settings +{ + + /// + /// 监听编辑器状态,当编辑器重新 focus 时,重新加载实例,避免某些情景下 svn 、git 等外部修改了数据却无法同步的异常。 + /// + [InitializeOnLoad] + public static class EditorStatusWatcher + { + public static Action OnEditorFocused; + static bool isFocused; + static EditorStatusWatcher() => EditorApplication.update += Update; + static void Update() + { + if (isFocused != InternalEditorUtility.isApplicationActive) + { + isFocused = InternalEditorUtility.isApplicationActive; + if (isFocused) + { + HybridCLRSettings.LoadOrCreate(); + OnEditorFocused?.Invoke(); + } + } + } + } + +} \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings/EditorStatusWatcher.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Settings/EditorStatusWatcher.cs.meta new file mode 100644 index 0000000..317bfd7 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings/EditorStatusWatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 093a9e6c1e7399244bbcd8983fdbfdee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettingProvider.cs b/Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettingProvider.cs new file mode 100644 index 0000000..5ada220 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettingProvider.cs @@ -0,0 +1,178 @@ +using System; +using System.Reflection; +using UnityEditor; +using UnityEditor.Presets; +using UnityEngine; +using UnityEngine.UIElements; + +namespace HybridCLR.Editor.Settings +{ + public class HybridCLRSettingsProvider : SettingsProvider + { + private SerializedObject _serializedObject; + private SerializedProperty _enable; + private SerializedProperty _useGlobalIl2cpp; + private SerializedProperty _hybridclrRepoURL; + private SerializedProperty _il2cppPlusRepoURL; + private SerializedProperty _hotUpdateAssemblyDefinitions; + private SerializedProperty _hotUpdateAssemblies; + private SerializedProperty _preserveHotUpdateAssemblies; + private SerializedProperty _hotUpdateDllCompileOutputRootDir; + private SerializedProperty _externalHotUpdateAssembliyDirs; + private SerializedProperty _strippedAOTDllOutputRootDir; + private SerializedProperty _patchAOTAssemblies; + private SerializedProperty _outputLinkFile; + private SerializedProperty _outputAOTGenericReferenceFile; + private SerializedProperty _maxGenericReferenceIteration; + private SerializedProperty _maxMethodBridgeGenericIteration; + private GUIStyle buttonStyle; + public HybridCLRSettingsProvider() : base("Project/HybridCLR Settings", SettingsScope.Project) { } + public override void OnActivate(string searchContext, VisualElement rootElement) + { + EditorStatusWatcher.OnEditorFocused += OnEditorFocused; + InitGUI(); + } + private void InitGUI() + { + var setting = HybridCLRSettings.LoadOrCreate(); + _serializedObject?.Dispose(); + _serializedObject = new SerializedObject(setting); + _enable = _serializedObject.FindProperty("enable"); + _useGlobalIl2cpp = _serializedObject.FindProperty("useGlobalIl2cpp"); + _hybridclrRepoURL = _serializedObject.FindProperty("hybridclrRepoURL"); + _il2cppPlusRepoURL = _serializedObject.FindProperty("il2cppPlusRepoURL"); + _hotUpdateAssemblyDefinitions = _serializedObject.FindProperty("hotUpdateAssemblyDefinitions"); + _hotUpdateAssemblies = _serializedObject.FindProperty("hotUpdateAssemblies"); + _preserveHotUpdateAssemblies = _serializedObject.FindProperty("preserveHotUpdateAssemblies"); + _hotUpdateDllCompileOutputRootDir = _serializedObject.FindProperty("hotUpdateDllCompileOutputRootDir"); + _externalHotUpdateAssembliyDirs = _serializedObject.FindProperty("externalHotUpdateAssembliyDirs"); + _strippedAOTDllOutputRootDir = _serializedObject.FindProperty("strippedAOTDllOutputRootDir"); + _patchAOTAssemblies = _serializedObject.FindProperty("patchAOTAssemblies"); + _outputLinkFile = _serializedObject.FindProperty("outputLinkFile"); + _outputAOTGenericReferenceFile = _serializedObject.FindProperty("outputAOTGenericReferenceFile"); + _maxGenericReferenceIteration = _serializedObject.FindProperty("maxGenericReferenceIteration"); + _maxMethodBridgeGenericIteration = _serializedObject.FindProperty("maxMethodBridgeGenericIteration"); + } + private void OnEditorFocused() + { + InitGUI(); + Repaint(); + } + public override void OnTitleBarGUI() + { + base.OnTitleBarGUI(); + var rect = GUILayoutUtility.GetLastRect(); + buttonStyle = buttonStyle ?? GUI.skin.GetStyle("IconButton"); + + #region 绘制官方网站跳转按钮 + var w = rect.x + rect.width; + rect.x = w - 57; + rect.y += 6; + rect.width = rect.height = 18; + var content = EditorGUIUtility.IconContent("_Help"); + content.tooltip = "点击访问 HybridCLR 官方文档"; + if (GUI.Button(rect, content, buttonStyle)) + { + Application.OpenURL("https://focus-creative-games.github.io/hybridclr/"); + } + #endregion + #region 绘制 Preset + rect.x += 19; + content = EditorGUIUtility.IconContent("Preset.Context"); + content.tooltip = "点击存储或加载 Preset ."; + if (GUI.Button(rect, content, buttonStyle)) + { + var target = HybridCLRSettings.Instance; + var receiver = ScriptableObject.CreateInstance(); + receiver.Init(target, this); + PresetSelector.ShowSelector(target, null, true, receiver); + } + #endregion + #region 绘制 Reset + rect.x += 19; + content = EditorGUIUtility.IconContent( +#if UNITY_2021_3_OR_NEWER + "pane options" +#else + "_Popup" +#endif + ); + content.tooltip = "Reset"; + if (GUI.Button(rect, content, buttonStyle)) + { + GenericMenu menu = new GenericMenu(); + menu.AddItem(new GUIContent("Reset"), false, () => + { + Undo.RecordObject(HybridCLRSettings.Instance, "Capture Value for Reset"); + var dv = ScriptableObject.CreateInstance(); + var json = EditorJsonUtility.ToJson(dv); + UnityEngine.Object.DestroyImmediate(dv); + EditorJsonUtility.FromJsonOverwrite(json, HybridCLRSettings.Instance); + HybridCLRSettings.Save(); + }); + menu.ShowAsContext(); + } + #endregion + } + public override void OnGUI(string searchContext) + { + using (CreateSettingsWindowGUIScope()) + { + //解决编辑器打包时出现的 _serializedObject.targetObject 意外销毁的情况 + if (_serializedObject == null||!_serializedObject.targetObject) + { + InitGUI(); + } + _serializedObject.Update(); + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(_enable); + EditorGUILayout.PropertyField(_hybridclrRepoURL); + EditorGUILayout.PropertyField(_il2cppPlusRepoURL); + EditorGUILayout.PropertyField(_useGlobalIl2cpp); + EditorGUILayout.PropertyField(_hotUpdateAssemblyDefinitions); + EditorGUILayout.PropertyField(_hotUpdateAssemblies); + EditorGUILayout.PropertyField(_preserveHotUpdateAssemblies); + EditorGUILayout.PropertyField(_hotUpdateDllCompileOutputRootDir); + EditorGUILayout.PropertyField(_externalHotUpdateAssembliyDirs); + EditorGUILayout.PropertyField(_strippedAOTDllOutputRootDir); + EditorGUILayout.PropertyField(_patchAOTAssemblies); + EditorGUILayout.PropertyField(_outputLinkFile); + EditorGUILayout.PropertyField(_outputAOTGenericReferenceFile); + EditorGUILayout.PropertyField(_maxGenericReferenceIteration); + EditorGUILayout.PropertyField(_maxMethodBridgeGenericIteration); + if (EditorGUI.EndChangeCheck()) + { + _serializedObject.ApplyModifiedProperties(); + HybridCLRSettings.Save(); + } + } + } + private IDisposable CreateSettingsWindowGUIScope() + { + var unityEditorAssembly = Assembly.GetAssembly(typeof(EditorWindow)); + var type = unityEditorAssembly.GetType("UnityEditor.SettingsWindow+GUIScope"); + return Activator.CreateInstance(type) as IDisposable; + } + public override void OnDeactivate() + { + base.OnDeactivate(); + EditorStatusWatcher.OnEditorFocused -= OnEditorFocused; + HybridCLRSettings.Save(); + } + + static HybridCLRSettingsProvider provider; + [SettingsProvider] + public static SettingsProvider CreateMyCustomSettingsProvider() + { + if (HybridCLRSettings.Instance && provider == null) + { + provider = new HybridCLRSettingsProvider(); + using (var so = new SerializedObject(HybridCLRSettings.Instance)) + { + provider.keywords = GetSearchKeywordsFromSerializedObject(so); + } + } + return provider; + } + } +} \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettingProvider.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettingProvider.cs.meta new file mode 100644 index 0000000..0a21f37 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettingProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d2bd1694fedc8b54c88bb9f6c67907d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettings.cs b/Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettings.cs new file mode 100644 index 0000000..92247bf --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettings.cs @@ -0,0 +1,54 @@ +using UnityEditorInternal; +using UnityEngine; + +namespace HybridCLR.Editor.Settings +{ + [FilePath("ProjectSettings/HybridCLRSettings.asset")] + public class HybridCLRSettings : ScriptableSingleton + { + [Header("开启HybridCLR插件")] + public bool enable = true; + + [Header("使用全局安装的il2cpp")] + public bool useGlobalIl2cpp; + + [Header("hybridclr 仓库 URL")] + public string hybridclrRepoURL = "https://gitee.com/focus-creative-games/hybridclr"; + + [Header("il2cpp_plus 仓库 URL")] + public string il2cppPlusRepoURL = "https://gitee.com/focus-creative-games/il2cpp_plus"; + + [Header("热更新Assembly Definitions")] + public AssemblyDefinitionAsset[] hotUpdateAssemblyDefinitions; + + [Header("热更新dlls")] + public string[] hotUpdateAssemblies; + + [Header("预留的热更新dlls")] + public string[] preserveHotUpdateAssemblies; + + [Header("热更新dll编译输出根目录")] + public string hotUpdateDllCompileOutputRootDir = "HybridCLRData/HotUpdateDlls"; + + [Header("外部热更新dll搜索路径")] + public string[] externalHotUpdateAssembliyDirs; + + [Header("裁减后AOT dll输出根目录")] + public string strippedAOTDllOutputRootDir = "HybridCLRData/AssembliesPostIl2CppStrip"; + + [Header("补充元数据AOT dlls")] + public string[] patchAOTAssemblies; + + [Header("生成的link.xml路径")] + public string outputLinkFile = "HybridCLRGenerate/link.xml"; + + [Header("自动扫描生成的AOTGenericReferences.cs路径")] + public string outputAOTGenericReferenceFile = "HybridCLRGenerate/AOTGenericReferences.cs"; + + [Header("AOT泛型实例化搜索迭代次数")] + public int maxGenericReferenceIteration = 10; + + [Header("MethodBridge泛型搜索迭代次数")] + public int maxMethodBridgeGenericIteration = 10; + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettings.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettings.cs.meta new file mode 100644 index 0000000..570bc8f --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings/HybridCLRSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e189374413a3f00468e49d51d8b27a09 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings/MenuProvider.cs b/Packages/com.code-philosophy.hybridclr/Editor/Settings/MenuProvider.cs new file mode 100644 index 0000000..c21c46d --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings/MenuProvider.cs @@ -0,0 +1,39 @@ +using HybridCLR.Editor.Installer; +using UnityEditor; +using UnityEngine; + +namespace HybridCLR.Editor.Settings +{ + public static class MenuProvider + { + + [MenuItem("HybridCLR/About", priority = 0)] + public static void OpenAbout() => Application.OpenURL("https://hybridclr.doc.code-philosophy.com/docs/intro"); + + [MenuItem("HybridCLR/Installer...", priority = 60)] + private static void Open() + { + InstallerWindow window = EditorWindow.GetWindow("HybridCLR Installer", true); + window.minSize = new Vector2(800f, 500f); + } + + [MenuItem("HybridCLR/Settings...", priority = 61)] + public static void OpenSettings() => SettingsService.OpenProjectSettings("Project/HybridCLR Settings"); + + [MenuItem("HybridCLR/Documents/Quick Start")] + public static void OpenQuickStart() => Application.OpenURL("https://hybridclr.doc.code-philosophy.com/docs/beginner/quickstart"); + + [MenuItem("HybridCLR/Documents/Performance")] + public static void OpenPerformance() => Application.OpenURL("https://hybridclr.doc.code-philosophy.com/docs/basic/performance"); + + [MenuItem("HybridCLR/Documents/FAQ")] + public static void OpenFAQ() => Application.OpenURL("https://hybridclr.doc.code-philosophy.com/docs/help/faq"); + + [MenuItem("HybridCLR/Documents/Common Errors")] + public static void OpenCommonErrors() => Application.OpenURL("https://hybridclr.doc.code-philosophy.com/docs/help/commonerrors"); + + [MenuItem("HybridCLR/Documents/Bug Report")] + public static void OpenBugReport() => Application.OpenURL("https://hybridclr.doc.code-philosophy.com/docs/help/issue"); + } + +} \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings/MenuProvider.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Settings/MenuProvider.cs.meta new file mode 100644 index 0000000..a4474b2 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings/MenuProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a475a5f281298b84da32373694704c68 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings/ScriptableSignleton.cs b/Packages/com.code-philosophy.hybridclr/Editor/Settings/ScriptableSignleton.cs new file mode 100644 index 0000000..903f802 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings/ScriptableSignleton.cs @@ -0,0 +1,89 @@ +using System; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; + +namespace HybridCLR.Editor.Settings +{ + public class ScriptableSingleton : ScriptableObject where T : ScriptableObject + { + private static T s_Instance; + public static T Instance + { + get + { + if (!s_Instance) + { + LoadOrCreate(); + } + return s_Instance; + } + } + public static T LoadOrCreate() + { + string filePath = GetFilePath(); + if (!string.IsNullOrEmpty(filePath)) + { + var arr = InternalEditorUtility.LoadSerializedFileAndForget(filePath); + s_Instance = arr.Length > 0 ? arr[0] as T : s_Instance??CreateInstance(); + } + else + { + Debug.LogError($"save location of {nameof(ScriptableSingleton)} is invalid"); + } + return s_Instance; + } + + public static void Save(bool saveAsText = true) + { + if (!s_Instance) + { + Debug.LogError("Cannot save ScriptableSingleton: no instance!"); + return; + } + + string filePath = GetFilePath(); + if (!string.IsNullOrEmpty(filePath)) + { + string directoryName = Path.GetDirectoryName(filePath); + if (!Directory.Exists(directoryName)) + { + Directory.CreateDirectory(directoryName); + } + UnityEngine.Object[] obj = new T[1] { s_Instance }; + InternalEditorUtility.SaveToSerializedFileAndForget(obj, filePath, saveAsText); + } + } + protected static string GetFilePath() + { + return typeof(T).GetCustomAttributes(inherit: true) + .Where(v => v is FilePathAttribute) + .Cast() + .FirstOrDefault() + ?.filepath; + } + } + [AttributeUsage(AttributeTargets.Class)] + public class FilePathAttribute : Attribute + { + internal string filepath; + /// + /// 单例存放路径 + /// + /// 相对 Project 路径 + public FilePathAttribute(string path) + { + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentException("Invalid relative path (it is empty)"); + } + if (path[0] == '/') + { + path = path.Substring(1); + } + filepath = path; + } + } +} \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings/ScriptableSignleton.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Settings/ScriptableSignleton.cs.meta new file mode 100644 index 0000000..fa1923b --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings/ScriptableSignleton.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 851c44a8da67a9742a7ea68815383f27 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings/SettingsPresetReceiver.cs b/Packages/com.code-philosophy.hybridclr/Editor/Settings/SettingsPresetReceiver.cs new file mode 100644 index 0000000..e60f3aa --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings/SettingsPresetReceiver.cs @@ -0,0 +1,39 @@ +using UnityEditor; +using UnityEditor.Presets; +using UnityEngine; + +namespace HybridCLR.Editor.Settings +{ + public class SettingsPresetReceiver : PresetSelectorReceiver + { + private Object m_Target; + private Preset m_InitialValue; + private SettingsProvider m_Provider; + + internal void Init(Object target, SettingsProvider provider) + { + m_Target = target; + m_InitialValue = new Preset(target); + m_Provider = provider; + } + public override void OnSelectionChanged(Preset selection) + { + if (selection != null) + { + Undo.RecordObject(m_Target, "Apply Preset " + selection.name); + selection.ApplyTo(m_Target); + } + else + { + Undo.RecordObject(m_Target, "Cancel Preset"); + m_InitialValue.ApplyTo(m_Target); + } + m_Provider.Repaint(); + } + public override void OnSelectionClosed(Preset selection) + { + OnSelectionChanged(selection); + Object.DestroyImmediate(this); + } + } +} \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Settings/SettingsPresetReceiver.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Settings/SettingsPresetReceiver.cs.meta new file mode 100644 index 0000000..5047283 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Settings/SettingsPresetReceiver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d8373e0cb30c4894db7cd4d0b77a7a48 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/SettingsUtil.cs b/Packages/com.code-philosophy.hybridclr/Editor/SettingsUtil.cs new file mode 100644 index 0000000..9a074ea --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/SettingsUtil.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; +using HybridCLR.Editor.Settings; + + +namespace HybridCLR.Editor +{ + public static class SettingsUtil + { + public static bool Enable + { + get => HybridCLRSettings.Instance.enable; + set + { + HybridCLRSettings.Instance.enable = value; + HybridCLRSettings.Save(); + } + } + + public static string PackageName { get; } = "com.code-philosophy.hybridclr"; + + public static string HybridCLRDataPathInPackage => $"Packages/{PackageName}/Data~"; + + public static string TemplatePathInPackage => $"{HybridCLRDataPathInPackage}/Templates"; + + public static string ProjectDir { get; } = Directory.GetParent(Application.dataPath).ToString(); + + public static string ScriptingAssembliesJsonFile { get; } = "ScriptingAssemblies.json"; + + public static string HotUpdateDllsRootOutputDir => HybridCLRSettings.Instance.hotUpdateDllCompileOutputRootDir; + + public static string AssembliesPostIl2CppStripDir => HybridCLRSettings.Instance.strippedAOTDllOutputRootDir; + + public static string HybridCLRDataDir => $"{ProjectDir}/HybridCLRData"; + + public static string LocalUnityDataDir => $"{HybridCLRDataDir}/LocalIl2CppData-{Application.platform}"; + + public static string LocalIl2CppDir => $"{LocalUnityDataDir}/il2cpp"; + + public static string GeneratedCppDir => $"{LocalIl2CppDir}/libil2cpp/hybridclr/generated"; + + public static string Il2CppBuildCacheDir { get; } = $"{ProjectDir}/Library/Il2cppBuildCache"; + + public static string GetHotUpdateDllsOutputDirByTarget(BuildTarget target) + { + return $"{HotUpdateDllsRootOutputDir}/{target}"; + } + + public static string GetAssembliesPostIl2CppStripDir(BuildTarget target) + { + return $"{AssembliesPostIl2CppStripDir}/{target}"; + } + + class AssemblyDefinitionData + { + public string name; + } + + /// + /// 热更新dll列表。不包含 preserveHotUpdateAssemblies。 + /// + public static List HotUpdateAssemblyNamesExcludePreserved + { + get + { + var gs = HybridCLRSettings.Instance; + var hotfixAssNames = (gs.hotUpdateAssemblyDefinitions ?? Array.Empty()).Select(ad => JsonUtility.FromJson(ad.text)); + + var hotfixAssembles = new List(); + foreach (var assName in hotfixAssNames) + { + hotfixAssembles.Add(assName.name); + } + hotfixAssembles.AddRange(gs.hotUpdateAssemblies ?? Array.Empty()); + return hotfixAssembles.ToList(); + } + } + + public static List HotUpdateAssemblyFilesExcludePreserved => HotUpdateAssemblyNamesExcludePreserved.Select(dll => dll + ".dll").ToList(); + + + public static List HotUpdateAssemblyNamesIncludePreserved + { + get + { + List allAsses = HotUpdateAssemblyNamesExcludePreserved; + string[] preserveAssemblyNames = HybridCLRSettings.Instance.preserveHotUpdateAssemblies; + if (preserveAssemblyNames != null && preserveAssemblyNames.Length > 0) + { + foreach (var assemblyName in preserveAssemblyNames) + { + if (allAsses.Contains(assemblyName)) + { + throw new Exception($"[HotUpdateAssemblyNamesIncludePreserved] assembly:'{assemblyName}' is duplicated"); + } + allAsses.Add(assemblyName); + } + } + + return allAsses; + } + } + + public static List HotUpdateAssemblyFilesIncludePreserved => HotUpdateAssemblyNamesIncludePreserved.Select(ass => ass + ".dll").ToList(); + + public static List AOTAssemblyNames => HybridCLRSettings.Instance.patchAOTAssemblies.ToList(); + + public static HybridCLRSettings HybridCLRSettings => HybridCLRSettings.Instance; + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/SettingsUtil.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/SettingsUtil.cs.meta new file mode 100644 index 0000000..323dcf6 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/SettingsUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 381c08faeafbc004f97504eeba87380d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Template.meta b/Packages/com.code-philosophy.hybridclr/Editor/Template.meta new file mode 100644 index 0000000..f2430d5 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Template.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9af6345cc5ab1ae4a81262ab4b537911 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Template/FileRegionReplace.cs b/Packages/com.code-philosophy.hybridclr/Editor/Template/FileRegionReplace.cs new file mode 100644 index 0000000..797477b --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Template/FileRegionReplace.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR.Editor.Template +{ + public class FileRegionReplace + { + private readonly string _tplCode; + + private readonly Dictionary _regionReplaceContents = new Dictionary(); + + public FileRegionReplace(string tplCode) + { + _tplCode = tplCode; + } + + public void Replace(string regionName, string regionContent) + { + _regionReplaceContents.Add(regionName, regionContent); + } + + public string GenFinalString() + { + string originContent = _tplCode; + + string resultContent = originContent; + + foreach (var c in _regionReplaceContents) + { + resultContent = ReplaceRegion(resultContent, c.Key, c.Value); + } + return resultContent; + } + + public void Commit(string outputFile) + { + string dir = Path.GetDirectoryName(outputFile); + Directory.CreateDirectory(dir); + string resultContent = GenFinalString(); + var utf8WithoutBOM = new System.Text.UTF8Encoding(false); + File.WriteAllText(outputFile, resultContent, utf8WithoutBOM); + } + + public static string ReplaceRegion(string resultText, string region, string replaceContent) + { + int startIndex = resultText.IndexOf("//!!!{{" + region); + if (startIndex == -1) + { + throw new Exception($"region:{region} start not find"); + } + int endIndex = resultText.IndexOf("//!!!}}" + region); + if (endIndex == -1) + { + throw new Exception($"region:{region} end not find"); + } + int replaceStart = resultText.IndexOf('\n', startIndex); + int replaceEnd = resultText.LastIndexOf('\n', endIndex); + if (replaceStart == -1 || replaceEnd == -1) + { + throw new Exception($"region:{region} not find"); + } + if (resultText.Substring(replaceStart, replaceEnd - replaceStart) == replaceContent) + { + return resultText; + } + resultText = resultText.Substring(0, replaceStart) + "\n" + replaceContent + "\n" + resultText.Substring(replaceEnd); + return resultText; + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Editor/Template/FileRegionReplace.cs.meta b/Packages/com.code-philosophy.hybridclr/Editor/Template/FileRegionReplace.cs.meta new file mode 100644 index 0000000..14a642a --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Editor/Template/FileRegionReplace.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15d4563ad83546c42bc65c99be9bd54a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/LICENSE b/Packages/com.code-philosophy.hybridclr/LICENSE new file mode 100644 index 0000000..dcad5cf --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Code Philosophy Technology Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Packages/com.code-philosophy.hybridclr/LICENSE.meta b/Packages/com.code-philosophy.hybridclr/LICENSE.meta new file mode 100644 index 0000000..d5478d5 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f09e582706a5776448316f6c584e63a6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Plugins.meta b/Packages/com.code-philosophy.hybridclr/Plugins.meta new file mode 100644 index 0000000..ccdd127 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a26873724919287449e2c9eec68ef1da +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Plugins/dnlib.dll b/Packages/com.code-philosophy.hybridclr/Plugins/dnlib.dll new file mode 100644 index 0000000000000000000000000000000000000000..170ffdead5f813ffafa66616f5ac4609875e9b37 GIT binary patch literal 1162752 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

Jc%IiB+v<;OEC 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 #NJrsVRsss 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

Apw9jI7!9iNyyRh7ogCC2!4G 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 literal 0 HcmV?d00001 diff --git a/Packages/com.code-philosophy.hybridclr/Plugins/dnlib.dll.meta b/Packages/com.code-philosophy.hybridclr/Plugins/dnlib.dll.meta new file mode 100644 index 0000000..bdb7a88 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Plugins/dnlib.dll.meta @@ -0,0 +1,87 @@ +fileFormatVersion: 2 +guid: b93c6604eb031674b80de14cd4458dc0 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 0 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude WebGL: 1 + Exclude Win: 1 + Exclude Win64: 1 + Exclude iOS: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + iPhone: iOS + second: + enabled: 0 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/README.md b/Packages/com.code-philosophy.hybridclr/README.md new file mode 100644 index 0000000..9b30ebb --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/README.md @@ -0,0 +1,91 @@ + +- [README 中文](./README_zh.md) +- [README English](./README.md) + +# HybridCLR + +[![license](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) + +![logo](https://github.com/focus-creative-games/hybridclr/raw/main/docs/images/logo.jpg) + +
+
+ +HybridCLR is a **almost perfect** full-platform native c# hot update solution for Unity with complete features, zero cost, high performance, and low memory**. + +HybridCLR expands the ability of il2cpp, making it change from pure [AOT](https://en.wikipedia.org/wiki/Ahead-of-time_compilation) runtime to 'AOT+Interpreter' hybrid runtime, and then natively supports dynamic loading of assembly , so that the games packaged based on il2cpp backend can be executed not only on the Android platform, but also on IOS, Consoles and other platforms that limit JIT efficiently in **AOT+interpreter** hybrid mode, completely supporting hot updates from the bottom layer. + +HybridCLR not only supports the traditional fully interpreted execution mode, but also pioneered [Differential Hybrid Execution](https://hybridclr.doc.code-philosophy.com/en/docs/business/differentialhybridexecution) technique. That is, you can add, delete, or modify the AOT dll at will, and intelligently make the changed or newly added classes and functions run in interpreter mode, but the unchanged classes and functions run in AOT mode, so that the running performance of the hot-updated game logic basically reaches the original AOT level. + +Welcome to embrace modern native C# hot update technology! ! ! + +## Documentation + +- [Official Documentation](https://hybridclr.doc.code-philosophy.com/en/docs/intro) +- [Quickstart](https://hybridclr.doc.code-philosophy.com/en/docs/beginner/quickstart) +- [Release Log](./RELEASELOG.md) + +## Features + +- Features complete. A nearly complete implementation of the [ECMA-335 specification](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), with only a very small number of [unsupported features](https://hybridclr.doc.code-philosophy.com/en/docs/basic/notsupportedfeatures). +- Zero learning and use costs. HybridCLR enhances the pure AOT runtime into a complete runtime, making hot update code work seamlessly with AOT code. The script class and the AOT class are in the same runtime, and you can freely write codes such as inheritance, reflection, and multi-threading (volatile, ThreadStatic, Task, async). No need to write any special code, no code generation, almost unlimited. +- Efficient execution. Implemented an extremely efficient register interpreter, all indicators are significantly better than other hot update schemes. [Performance Test Report](https://hybridclr.doc.code-philosophy.com/en/docs/basic/performance) +- Memory efficient. The classes defined in the hot update script occupy the same memory space as ordinary c# classes, which is far superior to other hot update solutions. [Memory and GC](https://hybridclr.doc.code-philosophy.com/en/docs/basic/memory) +- Due to the perfect support for generics, libraries that are not compatible with il2cpp due to AOT generics issues can now run perfectly under il2cpp +- Support some features not supported by il2cpp, such as __makeref, __reftype, __refvalue directives +- [Differential Hybrid Execution](https://hybridclr.doc.code-philosophy.com/en/docs/business/differentialhybridexecution) + +## Working Principle + +HybridCLR is inspired by mono's [mixed mode execution](https://www.mono-project.com/news/2017/11/13/mono-interpreter/) technology, and provides additional AOT runtimes such as unity's il2cpp The interpreter module is provided to transform them from pure AOT runtime to "AOT + Interpreter" hybrid operation mode. + +![icon](https://github.com/focus-creative-games/hybridclr/raw/main/docs/images/architecture.png) + +More specifically, HybridCLR does the following: + +- Implemented an efficient metadata (dll) parsing library +- Modified the metadata management module to realize the dynamic registration of metadata +- Implemented a compiler from IL instruction set to custom register instruction set +- Implemented an efficient register interpreter +- Provide a large number of instinct functions to improve the performance of the interpreter + +## The Difference From Other C# Hot-Update Solution + +HybridCLR is a native c# hot update solution. In layman's terms, il2cpp is equivalent to the aot module of mono, and HybridCLR is equivalent to the interpreter module of mono, and the combination of the two becomes a complete mono. HybridCLR makes il2cpp a full-featured runtime, natively (that is, through System.Reflection.Assembly.Load) supports dynamic loading of dlls, thereby supporting hot updates of the ios platform. + +Just because HybridCLR is implemented at the native runtime level, the types of the hot update part and the AOT part of the main project are completely equivalent and seamlessly unified. You can call, inherit, reflect, and multi-thread at will, without generating code or writing adapters. + +Other hot update solutions are independent vm, and the relationship with il2cpp is essentially equivalent to the relationship of embedding lua in mono. Therefore, the type system is not uniform. In order to allow the hot update type to inherit some AOT types, an adapter needs to be written, and the type in the interpreter cannot be recognized by the type system of the main project. Incomplete features, troublesome development, and low operating efficiency. + +## Supported Versions And Platforms + +- Support 2019.4.x, 2020.3.x, 2021.3.x, 2022.3.x full series of LTS versions. The `2023.2.0ax` version is also supported, but not released to the public. +- Supports all il2cpp supported platforms + +## Stability Status + +HybridCLR has been widely verified as a very efficient and stable solution for hot update of Unity. + +The official versions of **extremely stable** 1.x, 2.x, and 3.x are currently released, which are sufficient to meet the stability requirements of large and medium-sized commercial projects. +At present, at least thousands of commercial game projects have been integrated, and hundreds of them have been launched on both ends. The online projects include MMORPG, heavy card, heavy tower defense and other games. **Most top game companies** (such as Tencent and NetEase) are already using HybridCLR. + +You can read the [game projects in top game companies](https://hybridclr.doc.code-philosophy.com/en/docs/other/businesscase) those are using HybridCLR and has been launched. + +## Support And Contact + +- Official 1 group: 651188171 (full) +- Novice QQ group 1: 428404198 (full) +- Novice QQ group 2: **680274677 (recommended)** +- discord channel [https://discord.gg/BATfNfJnm2](https://discord.gg/BATfNfJnm2) +- Business cooperation email: business#code-philosophy.com +- [Commercial Support](https://hybridclr.doc.code-philosophy.com/en/docs/business/intro) + +## About The Author + +**walon** : Founder of **Code Philosophy (code philosophy)** + +Graduated from the Department of Physics of Tsinghua University, won the CMO gold medal in 2006, a member of the National Mathematical Olympiad Training Team, and was recommended to Tsinghua University for basic courses. Focus on game technology, good at developing architecture and basic technical facilities. + +## License + +HybridCLR is licensed under the [MIT](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) license diff --git a/Packages/com.code-philosophy.hybridclr/README.md.meta b/Packages/com.code-philosophy.hybridclr/README.md.meta new file mode 100644 index 0000000..b674416 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b4b6051e2483d664facc72a5102dcffc +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/README_zh.md b/Packages/com.code-philosophy.hybridclr/README_zh.md new file mode 100644 index 0000000..d5bb6b7 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/README_zh.md @@ -0,0 +1,91 @@ +- [README 中文](./README_zh.md) +- [README English](./README.md) + +# HybridCLR + +[![license](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) + +![logo](https://github.com/focus-creative-games/hybridclr/raw/main/docs/images/logo.jpg) + +
+
+ +HybridCLR是一个**特性完整、零成本、高性能、低内存**的**近乎完美**的Unity全平台原生c#热更方案。 + +HybridCLR扩充了il2cpp的代码,使它由纯[AOT](https://en.wikipedia.org/wiki/Ahead-of-time_compilation) runtime变成‘AOT+Interpreter’ 混合runtime,进而原生支持动态加载assembly,使得基于il2cpp backend打包的游戏不仅能在Android平台,也能在IOS、Consoles等限制了JIT的平台上高效地以**AOT+interpreter**混合模式执行,从底层彻底支持了热更新。 + +HybridCLR不仅支持传统的全解释执行模式,还开创性地实现了 [Differential Hybrid Execution(差分混合执行技术)](https://hybridclr.doc.code-philosophy.com/docs/business/differentialhybridexecution) 差分混合执行技术。即可以对AOT dll任意增删改,会智能地让变化或者新增的类和函数以interpreter模式运行,但未改动的类和函数以AOT方式运行,让热更新的游戏逻辑的运行性能基本达到原生AOT的水平。 + +欢迎拥抱现代原生C#热更新技术 !!! + +## 文档 + +- [官方文档](https://hybridclr.doc.code-philosophy.com/docs/intro) +- [快速上手](https://hybridclr.doc.code-philosophy.com/docs/beginner/quickstart) +- [发布日志](./RELEASELOG.md) + +## 特性 + +- 特性完整。 近乎完整实现了[ECMA-335规范](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/),只有极少量的[不支持的特性](https://hybridclr.doc.code-philosophy.com/docs/basic/notsupportedfeatures)。 +- 零学习和使用成本。 HybridCLR将纯AOT runtime增强为完整的runtime,使得热更新代码与AOT代码无缝工作。脚本类与AOT类在同一个运行时内,可以随意写继承、反射、多线程(volatile、ThreadStatic、Task、async)之类的代码。不需要额外写任何特殊代码、没有代码生成,几乎没有限制。 +- 执行高效。实现了一个极其高效的寄存器解释器,所有指标都大幅优于其他热更新方案。[性能测试报告](https://hybridclr.doc.code-philosophy.com/docs/basic/performance) +- 内存高效。 热更新脚本中定义的类跟普通c#类占用一样的内存空间,远优于其他热更新方案。[内存与GC](https://hybridclr.doc.code-philosophy.com/docs/basic/memory) +- 由于对泛型的完美支持,使得因为AOT泛型问题跟il2cpp不兼容的库现在能够完美地在il2cpp下运行 +- 支持一些il2cpp不支持的特性,如__makeref、 __reftype、__refvalue指令 +- [Differential Hybrid Execution(差分混合执行技术)](https://hybridclr.doc.code-philosophy.com/docs/business/differentialhybridexecution) + +## 工作原理 + +HybridCLR从mono的 [mixed mode execution](https://www.mono-project.com/news/2017/11/13/mono-interpreter/) 技术中得到启发,为unity的il2cpp之类的AOT runtime额外提供了interpreter模块,将它们由纯AOT运行时改造为"AOT + Interpreter"混合运行方式。 + +![icon](https://github.com/focus-creative-games/hybridclr/raw/main/docs/images/architecture.png) + +更具体地说,HybridCLR做了以下几点工作: + +- 实现了一个高效的元数据(dll)解析库 +- 改造了元数据管理模块,实现了元数据的动态注册 +- 实现了一个IL指令集到自定义的寄存器指令集的compiler +- 实现了一个高效的寄存器解释器 +- 额外提供大量的instinct函数,提升解释器性能 + +## 与其他流行的c#热更新方案的区别 + +HybridCLR是原生的c#热更新方案。通俗地说,il2cpp相当于mono的aot模块,HybridCLR相当于mono的interpreter模块,两者合一成为完整mono。HybridCLR使得il2cpp变成一个全功能的runtime,原生(即通过System.Reflection.Assembly.Load)支持动态加载dll,从而支持ios平台的热更新。 + +正因为HybridCLR是原生runtime级别实现,热更新部分的类型与主工程AOT部分类型是完全等价并且无缝统一的。可以随意调用、继承、反射、多线程,不需要生成代码或者写适配器。 + +其他热更新方案则是独立vm,与il2cpp的关系本质上相当于mono中嵌入lua的关系。因此类型系统不统一,为了让热更新类型能够继承AOT部分类型,需要写适配器,并且解释器中的类型不能为主工程的类型系统所识别。特性不完整、开发麻烦、运行效率低下。 + +## 支持的版本与平台 + +- 支持2019.4.x、2020.3.x、2021.3.x、2022.3.x全系列LTS版本。`2023.2.0ax`版本也已支持,但未对外发布。 +- 支持所有il2cpp支持的平台 + +## 稳定性状况 + +HybridCLR已经被广泛验证是非常高效、稳定的Unity热更新解决方案。 + +当前发布了**极其稳定**的1.x、2.x、3.x正式版本,足以满足大中型商业项目的稳定性要求。 +目前至少有上千个商业游戏项目完成接入,其中有几百款已经双端上线,上线的项目中包括MMORPG、重度卡牌、重度塔防之类的游戏。**绝大多数头部游戏公司**(如腾讯、网易)都已经在使用HybridCLR。 + +可查看我们已知的头部公司中使用HybridCLR并且已经上线的[项目列表](https://hybridclr.doc.code-philosophy.com/docs/other/businesscase)。 + + +## 支持与联系 + +- 官方1群:651188171(满) +- 新手1群:428404198(满) +- 新手2群:**680274677(推荐)** +- discord频道 https://discord.gg/BATfNfJnm2 +- 商业合作邮箱: business#code-philosophy.com +- [商业化支持](https://hybridclr.doc.code-philosophy.com/docs/business/intro) + +## 关于作者 + +**walon** :**Code Philosophy(代码哲学)** 创始人 + +毕业于清华大学物理系,2006年CMO金牌,奥数国家集训队成员,保送清华基科班。专注于游戏技术,擅长开发架构和基础技术设施。 + +## license + +HybridCLR is licensed under the [MIT](https://github.com/focus-creative-games/hybridclr/blob/main/LICENSE) license diff --git a/Packages/com.code-philosophy.hybridclr/README_zh.md.meta b/Packages/com.code-philosophy.hybridclr/README_zh.md.meta new file mode 100644 index 0000000..9da1eac --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/README_zh.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 52688f4469ff9454e8c3d8aaf045d9f4 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/RELEASELOG.md b/Packages/com.code-philosophy.hybridclr/RELEASELOG.md new file mode 100644 index 0000000..61ffc5e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/RELEASELOG.md @@ -0,0 +1,436 @@ +# 发布日志 + +## 4.0.15 + +发布日期 2024年1月2日. + +### Runtime + +- [fix] 修复计算未完全实例化的泛型类时将VAR和MVAR类型参数大小计算成sizeof(void*),导致计算出无效且过大的instance,在执行LayoutFieldsLocked过程中调用UpdateInstanceSizeForGenericClass错误地使用泛型基类instance覆盖设置了实例类型的instance值的严重bug +- [change] 支持打印热更新栈,虽然顺序不太正确 +- [change] 使用HYBRIDCLR_MALLOC之类分配函数替换IL2CPP_MALLOC +- [refactor] 重构Config接口,统一通过GetRuntimeOption和SetRuntimeOption获取和设置选项 +- [opt] 删除NewValueTypeVar和NewValueTypeInterpVar指令不必要的对结构memset操作 + +### Editor + +- [fix] 修复Additional Compiler Arguments中输入 -nullable:enable 之后,Editor抛出InvalidCastException的bug。来自报告 https://github.com/focus-creative-games/hybridclr/issues/116 +- [fix] 修复某些情况下报错:BuildFailedException: Build path contains a project previously built without the "Create Visual Studio Solution" +- [opt] 优化桥接函数生成,将同构的struct映射到同一个结构,减少了30-35%的桥接函数数量 +- [change] StripAOTDllCommand导出时不再设置BuildScriptsOnly选项 +- [change] 调整Installer窗口的显示内容 +- [refactor] RuntimeApi中设置hybridclr参数的功能统一通过GetRuntimeOption和SetRuntimeOption函数 + +## 4.0.14 + +发布日期 2023.12.11. + +### Runtime + +- [fix] 修复优化 box; brtrue|brfalse序列时,当类型为class或nullable类型时,无条件转换为无条件branch语句的bug +- [fix] 修复 ClassFieldLayoutCalculator未释放 _classMap的每个key-value对中value对象,造成内存泄露的bug +- [fix] 修复计算 ExplicitLayout的struct的native_size的bug +- [fix] 修复当出现签名完全相同的虚函数与虚泛型函数时,计算override未考虑泛型签名,错误地返回了不匹配的函数,导致虚表错误的bug +- [fix][2021] 修复开启faster(smaller) build选项后某些情况下完全泛型共享AOT函数未使用补充元数据来设置函数指针,导致调用时出错的bug + +## 4.0.13 + +发布日期 2023.11.27. + +### Runtime + +- [fix] 修复ConvertInvokeArgs有可能传递了非对齐args,导致CopyStackObject在armv7这种要求内存对齐的平台发生崩溃的bug +- [fix] 修复通过StructLayout指定size时,计算ClassFieldLayout的严重bug +- [fix] 修复bgt之类指令未取双重取反进行判断,导致当浮点数与Nan比较时由于不满足对称性执行了错误的分支的bug +- [fix] 修复Class::FromGenericParameter错误地设置了thread_static_fields_size=-1,导致为其分配ThreadStatic内存的严重bug +- [opt] Il2CppGenericInst分配统一使用MetadataCache::GetGenericInst分配唯一池对象,优化内存分配 +- [opt] 由于Interpreter部分Il2CppGenericInst统一使用MetadataCache::GetGenericInst,比较 Il2CppGenericContext时直接比较 class_inst和method_inst指针 + +### Editor + +- [fix] 修复裁剪aot dll中出现netstandard时,生成桥接函数异常的bug +- [fix] 修复当出现非常规字段名时生成的桥接函数代码文件有编译错误的bug +- [change] 删除不必要的Datas~/Templates目录,直接以原始文件为模板 +- [refactor] 重构 AssemblyCache和 AssemblyReferenceDeepCollector,消除冗余代码 + +## 4.0.12 + +发布日期 2023.11.02. + +### Editor + +- [fix] 修复BashUtil.RemoveDir的bug导致Installer安装失败的bug + +## 4.0.11 + +发布日期 2023.11.02. + +### Runtime + +- [fix] 修复开启完全泛型共享后, 对于某些MethodInfo,由于methodPointer与virtualMethodPointer使用补充元数据后的解释器函数,而invoker_method仍然为支持完全泛型共享的调用形式,导致invoker_method与methodPointer及virtualMethodPointer不匹配的bug +- [fix] 修复Il2CppGenericContextCompare比较时仅仅对比inst指针的bug,造成热更新模块大量泛型函数重复 +- [fix] 修复完全泛型共享时未正确设置MethodInfo的bug + +### Editor + +- [new] 检查当前安装的libil2cpp版本是否与package版本匹配,避免升级package后未重新install的问题 +- [new] Generate支持 netstandard +- [fix] 修复 ReversePInvokeWrap生成不必要地解析referenced dll,导致如果有aot dll引用了netstandard会出现解析错误的bug +- [fix] 修复BashUtil.RemoveDir在偶然情况下出现删除目录失败的问题。新增多次重试 +- [fix] 修复桥接函数计算时未归结函数参数类型,导致出现多个同名签名的bug + + +## 4.0.10 + +发布日期 2023.10.12. + +### Runtime + +- [merge][il2cpp] 合并2022.3.10-2022.3.11f1的il2cpp改动,修复2022.3.11版本不兼容的问题 + +## 4.0.9 + +发布日期 2023.10.11. + +### Runtime + +- [merge][il2cpp][fix] 合并2021.3.29-2021.3.31f1的il2cpp改动,修复在2021.3.31版本的不兼容问题 +- [merge][il2cpp] 合并2022.3.7-2022.3.10f1的il2cpp改动 + +### Editor + +- [fix] 修复2022版本iOS平台AddLil2cppSourceCodeToXcodeproj2022OrNewer的编译错误 + +## 4.0.8 + +发布日期 2023.10.10. + +### Runtime + +- [fix] 修复计算值类型泛型桥接函数签名时,错误地将值类型泛型参数类型也换成签名,导致与Editor计算的签名不一致的bug +- [fix][refactor] RuntimeApi相关函数由PInvoke改为InternalCall,解决Android平台调用RuntimeApi时触发重新加载libil2cpp.a的问题 + +### Editor + +- [refactor] RuntimeApi相关函数由PInvoke改为InternalCall +- [refactor] 调整HybridCLR.Editor模块一些不规范的命名空间 + +## 4.0.7 + +发布日期 2023.10.09. + +### Runtime + +- [fix] 修复initobj调用了CopyN,但CopyN未考虑对象的内存对齐的情况,在32位这种的平台可能发生未对齐访问异常的bug +- [fix] 修复计算未完全实例化的泛型函数的桥接函数签名时崩溃的bug +- [fix] 修复Il2cpp代码生成选项为faster(smaller)时,2021和2022版本GenericMethod::CreateMethodLocked的bug +- [remove] 移除所有array相关指令中index为int64_t的指令,简化代码 +- [remove] 移除ldfld_xxx_ref系列指令 + +### Editor + +- [fix] 修复生成桥接函数时,如果热更新程序集未包含任何代码直接引用了某个aot程序集,则没有为该aot程序集生成桥接函数,导致出现NotSupportNative2Managed异常的bug +- [fix] 修复mac下面路径过长导致拷贝文件失败的bug +- [fix] 修复发布PS5目标时未处理ScriptingAssemblies.json的bug +- [change] 打包时清空裁减aot dll目录 + +## 4.0.6 + +发布日期 2023.09.26. + +### Runtime + +- [fix] 修复2021和2022版本开启完全泛型共享后的bug +- [fix] 修复加载PlaceHolder Assembly后未增加assemblyVersion导致Assembly::GetAssemblies()错误地获得了旧程序集列表的bug + +## 4.0.5 + +发布日期 2023.09.25. + +### Runtime + +- [fix] 修复Transform中未析构pendingFlows造成内存泄露的bug +- [fix] 修复多维数组SetMdArrElement未区分带ref与不带ref结构的bug +- [fix] 修复CpobjVarVAr_WriteBarrier_n_4未设置size的bug +- [fix] 修复计算interface成员函数slot时未考虑到static之类函数的bug +- [fix] 修复2022版本ExplicitLayout未设置layout.alignment,导致计算出size==0的bug +- [fix] 修复InterpreterInvoke在完全泛型共享时,class类型的methodPointer与virtualMethodPointer有可能不一致,导致失误对this指针+1的bug +- [fix] ldobj当T为byte之类size<4的类型时,未将数据展开为int的bug +- [fix] 修复CopySize未考虑到内存对齐的问题 +- [opt] 优化stelem当元素为size较大的struct时统一当作含ref结构的问题 +- [opt] TemporaryMemoryArena默认内存块大小由1M调整8K +- [opt] 将Image::Image中Assembly::GetAllAssemblies()换成Assembly::GetAllAssemblies(AssemblyVector&),避免创建assembly快照而造成不必要的内存泄露 + +### Editor + +- [fix] 修复StandaloneLinux平台DllImport的dllName和裁剪dll路径的错误 +- [change] 对于小版本不兼容的Unity版本,不再禁止安装,而是提示警告 +- [fix] 修复桥接函数计算中MetaUtil.ToShareTypeSig将Ptr和ByRef计算成IntPtr的bug,正确应该是UIntPtr + +## 4.0.4 + +发布日期 2023.09.11。 + +### Runtime + +- [new][platform] 彻底支持所有平台,包括UWP和PS5 +- [fix][严重] 修复计算interpreter部分enum类型的桥接函数签名的bug +- [fix] 修复在某些平台下有编译错误的问题 +- [fix] 修复转换STOBJ指令未正确处理增量式GC的bug +- [fix] [fix] 修复 StindVarVar_ref指令未正确设置WriteBarrier的bug +- [fix] 修复2020 GenericMethod::CreateMethodLocked调用vm::MetadataAllocGenericMethod()未持有s_GenericMethodMutex锁的线程安全问题 + +### Editor + +- [fix] 修复AddLil2cppSourceCodeToXcodeproj2021OrOlder在Unity 2020下偶然同时包含了不同目录的两个ThreadPool.cpp文件导致出现编译错误的问题 +- [fix] 修复不正确地从EditorUserBuildSettings.selectedBuildTargetGroup获得BuildGroupTarget的bug +- [fix] StripAOTDllCommand生成AOT dll时的BuildOption采用当前Player的设置,避免当打包开启development时,StripAOTDllCommand生成Release aot dll,而打包生成debug aot dll,产生补充元数据及桥接函数生成不匹配的严重错误 +- [change] 为了更好地支持全平台,调整了RuntimeApi.cs中dllName的实现,默认取 __Internal +- [change] 为了更好地支持全平台,自2021起裁剪AOT dll全都通过MonoHook复制 + +## 4.0.3 + +发布日期 2023.08.31。 + +### Editor + +- [fix] 修复桥接函数计算的bug + +## 4.0.2 + +发布日期 2023.08.29。 + +### Runtime + +- [fix][严重] 修复LdobjVarVar_ref指令的bug。此bug由增量式GC代码引入 +- [fix] 修复未处理ResolveField获得的Field为nullptr时情形导致崩溃的bug +- [fix] 修复未正确处理AOT及interpreter interface中显式实现父接口函数的bug + +## 4.0.1 + +发布日期 2023.08.28。 + +### Runtime + +- [fix] 修复2020版本开启增量式GC后出现编译错误的问题 + +## 4.0.0 + +发布日期 2023.08.28。 + +### Runtime + +- [new] 支持增量式GC +- [refactor] 重构桥接函数,彻底支持所有il2cpp支持的平台 +- [opt] 大幅优化Native2Managed方向的传参 + +### Editor + +- [change] 删除增量式GC选项检查 +- [refactor] 重构桥接函数生成 + +## 3.4.2 + +发布日期 2023.08.14。 + +### Runtime + +- [fix] 修复RawImage::LoadTables读取_4byteGUIDIndex的bug +- [version] 支持2022.3.7版本 +- [version] 支持2021.3.29版本 + +### Editor + +- [fix] 修复计算AOTGenericReference未考虑到泛型调用泛型的情况,导致少计算了泛型及补充元数据 + +## 3.4.1 + +发布日期 2023.07.31。 + +### Runtime + +- [fix] 修复 InitializeRuntimeMetadata的内存可见性问题 +- [fix] 修复CustomAttribute未正确处理父类NamedArg导致崩溃的bug +- [opt] 优化Transfrom Instinct指令的代码,从HashMap中快速查找而不是挨个匹配 + +### Editor + +- [fix] 修复FilterHotFixAssemblies只对比程序集名尾部,导致有AOT的尾部与某个热更新程序集匹配时意外被过滤的bug +- [change] 检查Settings中热更新程序集列表配置中程序集名不能为空 + +## 3.4.0 + +发布日期 2023.07.17。 + +### Runtime + +- [version] 支持2021.3.28和2022.3.4版本 +- [opt] 删除MachineState::InitEvalStack分配_StackBase后不必要的memset +- [fix] 修复Exception机制的bug +- [fix] 修复CustomAttribute不支持Type[]类型参数的bug +- [fix] 修复不支持new string(xxx)用法的问题 +- [refactor] 重构VTableSetup实现 +- [fix] 修复未计算子interface中显式实现父interface的函数的bug +- [opt] Lazy初始化CustomAttributeData,而不是加载时全部初始化,明显减少Assembly.Load时间 +- [fix] 修复2022 当new byte\[]{a,b,c...}方式初始化较长的byte[]数据时,返回错误数据的bug + +### Editor + +- [fix] 修复计算桥接函数未考虑到泛型类的成员函数中可能包含的Native2Managed调用 +- [change] link.xml及AOTGenericReferences.cs默认输出路径改为HybridCLRGenerate,避免与顶层HybridCLRData混淆 +- [fix] 修复Win下生成的Lump文件中include路径以\为目录分隔符导致同步到Mac后找不到路径的bug +- [refactor] 重构Installer + + +## 3.3.0 + +发布日期 2023.07.03。 + +### Runtime + +- [fix] 修复localloc分配的内存未释放的bug +- [change] MachineState改用RegisterRoot的方式注册执行栈,避免GC时扫描整个堆栈 +- [opt] 优化Managed2NativeCallByReflectionInvoke性能,提前计算好传参方式 +- [refactor] 重构ConvertInvokeArgs + +### Editor + +- [fix] 修复2020-2021编译libil2cpp.a未包含brotli相关代码文件导致出现编译错误的bug +- [fix] 修复从导出xcode项目包含绝对路径导致传送到其他机器上编译时找不到路径的bug +- [fix] 解决Generate LinkXml、 MethodBridge、AOTGenericReference、ReversePInvokeWrap 生成不稳定的问题 +- [fix] 修复使用不兼容版本打开Installer时出现异常的bug +- [change] 禁用hybridclr后打包ios时不再修改导出的xcode工程 + +## 3.2.1 + +### Runtime + +- [fix] 修复il2cpp TypeNameParser未将类型名中转义字符'\'去掉,导致找不到嵌套子类型的bug + +### Editor + +- [new] Installer界面新增显示package版本 +- [new] CompileDll新增MacOS、Linux、WebGL目标 +- [fix] 修复重构文档站后的帮助文档的链接错误 +- [change] 为Anaylizer加上using 限定,解决某些情况下与项目的类型同名而产生编译冲突的问题 + +## 3.2.0 + +### Runtime + +- [fix] 修复未在PlaceHolder中的Assembly加载时,如果由于不在Assembly列表,也没有任何解释器栈,导致Class::resolve_parse_info_internal查找不到类型的bug +- [fix] 修复读取CustomAttribute System.Type类型数据崩溃的bug + +### Editor + +- [new] 支持直接从源码打包iOS,不再需要单独编译libil2cpp.a +- [opt] 优化版本不兼容时错误提示,不再抛出异常,而是显示"与当前版本不兼容" + + +## 3.1.1 + +### Runtime + +- [fix] 修复2021及更高版本,InterpreterModule::Managed2NativeCallByReflectionInvoke调用值类型成员函数时,对this指针多余this=this-1操作。 +- [fix] 修复解析CustomAttribute中Enum[]类型字段的bug +- [fix] 修复2021及更高版本反射调用值类型 close Delegate的Invoke函数时未修复target指针的bug +- [new] 新增对增量式GC宏的检查,避免build.gradle中意外开启增量式GC引发的极其隐蔽的问题 + +### Editor + +- [fix] 修复 Win32、Android32、WebGL平台的编译错误 +- [fix] 修复计算桥接函数时未考虑到补充元数据泛型实例化会导致访问到一些非公开的函数的情况,导致少生成一些必要的桥接函数 +- [opt] 生成AOTGenericReferences时,补充元数据assembly列表由注释改成List列表,方便在代码中直接使用。 +- [change] CheckSettings中不再自动设置Api Compatible Level + +## 3.1.0 + +### Runtime + +- [rollback] 还原对Unity 2020.3.x支持 +- [fix] 修复 WebGL平台ABI的bug + +### Editor + +- [rollback] 还原对Unity 2020.3.x支持 + +## 3.0.3 + +### Runtime + +- [fix] 修复Enum::GetValues返回值不正确的bug + +## 3.0.2 + +### Runtime + +- [fix] 修复Memory Profiler中创建内存快照时崩溃的bug + +### Editor + +- [remove] 移除 `HybridCLR/CreateAOTDllSnapshot`菜单 + + +## 3.0.1 + +### Runtime + +- [new] 支持2022.3.0 + +## 3.0.0 + +### Runtime + +- [fix] 修复不支持访问CustomData字段及值的bug +- [remove] 移除对2019及2020版本支持 + +### Editor + +- 包名更改为com.code-philosophy.hybridclr +- 移除UnityFS插件 +- 移除Zip插件 +- HybridCLR菜单位置调整 + +## 2.4.2 + +### Runtime + +- [version] 支持 2020.3.48,最后一个2020LTS版本 +- [version] 支持 2021.3.25 + +## 2.4.1 + +### Runtime + +### Editor + +- [fix] 修复遗漏 RELEASELOG.md.meta 文件的问题 + +## 2.4.0 + +### Runtime + +### Editor + +- [new] CheckSettings中检查ScriptingBackend及ApiCompatibleLevel,切换为正确的值 +- [new] 新增 MsvcStdextWorkaround.cs 解决2020 vs下stdext编译错误的问题 +- [fix] 修复当struct只包含一个float或double字段时,在arm64上计算桥接函数签名错误的bug + +## 2.3.1 + +### Runtime + +### Editor + +- [fix] 修复本地复制libil2cpp却仍然从仓库下载安装的bug + +## 2.3.0 + +### Runtime + +### Editor + +- [new] Installer支持从本地目录复制改造后的libil2cpp +- [fix] 修复2019版本MonoBleedingEdge的子目录中包含了过长路径的文件导致Installer复制文件出错的问题 + + diff --git a/Packages/com.code-philosophy.hybridclr/RELEASELOG.md.meta b/Packages/com.code-philosophy.hybridclr/RELEASELOG.md.meta new file mode 100644 index 0000000..47abd21 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/RELEASELOG.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8e53ce54bd8e88c4785c625555308dba +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Runtime.meta b/Packages/com.code-philosophy.hybridclr/Runtime.meta new file mode 100644 index 0000000..d5e99d3 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a6d5e365e1b7d9742bee023ea54b31f2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Runtime/HomologousImageMode.cs b/Packages/com.code-philosophy.hybridclr/Runtime/HomologousImageMode.cs new file mode 100644 index 0000000..dd839ca --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime/HomologousImageMode.cs @@ -0,0 +1,10 @@ + +namespace HybridCLR +{ + public enum HomologousImageMode + { + Consistent, // AOT dll需要跟主工程精确一致,即为裁剪后的AO dll + SuperSet, // AOT dll不需要跟主工程精确一致,但必须包含裁剪后的AOT dll的所有元数据,即为裁剪后dll的超集。推荐使用原始aot dll + } +} + diff --git a/Packages/com.code-philosophy.hybridclr/Runtime/HomologousImageMode.cs.meta b/Packages/com.code-philosophy.hybridclr/Runtime/HomologousImageMode.cs.meta new file mode 100644 index 0000000..dde78bf --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime/HomologousImageMode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0f0351553ad90e74aa586746b5965ded +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Runtime/HybridCLR.Runtime.asmdef b/Packages/com.code-philosophy.hybridclr/Runtime/HybridCLR.Runtime.asmdef new file mode 100644 index 0000000..98f5d3e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime/HybridCLR.Runtime.asmdef @@ -0,0 +1,14 @@ +{ + "name": "HybridCLR.Runtime", + "rootNamespace": "", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/Runtime/HybridCLR.Runtime.asmdef.meta b/Packages/com.code-philosophy.hybridclr/Runtime/HybridCLR.Runtime.asmdef.meta new file mode 100644 index 0000000..c73a6d4 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime/HybridCLR.Runtime.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 13ba8ce62aa80c74598530029cb2d649 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Runtime/LoadImageErrorCode.cs b/Packages/com.code-philosophy.hybridclr/Runtime/LoadImageErrorCode.cs new file mode 100644 index 0000000..195122a --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime/LoadImageErrorCode.cs @@ -0,0 +1,15 @@ + +namespace HybridCLR +{ + public enum LoadImageErrorCode + { + OK = 0, + BAD_IMAGE, // dll 不合法 + NOT_IMPLEMENT, // 不支持的元数据特性 + AOT_ASSEMBLY_NOT_FIND, // 对应的AOT assembly未找到 + HOMOLOGOUS_ONLY_SUPPORT_AOT_ASSEMBLY, // 不能给解释器assembly补充元数据 + HOMOLOGOUS_ASSEMBLY_HAS_LOADED, // 已经补充过了,不能再次补充 + INVALID_HOMOLOGOUS_MODE, // 非法HomologousImageMode + }; +} + diff --git a/Packages/com.code-philosophy.hybridclr/Runtime/LoadImageErrorCode.cs.meta b/Packages/com.code-philosophy.hybridclr/Runtime/LoadImageErrorCode.cs.meta new file mode 100644 index 0000000..4f77029 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime/LoadImageErrorCode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c7d5b71981fba643b4c21ed01bcb675 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Runtime/ReversePInvokeWrapperGenerationAttribute.cs b/Packages/com.code-philosophy.hybridclr/Runtime/ReversePInvokeWrapperGenerationAttribute.cs new file mode 100644 index 0000000..3308313 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime/ReversePInvokeWrapperGenerationAttribute.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class ReversePInvokeWrapperGenerationAttribute : Attribute + { + public int ReserveWrapperCount { get; } + + public ReversePInvokeWrapperGenerationAttribute(int reserveWrapperCount) + { + ReserveWrapperCount = reserveWrapperCount; + } + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Runtime/ReversePInvokeWrapperGenerationAttribute.cs.meta b/Packages/com.code-philosophy.hybridclr/Runtime/ReversePInvokeWrapperGenerationAttribute.cs.meta new file mode 100644 index 0000000..a46bd5a --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime/ReversePInvokeWrapperGenerationAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f99dd22d9d81b2540b4663b3bcdf0a79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Runtime/RuntimeApi.cs b/Packages/com.code-philosophy.hybridclr/Runtime/RuntimeApi.cs new file mode 100644 index 0000000..8169063 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime/RuntimeApi.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace HybridCLR +{ + public static class RuntimeApi + { + ///

+ /// 加载补充元数据assembly + /// + /// + /// + /// +#if UNITY_EDITOR + public static unsafe LoadImageErrorCode LoadMetadataForAOTAssembly(byte[] dllBytes, HomologousImageMode mode) + { + return LoadImageErrorCode.OK; + } +#else + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern LoadImageErrorCode LoadMetadataForAOTAssembly(byte[] dllBytes, HomologousImageMode mode); +#endif + + /// + /// 获取解释器线程栈的最大StackObject个数(size*8 为最终占用的内存大小) + /// + /// + public static int GetInterpreterThreadObjectStackSize() + { + return GetRuntimeOption(RuntimeOptionId.InterpreterThreadObjectStackSize); + } + + /// + /// 设置解释器线程栈的最大StackObject个数(size*8 为最终占用的内存大小) + /// + /// + public static void SetInterpreterThreadObjectStackSize(int size) + { + SetRuntimeOption(RuntimeOptionId.InterpreterThreadObjectStackSize, size); + } + + + /// + /// 获取解释器线程函数帧数量(sizeof(InterpreterFrame)*size 为最终占用的内存大小) + /// + /// + public static int GetInterpreterThreadFrameStackSize() + { + return GetRuntimeOption(RuntimeOptionId.InterpreterThreadFrameStackSize); + } + + /// + /// 设置解释器线程函数帧数量(sizeof(InterpreterFrame)*size 为最终占用的内存大小) + /// + /// + public static void SetInterpreterThreadFrameStackSize(int size) + { + SetRuntimeOption(RuntimeOptionId.InterpreterThreadFrameStackSize, size); + } + + +#if UNITY_EDITOR + + private static readonly Dictionary s_runtimeOptions = new Dictionary(); + + public static void SetRuntimeOption(RuntimeOptionId optionId, int value) + { + s_runtimeOptions[optionId] = value; + } +#else + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern void SetRuntimeOption(RuntimeOptionId optionId, int value); +#endif + +#if UNITY_EDITOR + public static int GetRuntimeOption(RuntimeOptionId optionId) + { + if (s_runtimeOptions.TryGetValue(optionId, out var value)) + { + return value; + } + return 0; + } +#else + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern int GetRuntimeOption(RuntimeOptionId optionId); +#endif + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Runtime/RuntimeApi.cs.meta b/Packages/com.code-philosophy.hybridclr/Runtime/RuntimeApi.cs.meta new file mode 100644 index 0000000..6ed5cdc --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime/RuntimeApi.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0d58bdc22b6d6b54ab6791baf16a0a3d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/Runtime/RuntimeOptionId.cs b/Packages/com.code-philosophy.hybridclr/Runtime/RuntimeOptionId.cs new file mode 100644 index 0000000..3dc24dc --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime/RuntimeOptionId.cs @@ -0,0 +1,9 @@ +namespace HybridCLR +{ + public enum RuntimeOptionId + { + InterpreterThreadObjectStackSize = 1, + InterpreterThreadFrameStackSize = 2, + ThreadExceptionFlowSize = 3, + } +} diff --git a/Packages/com.code-philosophy.hybridclr/Runtime/RuntimeOptionId.cs.meta b/Packages/com.code-philosophy.hybridclr/Runtime/RuntimeOptionId.cs.meta new file mode 100644 index 0000000..9c7181e --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/Runtime/RuntimeOptionId.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 64be598b47302644a96013c74d945653 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.code-philosophy.hybridclr/package.json b/Packages/com.code-philosophy.hybridclr/package.json new file mode 100644 index 0000000..c484abc --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/package.json @@ -0,0 +1,22 @@ +{ + "name": "com.code-philosophy.hybridclr", + "version": "4.0.15", + "displayName": "HybridCLR", + "description": "HybridCLR is a fully featured, zero-cost, high-performance, low-memory solution for Unity's all-platform native c# hotupdate.", + "category": "Runtime", + "documentationUrl": "https://hybridclr.doc.code-philosophy.com/#/", + "changelogUrl": "https://hybridclr.doc.code-philosophy.com/#/other/changelog", + "licensesUrl": "https://github.com/focus-creative-games/hybridclr_unity/blob/main/LICENSE", + "keywords": [ + "HybridCLR", + "hotupdate", + "hotfix", + "focus-creative-games", + "code-philosophy" + ], + "author": { + "name": "Code Philosophy", + "email": "hybridclr@code-philosophy.com", + "url": "https://code-philosophy.com" + } +} \ No newline at end of file diff --git a/Packages/com.code-philosophy.hybridclr/package.json.meta b/Packages/com.code-philosophy.hybridclr/package.json.meta new file mode 100644 index 0000000..65ee986 --- /dev/null +++ b/Packages/com.code-philosophy.hybridclr/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8ea8eca3a387d9d4988a2fca1036f2e7 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/manifest.json b/Packages/manifest.json index d5c98c7..d1db711 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,5 +1,6 @@ { "dependencies": { + "com.tuyoogame.yooasset": "2.3.6", "com.unity.collab-proxy": "2.5.1", "com.unity.feature.development": "1.0.1", "com.unity.ide.rider": "3.0.31", @@ -42,5 +43,14 @@ "com.unity.modules.vr": "1.0.0", "com.unity.modules.wind": "1.0.0", "com.unity.modules.xr": "1.0.0" - } + }, + "scopedRegistries": [ + { + "name": "package.openupm.com", + "url": "https://package.openupm.com", + "scopes": [ + "com.tuyoogame.yooasset" + ] + } + ] } diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 9aab4c1..209fa47 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -1,5 +1,23 @@ { "dependencies": { + "com.code-philosophy.hybridclr": { + "version": "file:com.code-philosophy.hybridclr", + "depth": 0, + "source": "embedded", + "dependencies": {} + }, + "com.tuyoogame.yooasset": { + "version": "2.3.6", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.scriptablebuildpipeline": "1.21.25", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0" + }, + "url": "https://package.openupm.com" + }, "com.unity.collab-proxy": { "version": "2.5.1", "depth": 0, @@ -74,6 +92,13 @@ "dependencies": {}, "url": "https://packages.unity.cn" }, + "com.unity.scriptablebuildpipeline": { + "version": "1.21.25", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.cn" + }, "com.unity.settings-manager": { "version": "1.0.3", "depth": 2, diff --git a/ProjectSettings/PackageManagerSettings.asset b/ProjectSettings/PackageManagerSettings.asset index c62d4e4..3fd2e4c 100644 --- a/ProjectSettings/PackageManagerSettings.asset +++ b/ProjectSettings/PackageManagerSettings.asset @@ -26,11 +26,19 @@ MonoBehaviour: m_IsDefault: 1 m_Capabilities: 7 m_ConfigSource: 0 - m_UserSelectedRegistryName: + - m_Id: scoped:project:package.openupm.com + m_Name: package.openupm.com + m_Url: https://package.openupm.com + m_Scopes: + - com.tuyoogame.yooasset + m_IsDefault: 0 + m_Capabilities: 0 + m_ConfigSource: 4 + m_UserSelectedRegistryName: package.openupm.com m_UserAddingNewScopedRegistry: 0 m_RegistryInfoDraft: m_Modified: 0 m_ErrorMessage: - m_UserModificationsInstanceId: -830 - m_OriginalInstanceId: -832 + m_UserModificationsInstanceId: -826 + m_OriginalInstanceId: -828 m_LoadAssets: 0