From 072a1176439768a0b9907fd6eaa6feccd11a9550 Mon Sep 17 00:00:00 2001
From: ALEXTANG <574809918@qq.com>
Date: Mon, 29 Aug 2022 14:33:00 +0800
Subject: [PATCH] HybirdCLR Helper
HybirdCLR Helper
---
Assets/TEngine/Scripts/Editor/HybridCLR.meta | 8 +
.../Scripts/Editor/HybridCLR/BuildConfig.cs | 70 +++
.../Editor/HybridCLR/BuildConfig.cs.meta | 11 +
.../Editor/HybridCLR/BuildConfig_Custom.cs | 36 ++
.../HybridCLR/BuildConfig_Custom.cs.meta | 11 +
.../Editor/HybridCLR/BuildProcessors.meta | 8 +
.../BPCopyStrippedAOTAssemblies.cs | 84 ++++
.../BPCopyStrippedAOTAssemblies.cs.meta | 11 +
.../BPFilterHotFixAssemblies.cs | 45 ++
.../BPFilterHotFixAssemblies.cs.meta | 11 +
.../BPPatchScriptAssembliesJson.cs | 148 +++++++
.../BPPatchScriptAssembliesJson.cs.meta | 11 +
.../BuildProcessors/UnityBinFileReader.meta | 8 +
.../UnityBinFileReader/UnityBinFile.cs | 107 +++++
.../UnityBinFileReader/UnityBinFile.cs.meta | 11 +
.../UnityBinFileReader/UnityBinFileDefines.cs | 397 ++++++++++++++++++
.../UnityBinFileDefines.cs.meta | 11 +
.../UnityBinFileReader/UnityBinUtils.cs | 78 ++++
.../UnityBinFileReader/UnityBinUtils.cs.meta | 11 +
.../Editor/HybridCLR/CompileDllHelper.cs | 65 +++
.../Editor/HybridCLR/CompileDllHelper.cs.meta | 11 +
.../Scripts/Editor/HybridCLR/Generators.meta | 8 +
.../HybridCLR/Generators/ConstStrings.cs | 13 +
.../HybridCLR/Generators/ConstStrings.cs.meta | 11 +
.../HybridCLR/Generators/FileRegionReplace.cs | 40 ++
.../Generators/FileRegionReplace.cs.meta | 11 +
.../HybridCLR/Generators/GeneratorConfig.cs | 70 +++
.../Generators/GeneratorConfig.cs.meta | 11 +
.../HybridCLR/Generators/MethodBridge.meta | 8 +
.../MethodBridge/IPlatformAdaptor.cs | 28 ++
.../MethodBridge/IPlatformAdaptor.cs.meta | 11 +
.../MethodBridge/MethodBridgeGenerator.cs | 353 ++++++++++++++++
.../MethodBridgeGenerator.cs.meta | 11 +
.../MethodBridge/MethodBridgeSig.cs | 156 +++++++
.../MethodBridge/MethodBridgeSig.cs.meta | 11 +
.../Generators/MethodBridge/ParamInfo.cs | 44 ++
.../Generators/MethodBridge/ParamInfo.cs.meta | 11 +
.../MethodBridge/ParamOrReturnType.cs | 38 ++
.../MethodBridge/ParamOrReturnType.cs.meta | 11 +
.../Generators/MethodBridge/PlatformABI.cs | 9 +
.../MethodBridge/PlatformABI.cs.meta | 11 +
.../MethodBridge/PlatformAdaptorBase.cs | 160 +++++++
.../MethodBridge/PlatformAdaptorBase.cs.meta | 11 +
.../MethodBridge/PlatformAdaptor_Arm64.cs | 208 +++++++++
.../PlatformAdaptor_Arm64.cs.meta | 11 +
.../PlatformAdaptor_Universal32.cs | 96 +++++
.../PlatformAdaptor_Universal32.cs.meta | 11 +
.../PlatformAdaptor_Universal64.cs | 189 +++++++++
.../PlatformAdaptor_Universal64.cs.meta | 11 +
.../SignatureProviderAttribute.cs | 19 +
.../SignatureProviderAttribute.cs.meta | 11 +
.../Generators/MethodBridge/TypeInfo.cs | 132 ++++++
.../Generators/MethodBridge/TypeInfo.cs.meta | 11 +
.../ValueTypeSizeAligmentCalculator.cs | 148 +++++++
.../ValueTypeSizeAligmentCalculator.cs.meta | 11 +
.../HybridCLR/Generators/TemplateUtil.cs | 38 ++
.../HybridCLR/Generators/TemplateUtil.cs.meta | 11 +
.../HybridCLR/Generators/Templates.meta | 8 +
.../Templates/MethodBridge_Arm64.cpp | 22 +
.../Templates/MethodBridge_Arm64.cpp.meta | 27 ++
.../Templates/MethodBridge_Universal32.cpp | 22 +
.../MethodBridge_Universal32.cpp.meta | 27 ++
.../Templates/MethodBridge_Universal64.cpp | 22 +
.../MethodBridge_Universal64.cpp.meta | 27 ++
.../Scripts/Editor/HybridCLR/Installer.meta | 8 +
.../Installer/InstallerController.cs | 224 ++++++++++
.../Installer/InstallerController.cs.meta | 11 +
.../HybridCLR/Installer/InstallerWindow.cs | 117 ++++++
.../Installer/InstallerWindow.cs.meta | 11 +
.../Editor/HybridCLR/MethodBridgeHelper.cs | 129 ++++++
.../HybridCLR/MethodBridgeHelper.cs.meta | 11 +
.../Scripts/Editor/TEngine.Editor.asmdef | 2 +-
72 files changed, 3764 insertions(+), 1 deletion(-)
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig_Custom.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig_Custom.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPCopyStrippedAOTAssemblies.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPCopyStrippedAOTAssemblies.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPFilterHotFixAssemblies.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPFilterHotFixAssemblies.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPPatchScriptAssembliesJson.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPPatchScriptAssembliesJson.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFile.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFile.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFileDefines.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFileDefines.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinUtils.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinUtils.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/CompileDllHelper.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/CompileDllHelper.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/ConstStrings.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/ConstStrings.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/FileRegionReplace.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/FileRegionReplace.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/GeneratorConfig.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/GeneratorConfig.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/IPlatformAdaptor.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/IPlatformAdaptor.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeGenerator.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeGenerator.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeSig.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeSig.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamInfo.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamInfo.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamOrReturnType.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamOrReturnType.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformABI.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformABI.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptorBase.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptorBase.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Arm64.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Arm64.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal32.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal32.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal64.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal64.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/SignatureProviderAttribute.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/SignatureProviderAttribute.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/TypeInfo.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/TypeInfo.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ValueTypeSizeAligmentCalculator.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ValueTypeSizeAligmentCalculator.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/TemplateUtil.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/TemplateUtil.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Arm64.cpp
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Arm64.cpp.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal32.cpp
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal32.cpp.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal64.cpp
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal64.cpp.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Installer.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerController.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerController.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerWindow.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerWindow.cs.meta
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/MethodBridgeHelper.cs
create mode 100644 Assets/TEngine/Scripts/Editor/HybridCLR/MethodBridgeHelper.cs.meta
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR.meta b/Assets/TEngine/Scripts/Editor/HybridCLR.meta
new file mode 100644
index 00000000..5f0e9530
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0cca09dc9d27f314da15fa746a01d51c
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig.cs
new file mode 100644
index 00000000..03f6cada
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig.cs
@@ -0,0 +1,70 @@
+using System;
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+
+namespace HybridCLR.Editor
+{
+ public static partial class BuildConfig
+ {
+#if !UNITY_IOS
+ [InitializeOnLoadMethod]
+ private static void Setup()
+ {
+ ///
+ /// unity允许使用UNITY_IL2CPP_PATH环境变量指定il2cpp的位置,因此我们不再直接修改安装位置的il2cpp,
+ /// 而是在本地目录
+ ///
+ var localIl2cppDir = LocalIl2CppDir;
+ if (!Directory.Exists(localIl2cppDir))
+ {
+ Debug.LogError($"本地il2cpp目录:{localIl2cppDir} 不存在,未安装本地il2cpp。请在菜单 HybridCLR/Installer 中执行安装");
+ }
+ Environment.SetEnvironmentVariable("UNITY_IL2CPP_PATH", localIl2cppDir);
+ }
+#endif
+
+ public static string ProjectDir => Directory.GetParent(Application.dataPath).ToString();
+
+ public static string ScriptingAssembliesJsonFile { get; } = "ScriptingAssemblies.json";
+
+ public static string HybridCLRBuildCacheDir => Application.dataPath + "/HybridCLRBuildCache";
+
+ public static string HotFixDllsOutputDir => $"{HybridCLRDataDir}/HotFixDlls";
+
+ public static string AssetBundleOutputDir => $"{HybridCLRBuildCacheDir}/AssetBundleOutput";
+
+ public static string AssetBundleSourceDataTempDir => $"{HybridCLRBuildCacheDir}/AssetBundleSourceData";
+
+ public static string HybridCLRDataDir { get; } = $"{ProjectDir}/HybridCLRData";
+
+ public static string AssembliesPostIl2CppStripDir => $"{HybridCLRDataDir}/AssembliesPostIl2CppStrip";
+
+ public static string LocalIl2CppDir => $"{HybridCLRDataDir}/LocalIl2CppData/il2cpp";
+
+ public static string MethodBridgeCppDir => $"{LocalIl2CppDir}/libil2cpp/hybridclr/interpreter";
+
+ public static string Il2CppBuildCacheDir { get; } = $"{ProjectDir}/Library/Il2cppBuildCache";
+
+ public static string GetHotFixDllsOutputDirByTarget(BuildTarget target)
+ {
+ return $"{HotFixDllsOutputDir}/{target}";
+ }
+
+ public static string GetAssembliesPostIl2CppStripDir(BuildTarget target)
+ {
+ return $"{AssembliesPostIl2CppStripDir}/{target}";
+ }
+
+ public static string GetAssetBundleOutputDirByTarget(BuildTarget target)
+ {
+ return $"{AssetBundleOutputDir}/{target}";
+ }
+
+ public static string GetAssetBundleTempDirByTarget(BuildTarget target)
+ {
+ return $"{AssetBundleSourceDataTempDir}/{target}";
+ }
+
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig.cs.meta
new file mode 100644
index 00000000..03ce5891
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bf7714fc37515834382cd5836b503a9f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig_Custom.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig_Custom.cs
new file mode 100644
index 00000000..16676171
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig_Custom.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEditor;
+using UnityEngine;
+
+namespace HybridCLR.Editor
+{
+ public static partial class BuildConfig
+ {
+
+ ///
+ /// 所有热更新dll列表。放到此列表中的dll在打包时OnFilterAssemblies回调中被过滤。
+ ///
+ public static List HotUpdateAssemblies { get; } = new List
+ {
+ "HotFix.dll",
+ "HotFix2.dll",
+ };
+
+ public static List AOTMetaAssemblies { get; } = new List()
+ {
+ "mscorlib.dll",
+ "System.dll",
+ "System.Core.dll", // 如果使用了Linq,需要这个
+
+ //
+ // 注意!修改这个列表请同步修改HotFix2模块中App.cs文件中的 LoadMetadataForAOTAssembly函数中aotDllList列表。
+ // 两者需要完全一致
+ //
+ };
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig_Custom.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig_Custom.cs.meta
new file mode 100644
index 00000000..a8fef316
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildConfig_Custom.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 33c09b498146d144a947ed6d8ff104f3
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors.meta
new file mode 100644
index 00000000..3d9bcb51
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5d7e4bb1668e0b341b9613b967e27f88
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPCopyStrippedAOTAssemblies.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPCopyStrippedAOTAssemblies.cs
new file mode 100644
index 00000000..68bed9ec
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPCopyStrippedAOTAssemblies.cs
@@ -0,0 +1,84 @@
+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 BPCopyStrippedAOTAssemblies : IPostprocessBuildWithReport
+#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 = BuildConfig.ProjectDir;
+#if UNITY_STANDALONE_WIN
+ return $"{projectDir}/Library/Bee/artifacts/WinPlayerBuildProgram/ManagedStripped";
+#elif UNITY_ANDROID
+ return $"{projectDir}/Library/Bee/artifacts/Android/ManagedStripped";
+#elif UNITY_IOS
+ return $"{projectDir}/Temp/StagingArea/Data/Managed/tempStrip";
+#elif UNITY_WEBGL
+ return $"{projectDir}/Library/Bee/artifacts/WebGL/ManagedStripped";
+#elif UNITY_EDITOR_OSX
+ return $"{projectDir}/Library/Bee/artifacts/MacStandalonePlayerBuildProgram/ManagedStripped";
+#else
+ throw new NotSupportedException("GetOriginBuildStripAssembliesDir");
+#endif
+ }
+#else
+ private string GetStripAssembliesDir2020(BuildTarget target)
+ {
+ string subPath = target == BuildTarget.Android ?
+ "assets/bin/Data/Managed" :
+ "Data/Managed/";
+ return $"{BuildConfig.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)
+ {
+ Debug.Log($"[BPCopyStrippedAOTAssemblies] CopyScripDlls. src:{srcStripDllPath} target:{target}");
+
+ var dstPath = BuildConfig.GetAssembliesPostIl2CppStripDir(target);
+
+ Directory.CreateDirectory(dstPath);
+
+ //string srcStripDllPath = BuildConfig.GetOriginBuildStripAssembliesDir(target);
+
+ foreach (var fileFullPath in Directory.GetFiles(srcStripDllPath, "*.dll"))
+ {
+ var file = Path.GetFileName(fileFullPath);
+ Debug.Log($"[BPCopyStrippedAOTAssemblies] copy strip dll {fileFullPath} ==> {dstPath}/{file}");
+ File.Copy($"{fileFullPath}", $"{dstPath}/{file}", true);
+ }
+ }
+
+ public void OnPostprocessBuild(BuildReport report)
+ {
+#if UNITY_2021_1_OR_NEWER && !UNITY_IOS
+ BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
+ CopyStripDlls(GetStripAssembliesDir2021(target), target);
+#endif
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPCopyStrippedAOTAssemblies.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPCopyStrippedAOTAssemblies.cs.meta
new file mode 100644
index 00000000..3ebc0e10
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPCopyStrippedAOTAssemblies.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/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPFilterHotFixAssemblies.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPFilterHotFixAssemblies.cs
new file mode 100644
index 00000000..30eb4205
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPFilterHotFixAssemblies.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor;
+using UnityEditor.Build;
+using UnityEngine;
+
+namespace HybridCLR.Editor.BuildProcessors
+{
+ ///
+ /// 将热更新dll从Build过程中过滤,防止打包到主工程中
+ ///
+ internal class BPFilterHotFixAssemblies : IFilterBuildAssemblies
+ {
+ public int callbackOrder => 0;
+
+ public string[] OnFilterAssemblies(BuildOptions buildOptions, string[] assemblies)
+ {
+ List allHotUpdateDllNames = BuildConfig.HotUpdateAssemblies;
+
+ // 检查是否重复填写
+ var hotUpdateDllSet = new HashSet();
+ foreach(var hotUpdateDll in allHotUpdateDllNames)
+ {
+ if (!hotUpdateDllSet.Add(hotUpdateDll))
+ {
+ throw new Exception($"热更新 assembly:{hotUpdateDll} 在列表中重复,请除去重复条目");
+ }
+ }
+
+ // 检查是否填写了正确的dll名称
+ foreach (var hotUpdateDll in BuildConfig.HotUpdateAssemblies)
+ {
+ if (assemblies.All(ass => !ass.EndsWith(hotUpdateDll)))
+ {
+ throw new Exception($"热更新 assembly:{hotUpdateDll} 不存在,请检查拼写错误");
+ }
+ Debug.Log($"[BPFilterHotFixAssemblies] 过滤热更新assembly:{hotUpdateDll}");
+ }
+
+ // 将热更dll从打包列表中移除
+ return assemblies.Where(ass => BuildConfig.HotUpdateAssemblies.All(dll => !ass.EndsWith(dll, StringComparison.OrdinalIgnoreCase))).ToArray();
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPFilterHotFixAssemblies.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPFilterHotFixAssemblies.cs.meta
new file mode 100644
index 00000000..2ab4ba54
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPFilterHotFixAssemblies.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/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPPatchScriptAssembliesJson.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPPatchScriptAssembliesJson.cs
new file mode 100644
index 00000000..d27eadac
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPPatchScriptAssembliesJson.cs
@@ -0,0 +1,148 @@
+using HybridCLR.Editor.GlobalManagers;
+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 BPPatchScriptAssembliesJson : IPreprocessBuildWithReport,
+#if UNITY_ANDROID
+ IPostGenerateGradleAndroidProject,
+#endif
+ IPostprocessBuildWithReport
+ {
+ public int callbackOrder => 0;
+
+
+ [Serializable]
+ private class ScriptingAssemblies
+ {
+ public List names;
+ public List types;
+ }
+
+ public void OnPostGenerateGradleAndroidProject(string path)
+ {
+ // 如果直接打包apk,没有机会在PostprocessBuild中修改ScriptingAssemblies.json。
+ // 因此需要在这个时机处理
+ PathScriptingAssembilesFile(path);
+ }
+
+ public void OnPostprocessBuild(BuildReport report)
+ {
+ // 如果target为Android,由于已经在OnPostGenerateGradelAndroidProject中处理过,
+ // 这里不再重复处理
+#if !UNITY_ANDROID
+
+ PathScriptingAssembilesFile(report.summary.outputPath);
+#endif
+ }
+
+ private void PathScriptingAssembilesFile(string path)
+ {
+#if UNITY_2020_1_OR_NEWER
+ AddHotFixAssembliesToScriptingAssembliesJson(path);
+#else
+ AddBackHotFixAssembliesToBinFile(path);
+#endif
+ }
+
+ private void AddHotFixAssembliesToScriptingAssembliesJson(string path)
+ {
+ Debug.Log($"AddBackHotFixAssembliesToJson. path:{path}");
+ if (!Directory.Exists(path))
+ {
+ path = Directory.GetParent(path).ToString();
+ }
+ /*
+ * ScriptingAssemblies.json 文件中记录了所有的dll名称,此列表在游戏启动时自动加载,
+ * 不在此列表中的dll在资源反序列化时无法被找到其类型
+ * 因此 OnFilterAssemblies 中移除的条目需要再加回来
+ */
+ string[] jsonFiles = Directory.GetFiles(path, BuildConfig.ScriptingAssembliesJsonFile, SearchOption.AllDirectories);
+
+ if (jsonFiles.Length == 0)
+ {
+ Debug.LogError($"can not find file {BuildConfig.ScriptingAssembliesJsonFile}");
+ return;
+ }
+
+ foreach (string file in jsonFiles)
+ {
+ string content = File.ReadAllText(file);
+ ScriptingAssemblies scriptingAssemblies = JsonUtility.FromJson(content);
+ foreach (string name in BuildConfig.HotUpdateAssemblies)
+ {
+ 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}");
+ }
+ }
+ content = JsonUtility.ToJson(scriptingAssemblies);
+
+ File.WriteAllText(file, content);
+ }
+ }
+
+ private void AddBackHotFixAssembliesToBinFile(string path)
+ {
+ /*
+ * Unity2019 中 dll 加载列表存储在 globalgamemanagers 文件中,此列表在游戏启动时自动加载,
+ * 不在此列表中的dll在资源反序列化时无法被找到其类型
+ * 因此 OnFilterAssemblies 中移除的条目需要再加回来
+ */
+#if UNITY_ANDROID
+ string[] binFiles = new string[] { "Temp/gradleOut/unityLibrary/src/main/assets/bin/Data/globalgamemanagers" }; // report.files 不包含 Temp/gradleOut 等目录
+#else
+ // 直接出包和输出vs工程时路径不同,report.summary.outputPath 记录的是前者路径
+ string[] binFiles = Directory.GetFiles(Path.GetDirectoryName(path), "globalgamemanagers", SearchOption.AllDirectories);
+#endif
+
+ if (binFiles.Length == 0)
+ {
+ Debug.LogError("can not find file ScriptingAssemblies.json");
+ return;
+ }
+
+ foreach (string binPath in binFiles)
+ {
+ var binFile = new UnityBinFile();
+ binFile.LoadFromFile(binPath);
+
+ ScriptsData scriptsData = binFile.scriptsData;
+ foreach (string name in BuildConfig.HotUpdateAssemblies)
+ {
+ if (!scriptsData.dllNames.Contains(name))
+ {
+ scriptsData.dllNames.Add(name);
+ scriptsData.dllTypes.Add(16); // user dll type
+ }
+ }
+ binFile.scriptsData = scriptsData;
+
+ binFile.RebuildAndFlushToFile(binPath);
+ }
+ }
+
+#region useless
+
+ public void OnPreprocessBuild(BuildReport report)
+ {
+
+ }
+
+#endregion
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPPatchScriptAssembliesJson.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPPatchScriptAssembliesJson.cs.meta
new file mode 100644
index 00000000..0affdc71
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/BPPatchScriptAssembliesJson.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/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader.meta
new file mode 100644
index 00000000..7cabb704
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e52fb09e14efee949ae80ae8aa9f9d44
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFile.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFile.cs
new file mode 100644
index 00000000..f389e351
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFile.cs
@@ -0,0 +1,107 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using UnityEngine;
+using System.Text;
+using System.Reflection;
+using System;
+using System.Linq;
+
+namespace HybridCLR.Editor.GlobalManagers
+{
+ ///
+ /// Unity 生成的二进制文件(本代码不支持5.x之前的版本)
+ ///
+ public unsafe class UnityBinFile
+ {
+ /*
+ * MonoManager: idx: 6;
+ * type: metaData.types[objects[6].typeID]
+ */
+ public const int kMonoManagerIdx = 6;
+
+ public string path { get; private set; }
+
+ public FileHeader header;
+ public MetaData metaData;
+ public ScriptsData scriptsData;
+
+ public void LoadFromFile(string path)
+ {
+ this.path = path;
+
+ var fs = new FileStream(path, FileMode.Open, FileAccess.Read);
+ var br = new BinaryReader(fs, Encoding.UTF8, true);
+
+ header.LoadFromStream(br);
+ // 按理说 metaData 应该新开一个buffer来避免加载时的对齐逻辑问题,但由于 sizeof(Header) = 20,已经对齐到4了,所以可以连续读
+ metaData.LoadFromStream(br, header.dataOffset);
+ scriptsData = metaData.GetScriptData(br);
+
+ br.Close();
+ fs.Close();
+ }
+
+ public void RebuildAndFlushToFile(string newPath)
+ {
+ var fsR = new FileStream(path, FileMode.Open, FileAccess.Read);
+ var brR = new BinaryReader(fsR, Encoding.UTF8, true);
+
+ var ms = new MemoryStream((int)(header.fileSize * 1.5f));
+ var bw = new BinaryWriter(ms, Encoding.UTF8, true);
+
+ /*
+ * 开始写入data
+ * dll名称列表存储于 data 区段,修改其数据并不会影响 MetaData 大小,因此 dataOffset 不会改变
+ */
+ ms.Position = header.dataOffset;
+
+ Dictionary newObjInfos = new Dictionary();
+ foreach (var kv in metaData.objects)
+ {
+ long objID = kv.Key;
+ ObjectInfo objInfo = kv.Value;
+
+ byte[] buff = new byte[objInfo.size];
+ fsR.Position = objInfo.realPos;
+ brR.Read(buff, 0, buff.Length);
+
+
+ {// unity 的数据偏移貌似会对齐到 8
+ int newPos = (((int)ms.Position + 7) >> 3) << 3;
+ int gapSize = newPos - (int)ms.Position;
+
+ for (int i = 0; i < gapSize; i++)
+ bw.Write((byte)0);
+
+ objInfo.dataPos = (uint)ms.Position - header.dataOffset; // 重定位数据偏移
+ }
+
+ if (objID != kMonoManagerIdx)
+ bw.Write(buff, 0, buff.Length);
+ else
+ objInfo.size = (uint)scriptsData.SaveToStream(bw);
+
+ newObjInfos.Add(objID, objInfo);
+ }
+
+ metaData.objects = newObjInfos;
+ header.fileSize = (uint)ms.Position;
+
+ ms.Position = 0;
+ header.SaveToStream(bw);
+ metaData.SaveToStream(bw);
+
+ brR.Close();
+ fsR.Close();
+
+ // 写入新文件
+ ms.Position = 0;
+ File.WriteAllBytes(newPath, ms.ToArray());
+
+ bw.Close();
+ ms.Close();
+ }
+ }
+
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFile.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFile.cs.meta
new file mode 100644
index 00000000..e53b7420
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFile.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ae7ec6e3674077d46898fe821d24bf85
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFileDefines.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFileDefines.cs
new file mode 100644
index 00000000..48a7920b
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFileDefines.cs
@@ -0,0 +1,397 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using UnityEngine;
+using static HybridCLR.Editor.GlobalManagers.UnityBinUtils;
+
+namespace HybridCLR.Editor.GlobalManagers
+{
+ public struct FileHeader
+ {
+ public const int kSize = 20;
+
+ public uint dataSize => fileSize - metadataSize;
+
+ public uint metadataSize;
+ public uint fileSize;
+ public uint version;
+ public uint dataOffset;
+ public byte endianess;
+
+ public void LoadFromStream(BinaryReader br)
+ {
+ long startPos = br.BaseStream.Position;
+ metadataSize = br.ReadUInt32();
+ fileSize = br.ReadUInt32();
+ version = br.ReadUInt32();
+ dataOffset = br.ReadUInt32();
+ endianess = br.ReadByte();
+ br.BaseStream.Position = startPos + kSize;
+
+ SwapEndianess();
+ }
+
+ public long SaveToStream(BinaryWriter bw)
+ {
+ SwapEndianess();
+
+ long startPos = bw.BaseStream.Position;
+ bw.Write(metadataSize);
+ bw.Write(fileSize);
+ bw.Write(version);
+ bw.Write(dataOffset);
+ bw.Write(endianess);
+ bw.BaseStream.Position = startPos + kSize;
+ return kSize;
+ }
+
+ void SwapEndianess()
+ {
+ SwapUInt(ref metadataSize);
+ SwapUInt(ref fileSize);
+ SwapUInt(ref version);
+ SwapUInt(ref dataOffset);
+ }
+ }
+
+ public struct MetaData
+ {
+ public long dataStartPos;
+
+ public string version;
+ public uint platform;
+ public bool enableTypeTree;
+ public int typeCount;
+ public ObjectType[] types;
+ public int objectCount;
+ public Dictionary objects;
+ public int scriptTypeCount;
+ public ScriptType[] scriptTypes;
+ public int externalsCount;
+ public ExternalInfo[] externals;
+
+#if UNITY_2019_2_OR_NEWER
+ public int refTypeCount;
+ public ObjectType[] refTypes;
+#endif
+ public string dummyStr;
+
+ public void LoadFromStream(BinaryReader br, uint dataOffset)
+ {
+ long startPos = br.BaseStream.Position;
+ dataStartPos = startPos;
+
+ version = br.ReadRawString();
+ platform = br.ReadUInt32();
+ enableTypeTree = br.ReadBoolean();
+ typeCount = br.ReadInt32();
+ types = new ObjectType[typeCount];
+
+ for (int i = 0; i < typeCount; i++)
+ {
+ types[i].LoadFromStream(br);
+ }
+
+ objectCount = br.ReadInt32();
+ objects = new Dictionary();
+ for(int i = 0; i < objectCount; i++)
+ {
+ long id = br.AlignedReadInt64();
+ ObjectInfo objInfo = new ObjectInfo();
+ objInfo.LoadFromStream(br);
+ objInfo.realPos = objInfo.dataPos + dataOffset;
+
+ objects.Add(id, objInfo);
+ }
+
+ scriptTypeCount = br.ReadInt32();
+ scriptTypes = new ScriptType[scriptTypeCount];
+ for(int i = 0; i < scriptTypeCount; i++)
+ {
+ scriptTypes[i].LoadFromStream(br);
+ }
+
+ externalsCount = br.ReadInt32();
+ externals = new ExternalInfo[externalsCount];
+ for(int i = 0; i < externalsCount; i++)
+ {
+ externals[i].LoadFromStream(br);
+ }
+
+#if UNITY_2019_2_OR_NEWER
+ refTypeCount = br.ReadInt32();
+ refTypes = new ObjectType[refTypeCount];
+ for(int i = 0; i < refTypeCount; i++)
+ {
+ refTypes[i].LoadFromStream(br);
+ }
+#endif
+ dummyStr = br.ReadRawString();
+ }
+
+ public long SaveToStream(BinaryWriter bw)
+ {
+ long startPos = bw.BaseStream.Position;
+ bw.WriteRawString(version);
+ bw.Write(platform);
+ bw.Write(enableTypeTree);
+
+ bw.Write(typeCount);
+ foreach(var type in types)
+ type.SaveToStream(bw);
+
+ bw.Write(objectCount);
+ foreach (var kv in objects)
+ {
+ bw.AlignedWriteInt64(kv.Key);
+ kv.Value.SaveToStream(bw);
+ }
+
+ bw.Write(scriptTypeCount);
+ foreach(var st in scriptTypes)
+ st.SaveToStream(bw);
+
+ bw.Write(externalsCount);
+ foreach(var external in externals)
+ external.SaveToStream(bw);
+
+#if UNITY_2019_2_OR_NEWER
+ bw.Write(refTypeCount);
+ foreach(var refT in refTypes)
+ refT.SaveToStream(bw);
+#endif
+
+ bw.WriteRawString(dummyStr);
+
+ return bw.BaseStream.Position - startPos;
+ }
+
+ public ScriptsData GetScriptData(BinaryReader br)
+ {
+ ObjectInfo objInfo = objects[UnityBinFile.kMonoManagerIdx];
+ br.BaseStream.Seek(objInfo.realPos, SeekOrigin.Begin);
+
+ ScriptsData data = new ScriptsData();
+ data.LoadFromStream(br);
+ return data;
+ }
+ }
+
+ public struct ObjectType
+ {
+ public int typeID;
+ public bool isStriped;
+ public short scriptTypeIndex;
+
+ public bool needReadScriptHash; // dont save
+
+ public Hash scriptSigHash;
+ public Hash typeHash;
+
+ public void LoadFromStream(BinaryReader br)
+ {
+ typeID = br.ReadInt32();
+ isStriped = br.ReadBoolean();
+ scriptTypeIndex = br.ReadInt16();
+
+ needReadScriptHash = typeID == -1 || typeID == 0x72;
+ if(needReadScriptHash)
+ scriptSigHash.LoadFromStream(br);
+
+ typeHash.LoadFromStream(br);
+
+ // GlobalManagers does not has TypeTrees
+ }
+
+ public long SaveToStream(BinaryWriter bw)
+ {
+ long startPos = bw.BaseStream.Position;
+ bw.Write(typeID);
+ bw.Write(isStriped);
+ bw.Write(scriptTypeIndex);
+
+ if(needReadScriptHash)
+ scriptSigHash.SaveToStream(bw);
+
+ typeHash.SaveToStream(bw);
+ return bw.BaseStream.Position - startPos;
+ }
+
+ public int Size()
+ {
+ int ret = 0;
+ ret += sizeof(int);
+ ret += sizeof(bool);
+ ret += sizeof(short);
+
+ if (needReadScriptHash)
+ ret += Hash.kSize;
+
+ ret += Hash.kSize;
+ return ret;
+ }
+ }
+
+ public struct ObjectInfo
+ {
+ public const int kSize = 12;
+
+ public uint dataPos;
+ public uint size;
+ public uint typeID;
+
+ public uint realPos; // dataPos + Header.dataOffset; // dont save
+
+ public void LoadFromStream(BinaryReader br)
+ {
+ dataPos = br.ReadUInt32();
+ size = br.ReadUInt32();
+ typeID = br.ReadUInt32();
+ }
+
+ public long SaveToStream(BinaryWriter bw)
+ {
+ bw.Write(dataPos);
+ bw.Write(size);
+ bw.Write(typeID);
+ return kSize;
+ }
+ }
+
+ public struct ScriptType
+ {
+ public int localFileIndex;
+ public long localIdentifierOfBin;
+
+ public void LoadFromStream(BinaryReader br)
+ {
+ localFileIndex = br.ReadInt32();
+ localIdentifierOfBin = br.AlignedReadInt64();
+ }
+
+ public long SaveToStream(BinaryWriter bw)
+ {
+ long startPos = bw.BaseStream.Position;
+ bw.Write(localFileIndex);
+ bw.AlignedWriteInt64(localIdentifierOfBin);
+ return bw.BaseStream.Position - startPos;
+ }
+ }
+
+ public struct ExternalInfo
+ {
+ public string dummy;
+ public Hash guid;
+ public int type;
+ public string name;
+
+ public void LoadFromStream(BinaryReader br)
+ {
+ dummy = br.ReadRawString();
+ guid.LoadFromStream(br);
+ type = br.ReadInt32();
+ name = br.ReadRawString();
+ }
+
+ public long SaveToStream(BinaryWriter bw)
+ {
+ long startPos = bw.BaseStream.Position;
+ bw.WriteRawString(dummy);
+ guid.SaveToStream(bw);
+ bw.Write(type);
+ bw.WriteRawString(name);
+ return bw.BaseStream.Position - startPos;
+ }
+ }
+
+ public struct ScriptsData
+ {
+ public ScriptID[] scriptIDs;
+ public List dllNames;
+ public List dllTypes; // 16 is user type
+
+ public void LoadFromStream(BinaryReader br)
+ {
+ {
+ int count = br.ReadInt32();
+ scriptIDs = new ScriptID[count];
+ for(int i = 0; i < count; i++)
+ scriptIDs[i].LoadFromStream(br);
+ }
+ {
+ int count = br.ReadInt32();
+ dllNames = new List(count);
+ for (var i = 0; i < count; i++)
+ dllNames.Add(br.ReadSizeString());
+ }
+ {
+ int count = br.ReadInt32();
+ dllTypes = new List(count);
+ for(var i = 0; i < count; i++)
+ dllTypes.Add(br.ReadInt32());
+ }
+ }
+
+ public long SaveToStream(BinaryWriter bw)
+ {
+ long startPos = bw.BaseStream.Position;
+ bw.Write(scriptIDs.Length);
+ for(int i = 0; i < scriptIDs.Length; i++)
+ scriptIDs[i].SaveToStream(bw);
+
+ bw.Write(dllNames.Count);
+ for(int i = 0, imax = dllNames.Count; i < imax; i++)
+ bw.WriteSizeString(dllNames[i]);
+
+ bw.Write(dllTypes.Count);
+ for(int i = 0, imax = dllTypes.Count; i < imax; i++)
+ bw.Write(dllTypes[i]);
+
+ return bw.BaseStream.Position - startPos;
+ }
+ }
+
+ public struct ScriptID
+ {
+ public int fileID;
+ public long pathID; // localIdentifier
+
+ public void LoadFromStream(BinaryReader br)
+ {
+ fileID = br.ReadInt32();
+ pathID = br.ReadInt64();
+ }
+
+ public long SaveToStream(BinaryWriter bw)
+ {
+ bw.Write(fileID);
+ bw.Write(pathID);
+ return 4 + 8;
+ }
+ }
+
+ public struct Hash
+ {
+ public const int kSize = 16;
+
+ public int[] data;
+
+ public void LoadFromStream(BinaryReader br)
+ {
+ data = new int[4];
+ for(int i = 0; i < data.Length; i++)
+ {
+ data[i] = br.ReadInt32();
+ }
+ }
+
+ public long SaveToStream(BinaryWriter bw)
+ {
+ for(int i = 0; i < data.Length; i++)
+ {
+ bw.Write(data[i]);
+ }
+ return kSize;
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFileDefines.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFileDefines.cs.meta
new file mode 100644
index 00000000..d9192c74
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinFileDefines.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 96788c7fe08d5d54d95a87cfbdcb643a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinUtils.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinUtils.cs
new file mode 100644
index 00000000..08901404
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinUtils.cs
@@ -0,0 +1,78 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using UnityEngine;
+using System.Text;
+
+namespace HybridCLR.Editor.GlobalManagers
+{
+ public static class UnityBinUtils
+ {
+ public static void SwapUInt(ref uint val)
+ {
+ val = (val >> 24) | ((val >> 8) & 0x0000ff00) | ((val << 8) & 0x00ff0000) | (val << 24);
+ }
+
+ public static string ReadRawString(this BinaryReader br)
+ {
+ long startPos = br.BaseStream.Position;
+ while (true)
+ {
+ byte val = br.ReadByte();
+ if(val == 0)
+ break;
+ }
+ int size = (int)(br.BaseStream.Position - startPos);
+ br.BaseStream.Position = startPos;
+
+ byte[] buffer = br.ReadBytes(size);
+ string ret = Encoding.UTF8.GetString(buffer, 0, size - 1);
+
+ return ret;
+ }
+
+ public static void WriteRawString(this BinaryWriter bw, string str)
+ {
+ byte[] buffer = Encoding.UTF8.GetBytes(str);
+ bw.Write(buffer, 0, buffer.Length);
+ bw.Write((byte)0);
+ }
+
+ public static string ReadSizeString(this BinaryReader br)
+ {
+ int size = br.ReadInt32();
+ byte[] buff = br.ReadBytes(size);
+ br.BaseStream.AlignOffset4();
+
+ string ret = Encoding.UTF8.GetString(buff);
+ return ret;
+ }
+
+ public static void WriteSizeString(this BinaryWriter bw, string str)
+ {
+ byte[] buff = Encoding.UTF8.GetBytes(str);
+ bw.Write(buff.Length);
+ bw.Write(buff, 0, buff.Length);
+ bw.BaseStream.AlignOffset4();
+ }
+
+ public static void AlignOffset4(this Stream stream)
+ {
+ int offset = (((int)stream.Position + 3) >> 2) << 2;
+ stream.Position = offset;
+ }
+
+ public static long AlignedReadInt64(this BinaryReader br)
+ {
+ br.BaseStream.AlignOffset4();
+ return br.ReadInt64();
+ }
+
+ public static void AlignedWriteInt64(this BinaryWriter bw, long val)
+ {
+ bw.BaseStream.AlignOffset4();
+ bw.Write(val);
+ }
+ }
+}
+
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinUtils.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinUtils.cs.meta
new file mode 100644
index 00000000..e0f9bf96
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/BuildProcessors/UnityBinFileReader/UnityBinUtils.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bf7c4cf970660614fb54d838ec6e7eda
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/CompileDllHelper.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/CompileDllHelper.cs
new file mode 100644
index 00000000..ee19f079
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/CompileDllHelper.cs
@@ -0,0 +1,65 @@
+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
+{
+ internal class CompileDllHelper
+ {
+ public static void CompileDll(string buildDir, BuildTarget target)
+ {
+ var group = BuildPipeline.GetBuildTargetGroup(target);
+
+ ScriptCompilationSettings scriptCompilationSettings = new ScriptCompilationSettings();
+ scriptCompilationSettings.group = group;
+ scriptCompilationSettings.target = target;
+ Directory.CreateDirectory(buildDir);
+ ScriptCompilationResult scriptCompilationResult = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, buildDir);
+ foreach (var ass in scriptCompilationResult.assemblies)
+ {
+ Debug.LogFormat("compile assemblies:{1}/{0}", ass, buildDir);
+ }
+ }
+
+ public static void CompileDll(BuildTarget target)
+ {
+ CompileDll(BuildConfig.GetHotFixDllsOutputDirByTarget(target), target);
+ }
+
+ [MenuItem("HybridCLR/CompileDll/ActiveBuildTarget")]
+ public static void CompileDllActiveBuildTarget()
+ {
+ CompileDll(EditorUserBuildSettings.activeBuildTarget);
+ }
+
+ [MenuItem("HybridCLR/CompileDll/Win32")]
+ public static void CompileDllWin32()
+ {
+ CompileDll(BuildTarget.StandaloneWindows);
+ }
+
+ [MenuItem("HybridCLR/CompileDll/Win64")]
+ public static void CompileDllWin64()
+ {
+ CompileDll(BuildTarget.StandaloneWindows64);
+ }
+
+ [MenuItem("HybridCLR/CompileDll/Android")]
+ public static void CompileDllAndroid()
+ {
+ CompileDll(BuildTarget.Android);
+ }
+
+ [MenuItem("HybridCLR/CompileDll/IOS")]
+ public static void CompileDllIOS()
+ {
+ CompileDll(BuildTarget.iOS);
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/CompileDllHelper.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/CompileDllHelper.cs.meta
new file mode 100644
index 00000000..bd9ed55e
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/CompileDllHelper.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 91aca02079207d746b74aeea1b595127
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators.meta
new file mode 100644
index 00000000..0dbbc8aa
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f85b93bff3478c045ae862a7cc216b18
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/ConstStrings.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/ConstStrings.cs
new file mode 100644
index 00000000..6cc11d7f
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/ConstStrings.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HybridCLR.Editor.Generators
+{
+ internal static class ConstStrings
+ {
+ public const string typeObjectPtr = "Il2CppObject*";
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/ConstStrings.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/ConstStrings.cs.meta
new file mode 100644
index 00000000..81ed29d2
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/ConstStrings.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e1465458aaad6884d95af7c4fc2de7a1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/FileRegionReplace.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/FileRegionReplace.cs
new file mode 100644
index 00000000..170b5381
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/FileRegionReplace.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HybridCLR.Editor.Generators
+{
+ public class FileRegionReplace
+ {
+ private readonly string _tplFile;
+
+ private readonly Dictionary _regionReplaceContents = new Dictionary();
+
+ public FileRegionReplace(string tplFile)
+ {
+ _tplFile = tplFile;
+ }
+
+ public void Replace(string regionName, string regionContent)
+ {
+ _regionReplaceContents.Add(regionName, regionContent);
+ }
+
+ public void Commit(string outputFile)
+ {
+ string originContent = File.ReadAllText(_tplFile, Encoding.UTF8);
+
+ string resultContent = originContent;
+
+ foreach (var c in _regionReplaceContents)
+ {
+ resultContent = TemplateUtil.ReplaceRegion(resultContent, c.Key, c.Value);
+ }
+ var utf8WithoutBOM = new System.Text.UTF8Encoding(false);
+ File.WriteAllText(outputFile, resultContent, utf8WithoutBOM);
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/FileRegionReplace.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/FileRegionReplace.cs.meta
new file mode 100644
index 00000000..07c87ea1
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/FileRegionReplace.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e5aa6559bd1b1e4488aa6746eda8202b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/GeneratorConfig.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/GeneratorConfig.cs
new file mode 100644
index 00000000..bc3a3c6f
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/GeneratorConfig.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+
+namespace HybridCLR.Editor.Generators
+{
+ internal class GeneratorConfig
+ {
+ ///
+ /// 目前已经根据热更新dll的依赖自动计算需要扫描哪些dll来收集桥接函数。
+ /// 只要你的热更新以assembly def形式放到项目中,是不需要改这个的
+ ///
+ ///
+ public static List GetExtraAssembiles()
+ {
+ return new List
+ {
+ // "mscorlib",
+ };
+ }
+
+ ///
+ /// 暂时没有仔细扫描泛型,如果运行时发现有生成缺失,先手动在此添加类
+ ///
+ ///
+ public static List PrepareCustomGenericTypes()
+ {
+ return new List
+ {
+ typeof(Action),
+ };
+ }
+
+ ///
+ /// 如果提示缺失桥接函数,将提示缺失的签名加入到下列列表是简单的做法。
+ /// 这里添加64位App缺失的桥接函数签名
+ ///
+ ///
+ public static List PrepareCustomMethodSignatures64()
+ {
+ return new List
+ {
+ "vi8i8",
+ "i4i8i8i4i4i8i8",
+ "i8i8S12",
+ "S12i8S12",
+ "S12i8S12S12",
+ "i16i8i16i16",
+ };
+ }
+
+ ///
+ /// 如果提示缺失桥接函数,将提示缺失的签名加入到下列列表是简单的做法。
+ /// 这里添加32位App缺失的桥接函数签名
+ ///
+ ///
+ public static List PrepareCustomMethodSignatures32()
+ {
+ return new List
+ {
+ "vi4i4",
+ "S12i4S12S12",
+ };
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/GeneratorConfig.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/GeneratorConfig.cs.meta
new file mode 100644
index 00000000..de1bd9ec
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/GeneratorConfig.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d1d14f8f858560948ae1dfa0fa572e51
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge.meta
new file mode 100644
index 00000000..d04da9be
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4aa66b41c89ed7742ad067898725f7ff
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/IPlatformAdaptor.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/IPlatformAdaptor.cs
new file mode 100644
index 00000000..3b52d254
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/IPlatformAdaptor.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HybridCLR.Editor.Generators.MethodBridge
+{
+ public interface IPlatformAdaptor
+ {
+ bool IsArch32 { get; }
+
+ TypeInfo CreateTypeInfo(Type type, bool returnValue);
+
+ void GenerateManaged2NativeMethod(MethodBridgeSig method, List outputLines);
+
+ void GenerateManaged2NativeStub(List methods, List lines);
+
+ void GenerateNative2ManagedMethod(MethodBridgeSig method, List outputLines);
+
+ void GenerateNative2ManagedStub(List methods, List lines);
+
+ void GenerateAdjustThunkMethod(MethodBridgeSig method, List outputLines);
+
+ void GenerateAdjustThunkStub(List methods, List lines);
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/IPlatformAdaptor.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/IPlatformAdaptor.cs.meta
new file mode 100644
index 00000000..8dd7196a
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/IPlatformAdaptor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 983dbdeb1fb7d0b43a863c6b22160ace
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeGenerator.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeGenerator.cs
new file mode 100644
index 00000000..cd57437d
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeGenerator.cs
@@ -0,0 +1,353 @@
+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.Generators.MethodBridge
+{
+
+ public class TypeGenInfo
+ {
+ public Type Type { get; set; }
+
+ public List GenericMethods { get; set; }
+ }
+
+ public class MethodBridgeGeneratorOptions
+ {
+ public List HotfixAssemblies { get; set; }
+
+ public List AllAssemblies { get; set; }
+
+ public PlatformABI CallConvention { get; set; }
+
+ public string OutputFile { get; set; }
+
+ public bool Optimized { get; set; }
+ }
+
+ public class MethodBridgeGenerator
+ {
+ private readonly HashSet _hotfixAssemblies;
+
+ private readonly List _assemblies;
+
+ private readonly PlatformABI _callConvention;
+
+ private readonly string _outputFile;
+
+ public readonly bool _optimized;
+
+ private readonly IPlatformAdaptor _platformAdaptor;
+
+ private readonly HashSet _managed2nativeMethodSet = new HashSet();
+
+ private List _managed2nativeMethodList;
+
+ private readonly HashSet _native2managedMethodSet = new HashSet();
+
+ private List _native2managedMethodList;
+
+ private readonly HashSet _adjustThunkMethodSet = new HashSet();
+
+ private List _adjustThunkMethodList;
+
+ public bool IsHotFixType(Type type)
+ {
+ return _hotfixAssemblies.Contains(type.Assembly);
+ }
+
+ public MethodBridgeGenerator(MethodBridgeGeneratorOptions options)
+ {
+ _hotfixAssemblies = new HashSet(options.HotfixAssemblies);
+ _assemblies = options.AllAssemblies;
+ _callConvention = options.CallConvention;
+ _outputFile = options.OutputFile;
+ _platformAdaptor = CreatePlatformAdaptor(options.CallConvention);
+ _optimized = options.Optimized;
+ }
+
+ private static IPlatformAdaptor CreatePlatformAdaptor(PlatformABI type)
+ {
+ switch (type)
+ {
+ case PlatformABI.Universal32: return new PlatformAdaptor_Universal32();
+ case PlatformABI.Universal64: return new PlatformAdaptor_Universal64();
+ case PlatformABI.Arm64: return new PlatformAdaptor_Arm64();
+ default: throw new NotSupportedException();
+ }
+ }
+
+ private string GetTemplateFile()
+ {
+ string tplFile;
+
+ switch (_callConvention)
+ {
+ case PlatformABI.Universal32: tplFile = "Universal32"; break;
+ case PlatformABI.Universal64: tplFile = "Universal64"; break;
+ case PlatformABI.Arm64: tplFile = "Arm64"; break;
+ default: throw new NotSupportedException();
+ };
+ return $"{Application.dataPath}/Editor/HybridCLR/Generators/Templates/MethodBridge_{tplFile}.cpp";
+ }
+
+ public IEnumerable GetGenerateTypes()
+ {
+ return new List();
+ }
+
+ private MethodBridgeSig CreateMethodBridgeSig(bool isStatic, ParameterInfo returnType, ParameterInfo[] parameters)
+ {
+ var paramInfos = new List();
+ if (!isStatic)
+ {
+ // FIXME arm32 is s_i4u4
+ paramInfos.Add(new ParamInfo() { Type = _platformAdaptor.IsArch32 ? TypeInfo.s_i4u4 : TypeInfo.s_i8u8 });
+ }
+ foreach (var paramInfo in parameters)
+ {
+ paramInfos.Add(new ParamInfo() { Type = _platformAdaptor.CreateTypeInfo(paramInfo.ParameterType, false) });
+ }
+ var mbs = new MethodBridgeSig()
+ {
+ ReturnInfo = new ReturnInfo() { Type = returnType != null ? _platformAdaptor.CreateTypeInfo(returnType.ParameterType, true) : TypeInfo.s_void },
+ ParamInfos = paramInfos,
+ };
+ return mbs;
+ }
+
+ private void AddManaged2NativeMethod(MethodBridgeSig method)
+ {
+ if (_managed2nativeMethodSet.Add(method))
+ {
+ method.Init();
+ }
+ }
+
+ private void AddNative2ManagedMethod(MethodBridgeSig method)
+ {
+ if (_native2managedMethodSet.Add(method))
+ {
+ method.Init();
+ }
+ }
+
+ private void AddAdjustThunkMethod(MethodBridgeSig method)
+ {
+ if (_adjustThunkMethodSet.Add(method))
+ {
+ method.Init();
+ }
+ }
+
+ private void ScanType(Type type)
+ {
+ if (type.IsGenericTypeDefinition)
+ {
+ return;
+ }
+ if (_optimized)
+ {
+ if (!type.IsNested)
+ {
+ if (!type.IsPublic)
+ {
+ return;
+ }
+ }
+ else
+ {
+ if (type.IsNestedPrivate)
+ {
+ return;
+ }
+ }
+ }
+ var typeDel = typeof(MulticastDelegate);
+ if (typeDel.IsAssignableFrom(type))
+ {
+ var method = type.GetMethod("Invoke");
+ if (method == null)
+ {
+ //Debug.LogError($"delegate:{typeDel.FullName} Invoke not exists");
+ return;
+ }
+ // Debug.Log($"== delegate:{type}");
+ var instanceCallMethod = CreateMethodBridgeSig(false, method.ReturnParameter, method.GetParameters());
+ AddManaged2NativeMethod(instanceCallMethod);
+ AddNative2ManagedMethod(instanceCallMethod);
+
+ var staticCallMethod = CreateMethodBridgeSig(true, method.ReturnParameter, method.GetParameters());
+ AddManaged2NativeMethod(staticCallMethod);
+ AddNative2ManagedMethod(staticCallMethod);
+ return;
+ }
+ foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public
+| BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy))
+ {
+ if (method.IsGenericMethodDefinition)
+ {
+ continue;
+ }
+
+ if (_optimized && (method.IsPrivate || (method.IsAssembly && !method.IsPublic && !method.IsFamily)))
+ {
+ continue;
+ }
+
+ if (!_optimized || (method.IsFamily || method.IsPublic))
+ {
+ var m2nMethod = CreateMethodBridgeSig(method.IsStatic, method.ReturnParameter, method.GetParameters());
+ AddManaged2NativeMethod(m2nMethod);
+
+ if (type.IsValueType && !method.IsStatic)
+ {
+ var adjustThunkMethod = CreateMethodBridgeSig(false, method.ReturnParameter, method.GetParameters());
+ AddAdjustThunkMethod(adjustThunkMethod);
+ }
+
+ if (method.IsVirtual)
+ {
+ AddNative2ManagedMethod(m2nMethod);
+ }
+ }
+ }
+
+ foreach (var method in type.GetConstructors(BindingFlags.Instance | BindingFlags.Public
+| BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy))
+ {
+ if (_optimized && (method.IsPrivate || (method.IsAssembly && !method.IsPublic && !method.IsFamily)))
+ {
+ continue;
+ }
+
+ if (!_optimized || (method.IsFamily || method.IsPublic))
+ {
+ var callMethod = CreateMethodBridgeSig(false, null, method.GetParameters());
+ AddManaged2NativeMethod(callMethod);
+
+ if (type.IsValueType && !method.IsStatic)
+ {
+ var invokeMethod = CreateMethodBridgeSig(false, null, method.GetParameters());
+ AddAdjustThunkMethod(invokeMethod);
+ }
+ }
+ }
+
+ foreach (var subType in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
+ {
+ ScanType(subType);
+ }
+ }
+
+ public void PrepareFromAssemblies()
+ {
+ foreach (var ass in _assemblies)
+ {
+ if (_hotfixAssemblies.Contains(ass))
+ {
+ continue;
+ }
+ //Debug.Log("prepare assembly:" + ass.FullName);
+ foreach (var type in ass.GetTypes())
+ {
+ ScanType(type);
+ }
+ }
+ }
+
+ private void PrepareMethodsFromCustomeGenericTypes()
+ {
+ foreach (var type in GeneratorConfig.PrepareCustomGenericTypes())
+ {
+ ScanType(type);
+ }
+ }
+
+ public void PrepareMethods()
+ {
+ PrepareMethodsFromCustomeGenericTypes();
+
+
+ foreach(var methodSig in _platformAdaptor.IsArch32 ? GeneratorConfig.PrepareCustomMethodSignatures32() : GeneratorConfig.PrepareCustomMethodSignatures64())
+ {
+ var method = MethodBridgeSig.CreateBySignatuer(methodSig);
+ AddManaged2NativeMethod(method);
+ AddAdjustThunkMethod(method);
+ }
+ PrepareFromAssemblies();
+
+ {
+ var sortedMethods = new SortedDictionary();
+ foreach (var method in _managed2nativeMethodSet)
+ {
+ sortedMethods.Add(method.CreateCallSigName(), method);
+ }
+ _managed2nativeMethodList = sortedMethods.Values.ToList();
+ }
+ {
+ var sortedMethods = new SortedDictionary();
+ foreach (var method in _native2managedMethodSet)
+ {
+ sortedMethods.Add(method.CreateCallSigName(), method);
+ }
+ _native2managedMethodList = sortedMethods.Values.ToList();
+ }
+ {
+ var sortedMethods = new SortedDictionary();
+ foreach (var method in _adjustThunkMethodSet)
+ {
+ sortedMethods.Add(method.CreateCallSigName(), method);
+ }
+ _adjustThunkMethodList = sortedMethods.Values.ToList();
+ }
+ }
+
+ public void Generate()
+ {
+ var frr = new FileRegionReplace(GetTemplateFile());
+
+ List lines = new List(20_0000);
+
+ Debug.LogFormat("== managed2native method count:{0}", _managed2nativeMethodList.Count);
+
+ foreach(var method in _managed2nativeMethodList)
+ {
+ _platformAdaptor.GenerateManaged2NativeMethod(method, lines);
+ }
+
+ _platformAdaptor.GenerateManaged2NativeStub(_managed2nativeMethodList, lines);
+
+ Debug.LogFormat("== native2managed method count:{0}", _native2managedMethodList.Count);
+
+ foreach (var method in _native2managedMethodList)
+ {
+ _platformAdaptor.GenerateNative2ManagedMethod(method, lines);
+ }
+
+ _platformAdaptor.GenerateNative2ManagedStub(_native2managedMethodList, lines);
+
+ Debug.LogFormat("== adjustThunk method count:{0}", _adjustThunkMethodList.Count);
+
+ foreach (var method in _adjustThunkMethodList)
+ {
+ _platformAdaptor.GenerateAdjustThunkMethod(method, lines);
+ }
+
+ _platformAdaptor.GenerateAdjustThunkStub(_adjustThunkMethodList, lines);
+
+ frr.Replace("INVOKE_STUB", string.Join("\n", lines));
+
+ Directory.CreateDirectory(Path.GetDirectoryName(_outputFile));
+
+ frr.Commit(_outputFile);
+ }
+
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeGenerator.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeGenerator.cs.meta
new file mode 100644
index 00000000..84054d46
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeGenerator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3171ed79d43e06c4b8c889b0a3f38969
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeSig.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeSig.cs
new file mode 100644
index 00000000..afba4813
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeSig.cs
@@ -0,0 +1,156 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace HybridCLR.Editor.Generators.MethodBridge
+{
+ public class MethodBridgeSig : IEquatable
+ {
+
+ private readonly static Regex s_sigPattern = new Regex(@"^(v|i1|i2|i4|i8|r4|r8|i16|sr|vf2|vf3|vf4|vd2|vd3|vd4|S\d+|A\d+|B\d+|C\d+)+$");
+
+ public static MethodBridgeSig CreateBySignatuer(string sigName)
+ {
+ var re = s_sigPattern.Match(sigName);
+ if (!re.Success)
+ {
+ throw new ArgumentException($"{sigName} is not valid signature");
+ }
+
+ var mbs = new MethodBridgeSig() { ParamInfos = new List()};
+ var sigs = re.Groups[1].Captures;
+ mbs.ReturnInfo = new ReturnInfo() { Type = CreateTypeInfoBySignature(sigs[0].Value)};
+ for(int i = 1; i < sigs.Count; i++)
+ {
+ mbs.ParamInfos.Add(new ParamInfo() { Type = CreateTypeInfoBySignature(sigs[i].Value)});
+ }
+ return mbs;
+ }
+
+
+ private static TypeInfo CreateTypeInfoBySignature(string sigName)
+ {
+ switch(sigName)
+ {
+ case "v": return new TypeInfo(typeof(void), ParamOrReturnType.VOID);
+ case "i1": return new TypeInfo(typeof(sbyte), ParamOrReturnType.I1_U1);
+ case "i2": return new TypeInfo(typeof(short), ParamOrReturnType.I2_U2);
+ case "i4": return new TypeInfo(typeof(int), ParamOrReturnType.I4_U4);
+ case "i8": return new TypeInfo(typeof(long), ParamOrReturnType.I8_U8);
+ case "r4": return new TypeInfo(typeof(float), ParamOrReturnType.R4);
+ case "r8": return new TypeInfo(typeof(double), ParamOrReturnType.R8);
+ case "i16": return TypeInfo.s_i16;
+ case "sr": return TypeInfo.s_ref;
+ case "vf2": return new TypeInfo(null, ParamOrReturnType.ARM64_HFA_FLOAT_2);
+ case "vf3": return new TypeInfo(null, ParamOrReturnType.ARM64_HFA_FLOAT_3);
+ case "vf4": return new TypeInfo(null, ParamOrReturnType.ARM64_HFA_FLOAT_4);
+ case "vd2": return new TypeInfo(null, ParamOrReturnType.ARM64_HFA_DOUBLE_2);
+ case "vd3": return new TypeInfo(null, ParamOrReturnType.ARM64_HFA_DOUBLE_3);
+ case "vd4": return new TypeInfo(null, ParamOrReturnType.ARM64_HFA_DOUBLE_4);
+ default:
+ {
+ if (sigName.StartsWith("S"))
+ {
+ return new TypeInfo(null, ParamOrReturnType.STRUCTURE_ALIGN1, int.Parse(sigName.Substring(1)));
+ }
+ if (sigName.StartsWith("A"))
+ {
+ return new TypeInfo(null, ParamOrReturnType.STRUCTURE_ALIGN2, int.Parse(sigName.Substring(1)));
+ }
+ if (sigName.StartsWith("B"))
+ {
+ return new TypeInfo(null, ParamOrReturnType.STRUCTURE_ALIGN4, int.Parse(sigName.Substring(1)));
+ }
+ if (sigName.StartsWith("C"))
+ {
+ return new TypeInfo(null, ParamOrReturnType.STRUCTURE_ALIGN8, int.Parse(sigName.Substring(1)));
+ }
+ throw new ArgumentException($"invalid signature:{sigName}");
+ }
+ }
+ }
+
+
+ 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;
+ }
+ }
+
+ 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((MethodBridgeSig)obj);
+ }
+
+ public bool Equals(MethodBridgeSig other)
+ {
+ if (other == null)
+ {
+ return false;
+ }
+
+ if (!ReturnInfo.Type.Equals(other.ReturnInfo.Type))
+ {
+ return false;
+ }
+ if (ParamInfos.Count != other.ParamInfos.Count)
+ {
+ return false;
+ }
+ for(int i = 0; i < ParamInfos.Count; i++)
+ {
+ if (!ParamInfos[i].Type.Equals(other.ParamInfos[i].Type))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ int hash = 17;
+
+ hash = hash * 23 + ReturnInfo.Type.GetHashCode();
+
+ foreach(var p in ParamInfos)
+ {
+ hash = hash * 23 + p.Type.GetHashCode();
+ }
+
+ return hash;
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeSig.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeSig.cs.meta
new file mode 100644
index 00000000..8ae3b558
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeSig.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cbe63fb39b5bdcc448f3589b475fb5d8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamInfo.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamInfo.cs
new file mode 100644
index 00000000..5537e19b
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamInfo.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HybridCLR.Editor.Generators.MethodBridge
+{
+
+ public class ParamInfo
+ {
+ public TypeInfo Type { get; set; }
+
+ public int Index { get; set; }
+
+ //public bool IsNative2ManagedByAddress => Type.PorType >= ParamOrReturnType.STRUCT_NOT_PASS_AS_VALUE;
+ public bool IsPassToManagedByAddress => Type.GetParamSlotNum() > 1;
+
+ public bool IsPassToNativeByAddress => Type.PorType == ParamOrReturnType.STRUCTURE_AS_REF_PARAM;
+
+ public string Native2ManagedParamValue(PlatformABI canv)
+ {
+ return IsPassToManagedByAddress ? $"(uint64_t)&__arg{Index}" : $"*(uint64_t*)&__arg{Index}";
+ }
+
+ public string Managed2NativeParamValue(PlatformABI canv)
+ {
+ return IsPassToNativeByAddress ? $"(uint64_t)(localVarBase+argVarIndexs[{Index}])" : $"*({Type.GetTypeName()}*)(localVarBase+argVarIndexs[{Index}])";
+ }
+ }
+
+ public class ReturnInfo
+ {
+ public TypeInfo Type { get; set; }
+
+ public bool IsVoid => Type.PorType == ParamOrReturnType.VOID;
+
+ public int GetParamSlotNum(PlatformABI canv)
+ {
+ return Type.GetParamSlotNum();
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamInfo.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamInfo.cs.meta
new file mode 100644
index 00000000..517be646
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamInfo.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c04e163336b93af44b4b565d0ab195e2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamOrReturnType.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamOrReturnType.cs
new file mode 100644
index 00000000..08e71134
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamOrReturnType.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HybridCLR.Editor.Generators.MethodBridge
+{
+ public enum ParamOrReturnType
+ {
+ VOID,
+ I1_U1,
+ //U1,
+ I2_U2,
+ //U2,
+ I4_U4,
+ I8_U8,
+ //I_U,
+ R4,
+ R8,
+ ARM64_HFA_FLOAT_2,
+ VALUE_TYPE_SIZE_LESS_EQUAL_8,
+ I16, // 8 < size <= 16
+ STRUCT_NOT_PASS_AS_VALUE, // struct pass not as value
+ STRUCTURE_AS_REF_PARAM, // size > 16
+ ARM64_HFA_FLOAT_3,
+ ARM64_HFA_FLOAT_4,
+ ARM64_HFA_DOUBLE_2,
+ ARM64_HFA_DOUBLE_3,
+ ARM64_HFA_DOUBLE_4,
+ ARM64_HVA_8,
+ ARM64_HVA_16,
+ STRUCTURE_ALIGN1, // size > 16
+ STRUCTURE_ALIGN2,
+ STRUCTURE_ALIGN4,
+ STRUCTURE_ALIGN8,
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamOrReturnType.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamOrReturnType.cs.meta
new file mode 100644
index 00000000..78fd4e0c
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ParamOrReturnType.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7886905937fafb64999dc4e358565982
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformABI.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformABI.cs
new file mode 100644
index 00000000..8c94e8b3
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformABI.cs
@@ -0,0 +1,9 @@
+namespace HybridCLR.Editor.Generators.MethodBridge
+{
+ public enum PlatformABI
+ {
+ Universal32,
+ Universal64,
+ Arm64,
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformABI.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformABI.cs.meta
new file mode 100644
index 00000000..e2574724
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformABI.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: deee8d06a7f05bf4d9ab4b78f0a8a47c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptorBase.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptorBase.cs
new file mode 100644
index 00000000..98358812
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptorBase.cs
@@ -0,0 +1,160 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+
+namespace HybridCLR.Editor.Generators.MethodBridge
+{
+ internal abstract class PlatformAdaptorBase : IPlatformAdaptor
+ {
+ public abstract bool IsArch32 { get; }
+
+ public abstract TypeInfo PointerType { get; }
+
+ protected abstract Dictionary CacheTypes { get; }
+
+ protected abstract TypeInfo CreateValueType(Type type, bool returnValue);
+
+ public abstract void GenerateManaged2NativeMethod(MethodBridgeSig method, List lines);
+
+ public abstract void GenerateNative2ManagedMethod(MethodBridgeSig method, List lines);
+
+ public abstract void GenerateAdjustThunkMethod(MethodBridgeSig method, List outputLines);
+
+ private static Dictionary _typeSizeCache64 = new Dictionary();
+
+ private static Dictionary _typeSizeCache32 = new Dictionary();
+
+ private static ValueTypeSizeAligmentCalculator s_calculator64 = new ValueTypeSizeAligmentCalculator(false);
+
+ private static ValueTypeSizeAligmentCalculator s_calculator32 = new ValueTypeSizeAligmentCalculator(true);
+
+ public static (int Size, int Aligment) ComputeSizeAndAligmentOfArch64(Type t)
+ {
+ if (_typeSizeCache64.TryGetValue(t, out var sizeAndAligment))
+ {
+ return sizeAndAligment;
+ }
+ // all this just to invoke one opcode with no arguments!
+ var method = new DynamicMethod("ComputeSizeOfImpl", typeof(int), Type.EmptyTypes, typeof(PlatformAdaptorBase), false);
+ var gen = method.GetILGenerator();
+ gen.Emit(OpCodes.Sizeof, t);
+ gen.Emit(OpCodes.Ret);
+ int clrSize = ((Func)method.CreateDelegate(typeof(Func)))();
+
+ sizeAndAligment = s_calculator64.SizeAndAligmentOf(t);
+ int customSize = sizeAndAligment.Item1;
+ if (customSize != clrSize)
+ {
+ s_calculator64.SizeAndAligmentOf(t);
+ Debug.LogError($"type:{t} size calculate error. HybridCLR Comput:{sizeAndAligment} CLR:{clrSize}");
+ }
+ _typeSizeCache64.Add(t, sizeAndAligment);
+ return sizeAndAligment;
+ }
+
+ protected static (int Size, int Aligment) ComputeSizeAndAligmentOfArch32(Type t)
+ {
+ if (_typeSizeCache32.TryGetValue(t, out var sa))
+ {
+ return sa;
+ }
+ // all this just to invoke one opcode with no arguments!
+ sa = s_calculator32.SizeAndAligmentOf(t);
+ _typeSizeCache32.Add(t, sa);
+ return sa;
+ }
+
+ public TypeInfo CreateTypeInfo(Type type, bool returnValue)
+ {
+ if (type.IsByRef)
+ {
+ return PointerType;
+ }
+ if (type == typeof(void))
+ {
+ return TypeInfo.s_void;
+ }
+ if (!type.IsValueType)
+ {
+ return PointerType;
+ }
+ if (CacheTypes.TryGetValue(type, out var cache))
+ {
+ return cache;
+ }
+ if (type.IsEnum)
+ {
+ return CreateTypeInfo(type.GetEnumUnderlyingType(), returnValue);
+ }
+ var ti = CreateValueType(type, returnValue);
+ // s_typeInfoCaches.Add(type, ti);
+ return ti;
+ }
+
+ protected static TypeInfo CreateGeneralValueType(Type type, int size, int aligment)
+ {
+ Debug.Assert(size % aligment == 0);
+ switch (aligment)
+ {
+ case 1: return new TypeInfo(type, ParamOrReturnType.STRUCTURE_ALIGN1, size);
+ case 2: return new TypeInfo(type, ParamOrReturnType.STRUCTURE_ALIGN2, size);
+ case 4: return new TypeInfo(type, ParamOrReturnType.STRUCTURE_ALIGN4, size);
+ case 8: return new TypeInfo(type, ParamOrReturnType.STRUCTURE_ALIGN8, size);
+ default: throw new NotSupportedException($"type:{type} not support aligment:{aligment}");
+ }
+ }
+
+ 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("};");
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptorBase.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptorBase.cs.meta
new file mode 100644
index 00000000..f18ef365
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptorBase.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ebf14107fd82b364cb7d61276d444829
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Arm64.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Arm64.cs
new file mode 100644
index 00000000..c0f063a1
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Arm64.cs
@@ -0,0 +1,208 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+
+namespace HybridCLR.Editor.Generators.MethodBridge
+{
+ internal class PlatformAdaptor_Arm64 : PlatformAdaptorBase
+ {
+
+ private static readonly Dictionary s_typeInfoCaches = new Dictionary()
+ {
+ { typeof(void), new TypeInfo(typeof(void), ParamOrReturnType.VOID)},
+ { typeof(bool), new TypeInfo(typeof(bool), ParamOrReturnType.I1_U1)},
+ { typeof(byte), new TypeInfo(typeof(byte), ParamOrReturnType.I1_U1)},
+ { typeof(sbyte), new TypeInfo(typeof(sbyte), ParamOrReturnType.I1_U1) },
+ { typeof(short), new TypeInfo(typeof(short), ParamOrReturnType.I2_U2) },
+ { typeof(ushort), new TypeInfo(typeof(ushort), ParamOrReturnType.I2_U2) },
+ { typeof(char), new TypeInfo(typeof(char), ParamOrReturnType.I2_U2) },
+ { typeof(int), new TypeInfo(typeof(int), ParamOrReturnType.I4_U4) },
+ { typeof(uint), new TypeInfo(typeof(uint), ParamOrReturnType.I4_U4) },
+ { typeof(long), new TypeInfo(typeof(long), ParamOrReturnType.I8_U8) },
+ { typeof(ulong), new TypeInfo(typeof(ulong), ParamOrReturnType.I8_U8)},
+ { typeof(float), new TypeInfo(typeof(float), ParamOrReturnType.R4)},
+ { typeof(double), new TypeInfo(typeof(double), ParamOrReturnType.R8)},
+ { typeof(IntPtr), new TypeInfo(null, ParamOrReturnType.I8_U8)},
+ { typeof(UIntPtr), new TypeInfo(null, ParamOrReturnType.I8_U8)},
+ { typeof(Vector2), new TypeInfo(typeof(Vector2), ParamOrReturnType.ARM64_HFA_FLOAT_2) },
+ { typeof(Vector3), new TypeInfo(typeof(Vector3), ParamOrReturnType.ARM64_HFA_FLOAT_3) },
+ { typeof(Vector4), new TypeInfo(typeof(Vector4), ParamOrReturnType.ARM64_HFA_FLOAT_4) },
+ { typeof(System.Numerics.Vector2), new TypeInfo(typeof(System.Numerics.Vector2), ParamOrReturnType.ARM64_HFA_FLOAT_2) },
+ { typeof(System.Numerics.Vector3), new TypeInfo(typeof(System.Numerics.Vector3), ParamOrReturnType.ARM64_HFA_FLOAT_3) },
+ { typeof(System.Numerics.Vector4), new TypeInfo(typeof(System.Numerics.Vector4), ParamOrReturnType.ARM64_HFA_FLOAT_4) },
+ };
+
+ public PlatformABI CallConventionType { get; } = PlatformABI.Universal64;
+
+ public override bool IsArch32 => false;
+
+ public override TypeInfo PointerType => TypeInfo.s_i8u8;
+
+ protected override Dictionary CacheTypes => s_typeInfoCaches;
+
+ public class HFATypeInfo
+ {
+ public Type Type { get; set; }
+
+ public int Count { get; set; }
+ }
+
+ private static bool IsNotHFAFastCheck(int typeSize)
+ {
+ return typeSize != 8 && typeSize != 12 && typeSize != 16 && typeSize != 24 && typeSize != 32;
+ }
+
+ private static bool ComputHFATypeInfo0(Type type, HFATypeInfo typeInfo)
+ {
+ var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ foreach (var field in fields)
+ {
+ Type ftype = field.FieldType;
+ if (ftype != typeof(float) && ftype != typeof(double))
+ {
+ if (!ftype.IsPrimitive && ftype.IsValueType)
+ {
+ if (!ComputHFATypeInfo0(ftype, typeInfo))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (ftype == typeInfo.Type || typeInfo.Type == null)
+ {
+ typeInfo.Type = ftype;
+ ++typeInfo.Count;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ return typeInfo.Count <= 4;
+ }
+
+ public static bool ComputHFATypeInfo(Type type, int typeSize, out HFATypeInfo typeInfo)
+ {
+ typeInfo = new HFATypeInfo();
+ if (IsNotHFAFastCheck(typeSize))
+ {
+ return false;
+ }
+ bool ok = ComputHFATypeInfo0(type, typeInfo);
+ if (ok && typeInfo.Count >= 2 && typeInfo.Count <= 4)
+ {
+ int fieldSize = typeInfo.Type == typeof(float) ? 4 : 8;
+ return typeSize == fieldSize * typeInfo.Count;
+ }
+ return false;
+ }
+
+ protected override TypeInfo CreateValueType(Type type, bool returnValue)
+ {
+ (int typeSize, int typeAligment) = ComputeSizeAndAligmentOfArch64(type);
+ if (ComputHFATypeInfo(type, typeSize, out HFATypeInfo hfaTypeInfo))
+ {
+ if (hfaTypeInfo.Type == typeof(float))
+ {
+ switch (hfaTypeInfo.Count)
+ {
+ case 2: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_FLOAT_2);
+ case 3: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_FLOAT_3);
+ case 4: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_FLOAT_4);
+ default: throw new NotSupportedException();
+ }
+ }
+ else
+ {
+ Debug.Assert(hfaTypeInfo.Type == typeof(double));
+ switch (hfaTypeInfo.Count)
+ {
+ case 2: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_DOUBLE_2);
+ case 3: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_DOUBLE_3);
+ case 4: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_DOUBLE_4);
+ default: throw new NotSupportedException();
+ }
+ }
+ }
+ else
+ {
+ // 64位下结构体内存对齐规则是一样的
+ return CreateArm64GeneralValueType(type, typeSize,returnValue);
+ }
+
+ }
+
+ private TypeInfo CreateArm64GeneralValueType(Type type, int typeSize, bool returnValue)
+ {
+ if (typeSize <= 8)
+ {
+ return TypeInfo.s_i8u8;
+ }
+ if (typeSize <= 16)
+ {
+ return TypeInfo.s_i16;
+ }
+ if (returnValue)
+ {
+ return new TypeInfo(type, ParamOrReturnType.STRUCTURE_ALIGN1, typeSize);
+ }
+ return TypeInfo.s_ref;
+ }
+
+ public override void GenerateManaged2NativeMethod(MethodBridgeSig method, List lines)
+ {
+ int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+ 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 => p.Managed2NativeParamValue(this.CallConventionType)).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)(GetInterpreterDirectlyCallMethodPointer(method)))({paramNameListStr});
+}}
+");
+ }
+
+ public override void GenerateNative2ManagedMethod(MethodBridgeSig method, List lines)
+ {
+ int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+ 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_{method.CreateCallSigName()}({paramListStr})
+{{
+ StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => p.Native2ManagedParamValue(this.CallConventionType)))} }};
+ StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
+ Interpreter::Execute(method, args, ret);
+ {(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
+}}
+");
+ }
+
+ public override void GenerateAdjustThunkMethod(MethodBridgeSig method, List lines)
+ {
+ int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+
+ 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_{method.CreateCallSigName()}({paramListStr})
+{{
+ StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => (p.Index == 0 ? $"(uint64_t)(*(uint8_t**)&__arg{p.Index} + sizeof(Il2CppObject))" : p.Native2ManagedParamValue(this.CallConventionType))))} }};
+ StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
+ Interpreter::Execute(method, args, ret);
+ {(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
+}}
+");
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Arm64.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Arm64.cs.meta
new file mode 100644
index 00000000..4b9a4a12
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Arm64.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bff17a6e8ee060c4eb9ac97fcf30bf78
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal32.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal32.cs
new file mode 100644
index 00000000..6201a9fb
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal32.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+
+namespace HybridCLR.Editor.Generators.MethodBridge
+{
+ internal class PlatformAdaptor_Universal32 : PlatformAdaptorBase
+ {
+
+ private static readonly Dictionary s_typeInfoCaches = new Dictionary()
+ {
+ { typeof(void), new TypeInfo(typeof(void), ParamOrReturnType.VOID)},
+ { typeof(bool), new TypeInfo(typeof(bool), ParamOrReturnType.I1_U1)},
+ { typeof(byte), new TypeInfo(typeof(byte), ParamOrReturnType.I1_U1)},
+ { typeof(sbyte), new TypeInfo(typeof(sbyte), ParamOrReturnType.I1_U1) },
+ { typeof(short), new TypeInfo(typeof(short), ParamOrReturnType.I2_U2) },
+ { typeof(ushort), new TypeInfo(typeof(ushort), ParamOrReturnType.I2_U2) },
+ { typeof(char), new TypeInfo(typeof(char), ParamOrReturnType.I2_U2) },
+ { typeof(int), new TypeInfo(typeof(int), ParamOrReturnType.I4_U4) },
+ { typeof(uint), new TypeInfo(typeof(uint), ParamOrReturnType.I4_U4) },
+ { typeof(long), new TypeInfo(typeof(long), ParamOrReturnType.I8_U8) },
+ { typeof(ulong), new TypeInfo(typeof(ulong), ParamOrReturnType.I8_U8)},
+ { typeof(float), new TypeInfo(typeof(float), ParamOrReturnType.R4)},
+ { typeof(double), new TypeInfo(typeof(double), ParamOrReturnType.R8)},
+ { typeof(IntPtr), new TypeInfo(null, ParamOrReturnType.I4_U4)},
+ { typeof(UIntPtr), new TypeInfo(null, ParamOrReturnType.I4_U4)},
+ };
+
+
+ public PlatformABI CallConventionType { get; } = PlatformABI.Universal32;
+
+ public override bool IsArch32 => true;
+
+ public override TypeInfo PointerType => TypeInfo.s_i4u4;
+
+ protected override Dictionary CacheTypes => s_typeInfoCaches;
+
+ protected override TypeInfo CreateValueType(Type type, bool returnValue)
+ {
+ (int typeSize, int typeAligment) = ComputeSizeAndAligmentOfArch32(type);
+ int actualAliment = typeAligment <= 4 ? 1 : 8;
+ return CreateGeneralValueType(type, typeSize, actualAliment);
+ }
+
+ public override void GenerateManaged2NativeMethod(MethodBridgeSig 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 => p.Managed2NativeParamValue(this.CallConventionType)).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)(GetInterpreterDirectlyCallMethodPointer(method)))({paramNameListStr});
+}}
+");
+ }
+ public override void GenerateNative2ManagedMethod(MethodBridgeSig method, List lines)
+ {
+ int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+ 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_{method.CreateCallSigName()}({paramListStr})
+{{
+ StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => p.Native2ManagedParamValue(this.CallConventionType)))} }};
+ StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
+ Interpreter::Execute(method, args, ret);
+ {(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
+}}
+");
+ }
+ public override void GenerateAdjustThunkMethod(MethodBridgeSig method, List lines)
+ {
+ int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+
+ 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_{method.CreateCallSigName()}({paramListStr})
+{{
+ StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => (p.Index == 0 ? $"(uint64_t)(*(uint8_t**)&__arg{p.Index} + sizeof(Il2CppObject))" : p.Native2ManagedParamValue(this.CallConventionType))))} }};
+ StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
+ Interpreter::Execute(method, args, ret);
+ {(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
+}}
+");
+
+ }
+ }
+
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal32.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal32.cs.meta
new file mode 100644
index 00000000..3b2f55a1
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal32.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fb741900113b22443a2054ddba6b131b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal64.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal64.cs
new file mode 100644
index 00000000..7bdf0962
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal64.cs
@@ -0,0 +1,189 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+
+namespace HybridCLR.Editor.Generators.MethodBridge
+{
+ internal class PlatformAdaptor_Universal64 : PlatformAdaptorBase
+ {
+
+ private static readonly Dictionary s_typeInfoCaches = new Dictionary()
+ {
+ { typeof(void), new TypeInfo(typeof(void), ParamOrReturnType.VOID)},
+ { typeof(bool), new TypeInfo(typeof(bool), ParamOrReturnType.I1_U1)},
+ { typeof(byte), new TypeInfo(typeof(byte), ParamOrReturnType.I1_U1)},
+ { typeof(sbyte), new TypeInfo(typeof(sbyte), ParamOrReturnType.I1_U1) },
+ { typeof(short), new TypeInfo(typeof(short), ParamOrReturnType.I2_U2) },
+ { typeof(ushort), new TypeInfo(typeof(ushort), ParamOrReturnType.I2_U2) },
+ { typeof(char), new TypeInfo(typeof(char), ParamOrReturnType.I2_U2) },
+ { typeof(int), new TypeInfo(typeof(int), ParamOrReturnType.I4_U4) },
+ { typeof(uint), new TypeInfo(typeof(uint), ParamOrReturnType.I4_U4) },
+ { typeof(long), new TypeInfo(typeof(long), ParamOrReturnType.I8_U8) },
+ { typeof(ulong), new TypeInfo(typeof(ulong), ParamOrReturnType.I8_U8)},
+ { typeof(float), new TypeInfo(typeof(float), ParamOrReturnType.R4)},
+ { typeof(double), new TypeInfo(typeof(double), ParamOrReturnType.R8)},
+ { typeof(IntPtr), new TypeInfo(null, ParamOrReturnType.I8_U8)},
+ { typeof(UIntPtr), new TypeInfo(null, ParamOrReturnType.I8_U8)},
+ { typeof(Vector2), new TypeInfo(typeof(Vector2), ParamOrReturnType.ARM64_HFA_FLOAT_2) },
+ { typeof(Vector3), new TypeInfo(typeof(Vector3), ParamOrReturnType.ARM64_HFA_FLOAT_3) },
+ { typeof(Vector4), new TypeInfo(typeof(Vector4), ParamOrReturnType.ARM64_HFA_FLOAT_4) },
+ { typeof(System.Numerics.Vector2), new TypeInfo(typeof(System.Numerics.Vector2), ParamOrReturnType.ARM64_HFA_FLOAT_2) },
+ { typeof(System.Numerics.Vector3), new TypeInfo(typeof(System.Numerics.Vector3), ParamOrReturnType.ARM64_HFA_FLOAT_3) },
+ { typeof(System.Numerics.Vector4), new TypeInfo(typeof(System.Numerics.Vector4), ParamOrReturnType.ARM64_HFA_FLOAT_4) },
+ };
+
+ public PlatformABI CallConventionType { get; } = PlatformABI.Universal64;
+
+ public override bool IsArch32 => false;
+
+ public override TypeInfo PointerType => TypeInfo.s_i8u8;
+
+ protected override Dictionary CacheTypes => s_typeInfoCaches;
+
+ public class HFATypeInfo
+ {
+ public Type Type { get; set; }
+
+ public int Count { get; set; }
+ }
+
+ private static bool IsNotHFAFastCheck(int typeSize)
+ {
+ return typeSize != 8 && typeSize != 12 && typeSize != 16 && typeSize != 24 && typeSize != 32;
+ }
+
+ private static bool ComputHFATypeInfo0(Type type, HFATypeInfo typeInfo)
+ {
+ var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ foreach (var field in fields)
+ {
+ Type ftype = field.FieldType;
+ if (ftype != typeof(float) && ftype != typeof(double))
+ {
+ if (!ftype.IsPrimitive && ftype.IsValueType)
+ {
+ if (!ComputHFATypeInfo0(ftype, typeInfo))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (ftype == typeInfo.Type || typeInfo.Type == null)
+ {
+ typeInfo.Type = ftype;
+ ++typeInfo.Count;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ return typeInfo.Count <= 4;
+ }
+
+ public static bool ComputHFATypeInfo(Type type, int typeSize, out HFATypeInfo typeInfo)
+ {
+ typeInfo = new HFATypeInfo();
+ if (IsNotHFAFastCheck(typeSize))
+ {
+ return false;
+ }
+ bool ok = ComputHFATypeInfo0(type, typeInfo);
+ if (ok && typeInfo.Count >= 2 && typeInfo.Count <= 4)
+ {
+ int fieldSize = typeInfo.Type == typeof(float) ? 4 : 8;
+ return typeSize == fieldSize * typeInfo.Count;
+ }
+ return false;
+ }
+
+ protected override TypeInfo CreateValueType(Type type, bool returnValue)
+ {
+ (int typeSize, int typeAligment) = ComputeSizeAndAligmentOfArch64(type);
+ if (ComputHFATypeInfo(type, typeSize, out HFATypeInfo hfaTypeInfo))
+ {
+ if (hfaTypeInfo.Type == typeof(float))
+ {
+ switch (hfaTypeInfo.Count)
+ {
+ case 2: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_FLOAT_2);
+ case 3: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_FLOAT_3);
+ case 4: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_FLOAT_4);
+ default: throw new NotSupportedException();
+ }
+ }
+ else
+ {
+ Debug.Assert(hfaTypeInfo.Type == typeof(double));
+ switch (hfaTypeInfo.Count)
+ {
+ case 2: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_DOUBLE_2);
+ case 3: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_DOUBLE_3);
+ case 4: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_DOUBLE_4);
+ default: throw new NotSupportedException();
+ }
+ }
+ }
+ else
+ {
+ // 64位下结构体内存对齐规则是一样的
+ return CreateGeneralValueType(type, typeSize, 1 /*typeAligment*/);
+ }
+
+ }
+
+ public override void GenerateManaged2NativeMethod(MethodBridgeSig method, List lines)
+ {
+ int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+
+ string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" }));
+ string paramTypeListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()}").Concat(new string[] { "const MethodInfo*" })); ;
+ string paramNameListStr = string.Join(", ", method.ParamInfos.Select(p => p.Managed2NativeParamValue(this.CallConventionType)).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)(GetInterpreterDirectlyCallMethodPointer(method)))({paramNameListStr});
+}}
+");
+ }
+ public override void GenerateNative2ManagedMethod(MethodBridgeSig method, List lines)
+ {
+ int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+ 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_{method.CreateCallSigName()}({paramListStr})
+{{
+ StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => p.Native2ManagedParamValue(this.CallConventionType)))} }};
+ StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
+ Interpreter::Execute(method, args, ret);
+ {(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
+}}
+");
+ }
+
+ public override void GenerateAdjustThunkMethod(MethodBridgeSig method, List lines)
+ {
+ int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+ 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_{method.CreateCallSigName()}({paramListStr})
+{{
+ StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => (p.Index == 0 ? $"(uint64_t)(*(uint8_t**)&__arg{p.Index} + sizeof(Il2CppObject))" : p.Native2ManagedParamValue(this.CallConventionType))))} }};
+ StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
+ Interpreter::Execute(method, args, ret);
+ {(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
+}}
+");
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal64.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal64.cs.meta
new file mode 100644
index 00000000..d782aae7
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal64.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 26324be9505c9f54996bcbb62ba49132
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/SignatureProviderAttribute.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/SignatureProviderAttribute.cs
new file mode 100644
index 00000000..d02a888a
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/SignatureProviderAttribute.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HybridCLR.Editor.Generators.MethodBridge
+{
+ [AttributeUsage(AttributeTargets.Method)]
+ public class SignatureProviderAttribute : Attribute
+ {
+ public List Platforms { get; }
+
+ public SignatureProviderAttribute(params PlatformABI[] platforms)
+ {
+ Platforms = new List(platforms);
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/SignatureProviderAttribute.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/SignatureProviderAttribute.cs.meta
new file mode 100644
index 00000000..939362c2
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/SignatureProviderAttribute.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 50c5ec2d43d3fda4a8b8cfa75cb37a74
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/TypeInfo.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/TypeInfo.cs
new file mode 100644
index 00000000..437aeecf
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/TypeInfo.cs
@@ -0,0 +1,132 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using UnityEngine;
+
+namespace HybridCLR.Editor.Generators.MethodBridge
+{
+ public class TypeInfo : IEquatable
+ {
+
+ public static readonly TypeInfo s_void = new TypeInfo(typeof(void), ParamOrReturnType.VOID);
+ public static readonly TypeInfo s_i4u4 = new TypeInfo(null, ParamOrReturnType.I4_U4);
+ public static readonly TypeInfo s_i8u8 = new TypeInfo(null, ParamOrReturnType.I8_U8);
+ public static readonly TypeInfo s_i16 = new TypeInfo(null, ParamOrReturnType.I16);
+ public static readonly TypeInfo s_ref = new TypeInfo(null, ParamOrReturnType.STRUCTURE_AS_REF_PARAM);
+
+ public TypeInfo(Type type, ParamOrReturnType portype)
+ {
+ this.Type = type;
+ PorType = portype;
+ Size = 0;
+ }
+
+ public TypeInfo(Type type, ParamOrReturnType portype, int size)
+ {
+ this.Type = type;
+ PorType = portype;
+ Size = size;
+ }
+
+ public Type Type { get; }
+
+ public ParamOrReturnType PorType { get; }
+
+ public int Size { get; }
+
+ public bool Equals(TypeInfo other)
+ {
+ return PorType == other.PorType && Size == other.Size;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals((TypeInfo)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return (int)PorType * 23 + Size;
+ }
+
+ public string CreateSigName()
+ {
+ switch (PorType)
+ {
+ case ParamOrReturnType.VOID: return "v";
+ case ParamOrReturnType.I1_U1: return "i1";
+ case ParamOrReturnType.I2_U2: return "i2";
+ case ParamOrReturnType.I4_U4: return "i4";
+ case ParamOrReturnType.I8_U8: return "i8";
+ case ParamOrReturnType.R4: return "r4";
+ case ParamOrReturnType.R8: return "r8";
+ case ParamOrReturnType.I16: return "i16";
+ case ParamOrReturnType.STRUCTURE_AS_REF_PARAM: return "sr";
+ case ParamOrReturnType.ARM64_HFA_FLOAT_2: return "vf2";
+ case ParamOrReturnType.ARM64_HFA_FLOAT_3: return "vf3";
+ case ParamOrReturnType.ARM64_HFA_FLOAT_4: return "vf4";
+ case ParamOrReturnType.ARM64_HFA_DOUBLE_2: return "vd2";
+ case ParamOrReturnType.ARM64_HFA_DOUBLE_3: return "vd3";
+ case ParamOrReturnType.ARM64_HFA_DOUBLE_4: return "vd4";
+ case ParamOrReturnType.STRUCTURE_ALIGN1: return "S" + Size;
+ case ParamOrReturnType.STRUCTURE_ALIGN2: return "A" + Size;
+ case ParamOrReturnType.STRUCTURE_ALIGN4: return "B" + Size;
+ case ParamOrReturnType.STRUCTURE_ALIGN8: return "C" + Size;
+ default: throw new NotSupportedException(PorType.ToString());
+ };
+ }
+
+ public string GetTypeName()
+ {
+ switch (PorType)
+ {
+ case ParamOrReturnType.VOID: return "void";
+ case ParamOrReturnType.I1_U1: return "int8_t";
+ case ParamOrReturnType.I2_U2: return "int16_t";
+ case ParamOrReturnType.I4_U4: return "int32_t";
+ case ParamOrReturnType.I8_U8: return "int64_t";
+ case ParamOrReturnType.R4: return "float";
+ case ParamOrReturnType.R8: return "double";
+ case ParamOrReturnType.I16: return "ValueTypeSize16";
+ case ParamOrReturnType.STRUCTURE_AS_REF_PARAM: return "uint64_t";
+ case ParamOrReturnType.ARM64_HFA_FLOAT_2: return "HtVector2f";
+ case ParamOrReturnType.ARM64_HFA_FLOAT_3: return "HtVector3f";
+ case ParamOrReturnType.ARM64_HFA_FLOAT_4: return "HtVector4f";
+ case ParamOrReturnType.ARM64_HFA_DOUBLE_2: return "HtVector2d";
+ case ParamOrReturnType.ARM64_HFA_DOUBLE_3: return "HtVector3d";
+ case ParamOrReturnType.ARM64_HFA_DOUBLE_4: return "HtVector4d";
+ case ParamOrReturnType.STRUCTURE_ALIGN1: return $"ValueTypeSize<{Size}>";
+ case ParamOrReturnType.STRUCTURE_ALIGN2: return $"ValueTypeSizeAlign2<{Size}>";
+ case ParamOrReturnType.STRUCTURE_ALIGN4: return $"ValueTypeSizeAlign4<{Size}>";
+ case ParamOrReturnType.STRUCTURE_ALIGN8: return $"ValueTypeSizeAlign8<{Size}>";
+ default: throw new NotImplementedException(PorType.ToString());
+ };
+ }
+ public int GetParamSlotNum()
+ {
+ switch (PorType)
+ {
+ case ParamOrReturnType.VOID: return 0;
+ case ParamOrReturnType.I16: return 2;
+ case ParamOrReturnType.STRUCTURE_AS_REF_PARAM: return 1;
+ case ParamOrReturnType.ARM64_HFA_FLOAT_3: return 2;
+ case ParamOrReturnType.ARM64_HFA_FLOAT_4: return 2;
+ case ParamOrReturnType.ARM64_HFA_DOUBLE_2: return 2;
+ case ParamOrReturnType.ARM64_HFA_DOUBLE_3: return 3;
+ case ParamOrReturnType.ARM64_HFA_DOUBLE_4: return 4;
+ case ParamOrReturnType.ARM64_HVA_8:
+ case ParamOrReturnType.ARM64_HVA_16: throw new NotSupportedException();
+ case ParamOrReturnType.STRUCTURE_ALIGN1:
+ case ParamOrReturnType.STRUCTURE_ALIGN2:
+ case ParamOrReturnType.STRUCTURE_ALIGN4:
+ case ParamOrReturnType.STRUCTURE_ALIGN8: return (Size + 7) / 8;
+ default:
+ {
+ Debug.Assert(PorType < ParamOrReturnType.STRUCT_NOT_PASS_AS_VALUE);
+ Debug.Assert(Size <= 8);
+ return 1;
+ }
+ }
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/TypeInfo.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/TypeInfo.cs.meta
new file mode 100644
index 00000000..1ba9358d
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/TypeInfo.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5afd7344483678a4abcb56158fd1442d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ValueTypeSizeAligmentCalculator.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ValueTypeSizeAligmentCalculator.cs
new file mode 100644
index 00000000..c1ca7d4a
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ValueTypeSizeAligmentCalculator.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HybridCLR.Editor.Generators.MethodBridge
+{
+
+
+ public class ValueTypeSizeAligmentCalculator
+ {
+ private static Dictionary s_primitives = new Dictionary(14) {
+ { "Byte", 1 },
+ { "SByte", 1 },
+ { "Boolean", 1 },
+ { "Int16", 2 },
+ { "UInt16", 2 },
+ { "Char", 2 },
+ { "Int32", 4 },
+ { "UInt32", 4 },
+ { "Single", 4 },
+ { "Int64", 8 },
+ { "UInt64", 8 },
+ { "Double", 8 },
+ //{ "IntPtr", _referenceSize }, // so rule return the same results
+ //{ "UIntPtr", _referenceSize }, // on 32 and 64 bits architectures
+ };
+
+ public ValueTypeSizeAligmentCalculator(bool arch32)
+ {
+ _referenceSize = arch32 ? 4 : 8;
+ }
+
+ // actually we should use IntPtr.Size but that would make the rule
+ // return different results on 64 bits systems
+ private readonly int _referenceSize;
+
+ // Note: Needs to be public since this is being tested by our unit tests
+
+
+ private static bool IsIgnoreField(FieldInfo field)
+ {
+ var ignoreAttr = field.GetCustomAttributes().Where(a => a.GetType().Name == "IgnoreAttribute").FirstOrDefault();
+ if (ignoreAttr == null)
+ {
+ return false;
+ }
+
+ var p = ignoreAttr.GetType().GetProperty("DoesNotContributeToSize");
+ return (bool)p.GetValue(ignoreAttr);
+ }
+
+ private (int Size, int Aligment) SizeAndAligmentOfStruct(Type type)
+ {
+ int totalSize = 0;
+ int packAligment = 8;
+ int maxAligment = 1;
+
+ StructLayoutAttribute sa = type.StructLayoutAttribute;
+ if (sa != null && sa.Pack > 0)
+ {
+ packAligment = sa.Pack;
+ }
+ bool useSLSize = true;
+ foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
+ {
+ // add size of the type
+ var (fs, fa) = SizeAndAligmentOf(field.FieldType);
+ fa = Math.Min(fa, packAligment);
+ if (fa > maxAligment)
+ {
+ maxAligment = fa;
+ }
+ if (IsIgnoreField(field))
+ {
+ continue;
+ }
+ if (sa != null && sa.Value == LayoutKind.Explicit)
+ {
+ int offset = field.GetCustomAttribute().Value;
+ totalSize = Math.Max(totalSize, offset + fs);
+ if (offset > sa.Size)
+ {
+ useSLSize = false;
+ }
+ }
+ else
+ {
+ if (totalSize % fa != 0)
+ {
+ totalSize = (totalSize + fa - 1) / fa * fa;
+ }
+ totalSize += fs;
+ if (sa != null && sa.Value == LayoutKind.Sequential && totalSize > sa.Size)
+ {
+ useSLSize = false;
+ }
+ }
+ }
+ if (totalSize == 0)
+ {
+ totalSize = maxAligment;
+ }
+ if (totalSize % maxAligment != 0)
+ {
+ totalSize = (totalSize + maxAligment - 1) / maxAligment * maxAligment;
+ }
+ if (sa != null && sa.Size > 0)
+ {
+ if (/*sa.Value == LayoutKind.Explicit &&*/ useSLSize)
+ {
+ totalSize = sa.Size;
+ while(totalSize % maxAligment != 0)
+ {
+ maxAligment /= 2;
+ }
+ }
+ }
+ return (totalSize, maxAligment);
+ }
+
+ public (int Size, int Aligment) SizeAndAligmentOf(Type type)
+ {
+ if (type.IsByRef || !type.IsValueType || type.IsArray)
+ return (_referenceSize, _referenceSize);
+
+ // list based on Type.IsPrimitive
+ if (type.Namespace == "System")
+ {
+ if (s_primitives.TryGetValue(type.Name, out var size))
+ {
+ return (size, size);
+ }
+ if (type.Name == "IntPtr" || type.Name == "UIntPtr")
+ {
+ return (_referenceSize, _referenceSize);
+ }
+ }
+ if (type.IsEnum)
+ return SizeAndAligmentOf(type.GetEnumUnderlyingType());
+
+ return SizeAndAligmentOfStruct(type);
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ValueTypeSizeAligmentCalculator.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ValueTypeSizeAligmentCalculator.cs.meta
new file mode 100644
index 00000000..97cf075f
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/MethodBridge/ValueTypeSizeAligmentCalculator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 49b3dbcebadb1b543a42e01afec07ed1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/TemplateUtil.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/TemplateUtil.cs
new file mode 100644
index 00000000..1373b61c
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/TemplateUtil.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HybridCLR.Editor.Generators
+{
+ public static class TemplateUtil
+ {
+ public static string EscapeIntegerName(int i)
+ {
+ return i >= 0 ? i.ToString() : "minus" + (-i);
+ }
+
+ 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");
+ }
+ resultText = resultText.Substring(0, replaceStart) + "\n" + replaceContent + "\n" + resultText.Substring(replaceEnd);
+ return resultText;
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/TemplateUtil.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/TemplateUtil.cs.meta
new file mode 100644
index 00000000..7b6b91b1
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/TemplateUtil.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 32ec2cc1cf5c468468308fa6308fba19
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates.meta
new file mode 100644
index 00000000..31e4b541
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3a1563e7820e5b648a6a6691677f564c
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Arm64.cpp b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Arm64.cpp
new file mode 100644
index 00000000..e5cfc758
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Arm64.cpp
@@ -0,0 +1,22 @@
+#include "MethodBridge.h"
+
+#include
+#include "vm/ClassInlines.h"
+#include "vm/Object.h"
+#include "vm/Class.h"
+
+#include "../metadata/MetadataModule.h"
+#include "../metadata/MetadataUtil.h"
+
+#include "Interpreter.h"
+#include "MemoryUtil.h"
+#include "InstrinctDef.h"
+
+using namespace hybridclr::interpreter;
+using hybridclr::GetInterpreterDirectlyCallMethodPointer;
+
+#if HYBRIDCLR_ABI_ARM_64
+//!!!{{INVOKE_STUB
+
+//!!!}}INVOKE_STUB
+#endif
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Arm64.cpp.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Arm64.cpp.meta
new file mode 100644
index 00000000..0ae25622
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Arm64.cpp.meta
@@ -0,0 +1,27 @@
+fileFormatVersion: 2
+guid: 7e694feed8374f94380fe48bb70e9be1
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 1
+ settings:
+ DefaultValueInitialized: true
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal32.cpp b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal32.cpp
new file mode 100644
index 00000000..7a2ca8cf
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal32.cpp
@@ -0,0 +1,22 @@
+#include "MethodBridge.h"
+
+#include
+#include "vm/ClassInlines.h"
+#include "vm/Object.h"
+#include "vm/Class.h"
+
+#include "../metadata/MetadataModule.h"
+#include "../metadata/MetadataUtil.h"
+
+#include "Interpreter.h"
+#include "MemoryUtil.h"
+#include "InstrinctDef.h"
+
+using namespace hybridclr::interpreter;
+using hybridclr::GetInterpreterDirectlyCallMethodPointer;
+
+#if HYBRIDCLR_ABI_UNIVERSAL_32
+//!!!{{INVOKE_STUB
+
+//!!!}}INVOKE_STUB
+#endif
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal32.cpp.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal32.cpp.meta
new file mode 100644
index 00000000..df0e9bf5
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal32.cpp.meta
@@ -0,0 +1,27 @@
+fileFormatVersion: 2
+guid: 27135a158cd4b5049966f6f46d15ab10
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 1
+ settings:
+ DefaultValueInitialized: true
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal64.cpp b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal64.cpp
new file mode 100644
index 00000000..459d43df
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal64.cpp
@@ -0,0 +1,22 @@
+#include "MethodBridge.h"
+
+#include
+#include "vm/ClassInlines.h"
+#include "vm/Object.h"
+#include "vm/Class.h"
+
+#include "../metadata/MetadataModule.h"
+#include "../metadata/MetadataUtil.h"
+
+#include "Interpreter.h"
+#include "MemoryUtil.h"
+#include "InstrinctDef.h"
+
+using namespace hybridclr::interpreter;
+using hybridclr::GetInterpreterDirectlyCallMethodPointer;
+
+#if HYBRIDCLR_ABI_UNIVERSAL_64
+//!!!{{INVOKE_STUB
+
+//!!!}}INVOKE_STUB
+#endif
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal64.cpp.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal64.cpp.meta
new file mode 100644
index 00000000..294d27b3
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal64.cpp.meta
@@ -0,0 +1,27 @@
+fileFormatVersion: 2
+guid: ca76fdf59c873e441aa5043ad00d4537
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Any:
+ second:
+ enabled: 0
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 1
+ settings:
+ DefaultValueInitialized: true
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Installer.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Installer.meta
new file mode 100644
index 00000000..47b8a312
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Installer.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a4a3d499c10d66f43af10a859e276a8f
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerController.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerController.cs
new file mode 100644
index 00000000..45070d9b
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerController.cs
@@ -0,0 +1,224 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEditor;
+using UnityEngine;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+
+using Debug = UnityEngine.Debug;
+
+namespace HybridCLR.Editor.Installer
+{
+ public enum InstallErrorCode
+ {
+ Ok,
+ Il2CppInstallPathNotMatchIl2CppBranch,
+ Il2CppInstallPathNotExists,
+ NotIl2CppPath,
+ }
+
+ public partial class InstallerController
+ {
+ private string m_Il2CppInstallDirectory;
+
+ public string Il2CppInstallDirectory
+ {
+ get
+ {
+ return m_Il2CppInstallDirectory;
+ }
+ set
+ {
+ m_Il2CppInstallDirectory = value?.Replace('\\', '/');
+ if (!string.IsNullOrEmpty(m_Il2CppInstallDirectory))
+ {
+ EditorPrefs.SetString("UnityInstallDirectory", m_Il2CppInstallDirectory);
+ }
+ }
+ }
+
+ private string GetIl2CppPlusBranchByUnityVersion(string unityVersion)
+ {
+ if (unityVersion.Contains("2019."))
+ {
+ return "2019.4.40";
+ }
+ if (unityVersion.Contains("2020."))
+ {
+ return "2020.3.33";
+ }
+ if (unityVersion.Contains("2021."))
+ {
+ return "2021.3.1";
+ }
+ return "not support";
+ }
+
+ public string Il2CppBranch => GetIl2CppPlusBranchByUnityVersion(Application.unityVersion);
+
+ public string InitLocalIl2CppBatFile => Application.dataPath + "/../HybridCLRData/init_local_il2cpp_data.bat";
+
+ public string InitLocalIl2CppBashFile => Application.dataPath + "/../HybridCLRData/init_local_il2cpp_data.sh";
+
+ public InstallerController()
+ {
+ PrepareIl2CppInstallPath();
+ }
+
+ void PrepareIl2CppInstallPath()
+ {
+#if UNITY_EDITOR_OSX
+ m_Il2CppInstallDirectory = EditorPrefs.GetString("Il2CppInstallDirectory");
+ if (CheckValidIl2CppInstallDirectory(Il2CppBranch, m_Il2CppInstallDirectory) == InstallErrorCode.Ok)
+ {
+ return;
+ }
+ var il2cppBranch = Il2CppBranch;
+ var curAppInstallPath = EditorApplication.applicationPath;
+ if (curAppInstallPath.Contains(il2cppBranch))
+ {
+ Il2CppInstallDirectory = $"{curAppInstallPath}/Contents/il2cpp";
+ return;
+ }
+ string unityHubRootDir = Directory.GetParent(curAppInstallPath).Parent.Parent.ToString();
+ foreach (var unityInstallDir in Directory.GetDirectories(unityHubRootDir, "*", SearchOption.TopDirectoryOnly))
+ {
+ Debug.Log("nity install dir:" + unityInstallDir);
+ if (unityInstallDir.Contains(il2cppBranch))
+ {
+ Il2CppInstallDirectory = $"{unityInstallDir}/Unity.app/Contents/il2cpp";
+ return;
+ }
+ }
+
+ Il2CppInstallDirectory = $"{curAppInstallPath}/Contents/il2cpp";
+#else
+ m_Il2CppInstallDirectory = EditorPrefs.GetString("Il2CppInstallDirectory");
+ if (CheckValidIl2CppInstallDirectory(Il2CppBranch, m_Il2CppInstallDirectory) == InstallErrorCode.Ok)
+ {
+ return;
+ }
+ var il2cppBranch = Il2CppBranch;
+ var curAppInstallPath = EditorApplication.applicationPath;
+ if (curAppInstallPath.Contains(il2cppBranch))
+ {
+ Il2CppInstallDirectory = $"{Directory.GetParent(curAppInstallPath)}/Data/il2cpp";
+ return;
+ }
+ string unityHubRootDir = Directory.GetParent(curAppInstallPath).Parent.Parent.ToString();
+ Debug.Log("unity hub root dir:" + unityHubRootDir);
+ foreach (var unityInstallDir in Directory.GetDirectories(unityHubRootDir, "*", SearchOption.TopDirectoryOnly))
+ {
+ Debug.Log("nity install dir:" + unityInstallDir);
+ if (unityInstallDir.Contains(il2cppBranch))
+ {
+ Il2CppInstallDirectory = $"{unityInstallDir}/Editor/Data/il2cpp";
+ return;
+ }
+ }
+
+ Il2CppInstallDirectory = $"{Directory.GetParent(curAppInstallPath)}/Data/il2cpp";
+#endif
+ }
+
+ public void InitHybridCLR(string il2cppBranch, string il2cppInstallPath)
+ {
+ if (CheckValidIl2CppInstallDirectory(il2cppBranch, il2cppInstallPath) != InstallErrorCode.Ok)
+ {
+ Debug.LogError($"请正确设置 il2cpp 安装目录");
+ return;
+ }
+
+ if (Application.platform == RuntimePlatform.WindowsEditor)
+ {
+ RunInitLocalIl2CppDataBat(il2cppBranch, il2cppInstallPath);
+ }
+ else
+ {
+ RunInitLocalIl2CppDataBash(il2cppBranch, il2cppInstallPath);
+ }
+ }
+
+ public bool HasInstalledHybridCLR()
+ {
+ return Directory.Exists($"{BuildConfig.LocalIl2CppDir}/libil2cpp/hybridclr");
+ }
+
+ public InstallErrorCode CheckValidIl2CppInstallDirectory(string il2cppBranch, string installDir)
+ {
+ installDir = installDir.Replace('\\', '/');
+ if (!Directory.Exists(installDir))
+ {
+ return InstallErrorCode.Il2CppInstallPathNotExists;
+ }
+
+ if (!installDir.Contains(il2cppBranch))
+ {
+ return InstallErrorCode.Il2CppInstallPathNotMatchIl2CppBranch;
+ }
+
+ if (!installDir.EndsWith("/il2cpp"))
+ {
+ return InstallErrorCode.NotIl2CppPath;
+ }
+
+ return InstallErrorCode.Ok;
+ }
+
+ public bool IsUnity2019(string branch)
+ {
+ return branch.Contains("2019.");
+ }
+
+ private void RunInitLocalIl2CppDataBat(string il2cppBranch, string il2cppInstallPath)
+ {
+ using (Process p = new Process())
+ {
+ p.StartInfo.WorkingDirectory = BuildConfig.HybridCLRDataDir;
+ p.StartInfo.FileName = InitLocalIl2CppBatFile;
+ p.StartInfo.UseShellExecute = true;
+ p.StartInfo.Arguments = $"{il2cppBranch} \"{il2cppInstallPath}\"";
+ p.Start();
+ p.WaitForExit();
+ if (IsUnity2019(il2cppBranch))
+ {
+ string srcIl2CppDll = $"{BuildConfig.HybridCLRDataDir}/ModifiedUnityAssemblies/2019.4.40/Unity.IL2CPP.dll";
+ string dstIl2CppDll = $"{BuildConfig.LocalIl2CppDir}/build/deploy/net471/Unity.IL2CPP.dll";
+ File.Copy(srcIl2CppDll, dstIl2CppDll, true);
+ Debug.Log($"copy {srcIl2CppDll} => {dstIl2CppDll}");
+ }
+ if (p.ExitCode == 0 && HasInstalledHybridCLR())
+ {
+ Debug.Log("HybirdCLR 安装成功");
+ }
+ }
+ }
+
+ private void RunInitLocalIl2CppDataBash(string il2cppBranch, string il2cppInstallPath)
+ {
+ using (Process p = new Process())
+ {
+ p.StartInfo.WorkingDirectory = Application.dataPath + "/../HybridCLRData";
+ p.StartInfo.FileName = "/bin/bash";
+ p.StartInfo.UseShellExecute = false;
+ p.StartInfo.CreateNoWindow = true;
+ p.StartInfo.Arguments = $"init_local_il2cpp_data.sh {il2cppBranch} '{il2cppInstallPath}'";
+ p.StartInfo.RedirectStandardOutput = true;
+ p.StartInfo.RedirectStandardError = true;
+ p.Start();
+ string output = p.StandardOutput.ReadToEnd();
+ Debug.Log(output);
+ p.WaitForExit();
+ if (HasInstalledHybridCLR())
+ {
+ Debug.Log("安装成功!!!");
+ }
+ }
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerController.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerController.cs.meta
new file mode 100644
index 00000000..6b30944d
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/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/Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerWindow.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerWindow.cs
new file mode 100644
index 00000000..47783680
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerWindow.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 UnityEngine;
+
+
+namespace HybridCLR.Editor.Installer
+{
+ public class InstallerWindow : EditorWindow
+ {
+ private InstallerController m_Controller;
+
+ [MenuItem("HybridCLR/Installer...", false, 0)]
+ private static void Open()
+ {
+ InstallerWindow window = GetWindow("HybridCLR Installer", true);
+ window.minSize = new Vector2(800f, 500f);
+ }
+
+ private void OnEnable()
+ {
+ m_Controller = new InstallerController();
+ }
+
+ private void OnGUI()
+ {
+ GUI.enabled = true;
+ GUILayout.Space(10f);
+ EditorGUILayout.LabelField("=======================说明====================");
+ EditorGUILayout.LabelField(
+ $"你所在项目的Unity版本可以与il2cpp_plus版本:{m_Controller.Il2CppBranch} 不一样。\n"
+ + $"由于安装HybridCLR时需要从il2cpp_plus对应版本(而不是你项目版本)拷贝il2cpp目录,\n"
+ + $"你必须同时也安装相应版本 {m_Controller.Il2CppBranch},否则无法安装", EditorStyles.wordWrappedLabel);
+ EditorGUILayout.LabelField("==============================================");
+ GUILayout.Space(10f);
+
+ EditorGUILayout.BeginVertical("box");
+ EditorGUILayout.LabelField($"安装状态:{(m_Controller.HasInstalledHybridCLR() ? "已安装" : "未安装")}", EditorStyles.boldLabel);
+ GUILayout.Space(5f);
+ EditorGUILayout.LabelField($"当前Unity版本: {Application.unityVersion},匹配的il2cpp_plus分支: {m_Controller.Il2CppBranch}");
+ GUISelectUnityDirectory($"il2cpp_plus分支对应Unity版本的il2cpp路径", "Select");
+ GUILayout.Space(10f);
+ GUIInstallButton("安装最新HybridCLR插件代码到本项目", "安装", InitHybridCLR);
+ EditorGUILayout.EndVertical();
+ }
+
+ private void GUIInstallButton(string content, string button, Action onClick)
+ {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField(content);
+ GUI.enabled = m_Controller.CheckValidIl2CppInstallDirectory(m_Controller.Il2CppBranch, m_Controller.Il2CppInstallDirectory) == InstallErrorCode.Ok;
+ if (GUILayout.Button(button, GUILayout.Width(100)))
+ {
+ onClick?.Invoke();
+ GUIUtility.ExitGUI();
+ }
+ GUI.enabled = true;
+ EditorGUILayout.EndHorizontal();
+
+ }
+
+
+ private void GUISelectUnityDirectory(string content, string selectButton)
+ {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUILayout.LabelField(content, GUILayout.MaxWidth(300));
+ string il2cppInstallDirectory = m_Controller.Il2CppInstallDirectory = EditorGUILayout.TextField(m_Controller.Il2CppInstallDirectory);
+ if (GUILayout.Button(selectButton, GUILayout.Width(100)))
+ {
+ string temp = EditorUtility.OpenFolderPanel(content, m_Controller.Il2CppInstallDirectory, string.Empty);
+ if (!string.IsNullOrEmpty(temp))
+ {
+ il2cppInstallDirectory = m_Controller.Il2CppInstallDirectory = temp;
+ }
+ }
+ EditorGUILayout.EndHorizontal();
+
+ InstallErrorCode err = m_Controller.CheckValidIl2CppInstallDirectory(m_Controller.Il2CppBranch, il2cppInstallDirectory);
+ switch (err)
+ {
+ case InstallErrorCode.Ok:
+ {
+ if (!il2cppInstallDirectory.Contains(m_Controller.Il2CppBranch))
+ {
+ EditorGUILayout.HelpBox($"li2cpp 路径未包含 '{m_Controller.Il2CppBranch}',请确保选择了 {m_Controller.Il2CppBranch} 版本的安装目录 ", MessageType.Warning);
+ }
+ break;
+ }
+ case InstallErrorCode.Il2CppInstallPathNotExists:
+ {
+ EditorGUILayout.HelpBox("li2cpp 路径不存在", MessageType.Error);
+ break;
+ }
+ case InstallErrorCode.Il2CppInstallPathNotMatchIl2CppBranch:
+ {
+ EditorGUILayout.HelpBox($"il2cpp 版本不匹配,必须为 {m_Controller.Il2CppBranch} 版本相应目录", MessageType.Error);
+ break;
+ }
+ case InstallErrorCode.NotIl2CppPath:
+ {
+ EditorGUILayout.HelpBox($"当前选择的路径不是il2cpp目录(必须类似 xxx/il2cpp)", MessageType.Error);
+ break;
+ }
+ default: throw new Exception($"not support {err}");
+ }
+ }
+
+ private void InitHybridCLR()
+ {
+ m_Controller.InitHybridCLR(m_Controller.Il2CppBranch, m_Controller.Il2CppInstallDirectory);
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerWindow.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/Installer/InstallerWindow.cs.meta
new file mode 100644
index 00000000..f404c28d
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/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/Assets/TEngine/Scripts/Editor/HybridCLR/MethodBridgeHelper.cs b/Assets/TEngine/Scripts/Editor/HybridCLR/MethodBridgeHelper.cs
new file mode 100644
index 00000000..57389a4a
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/MethodBridgeHelper.cs
@@ -0,0 +1,129 @@
+using HybridCLR.Editor.Generators;
+using HybridCLR.Editor.Generators.MethodBridge;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using UnityEditor;
+using UnityEngine;
+
+namespace HybridCLR.Editor
+{
+ internal class MethodBridgeHelper
+ {
+
+ private static void CleanIl2CppBuildCache()
+ {
+ string il2cppBuildCachePath = BuildConfig.Il2CppBuildCacheDir;
+ if (!Directory.Exists(il2cppBuildCachePath))
+ {
+ return;
+ }
+ Debug.Log($"clean il2cpp build cache:{il2cppBuildCachePath}");
+ Directory.Delete(il2cppBuildCachePath, true);
+ }
+
+ private static List CollectDependentAssemblies(Dictionary allAssByName, List dlls)
+ {
+ for(int i = 0; i < dlls.Count; i++)
+ {
+ Assembly ass = dlls[i];
+ foreach (var depAssName in ass.GetReferencedAssemblies())
+ {
+ if (!allAssByName.ContainsKey(depAssName.Name))
+ {
+ Debug.Log($"ignore ref assembly:{depAssName.Name}");
+ continue;
+ }
+ Assembly depAss = allAssByName[depAssName.Name];
+ if (!dlls.Contains(depAss))
+ {
+ dlls.Add(depAss);
+ }
+ }
+ }
+ return dlls;
+ }
+
+ private static List GetScanAssembiles()
+ {
+ var allAssByName = new Dictionary();
+ foreach(var ass in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ allAssByName[ass.GetName().Name] = ass;
+ }
+ //CompileDllHelper.CompileDllActiveBuildTarget();
+
+ var rootAssemblies = BuildConfig.HotUpdateAssemblies
+ .Select(dll => Path.GetFileNameWithoutExtension(dll)).Concat(GeneratorConfig.GetExtraAssembiles())
+ .Where(name => allAssByName.ContainsKey(name)).Select(name => allAssByName[name]).ToList();
+ //var rootAssemblies = GeneratorConfig.GetExtraAssembiles()
+ // .Where(name => allAssByName.ContainsKey(name)).Select(name => allAssByName[name]).ToList();
+ CollectDependentAssemblies(allAssByName, rootAssemblies);
+ rootAssemblies.Sort((a, b) => a.GetName().Name.CompareTo(b.GetName().Name));
+ Debug.Log($"assembly count:{rootAssemblies.Count}");
+ foreach(var ass in rootAssemblies)
+ {
+ //Debug.Log($"scan assembly:{ass.GetName().Name}");
+ }
+ return rootAssemblies;
+ }
+
+ private static void GenerateMethodBridgeCppFile(PlatformABI platform, string fileName, bool optimized)
+ {
+ string outputFile = $"{BuildConfig.MethodBridgeCppDir}/{fileName}.cpp";
+ var g = new MethodBridgeGenerator(new MethodBridgeGeneratorOptions()
+ {
+ CallConvention = platform,
+ HotfixAssemblies = BuildConfig.HotUpdateAssemblies.Select(name =>
+ AppDomain.CurrentDomain.GetAssemblies().First(ass => ass.GetName().Name + ".dll" == name)).ToList(),
+ AllAssemblies = optimized ? GetScanAssembiles() : AppDomain.CurrentDomain.GetAssemblies().ToList(),
+ OutputFile = outputFile,
+ Optimized = optimized,
+ });
+
+ g.PrepareMethods();
+ g.Generate();
+ Debug.LogFormat("== output:{0} ==", outputFile);
+ CleanIl2CppBuildCache();
+ }
+
+ //[MenuItem("HybridCLR/MethodBridge/Arm64")]
+ //public static void MethodBridge_Arm64()
+ //{
+ // GenerateMethodBridgeCppFile(PlatformABI.Arm64, "MethodBridge_Arm64");
+ //}
+
+ //[MenuItem("HybridCLR/MethodBridge/Universal64")]
+ //public static void MethodBridge_Universal64()
+ //{
+ // GenerateMethodBridgeCppFile(PlatformABI.Universal64, "MethodBridge_Universal64");
+ //}
+
+ //[MenuItem("HybridCLR/MethodBridge/Universal32")]
+ //public static void MethodBridge_Universal32()
+ //{
+ // GenerateMethodBridgeCppFile(PlatformABI.Universal32, "MethodBridge_Universal32");
+ //}
+
+ public static void GenerateMethodBridgeAll(bool optimized)
+ {
+ GenerateMethodBridgeCppFile(PlatformABI.Arm64, "MethodBridge_Arm64", optimized);
+ GenerateMethodBridgeCppFile(PlatformABI.Universal64, "MethodBridge_Universal64", optimized);
+ GenerateMethodBridgeCppFile(PlatformABI.Universal32, "MethodBridge_Universal32", optimized);
+ }
+
+ [MenuItem("HybridCLR/MethodBridge/All_高度精简")]
+ public static void MethodBridge_All_Optimized()
+ {
+ GenerateMethodBridgeAll(true);
+ }
+
+ [MenuItem("HybridCLR/MethodBridge/All_完整(新手及开发期推荐)")]
+ public static void MethodBridge_All_Normal()
+ {
+ GenerateMethodBridgeAll(false);
+ }
+ }
+}
diff --git a/Assets/TEngine/Scripts/Editor/HybridCLR/MethodBridgeHelper.cs.meta b/Assets/TEngine/Scripts/Editor/HybridCLR/MethodBridgeHelper.cs.meta
new file mode 100644
index 00000000..91c08cb2
--- /dev/null
+++ b/Assets/TEngine/Scripts/Editor/HybridCLR/MethodBridgeHelper.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 18beea79433bdce44af834574cd9c212
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/TEngine/Scripts/Editor/TEngine.Editor.asmdef b/Assets/TEngine/Scripts/Editor/TEngine.Editor.asmdef
index 90c2c5e2..9b507b71 100644
--- a/Assets/TEngine/Scripts/Editor/TEngine.Editor.asmdef
+++ b/Assets/TEngine/Scripts/Editor/TEngine.Editor.asmdef
@@ -7,7 +7,7 @@
"Editor"
],
"excludePlatforms": [],
- "allowUnsafeCode": false,
+ "allowUnsafeCode": true,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,