guodong 3 жил өмнө
parent
commit
ba01de5f80
100 өөрчлөгдсөн 4687 нэмэгдсэн , 128 устгасан
  1. 5 0
      .gitignore
  2. 7 1
      GameClient/Assets/BuildSetting1.asset
  3. 0 45
      GameClient/Assets/Editor/BuildEditor/BuildHotfixEditor.cs
  4. 8 0
      GameClient/Assets/Editor/HybridCLR.meta
  5. 124 0
      GameClient/Assets/Editor/HybridCLR/AssetBundleBuildHelper.cs
  6. 1 1
      GameClient/Assets/Editor/HybridCLR/AssetBundleBuildHelper.cs.meta
  7. 95 0
      GameClient/Assets/Editor/HybridCLR/BuildConfig.cs
  8. 11 0
      GameClient/Assets/Editor/HybridCLR/BuildConfig.cs.meta
  9. 52 0
      GameClient/Assets/Editor/HybridCLR/BuildConfig_Custom.cs
  10. 11 0
      GameClient/Assets/Editor/HybridCLR/BuildConfig_Custom.cs.meta
  11. 148 0
      GameClient/Assets/Editor/HybridCLR/BuildPlayerHelper.cs
  12. 11 0
      GameClient/Assets/Editor/HybridCLR/BuildPlayerHelper.cs.meta
  13. 175 0
      GameClient/Assets/Editor/HybridCLR/BuildProcessor_2019.cs
  14. 11 0
      GameClient/Assets/Editor/HybridCLR/BuildProcessor_2019.cs.meta
  15. 165 0
      GameClient/Assets/Editor/HybridCLR/BuildProcessor_2020_1_OR_NEWER.cs
  16. 11 0
      GameClient/Assets/Editor/HybridCLR/BuildProcessor_2020_1_OR_NEWER.cs.meta
  17. 65 0
      GameClient/Assets/Editor/HybridCLR/CompileDllHelper.cs
  18. 11 0
      GameClient/Assets/Editor/HybridCLR/CompileDllHelper.cs.meta
  19. 8 0
      GameClient/Assets/Editor/HybridCLR/Generators.meta
  20. 13 0
      GameClient/Assets/Editor/HybridCLR/Generators/ConstStrings.cs
  21. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/ConstStrings.cs.meta
  22. 40 0
      GameClient/Assets/Editor/HybridCLR/Generators/FileRegionReplace.cs
  23. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/FileRegionReplace.cs.meta
  24. 70 0
      GameClient/Assets/Editor/HybridCLR/Generators/GeneratorConfig.cs
  25. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/GeneratorConfig.cs.meta
  26. 8 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge.meta
  27. 26 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/IPlatformAdaptor.cs
  28. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/IPlatformAdaptor.cs.meta
  29. 323 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeGenerator.cs
  30. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeGenerator.cs.meta
  31. 156 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeSig.cs
  32. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeSig.cs.meta
  33. 44 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/ParamInfo.cs
  34. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/ParamInfo.cs.meta
  35. 38 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/ParamOrReturnType.cs
  36. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/ParamOrReturnType.cs.meta
  37. 9 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformABI.cs
  38. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformABI.cs.meta
  39. 144 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptorBase.cs
  40. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptorBase.cs.meta
  41. 354 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Arm64.cs
  42. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Arm64.cs.meta
  43. 240 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal32.cs
  44. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal32.cs.meta
  45. 337 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal64.cs
  46. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal64.cs.meta
  47. 19 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/SignatureProviderAttribute.cs
  48. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/SignatureProviderAttribute.cs.meta
  49. 132 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/TypeInfo.cs
  50. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/TypeInfo.cs.meta
  51. 148 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/ValueTypeSizeAligmentCalculator.cs
  52. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/ValueTypeSizeAligmentCalculator.cs.meta
  53. 38 0
      GameClient/Assets/Editor/HybridCLR/Generators/TemplateUtil.cs
  54. 11 0
      GameClient/Assets/Editor/HybridCLR/Generators/TemplateUtil.cs.meta
  55. 8 0
      GameClient/Assets/Editor/HybridCLR/Generators/Templates.meta
  56. 22 0
      GameClient/Assets/Editor/HybridCLR/Generators/Templates/MethodBridge_Arm64.cpp
  57. 27 0
      GameClient/Assets/Editor/HybridCLR/Generators/Templates/MethodBridge_Arm64.cpp.meta
  58. 22 0
      GameClient/Assets/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal32.cpp
  59. 27 0
      GameClient/Assets/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal32.cpp.meta
  60. 22 0
      GameClient/Assets/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal64.cpp
  61. 27 0
      GameClient/Assets/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal64.cpp.meta
  62. 117 0
      GameClient/Assets/Editor/HybridCLR/MethodBridgeHelper.cs
  63. 11 0
      GameClient/Assets/Editor/HybridCLR/MethodBridgeHelper.cs.meta
  64. 8 0
      GameClient/Assets/Editor/HybridCLR/UnityBinFileReader.meta
  65. 107 0
      GameClient/Assets/Editor/HybridCLR/UnityBinFileReader/UnityBinFile.cs
  66. 11 0
      GameClient/Assets/Editor/HybridCLR/UnityBinFileReader/UnityBinFile.cs.meta
  67. 397 0
      GameClient/Assets/Editor/HybridCLR/UnityBinFileReader/UnityBinFileDefines.cs
  68. 11 0
      GameClient/Assets/Editor/HybridCLR/UnityBinFileReader/UnityBinFileDefines.cs.meta
  69. 78 0
      GameClient/Assets/Editor/HybridCLR/UnityBinFileReader/UnityBinUtils.cs
  70. 11 0
      GameClient/Assets/Editor/HybridCLR/UnityBinFileReader/UnityBinUtils.cs.meta
  71. 8 0
      GameClient/Assets/Editor/HybridCLRExtension.meta
  72. 45 0
      GameClient/Assets/Editor/HybridCLRExtension/DllHelper.cs
  73. 11 0
      GameClient/Assets/Editor/HybridCLRExtension/DllHelper.cs.meta
  74. 3 0
      GameClient/Assets/Editor/Xasset/Builds/BuildTask.cs
  75. 0 1
      GameClient/Assets/Editor/Xasset/Builds/Settings.cs
  76. 0 2
      GameClient/Assets/Editor/Xasset/Initializer.cs
  77. 1 3
      GameClient/Assets/Game/HotUpdate/Data/InstanceZonesDataManager.cs
  78. 0 4
      GameClient/Assets/Game/HotUpdate/Data/VO/ItemData.cs
  79. 1 3
      GameClient/Assets/Game/HotUpdate/ETCodes/Hotfix/App/ServerInfo/ServerInfosComponentSystem.cs
  80. 1 3
      GameClient/Assets/Game/HotUpdate/Game.HotUpdate.asmdef
  81. 47 0
      GameClient/Assets/Game/HotUpdate/HotUpdateEntry.cs
  82. 0 1
      GameClient/Assets/Game/HotUpdate/Views/CommonGame/GetSuitItemVIew.cs
  83. 0 1
      GameClient/Assets/Game/HotUpdate/Views/Loading/LoadingView.cs
  84. 0 1
      GameClient/Assets/Game/HotUpdate/Views/Log/LogView.cs
  85. 0 5
      GameClient/Assets/Game/HotUpdate/Views/MainStory/StoryController.cs
  86. 0 2
      GameClient/Assets/Game/HotUpdate/Views/MainUI/MainUIView.cs
  87. 25 21
      GameClient/Assets/Game/Launcher/HotUpdateProxy/HotUpdateCodeLoader.cs
  88. 8 0
      GameClient/Assets/Game/Launcher/HybridCLR.meta
  89. 274 0
      GameClient/Assets/Game/Launcher/HybridCLR/RefTypes.cs
  90. 11 0
      GameClient/Assets/Game/Launcher/HybridCLR/RefTypes.cs.meta
  91. 36 0
      GameClient/Assets/Game/Launcher/HybridCLR/RuntimeApi.cs
  92. 11 0
      GameClient/Assets/Game/Launcher/HybridCLR/RuntimeApi.cs.meta
  93. 4 2
      GameClient/Assets/Game/Launcher/LauncherConfig.cs
  94. BIN
      GameClient/Assets/Plugins/Android/libs/arm64-v8a/libsqlite3.so
  95. 8 8
      GameClient/Assets/Plugins/Android/libs/arm64-v8a/libsqlite3.so.meta
  96. 21 22
      GameClient/Assets/Plugins/Android/libs/armeabi-v7a/libkcp.so.meta
  97. BIN
      GameClient/Assets/Plugins/System.Numerics.Vectors.dll
  98. 5 2
      GameClient/Assets/Plugins/Windows/x86/Live2DCubismCore.dll.meta
  99. 8 0
      GameClient/Assets/ResIn/Dll.meta
  100. 8 0
      GameClient/Assets/ResIn/Dll/AOT.meta

+ 5 - 0
.gitignore

@@ -24,3 +24,8 @@
 /GameClient/Assets/Game/CSShare
 /GameClient/Assets/StreamingAssets/Bundles
 /GameClient/BuildlesUnity
+/GameClient/HybridCLRData/LocalIl2CppData
+/GameClient/HybridCLRData/AssembliesPostIl2CppStrip
+/GameClient/HybridCLRData/HotFixDlls
+/GameClient/HybridCLRData/il2cpp_plus_repo/
+/GameClient/HybridCLRData/hybridclr_repo/

+ 7 - 1
GameClient/Assets/BuildSetting1.asset

@@ -18,7 +18,7 @@ MonoBehaviour:
   - Assets/Res/Effect/DressUp
   - Assets/Res/Effect/UI
   - Assets/ResIn/UI
-  - Assets/Res/Texture
+  - Assets/ResIn/Dll
   dirTypeList:
   - texture_dressup_es_
   - texture_dressup_zr_
@@ -26,3 +26,9 @@ MonoBehaviour:
   - texture_dressup_js_
   - texture_dressup_ts_
   - texture_dressup_ss_
+  - prefab_
+  - txt_
+  - material_effect_
+  - texture_icon_
+  - fight_
+  - texture_fieldguide_icon_

+ 0 - 45
GameClient/Assets/Editor/BuildEditor/BuildHotfixEditor.cs

@@ -1,45 +0,0 @@
-using System.IO;
-using UnityEditor;
-using UnityEngine;
-using GFGGame;
-
-namespace GFGEditor
-{
-    [InitializeOnLoad]
-    public class BuildHotfixEditor
-    {
-        //Unity代码生成dll位置
-        private const string ScriptAssembliesDir = "Library/ScriptAssemblies";
-        //热更代码dll文件
-        private const string HotfixDll = "Game.HotUpdate.dll";
-        //热更代码pdb文件
-        private const string HotfixPdb = "Game.HotUpdate.pdb";
-        //热更代码存放位置
-        private const string CodeDir = "Assets/Res/Code/";
-        //热更代码存放位置
-        private const string EditorDllDir = "Assets/Editor/Excel/DLL/";
-
-        static BuildHotfixEditor()
-        {
-            CopyCode();
-        }
-
-        static void CopyCode()
-        {
-            Debug.Log($"Copy Hotfix Code");
-            if (!Directory.Exists(CodeDir))
-                Directory.CreateDirectory(CodeDir);
-            var path = Path.Combine(ScriptAssembliesDir, HotfixDll);
-            if (File.Exists(path))
-            {
-                File.Copy(path, Path.Combine(CodeDir, "Game.HotUpdate.dll.bytes"), true);
-                //File.Delete(path);
-                path = Path.Combine(ScriptAssembliesDir, HotfixPdb);
-                File.Copy(path, Path.Combine(CodeDir, "Game.HotUpdate.pdb.bytes"), true);
-                //File.Delete(path);
-                Debug.Log($"复制Game.HotUpdate.dll, Game.HotUpdate.pdb到Res/Code完成");
-                AssetDatabase.Refresh();
-            }
-        }
-    }
-}

+ 8 - 0
GameClient/Assets/Editor/HybridCLR.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 009bc4a25347e4c4e9958470806ac819
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 124 - 0
GameClient/Assets/Editor/HybridCLR/AssetBundleBuildHelper.cs

@@ -0,0 +1,124 @@
+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
+{
+    public static class AssetBundleBuildHelper
+    {
+
+        public static string ToRelativeAssetPath(string s)
+        {
+            return s.Substring(s.IndexOf("Assets/"));
+        }
+
+        /// <summary>
+        /// 将HotFix.dll和HotUpdatePrefab.prefab打入common包.
+        /// 将HotUpdateScene.unity打入scene包.
+        /// </summary>
+        /// <param name="tempDir"></param>
+        /// <param name="outputDir"></param>
+        /// <param name="target"></param>
+        private static void BuildAssetBundles(string tempDir, string outputDir, BuildTarget target)
+        {
+            Directory.CreateDirectory(tempDir);
+            Directory.CreateDirectory(outputDir);
+            CompileDllHelper.CompileDll(target);
+
+
+            List<string> notSceneAssets = new List<string>();
+
+            string hotfixDllSrcDir = BuildConfig.GetHotFixDllsOutputDirByTarget(target);
+            foreach (var dll in BuildConfig.AllHotUpdateDllNames)
+            {
+                string dllPath = $"{hotfixDllSrcDir}/{dll}";
+                string dllBytesPath = $"{tempDir}/{dll}.bytes";
+                File.Copy(dllPath, dllBytesPath, true);
+                notSceneAssets.Add(dllBytesPath);
+            }
+
+            string aotDllDir = BuildConfig.GetAssembliesPostIl2CppStripDir(target);
+            foreach (var dll in BuildConfig.AOTMetaDlls)
+            {
+                string dllPath = $"{aotDllDir}/{dll}";
+                if (!File.Exists(dllPath))
+                {
+                    Debug.LogError($"ab中添加AOT补充元数据dll:{dllPath} 时发生错误,文件不存在。裁剪后的AOT dll在BuildPlayer时才能生成,因此需要你先构建一次游戏App后再打包。");
+                    continue;
+                }
+                string dllBytesPath = $"{tempDir}/{dll}.bytes";
+                File.Copy(dllPath, dllBytesPath, true);
+                notSceneAssets.Add(dllBytesPath);
+            }
+
+            string testPrefab = $"{Application.dataPath}/Prefabs/HotUpdatePrefab.prefab";
+            notSceneAssets.Add(testPrefab);
+            AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
+
+            List<AssetBundleBuild> abs = new List<AssetBundleBuild>();
+            AssetBundleBuild notSceneAb = new AssetBundleBuild
+            {
+                assetBundleName = "common",
+                assetNames = notSceneAssets.Select(s => ToRelativeAssetPath(s)).ToArray(),
+            };
+            abs.Add(notSceneAb);
+
+            BuildPipeline.BuildAssetBundles(outputDir, abs.ToArray(), BuildAssetBundleOptions.None, target);
+
+            AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
+
+            string streamingAssetPathDst = $"{Application.streamingAssetsPath}";
+            Directory.CreateDirectory(streamingAssetPathDst);
+
+            foreach (var ab in abs)
+            {
+                AssetDatabase.CopyAsset(ToRelativeAssetPath($"{outputDir}/{ab.assetBundleName}"),
+                    ToRelativeAssetPath($"{streamingAssetPathDst}/{ab.assetBundleName}"));
+            }
+        }
+
+        public static void BuildAssetBundleByTarget(BuildTarget target)
+        {
+            BuildAssetBundles(BuildConfig.GetAssetBundleTempDirByTarget(target), BuildConfig.GetAssetBundleOutputDirByTarget(target), target);
+        }
+
+        [MenuItem("HybridCLR/BuildBundles/ActiveBuildTarget")]
+        public static void BuildSceneAssetBundleActiveBuildTarget()
+        {
+            BuildAssetBundleByTarget(EditorUserBuildSettings.activeBuildTarget);
+        }
+
+        [MenuItem("HybridCLR/BuildBundles/Win64")]
+        public static void BuildSceneAssetBundleWin64()
+        {
+            var target = BuildTarget.StandaloneWindows64;
+            BuildAssetBundleByTarget(target);
+        }
+
+        [MenuItem("HybridCLR/BuildBundles/Win32")]
+        public static void BuildSceneAssetBundleWin32()
+        {
+            var target = BuildTarget.StandaloneWindows;
+            BuildAssetBundleByTarget(target);
+        }
+
+        [MenuItem("HybridCLR/BuildBundles/Android")]
+        public static void BuildSceneAssetBundleAndroid()
+        {
+            var target = BuildTarget.Android;
+            BuildAssetBundleByTarget(target);
+        }
+
+        [MenuItem("HybridCLR/BuildBundles/IOS")]
+        public static void BuildSceneAssetBundleIOS()
+        {
+            var target = BuildTarget.iOS;
+            BuildAssetBundleByTarget(target);
+        }
+    }
+}

+ 1 - 1
GameClient/Assets/Editor/BuildEditor/BuildHotfixEditor.cs.meta → GameClient/Assets/Editor/HybridCLR/AssetBundleBuildHelper.cs.meta

@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 0a3855d0b3adb7e40a32dc23f67704ca
+guid: 1a8357532218e6f49a9bb9401382d6d4
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2

+ 95 - 0
GameClient/Assets/Editor/HybridCLR/BuildConfig.cs

@@ -0,0 +1,95 @@
+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
+{
+    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。请手动执行一次 {HybridCLRDataDir} 目录下的 init_local_il2cpp_data.bat 或者 init_local_il2cpp_data.sh 文件");
+            }
+            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 GetOriginBuildStripAssembliesDir(BuildTarget target)
+        {
+#if UNITY_2021_1_OR_NEWER
+#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}/Library/PlayerDataCache/iOS/Data/Managed";
+#elif UNITY_WEBGL
+            return $"{ProjectDir}/Library/Bee/artifacts/WebGL/ManagedStripped";
+#else
+            throw new NotSupportedException("GetOriginBuildStripAssembliesDir");
+#endif
+#else
+            return target == BuildTarget.Android ?
+                $"{ProjectDir}/Temp/StagingArea/assets/bin/Data/Managed" :
+                $"{ProjectDir}/Temp/StagingArea/Data/Managed/";
+#endif
+        }
+
+        public static string GetAssetBundleOutputDirByTarget(BuildTarget target)
+        {
+            return $"{AssetBundleOutputDir}/{target}";
+        }
+
+        public static string GetAssetBundleTempDirByTarget(BuildTarget target)
+        {
+            return $"{AssetBundleSourceDataTempDir}/{target}";
+        }
+
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 52 - 0
GameClient/Assets/Editor/HybridCLR/BuildConfig_Custom.cs

@@ -0,0 +1,52 @@
+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
+{
+    public static partial class BuildConfig
+    {
+
+        /// <summary>
+        /// 需要在Prefab上挂脚本的热更dll名称列表,不需要挂到Prefab上的脚本可以不放在这里
+        /// 但放在这里的dll即使勾选了 AnyPlatform 也会在打包过程中被排除
+        /// 
+        /// 另外请务必注意: 需要挂脚本的dll的名字最好别改,因为这个列表无法热更(上线后删除或添加某些非挂脚本dll没问题)。
+        /// 
+        /// 注意:多热更新dll不是必须的!大多数项目完全可以只有HotFix.dll这一个热更新模块,纯粹出于演示才故意设计了两个热更新模块。
+        /// 另外,是否热更新跟dll名毫无关系,凡是不打包到主工程的,都可以是热更新dll。
+        /// </summary>
+        public static List<string> MonoHotUpdateDllNames { get; } = new List<string>()
+        {
+            
+        };
+
+        /// <summary>
+        /// 所有热更新dll列表。放到此列表中的dll在打包时OnFilterAssemblies回调中被过滤。
+        /// </summary>
+        public static List<string> AllHotUpdateDllNames { get; } = MonoHotUpdateDllNames.Concat(new List<string>
+        {
+            // 这里放除了s_monoHotUpdateDllNames以外的脚本不需要挂到资源上的dll列表
+            "Game.HotUpdate.dll",
+        }).ToList();
+
+        public static List<string> AOTMetaDlls { get; } = new List<string>()
+        {
+            "mscorlib.dll",
+            "System.dll",
+            "System.Core.dll", // 如果使用了Linq,需要这个
+            "ThirdParty.dll",
+            "Game.Launcher.dll",
+        };
+
+        public static List<string> AssetBundleFiles { get; } = new List<string>
+        {
+            "common",
+        };
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 148 - 0
GameClient/Assets/Editor/HybridCLR/BuildPlayerHelper.cs

@@ -0,0 +1,148 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+
+namespace HybridCLR
+{
+    public class BuildPlayerHelper
+    {
+        public static void CopyAssetBundles(string outputDir)
+        {
+            Directory.CreateDirectory(outputDir);
+
+            foreach(var ab in BuildConfig.AssetBundleFiles)
+            {
+                string srcFile = $"{Application.streamingAssetsPath}/{ab}";
+                string dstFile = $"{outputDir}/{Path.GetFileName(ab)}";
+                File.Copy(srcFile, dstFile, true);
+            }
+        }
+
+        [MenuItem("HybridCLR/Build/Win64")]
+        public static void Build_Win64()
+        {
+            BuildTarget target = BuildTarget.StandaloneWindows64;
+            BuildTarget activeTarget = EditorUserBuildSettings.activeBuildTarget;
+            if (activeTarget != BuildTarget.StandaloneWindows64 && activeTarget != BuildTarget.StandaloneWindows)
+            {
+                Debug.LogError("请先切到Win平台再打包");
+                return;
+            }
+            // Get filename.
+            string outputPath = $"{BuildConfig.ProjectDir}/Release-Win64";
+
+            var buildOptions = BuildOptions.None;
+
+            string location = $"{outputPath}/HybridCLRTrial.exe";
+
+            Debug.Log("====> Build App");
+            BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions()
+            {
+                scenes = new string[] { "Assets/Scenes/main.unity" },
+                locationPathName = location,
+                options = buildOptions,
+                target = target,
+                targetGroup = BuildTargetGroup.Standalone,
+            };
+
+            var report = BuildPipeline.BuildPlayer(buildPlayerOptions);
+            if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
+            {
+                Debug.LogError("打包失败");
+                return;
+            }
+
+            Debug.Log("====> Build AssetBundle");
+            AssetBundleBuildHelper.BuildAssetBundleByTarget(target);
+            Debug.Log("====> 复制 AssetBundle");
+            CopyAssetBundles($"{outputPath}/HybridCLRTrial_Data/StreamingAssets");
+
+#if UNITY_EDITOR
+            Application.OpenURL($"file:///{outputPath}");
+#endif
+        }
+
+        [MenuItem("HybridCLR/Build/Win32")]
+        public static void Build_Win32()
+        {
+            BuildTarget target = BuildTarget.StandaloneWindows;
+            BuildTarget activeTarget = EditorUserBuildSettings.activeBuildTarget;
+            if (activeTarget != BuildTarget.StandaloneWindows64 && activeTarget != BuildTarget.StandaloneWindows)
+            {
+                Debug.LogError("请先切到Win平台再打包");
+                return;
+            }
+            // Get filename.
+            string outputPath = $"{BuildConfig.ProjectDir}/Release-Win32";
+
+            var buildOptions = BuildOptions.None;
+
+            string location = $"{outputPath}/HybridCLRTrial.exe";
+
+            Debug.Log("====> Build App");
+            BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions()
+            {
+                scenes = new string[] { "Assets/Scenes/main.unity" },
+                locationPathName = location,
+                options = buildOptions,
+                target = target,
+                targetGroup = BuildTargetGroup.Standalone,
+            };
+
+            var report = BuildPipeline.BuildPlayer(buildPlayerOptions);
+            if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
+            {
+                Debug.LogError("打包失败");
+                return;
+            }
+
+            Debug.Log("====> Build AssetBundle");
+            AssetBundleBuildHelper.BuildAssetBundleByTarget(target);
+            Debug.Log("====> 复制 AssetBundle");
+            CopyAssetBundles($"{outputPath}/HybridCLRTrial_Data/StreamingAssets");
+
+#if UNITY_EDITOR
+            Application.OpenURL($"file:///{outputPath}");
+#endif
+        }
+
+        [MenuItem("HybridCLR/Build/Android64")]
+        public static void Build_Android64()
+        {
+            BuildTarget target = BuildTarget.Android;
+            BuildTarget activeTarget = EditorUserBuildSettings.activeBuildTarget;
+            if (activeTarget != BuildTarget.Android)
+            {
+                Debug.LogError("请先切到Android平台再打包");
+                return;
+            }
+            // Get filename.
+            string outputPath = $"{BuildConfig.ProjectDir}/Release-Android";
+
+            var buildOptions = BuildOptions.None;
+
+            string location = outputPath + "/HybridCLRTrial.apk";
+            BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions()
+            {
+                scenes = new string[] { "Assets/Scenes/main.unity" },
+                locationPathName = location,
+                options = buildOptions,
+                target = target,
+                targetGroup = BuildTargetGroup.Android,
+            };
+
+            Debug.Log("====> 第1次 Build App(为了生成补充AOT元数据dll)");
+            BuildPipeline.BuildPlayer(buildPlayerOptions);
+            Debug.Log("====> Build AssetBundle");
+            AssetBundleBuildHelper.BuildAssetBundleByTarget(target);
+
+            Debug.Log("====> 第2次打包");
+            BuildPipeline.BuildPlayer(buildPlayerOptions);
+#if UNITY_EDITOR
+            Application.OpenURL($"file:///{outputPath}");
+#endif
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/Editor/HybridCLR/BuildPlayerHelper.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7796c8df856ac4a4a9d644329c1f0958
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 175 - 0
GameClient/Assets/Editor/HybridCLR/BuildProcessor_2019.cs

@@ -0,0 +1,175 @@
+#if UNITY_2018_1_OR_NEWER && !UNITY_2020_1_OR_NEWER
+using System.Collections;
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEditor.Build;
+using UnityEditor.Build.Reporting;
+using UnityEngine;
+using UnityEngine.SceneManagement;
+using System.Linq;
+using System.IO;
+using System;
+using UnityEditor.UnityLinker;
+using System.Reflection;
+using UnityEditor.Il2Cpp;
+using HybridCLR.Editor.GlobalManagers;
+#if UNITY_ANDROID
+using UnityEditor.Android;
+#endif
+
+namespace HybridCLR
+{
+    public class BuildProcessor_2019 : IPreprocessBuildWithReport, IPostprocessBuildWithReport
+#if UNITY_ANDROID
+        , IPostGenerateGradleAndroidProject
+#endif
+        , IProcessSceneWithReport, IFilterBuildAssemblies, IPostBuildPlayerScriptDLLs, IUnityLinkerProcessor, IIl2CppProcessor
+    {
+        /// <summary>
+        /// 需要在Prefab上挂脚本的热更dll名称列表,不需要挂到Prefab上的脚本可以不放在这里
+        /// 但放在这里的dll即使勾选了 AnyPlatform 也会在打包过程中被排除
+        /// 
+        /// 另外请务必注意!: 需要挂脚本的dll的名字最好别改,因为这个列表无法热更(上线后删除或添加某些非挂脚本dll没问题)
+        /// </summary>
+        static List<string> monoDllNames = new List<string>() { "HotFix.dll"};
+
+        static MethodInfo s_BuildReport_AddMessage;
+
+        int IOrderedCallback.callbackOrder => 0;
+
+        static BuildProcessor_2019()
+        {
+            s_BuildReport_AddMessage = typeof(BuildReport).GetMethod("AddMessage", BindingFlags.Instance | BindingFlags.NonPublic);
+        }
+
+        void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
+        {
+            if (!Application.isBatchMode && !EditorUtility.DisplayDialog("确认", "建议 Build 之前先打包 AssetBundle\r\n是否继续?", "继续", "取消"))
+            {
+                s_BuildReport_AddMessage.Invoke(report, new object[] { LogType.Exception, "用户取消", "BuildFailedException" });
+                return;
+            }
+        }
+
+        string[] IFilterBuildAssemblies.OnFilterAssemblies(BuildOptions buildOptions, string[] assemblies)
+        {
+            // 将热更dll从打包列表中移除
+            List<string> newNames = new List<string>(assemblies.Length);
+
+            foreach(string assembly in assemblies)
+            {
+                bool found = false;
+                foreach(string removeName in monoDllNames)
+                {
+                    if(assembly.EndsWith(removeName, StringComparison.OrdinalIgnoreCase))
+                    {
+                        found = true;
+                        break;
+                    }
+                }
+
+                if(!found)
+                    newNames.Add(assembly);
+            }
+            
+            return newNames.ToArray();
+        }
+
+
+        [Serializable]
+        public class ScriptingAssemblies
+        {
+            public List<string> names;
+            public List<int> types;
+        }
+
+        void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport report)
+        {
+            AddBackHotFixAssembliesTo_BinFile(report, null);
+        }
+
+#if UNITY_ANDROID
+        void IPostGenerateGradleAndroidProject.OnPostGenerateGradleAndroidProject(string path)
+        {
+            // 由于 Android 平台在 OnPostprocessBuild 调用时已经生成完 apk 文件,因此需要提前调用
+            AddBackHotFixAssembliesTo_BinFile(null, path);
+        }
+#endif
+
+        private void AddBackHotFixAssembliesTo_BinFile(BuildReport report, 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(report.summary.outputPath), "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 monoDllNames)
+                {
+                    if(!scriptsData.dllNames.Contains(name))
+                    {
+                        scriptsData.dllNames.Add(name);
+                        scriptsData.dllTypes.Add(16); // user dll type
+                    }
+                }
+                binFile.scriptsData = scriptsData;
+
+                binFile.RebuildAndFlushToFile(binPath);
+            }
+        }
+
+
+        void IProcessSceneWithReport.OnProcessScene(Scene scene, BuildReport report)
+        {
+
+        }
+
+        void IPostBuildPlayerScriptDLLs.OnPostBuildPlayerScriptDLLs(BuildReport report)
+        {
+
+        }
+
+        string IUnityLinkerProcessor.GenerateAdditionalLinkXmlFile(BuildReport report, UnityLinkerBuildPipelineData data)
+        {
+            return String.Empty;
+        }
+
+        void IUnityLinkerProcessor.OnBeforeRun(BuildReport report, UnityLinkerBuildPipelineData data)
+        {
+        }
+
+        void IUnityLinkerProcessor.OnAfterRun(BuildReport report, UnityLinkerBuildPipelineData data)
+        {
+        }
+
+        void IIl2CppProcessor.OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data)
+        {
+
+        }
+
+
+#if UNITY_IOS
+    // hook UnityEditor.BuildCompletionEventsHandler.ReportPostBuildCompletionInfo() ? 因为没有 mac 打包平台因此不清楚
+#endif
+    }
+
+}
+#endif

+ 11 - 0
GameClient/Assets/Editor/HybridCLR/BuildProcessor_2019.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ca7af90ea994cd145a19373563c301fc
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 165 - 0
GameClient/Assets/Editor/HybridCLR/BuildProcessor_2020_1_OR_NEWER.cs

@@ -0,0 +1,165 @@
+#if UNITY_2020_1_OR_NEWER
+using System.Collections;
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEditor.Build;
+using UnityEditor.Build.Reporting;
+using UnityEngine;
+using UnityEngine.SceneManagement;
+using System.Linq;
+using System.IO;
+using System;
+using UnityEditor.UnityLinker;
+using System.Reflection;
+using UnityEditor.Il2Cpp;
+#if UNITY_ANDROID
+using UnityEditor.Android;
+#endif
+
+namespace HybridCLR
+{
+    public class BuildProcessor_2020_1_OR_NEWER : IPreprocessBuildWithReport,
+#if UNITY_ANDROID
+        IPostGenerateGradleAndroidProject,
+#endif
+        IPostprocessBuildWithReport,
+        IFilterBuildAssemblies,
+        IUnityLinkerProcessor
+#if !UNITY_2021_1_OR_NEWER
+    , IIl2CppProcessor
+#endif
+    {
+        public int callbackOrder => 0;
+
+        public string[] OnFilterAssemblies(BuildOptions buildOptions, string[] assemblies)
+        {
+            // 将热更dll从打包列表中移除
+            return assemblies.Where(ass => BuildConfig.AllHotUpdateDllNames.All(dll => !ass.EndsWith(dll, StringComparison.OrdinalIgnoreCase))).ToArray();
+        }
+
+
+        [Serializable]
+        private class ScriptingAssemblies
+        {
+            public List<string> names;
+            public List<int> types;
+        }
+
+        public void OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data)
+        {
+            Debug.Log("==== OnBeforeConvertRun");
+            // 此回调只在 2020中调用
+            CopyStripDlls(data.target);
+        }
+
+        public void OnPostGenerateGradleAndroidProject(string path)
+        {
+            Debug.Log("==== OnPostGenerateGradleAndroidProject");
+            // 由于 Android 平台在 OnPostprocessBuild 调用时已经生成完 apk 文件,因此需要提前调用
+            AddBackHotFixAssembliesToJson(null, path);
+
+            // 对于 2020, 已经在OnBeforeConvertRun中复制了,因此这儿不再复制
+//#if UNITY_2021_1_OR_NEWER
+//            BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
+//            CopyStripDlls(target);
+//#endif
+        }
+
+        public void OnPostprocessBuild(BuildReport report)
+        {
+            Debug.Log("==== OnPostprocessBuild");
+#if !UNITY_ANDROID
+
+            AddBackHotFixAssembliesToJson(report, report.summary.outputPath);
+#endif
+        // Unity 2021开始,不再清理这个Temp目录,因此在这个时机复制较为合适
+#if UNITY_2021_1_OR_NEWER
+            BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
+            CopyStripDlls(target);
+#endif
+        }
+        
+        private void AddBackHotFixAssembliesToJson(BuildReport report, string path)
+        {
+            /*
+             * ScriptingAssemblies.json 文件中记录了所有的dll名称,此列表在游戏启动时自动加载,
+             * 不在此列表中的dll在资源反序列化时无法被找到其类型
+             * 因此 OnFilterAssemblies 中移除的条目需要再加回来
+             */
+            string[] jsonFiles = Directory.GetFiles(Path.GetDirectoryName(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<ScriptingAssemblies>(content);
+                foreach (string name in BuildConfig.MonoHotUpdateDllNames)
+                {
+                    if(!scriptingAssemblies.names.Contains(name))
+                    {
+                        scriptingAssemblies.names.Add(name);
+                        scriptingAssemblies.types.Add(16); // user dll type
+                    }
+                }
+                content = JsonUtility.ToJson(scriptingAssemblies);
+
+                File.WriteAllText(file, content);
+            }
+        }
+
+        private void CopyStripDlls(BuildTarget 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($"copy strip dll {fileFullPath} ==> {dstPath}/{file}");
+                File.Copy($"{fileFullPath}", $"{dstPath}/{file}", true);
+            }
+        }
+
+        #region useless
+
+        private static void BuildExceptionEventHandler(object sender, UnhandledExceptionEventArgs e)
+        {
+
+        }
+
+        public void OnPreprocessBuild(BuildReport report)
+        {
+
+        }
+
+        public string GenerateAdditionalLinkXmlFile(BuildReport report, UnityLinkerBuildPipelineData data)
+        {
+            return String.Empty;
+        }
+
+        public void OnBeforeRun(BuildReport report, UnityLinkerBuildPipelineData data)
+        {
+
+        }
+
+        public void OnAfterRun(BuildReport report, UnityLinkerBuildPipelineData data)
+        {
+        }
+
+
+#if UNITY_IOS
+    // hook UnityEditor.BuildCompletionEventsHandler.ReportPostBuildCompletionInfo() ? 因为没有 mac 打包平台因此不清楚
+#endif
+        #endregion
+    }
+
+}
+#endif

+ 11 - 0
GameClient/Assets/Editor/HybridCLR/BuildProcessor_2020_1_OR_NEWER.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: af5a0eff26871774893f1c7ec32b2bde
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 65 - 0
GameClient/Assets/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
+{
+    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);
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 8 - 0
GameClient/Assets/Editor/HybridCLR/Generators.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f85b93bff3478c045ae862a7cc216b18
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
GameClient/Assets/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.Generators
+{
+    internal static class ConstStrings
+    {
+        public const string typeObjectPtr = "Il2CppObject*";
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 40 - 0
GameClient/Assets/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.Generators
+{
+    public class FileRegionReplace
+    {
+        private readonly string _tplFile;
+
+        private readonly Dictionary<string, string> _regionReplaceContents = new Dictionary<string, string>();
+
+        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);
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 70 - 0
GameClient/Assets/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.Generators
+{
+    internal class GeneratorConfig
+    {
+        /// <summary>
+        /// 目前已经根据热更新dll的依赖自动计算需要扫描哪些dll来收集桥接函数。
+        /// 只要你的热更新以assembly def形式放到项目中,是不需要改这个的
+        /// </summary>
+        /// <returns></returns>
+        public static List<string> GetExtraAssembiles()
+        {
+            return new List<string>
+            {
+                // "mscorlib",
+            };
+        }
+
+        /// <summary>
+        /// 暂时没有仔细扫描泛型,如果运行时发现有生成缺失,先手动在此添加类
+        /// </summary>
+        /// <returns></returns>
+        public static List<Type> PrepareCustomGenericTypes()
+        {
+            return new List<Type>
+            {
+                typeof(Action<int, string, Vector3>),
+            };
+        }
+
+        /// <summary>
+        /// 如果提示缺失桥接函数,将提示缺失的签名加入到下列列表是简单的做法。
+        /// 这里添加64位App缺失的桥接函数签名
+        /// </summary>
+        /// <returns></returns>
+        public static List<string> PrepareCustomMethodSignatures64()
+        {
+            return new List<string>
+            {
+                "vi8i8",
+                "i4i8i8i4i4i8i8",
+                "i8i8S12",
+                "S12i8S12",
+                "S12i8S12S12",
+                "i16i8i16i16",
+            };
+        }
+
+        /// <summary>
+        /// 如果提示缺失桥接函数,将提示缺失的签名加入到下列列表是简单的做法。
+        /// 这里添加32位App缺失的桥接函数签名
+        /// </summary>
+        /// <returns></returns>
+        public static List<string> PrepareCustomMethodSignatures32()
+        {
+            return new List<string>
+            {
+                "vi4i4",
+                "S12i4S12S12",
+            };
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 8 - 0
GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4aa66b41c89ed7742ad067898725f7ff
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 26 - 0
GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/IPlatformAdaptor.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HybridCLR.Generators.MethodBridge
+{
+    public interface IPlatformAdaptor
+    {
+        bool IsArch32 { get; }
+
+        TypeInfo CreateTypeInfo(Type type, bool returnValue);
+
+        IEnumerable<MethodBridgeSig> GetPreserveMethods();
+
+        void GenerateCall(MethodBridgeSig method, List<string> outputLines);
+
+        void GenerateInvoke(MethodBridgeSig method, List<string> outputLines);
+
+        void GenCallStub(List<MethodBridgeSig> methods, List<string> lines);
+
+        void GenInvokeStub(List<MethodBridgeSig> methods, List<string> lines);
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 323 - 0
GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/MethodBridgeGenerator.cs

@@ -0,0 +1,323 @@
+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.Generators.MethodBridge
+{
+
+    public class TypeGenInfo
+    {
+        public Type Type { get; set; }
+
+        public List<MethodInfo> GenericMethods { get; set; }
+    }
+
+    public class MethodBridgeGeneratorOptions
+    {
+        public List<Assembly> Assemblies { get; set; }
+
+        public PlatformABI CallConvention { get; set; }
+
+        public string OutputFile { get; set; }
+    }
+
+    public class MethodBridgeGenerator
+    {
+        private readonly List<Assembly> _assemblies;
+
+        private readonly PlatformABI _callConvention;
+
+        private readonly string _outputFile;
+
+        private readonly IPlatformAdaptor _platformAdaptor;
+
+        private readonly HashSet<MethodBridgeSig> _callMethodSet = new HashSet<MethodBridgeSig>();
+
+        private List<MethodBridgeSig> _callMethodList;
+
+        private readonly HashSet<MethodBridgeSig> _invokeMethodSet = new HashSet<MethodBridgeSig>();
+
+        private List<MethodBridgeSig> _invokeMethodList;
+
+        public MethodBridgeGenerator(MethodBridgeGeneratorOptions options)
+        {
+            _assemblies = options.Assemblies;
+            _callConvention = options.CallConvention;
+            _outputFile = options.OutputFile;
+            _platformAdaptor = CreatePlatformAdaptor(options.CallConvention);
+        }
+
+        private static IPlatformAdaptor CreatePlatformAdaptor(PlatformABI type)
+        {
+            return type switch
+            {
+                PlatformABI.Universal32 => new PlatformAdaptor_Universal32(),
+                PlatformABI.Universal64 => new PlatformAdaptor_Universal64(),
+                PlatformABI.Arm64 => new PlatformAdaptor_Arm64(),
+                _ => throw new NotSupportedException(),
+            };
+        }
+
+        private string GetTemplateFile()
+        {
+            string tplFile = _callConvention switch
+            {
+                PlatformABI.Universal32 => "Universal32",
+                PlatformABI.Universal64 => "Universal64",
+                PlatformABI.Arm64 => "Arm64",
+                _ => throw new NotSupportedException(),
+            };
+            return $"{Application.dataPath}/Editor/HybridCLR/Generators/Templates/MethodBridge_{tplFile}.cpp";
+        }
+
+        public IEnumerable<TypeGenInfo> GetGenerateTypes()
+        {
+            return new List<TypeGenInfo>();
+        }
+
+        private MethodBridgeSig CreateMethodBridgeSig(bool isStatic, ParameterInfo returnType, ParameterInfo[] parameters)
+        {
+            var paramInfos = new List<ParamInfo>();
+            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 AddCallMethod(MethodBridgeSig method)
+        {
+            if (_callMethodSet.Add(method))
+            {
+                method.Init();
+            }
+        }
+
+        private void AddInvokeMethod(MethodBridgeSig method)
+        {
+            if (_invokeMethodSet.Add(method))
+            {
+                method.Init();
+            }
+        }
+
+        private void ScanType(Type type)
+        {
+            if (type.IsGenericTypeDefinition)
+            {
+                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;
+                }
+                var instanceCallMethod = CreateMethodBridgeSig(false, method.ReturnParameter, method.GetParameters());
+                AddCallMethod(instanceCallMethod);
+                var staticCallMethod = CreateMethodBridgeSig(true, method.ReturnParameter, method.GetParameters());
+                AddCallMethod(staticCallMethod);
+
+                var invokeMethod = CreateMethodBridgeSig(true, method.ReturnParameter, method.GetParameters());
+                AddInvokeMethod(invokeMethod);
+                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;
+                }
+                var callMethod = CreateMethodBridgeSig(method.IsStatic, method.ReturnParameter, method.GetParameters());
+                AddCallMethod(callMethod);
+
+                var invokeMethod = CreateMethodBridgeSig(true, method.ReturnParameter, method.GetParameters());
+                AddInvokeMethod(invokeMethod);
+            }
+
+            foreach (var method in type.GetConstructors(BindingFlags.Instance | BindingFlags.Public
+| BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy))
+            {
+                var callMethod = CreateMethodBridgeSig(false, null, method.GetParameters());
+                AddCallMethod(callMethod);
+
+                var invokeMethod = CreateMethodBridgeSig(true, null, method.GetParameters());
+                AddInvokeMethod(invokeMethod);
+            }
+
+            foreach (var subType in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
+            {
+                ScanType(subType);
+            }
+        }
+
+        public void PrepareFromAssemblies()
+        {
+            foreach (var ass in _assemblies)
+            {
+                //Debug.Log("prepare assembly:" + ass.FullName);
+                foreach (var type in ass.GetTypes())
+                {
+                    ScanType(type);
+                }
+            }
+        }
+
+        public void PrepareCommon1()
+        {
+            // (void + int64 + float) * (int64 + float) * (0 - 20) = 120
+            TypeInfo typeVoid = new TypeInfo(typeof(void), ParamOrReturnType.VOID);
+            TypeInfo typeLong = new TypeInfo(typeof(long), ParamOrReturnType.I8_U8);
+            TypeInfo typeDouble = new TypeInfo(typeof(double), ParamOrReturnType.R8);
+            int maxParamCount = 20;
+                
+            foreach (var returnType in new TypeInfo[] { typeVoid, typeLong, typeDouble })
+            {
+                var rt = new ReturnInfo() { Type = returnType };
+                foreach (var argType in new TypeInfo[] { typeLong, typeDouble })
+                {
+                    for (int paramCount = 0; paramCount <= maxParamCount; paramCount++)
+                    {
+                        var paramInfos = new List<ParamInfo>();
+                        for (int i = 0; i < paramCount; i++)
+                        {
+                            paramInfos.Add(new ParamInfo() { Type = argType });
+                        }
+                        var mbs = new MethodBridgeSig() { ReturnInfo = rt, ParamInfos =  paramInfos};
+                        AddCallMethod(mbs);
+                    }
+                }
+            }
+        }
+
+        public void PrepareCommon2()
+        {
+            // (void + int64 + float) * (int64 + float + sr) ^ (0 - 4) = 363
+            TypeInfo typeVoid = new TypeInfo(typeof(void), ParamOrReturnType.VOID);
+            TypeInfo typeLong = new TypeInfo(typeof(long), ParamOrReturnType.I8_U8);
+            TypeInfo typeDouble = new TypeInfo(typeof(double), ParamOrReturnType.R8);
+
+            int maxParamCount = 4;
+
+            var argTypes = new TypeInfo[] { typeLong, typeDouble };
+            int paramTypeNum = argTypes.Length;
+            foreach (var returnType in new TypeInfo[] { typeVoid, typeLong, typeDouble })
+            {
+                var rt = new ReturnInfo() { Type = returnType };
+                for(int paramCount = 1; paramCount <= maxParamCount; paramCount++)
+                {
+                    int totalCombinationNum = (int)Math.Pow(paramTypeNum, paramCount);
+
+                    for (int k = 0; k < totalCombinationNum; k++)
+                    {
+                        var paramInfos = new List<ParamInfo>();
+                        int c = k;
+                        for(int i = 0; i < paramCount; i++)
+                        {
+                            paramInfos.Add(new ParamInfo { Type = argTypes[c % paramTypeNum] });
+                            c /= paramTypeNum;
+                        }
+                        var mbs = new MethodBridgeSig() { ReturnInfo = rt, ParamInfos = paramInfos };
+                        AddCallMethod(mbs);
+                    }
+                }
+            }
+        }
+
+        private void PrepareMethodsFromCustomeGenericTypes()
+        {
+            foreach (var type in GeneratorConfig.PrepareCustomGenericTypes())
+            {
+                ScanType(type);
+            }
+        }
+
+        public void PrepareMethods()
+        {
+            PrepareCommon1();
+            PrepareCommon2();
+            PrepareMethodsFromCustomeGenericTypes();
+
+
+            foreach(var methodSig in _platformAdaptor.IsArch32 ? GeneratorConfig.PrepareCustomMethodSignatures32() : GeneratorConfig.PrepareCustomMethodSignatures64())
+            {
+                var method = MethodBridgeSig.CreateBySignatuer(methodSig);
+                AddCallMethod(method);
+                AddInvokeMethod(method);
+            }
+            foreach(var method in _platformAdaptor.GetPreserveMethods())
+            {
+                AddCallMethod(method);
+                AddInvokeMethod(method);
+            }
+            PrepareFromAssemblies();
+
+            {
+                var sortedMethods = new SortedDictionary<string, MethodBridgeSig>();
+                foreach (var method in _callMethodSet)
+                {
+                    sortedMethods.Add(method.CreateCallSigName(), method);
+                }
+                _callMethodList = sortedMethods.Values.ToList();
+            }
+            {
+                var sortedMethods = new SortedDictionary<string, MethodBridgeSig>();
+                foreach (var method in _invokeMethodSet)
+                {
+                    sortedMethods.Add(method.CreateCallSigName(), method);
+                }
+                _invokeMethodList = sortedMethods.Values.ToList();
+            }
+        }
+
+        public void Generate()
+        {
+            var frr = new FileRegionReplace(GetTemplateFile());
+
+            List<string> lines = new List<string>(20_0000);
+
+            Debug.LogFormat("== call method count:{0}", _callMethodList.Count);
+
+            foreach(var method in _callMethodList)
+            {
+                _platformAdaptor.GenerateCall(method, lines);
+            }
+
+            Debug.LogFormat("== invoke method count:{0}", _invokeMethodList.Count);
+            foreach (var method in _invokeMethodList)
+            {
+                _platformAdaptor.GenerateInvoke(method, lines);
+            }
+
+            _platformAdaptor.GenCallStub(_callMethodList, lines);
+            _platformAdaptor.GenInvokeStub(_invokeMethodList, lines);
+
+            frr.Replace("INVOKE_STUB", string.Join("\n", lines));
+
+            Directory.CreateDirectory(Path.GetDirectoryName(_outputFile));
+
+            frr.Commit(_outputFile);
+        }
+
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 156 - 0
GameClient/Assets/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.Generators.MethodBridge
+{
+    public class MethodBridgeSig : IEquatable<MethodBridgeSig>
+    {
+
+        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<ParamInfo>()};
+            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<ParamInfo> 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;
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 44 - 0
GameClient/Assets/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.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();
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 38 - 0
GameClient/Assets/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.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,
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 9 - 0
GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformABI.cs

@@ -0,0 +1,9 @@
+namespace HybridCLR.Generators.MethodBridge
+{
+    public enum PlatformABI
+    {
+        Universal32,
+        Universal64,
+        Arm64,
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 144 - 0
GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptorBase.cs

@@ -0,0 +1,144 @@
+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.Generators.MethodBridge
+{
+    internal abstract class PlatformAdaptorBase : IPlatformAdaptor
+    {
+        public abstract bool IsArch32 { get; }
+
+        public abstract TypeInfo PointerType { get; }
+
+        protected abstract Dictionary<Type, TypeInfo> CacheTypes { get; }
+
+        protected abstract TypeInfo CreateValueType(Type type, bool returnValue);
+
+        public abstract void GenerateCall(MethodBridgeSig method, List<string> lines);
+
+        public abstract void GenerateInvoke(MethodBridgeSig method, List<string> lines);
+
+        public abstract IEnumerable<MethodBridgeSig> GetPreserveMethods();
+
+        private static Dictionary<Type, (int, int)> _typeSizeCache64 = new Dictionary<Type, (int, int)>();
+
+        private static Dictionary<Type, (int, int)> _typeSizeCache32 = new Dictionary<Type, (int, int)>();
+
+        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<int>)method.CreateDelegate(typeof(Func<int>)))();
+
+            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 GenCallStub(List<MethodBridgeSig> methods, List<string> lines)
+        {
+            lines.Add($@"
+NativeCallMethod hybridclr::interpreter::g_callStub[] = 
+{{
+");
+
+            foreach (var method in methods)
+            {
+                lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", (Il2CppMethodPointer)__Native2ManagedCall_{method.CreateInvokeSigName()}, (Il2CppMethodPointer)__Native2ManagedCall_AdjustorThunk_{method.CreateCallSigName()}, __Managed2NativeCall_{method.CreateInvokeSigName()}}},");
+            }
+
+            lines.Add($"\t{{nullptr, nullptr}},");
+            lines.Add("};");
+        }
+
+        public void GenInvokeStub(List<MethodBridgeSig> methods, List<string> lines)
+        {
+            lines.Add($@"
+NativeInvokeMethod hybridclr::interpreter::g_invokeStub[] = 
+{{
+");
+
+            foreach (var method in methods)
+            {
+                lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", __Invoke_instance_{method.CreateInvokeSigName()}, __Invoke_static_{method.CreateInvokeSigName()}}},");
+            }
+
+            lines.Add($"\t{{nullptr, nullptr, nullptr}},");
+            lines.Add("};");
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 354 - 0
GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Arm64.cs

@@ -0,0 +1,354 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+
+namespace HybridCLR.Generators.MethodBridge
+{
+    internal class PlatformAdaptor_Arm64 : PlatformAdaptorBase
+    {
+
+        private static readonly Dictionary<Type, TypeInfo> s_typeInfoCaches = new Dictionary<Type, TypeInfo>()
+        {
+            { 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<Type, TypeInfo> 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 IEnumerable<MethodBridgeSig> PrepareCommon1()
+        {
+            // (void + int32 + int64 + float + double) * (int32 + int64 + float + double) * (0 - 20) = 420
+            TypeInfo typeVoid = new TypeInfo(typeof(void), ParamOrReturnType.VOID);
+            TypeInfo typeInt = new TypeInfo(typeof(int), ParamOrReturnType.I4_U4);
+            TypeInfo typeLong = new TypeInfo(typeof(long), ParamOrReturnType.I8_U8);
+            TypeInfo typeFloat = new TypeInfo(typeof(float), ParamOrReturnType.R4);
+            TypeInfo typeDouble = new TypeInfo(typeof(double), ParamOrReturnType.R8);
+            int maxParamCount = 20;
+
+            foreach (var returnType in new TypeInfo[] { typeVoid, typeInt, typeLong, typeFloat, typeDouble })
+            {
+                var rt = new ReturnInfo() { Type = returnType };
+                foreach (var argType in new TypeInfo[] { typeInt, typeLong, typeFloat, typeDouble })
+                {
+                    for (int paramCount = 0; paramCount <= maxParamCount; paramCount++)
+                    {
+                        var paramInfos = new List<ParamInfo>();
+                        for (int i = 0; i < paramCount; i++)
+                        {
+                            paramInfos.Add(new ParamInfo() { Type = argType });
+                        }
+                        var mbs = new MethodBridgeSig() { ReturnInfo = rt, ParamInfos = paramInfos };
+                        yield return mbs;
+                    }
+                }
+            }
+        }
+
+        public IEnumerable<MethodBridgeSig> PrepareCommon2()
+        {
+            // (void + int32 + int64 + float + double + v2f + v3f + v4f + s2) * (int32 + int64 + float + double + v2f + v3f + v4f + s2 + sr) ^ (0 - 2) = 399
+            TypeInfo typeVoid = new TypeInfo(typeof(void), ParamOrReturnType.VOID);
+            TypeInfo typeInt = new TypeInfo(typeof(int), ParamOrReturnType.I4_U4);
+            TypeInfo typeLong = new TypeInfo(typeof(long), ParamOrReturnType.I8_U8);
+            TypeInfo typeFloat = new TypeInfo(typeof(float), ParamOrReturnType.R4);
+            TypeInfo typeDouble = new TypeInfo(typeof(double), ParamOrReturnType.R8);
+            TypeInfo typeV2f = new TypeInfo(typeof(Vector2), ParamOrReturnType.ARM64_HFA_FLOAT_2);
+            TypeInfo typeV3f = new TypeInfo(typeof(Vector3), ParamOrReturnType.ARM64_HFA_FLOAT_3);
+            TypeInfo typeV4f = new TypeInfo(typeof(Vector4), ParamOrReturnType.ARM64_HFA_FLOAT_4);
+
+            int maxParamCount = 2;
+
+            var argTypes = new TypeInfo[] { typeInt, typeLong, typeFloat, typeDouble, typeV2f, typeV3f, typeV4f };
+            int paramTypeNum = argTypes.Length;
+            foreach (var returnType in new TypeInfo[] { typeVoid, typeInt, typeLong, typeFloat, typeDouble, typeV2f, typeV3f, typeV4f })
+            {
+                var rt = new ReturnInfo() { Type = returnType };
+                for (int paramCount = 0; paramCount <= maxParamCount; paramCount++)
+                {
+                    int totalCombinationNum = (int)Math.Pow(paramTypeNum, paramCount);
+
+                    for (int k = 0; k < totalCombinationNum; k++)
+                    {
+                        var paramInfos = new List<ParamInfo>();
+                        int c = k;
+                        for (int i = 0; i < paramCount; i++)
+                        {
+                            paramInfos.Add(new ParamInfo { Type = argTypes[c % paramTypeNum] });
+                            c /= paramTypeNum;
+                        }
+                        var mbs = new MethodBridgeSig() { ReturnInfo = rt, ParamInfos = paramInfos };
+                        yield return mbs;
+                    }
+                }
+            }
+        }
+
+        public override IEnumerable<MethodBridgeSig> GetPreserveMethods()
+        {
+            foreach (var method in PrepareCommon1())
+            {
+                yield return method;
+            }
+            foreach (var method in PrepareCommon2())
+            {
+                yield return method;
+            }
+        }
+
+        public override void GenerateCall(MethodBridgeSig method, List<string> lines)
+        {
+            //int totalQuadWordNum = method.ParamInfos.Sum(p => p.GetParamSlotNum(this.CallConventionType)) + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+            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" }));
+
+            string invokeAssignArgs = @$"
+	if (hybridclr::IsInstanceMethod(method))
+	{{
+        args[0].ptr = __this;
+{string.Join("\n", method.ParamInfos.Skip(1).Select(p => $"\t\targs[{p.Index}].u64 = *(uint64_t*)__args[{p.Index - 1}];"))}
+    }}
+	else
+	{{
+{string.Join("\n", method.ParamInfos.Select(p => $"\t\targs[{p.Index}].u64 = *(uint64_t*)__args[{p.Index}];"))}
+    }}
+";
+
+            lines.Add($@"
+static {method.ReturnInfo.Type.GetTypeName()} __Native2ManagedCall_{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;" : "")}
+}}
+
+static {method.ReturnInfo.Type.GetTypeName()} __Native2ManagedCall_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;" : "")}
+}}
+
+static void __Managed2NativeCall_{method.CreateCallSigName()}(const MethodInfo* method, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret)
+{{
+    if (hybridclr::metadata::IsInstanceMethod(method) && !localVarBase[argVarIndexs[0]].obj)
+    {{
+        il2cpp::vm::Exception::RaiseNullReferenceException();
+    }}
+    Interpreter::RuntimeClassCCtorInit(method);
+    typedef {method.ReturnInfo.Type.GetTypeName()} (*NativeMethod)({paramListStr});
+    {(!method.ReturnInfo.IsVoid ? $"*({method.ReturnInfo.Type.GetTypeName()}*)ret = " : "")}((NativeMethod)(GetInterpreterDirectlyCallMethodPointer(method)))({paramNameListStr});
+}}
+");
+        }
+
+        public override void GenerateInvoke(MethodBridgeSig method, List<string> lines)
+        {
+            //int totalQuadWordNum = method.ParamInfos.Sum(p => p.GetParamSlotNum(this.CallConventionType)) + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+            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" }));
+
+            string invokeAssignArgs = @$"
+	if (hybridclr::IsInstanceMethod(method))
+	{{
+        args[0].ptr = __this;
+{string.Join("\n", method.ParamInfos.Skip(1).Select(p => $"\t\targs[{p.Index}].u64 = *(uint64_t*)__args[{p.Index - 1}];"))}
+    }}
+	else
+	{{
+{string.Join("\n", method.ParamInfos.Select(p => $"\t\targs[{p.Index}].u64 = *(uint64_t*)__args[{p.Index}];"))}
+    }}
+";
+
+
+            lines.Add($@"
+#ifdef HYBRIDCLR_UNITY_2021_OR_NEW
+static void __Invoke_instance_{method.CreateCallSigName()}(Il2CppMethodPointer __methodPtr, const MethodInfo* __method, void* __this, void** __args, void* __ret)
+{{
+    StackObject args[{totalQuadWordNum + 1}] = {{ (uint64_t)__this }};
+    ConvertInvokeArgs(args+1, __method, __args);
+    Interpreter::Execute(__method, args, __ret);
+}}
+
+static void __Invoke_static_{method.CreateCallSigName()}(Il2CppMethodPointer __methodPtr, const MethodInfo* __method, void* __this, void** __args, void* __ret)
+{{
+    StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{ }};
+    ConvertInvokeArgs(args, __method, __args);
+    Interpreter::Execute(__method, args, __ret);
+}}
+#else
+static void* __Invoke_instance_{method.CreateCallSigName()}(Il2CppMethodPointer __methodPtr, const MethodInfo* __method, void* __this, void** __args)
+{{
+    StackObject args[{totalQuadWordNum + 1}] = {{ (uint64_t)AdjustValueTypeSelfPointer(({ConstStrings.typeObjectPtr})__this, __method)}};
+    ConvertInvokeArgs(args+1, __method, __args);
+    StackObject* ret = {(!method.ReturnInfo.IsVoid ? "args + " + (method.ParamInfos.Count + 1) : "nullptr")};
+    Interpreter::Execute(__method, args, ret);
+    return {(!method.ReturnInfo.IsVoid ? $"TranslateNativeValueToBoxValue(__method->return_type, ret)" : "nullptr")};
+}}
+
+static void* __Invoke_static_{method.CreateCallSigName()}(Il2CppMethodPointer __methodPtr, const MethodInfo* __method, void* __this, void** __args)
+{{
+    StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{ }};
+    ConvertInvokeArgs(args, __method, __args);
+    StackObject* ret = {(!method.ReturnInfo.IsVoid ? "args + " + method.ParamInfos.Count : "nullptr")};
+    Interpreter::Execute(__method, args, ret);
+    return {(!method.ReturnInfo.IsVoid ? $"TranslateNativeValueToBoxValue(__method->return_type, ret)" : "nullptr")};
+}}
+#endif
+");
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 240 - 0
GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal32.cs

@@ -0,0 +1,240 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+
+namespace HybridCLR.Generators.MethodBridge
+{
+    internal class PlatformAdaptor_Universal32 : PlatformAdaptorBase
+    {
+
+        private static readonly Dictionary<Type, TypeInfo> s_typeInfoCaches = new Dictionary<Type, TypeInfo>()
+        {
+            { 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<Type, TypeInfo> 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 IEnumerable<MethodBridgeSig> PrepareCommon1()
+        {
+            // (void + int32 + int64 + float + double) * (int32 + int64 + float + double) * (0 - 20) = 420
+            TypeInfo typeVoid = new TypeInfo(typeof(void), ParamOrReturnType.VOID);
+            TypeInfo typeInt = new TypeInfo(typeof(int), ParamOrReturnType.I4_U4);
+            TypeInfo typeLong = new TypeInfo(typeof(long), ParamOrReturnType.I8_U8);
+            TypeInfo typeFloat = new TypeInfo(typeof(float), ParamOrReturnType.R4);
+            TypeInfo typeDouble = new TypeInfo(typeof(double), ParamOrReturnType.R8);
+            int maxParamCount = 20;
+
+            foreach (var returnType in new TypeInfo[] { typeVoid, typeInt, typeLong, typeFloat, typeDouble })
+            {
+                var rt = new ReturnInfo() { Type = returnType };
+                foreach (var argType in new TypeInfo[] { typeInt, typeLong, typeFloat, typeDouble })
+                {
+                    for (int paramCount = 0; paramCount <= maxParamCount; paramCount++)
+                    {
+                        var paramInfos = new List<ParamInfo>();
+                        for (int i = 0; i < paramCount; i++)
+                        {
+                            paramInfos.Add(new ParamInfo() { Type = argType });
+                        }
+                        var mbs = new MethodBridgeSig() { ReturnInfo = rt, ParamInfos = paramInfos };
+                        yield return mbs;
+                    }
+                }
+            }
+        }
+
+        public IEnumerable<MethodBridgeSig> PrepareCommon2()
+        {
+            // (void + int32 + int64 + float + double + v2f + v3f + v4f + s2) * (int32 + int64 + float + double + v2f + v3f + v4f + s2 + sr) ^ (0 - 2) = 399
+            TypeInfo typeVoid = new TypeInfo(typeof(void), ParamOrReturnType.VOID);
+            TypeInfo typeInt = new TypeInfo(typeof(int), ParamOrReturnType.I4_U4);
+            TypeInfo typeLong = new TypeInfo(typeof(long), ParamOrReturnType.I8_U8);
+            TypeInfo typeFloat = new TypeInfo(typeof(float), ParamOrReturnType.R4);
+            TypeInfo typeDouble = new TypeInfo(typeof(double), ParamOrReturnType.R8);
+            //TypeInfo typeStructRef = new TypeInfo(null, ParamOrReturnType.STRUCTURE_AS_REF_PARAM);
+
+            int maxParamCount = 2;
+
+            var argTypes = new TypeInfo[] { typeInt, typeLong, typeFloat, typeDouble };
+            int paramTypeNum = argTypes.Length;
+            foreach (var returnType in new TypeInfo[] { typeVoid, typeInt, typeLong, typeFloat, typeDouble })
+            {
+                var rt = new ReturnInfo() { Type = returnType };
+                for (int paramCount = 0; paramCount <= maxParamCount; paramCount++)
+                {
+                    int totalCombinationNum = (int)Math.Pow(paramTypeNum, paramCount);
+
+                    for (int k = 0; k < totalCombinationNum; k++)
+                    {
+                        var paramInfos = new List<ParamInfo>();
+                        int c = k;
+                        for (int i = 0; i < paramCount; i++)
+                        {
+                            paramInfos.Add(new ParamInfo { Type = argTypes[c % paramTypeNum] });
+                            c /= paramTypeNum;
+                        }
+                        var mbs = new MethodBridgeSig() { ReturnInfo = rt, ParamInfos = paramInfos };
+                        yield return mbs;
+                    }
+                }
+            }
+        }
+
+        public override IEnumerable<MethodBridgeSig> GetPreserveMethods()
+        {
+            foreach (var method in PrepareCommon1())
+            {
+                yield return method;
+            }
+            foreach (var method in PrepareCommon2())
+            {
+                yield return method;
+            }
+        }
+
+        public override void GenerateCall(MethodBridgeSig method, List<string> lines)
+        {
+            //int totalQuadWordNum = method.ParamInfos.Sum(p => p.GetParamSlotNum(this.CallConventionType)) + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+            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" }));
+
+            string invokeAssignArgs = @$"
+	if (hybridclr::IsInstanceMethod(method))
+	{{
+        args[0].ptr = __this;
+{string.Join("\n", method.ParamInfos.Skip(1).Select(p => $"\t\targs[{p.Index}].u64 = *(uint64_t*)__args[{p.Index - 1}];"))}
+    }}
+	else
+	{{
+{string.Join("\n", method.ParamInfos.Select(p => $"\t\targs[{p.Index}].u64 = *(uint64_t*)__args[{p.Index}];"))}
+    }}
+";
+
+            lines.Add($@"
+static {method.ReturnInfo.Type.GetTypeName()} __Native2ManagedCall_{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;" : "")}
+}}
+
+static {method.ReturnInfo.Type.GetTypeName()} __Native2ManagedCall_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;" : "")}
+}}
+
+static void __Managed2NativeCall_{method.CreateCallSigName()}(const MethodInfo* method, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret)
+{{
+    if (hybridclr::metadata::IsInstanceMethod(method) && !localVarBase[argVarIndexs[0]].obj)
+    {{
+        il2cpp::vm::Exception::RaiseNullReferenceException();
+    }}
+    Interpreter::RuntimeClassCCtorInit(method);
+    typedef {method.ReturnInfo.Type.GetTypeName()} (*NativeMethod)({paramListStr});
+    {(!method.ReturnInfo.IsVoid ? $"*({method.ReturnInfo.Type.GetTypeName()}*)ret = " : "")}((NativeMethod)(GetInterpreterDirectlyCallMethodPointer(method)))({paramNameListStr});
+}}
+");
+
+        }
+
+
+        public override void GenerateInvoke(MethodBridgeSig method, List<string> lines)
+        {
+            //int totalQuadWordNum = method.ParamInfos.Sum(p => p.GetParamSlotNum(this.CallConventionType)) + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+            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" }));
+
+            string invokeAssignArgs = @$"
+	if (hybridclr::IsInstanceMethod(method))
+	{{
+        args[0].ptr = __this;
+{string.Join("\n", method.ParamInfos.Skip(1).Select(p => $"\t\targs[{p.Index}].u64 = *(uint64_t*)__args[{p.Index - 1}];"))}
+    }}
+	else
+	{{
+{string.Join("\n", method.ParamInfos.Select(p => $"\t\targs[{p.Index}].u64 = *(uint64_t*)__args[{p.Index}];"))}
+    }}
+";
+
+
+            lines.Add($@"
+#ifdef HYBRIDCLR_UNITY_2021_OR_NEW
+static void __Invoke_instance_{method.CreateCallSigName()}(Il2CppMethodPointer __methodPtr, const MethodInfo* __method, void* __this, void** __args, void* __ret)
+{{
+    StackObject args[{totalQuadWordNum + 1}] = {{ (uint64_t)__this }};
+    ConvertInvokeArgs(args+1, __method, __args);
+    Interpreter::Execute(__method, args, __ret);
+}}
+
+static void __Invoke_static_{method.CreateCallSigName()}(Il2CppMethodPointer __methodPtr, const MethodInfo* __method, void* __this, void** __args, void* __ret)
+{{
+    StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{ }};
+    ConvertInvokeArgs(args, __method, __args);
+    Interpreter::Execute(__method, args, __ret);
+}}
+#else
+static void* __Invoke_instance_{method.CreateCallSigName()}(Il2CppMethodPointer __methodPtr, const MethodInfo* __method, void* __this, void** __args)
+{{
+    StackObject args[{totalQuadWordNum + 1}] = {{ (uint64_t)AdjustValueTypeSelfPointer(({ConstStrings.typeObjectPtr})__this, __method)}};
+    ConvertInvokeArgs(args+1, __method, __args);
+    StackObject* ret = {(!method.ReturnInfo.IsVoid ? "args + " + (method.ParamInfos.Count + 1) : "nullptr")};
+    Interpreter::Execute(__method, args, ret);
+    return {(!method.ReturnInfo.IsVoid ? $"TranslateNativeValueToBoxValue(__method->return_type, ret)" : "nullptr")};
+}}
+
+static void* __Invoke_static_{method.CreateCallSigName()}(Il2CppMethodPointer __methodPtr, const MethodInfo* __method, void* __this, void** __args)
+{{
+    StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{ }};
+    ConvertInvokeArgs(args, __method, __args);
+    StackObject* ret = {(!method.ReturnInfo.IsVoid ? "args + " + method.ParamInfos.Count : "nullptr")};
+    Interpreter::Execute(__method, args, ret);
+    return {(!method.ReturnInfo.IsVoid ? $"TranslateNativeValueToBoxValue(__method->return_type, ret)" : "nullptr")};
+}}
+#endif
+");
+        }
+    }
+
+}

+ 11 - 0
GameClient/Assets/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: 

+ 337 - 0
GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/PlatformAdaptor_Universal64.cs

@@ -0,0 +1,337 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+
+namespace HybridCLR.Generators.MethodBridge
+{
+    internal class PlatformAdaptor_Universal64 : PlatformAdaptorBase
+    {
+
+        private static readonly Dictionary<Type, TypeInfo> s_typeInfoCaches = new Dictionary<Type, TypeInfo>()
+        {
+            { 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<Type, TypeInfo> 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 IEnumerable<MethodBridgeSig> PrepareCommon1()
+        {
+            // (void + int32 + int64 + float + double) * (int32 + int64 + float + double) * (0 - 20) = 420
+            TypeInfo typeVoid = new TypeInfo(typeof(void), ParamOrReturnType.VOID);
+            TypeInfo typeInt = new TypeInfo(typeof(int), ParamOrReturnType.I4_U4);
+            TypeInfo typeLong = new TypeInfo(typeof(long), ParamOrReturnType.I8_U8);
+            TypeInfo typeFloat = new TypeInfo(typeof(float), ParamOrReturnType.R4);
+            TypeInfo typeDouble = new TypeInfo(typeof(double), ParamOrReturnType.R8);
+            int maxParamCount = 20;
+
+            foreach (var returnType in new TypeInfo[] { typeVoid, typeInt, typeLong, typeFloat, typeDouble })
+            {
+                var rt = new ReturnInfo() { Type = returnType };
+                foreach (var argType in new TypeInfo[] { typeInt, typeLong, typeFloat, typeDouble })
+                {
+                    for (int paramCount = 0; paramCount <= maxParamCount; paramCount++)
+                    {
+                        var paramInfos = new List<ParamInfo>();
+                        for (int i = 0; i < paramCount; i++)
+                        {
+                            paramInfos.Add(new ParamInfo() { Type = argType });
+                        }
+                        var mbs = new MethodBridgeSig() { ReturnInfo = rt, ParamInfos = paramInfos };
+                        yield return mbs;
+                    }
+                }
+            }
+        }
+
+        public IEnumerable<MethodBridgeSig> PrepareCommon2()
+        {
+            // (void + int32 + int64 + float + double + v2f + v3f + v4f + s2) * (int32 + int64 + float + double + v2f + v3f + v4f + s2 + sr) ^ (0 - 2) = 399
+            TypeInfo typeVoid = new TypeInfo(typeof(void), ParamOrReturnType.VOID);
+            TypeInfo typeInt = new TypeInfo(typeof(int), ParamOrReturnType.I4_U4);
+            TypeInfo typeLong = new TypeInfo(typeof(long), ParamOrReturnType.I8_U8);
+            TypeInfo typeFloat = new TypeInfo(typeof(float), ParamOrReturnType.R4);
+            TypeInfo typeDouble = new TypeInfo(typeof(double), ParamOrReturnType.R8);
+            TypeInfo typeV2f = new TypeInfo(typeof(Vector2), ParamOrReturnType.ARM64_HFA_FLOAT_2);
+            TypeInfo typeV3f = new TypeInfo(typeof(Vector3), ParamOrReturnType.ARM64_HFA_FLOAT_3);
+            TypeInfo typeV4f = new TypeInfo(typeof(Vector4), ParamOrReturnType.ARM64_HFA_FLOAT_4);
+
+            int maxParamCount = 2;
+
+            var argTypes = new TypeInfo[] { typeInt, typeLong, typeFloat, typeDouble, typeV2f, typeV3f, typeV4f };
+            int paramTypeNum = argTypes.Length;
+            foreach (var returnType in new TypeInfo[] { typeVoid, typeInt, typeLong, typeFloat, typeDouble, typeV2f, typeV3f, typeV4f })
+            {
+                var rt = new ReturnInfo() { Type = returnType };
+                for (int paramCount = 0; paramCount <= maxParamCount; paramCount++)
+                {
+                    int totalCombinationNum = (int)Math.Pow(paramTypeNum, paramCount);
+
+                    for (int k = 0; k < totalCombinationNum; k++)
+                    {
+                        var paramInfos = new List<ParamInfo>();
+                        int c = k;
+                        for (int i = 0; i < paramCount; i++)
+                        {
+                            paramInfos.Add(new ParamInfo { Type = argTypes[c % paramTypeNum] });
+                            c /= paramTypeNum;
+                        }
+                        var mbs = new MethodBridgeSig() { ReturnInfo = rt, ParamInfos = paramInfos };
+                        yield return mbs;
+                    }
+                }
+            }
+        }
+
+        public override IEnumerable<MethodBridgeSig> GetPreserveMethods()
+        {
+            foreach (var method in PrepareCommon1())
+            {
+                yield return method;
+            }
+            foreach (var method in PrepareCommon2())
+            {
+                yield return method;
+            }
+        }
+
+        public override void GenerateCall(MethodBridgeSig method, List<string> lines)
+        {
+            //int totalQuadWordNum = method.ParamInfos.Sum(p => p.GetParamSlotNum(this.CallConventionType)) + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+            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" }));
+
+            string invokeAssignArgs = @$"
+	if (hybridclr::IsInstanceMethod(method))
+	{{
+        args[0].ptr = __this;
+{string.Join("\n", method.ParamInfos.Skip(1).Select(p => $"\t\targs[{p.Index}].u64 = *(uint64_t*)__args[{p.Index - 1}];"))}
+    }}
+	else
+	{{
+{string.Join("\n", method.ParamInfos.Select(p => $"\t\targs[{p.Index}].u64 = *(uint64_t*)__args[{p.Index}];"))}
+    }}
+";
+
+            lines.Add($@"
+static {method.ReturnInfo.Type.GetTypeName()} __Native2ManagedCall_{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;" : "")}
+}}
+
+static {method.ReturnInfo.Type.GetTypeName()} __Native2ManagedCall_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;" : "")}
+}}
+
+static void __Managed2NativeCall_{method.CreateCallSigName()}(const MethodInfo* method, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret)
+{{
+    if (hybridclr::metadata::IsInstanceMethod(method) && !localVarBase[argVarIndexs[0]].obj)
+    {{
+        il2cpp::vm::Exception::RaiseNullReferenceException();
+    }}
+    Interpreter::RuntimeClassCCtorInit(method);
+    typedef {method.ReturnInfo.Type.GetTypeName()} (*NativeMethod)({paramListStr});
+    {(!method.ReturnInfo.IsVoid ? $"*({method.ReturnInfo.Type.GetTypeName()}*)ret = " : "")}((NativeMethod)(GetInterpreterDirectlyCallMethodPointer(method)))({paramNameListStr});
+}}
+");
+        }
+
+        public override void GenerateInvoke(MethodBridgeSig method, List<string> lines)
+        {
+            //int totalQuadWordNum = method.ParamInfos.Sum(p => p.GetParamSlotNum(this.CallConventionType)) + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
+            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" }));
+
+            string invokeAssignArgs = @$"
+	if (hybridclr::IsInstanceMethod(method))
+	{{
+        args[0].ptr = __this;
+{string.Join("\n", method.ParamInfos.Skip(1).Select(p => $"\t\targs[{p.Index}].u64 = *(uint64_t*)__args[{p.Index - 1}];"))}
+    }}
+	else
+	{{
+{string.Join("\n", method.ParamInfos.Select(p => $"\t\targs[{p.Index}].u64 = *(uint64_t*)__args[{p.Index}];"))}
+    }}
+";
+
+
+            lines.Add($@"
+#ifdef HYBRIDCLR_UNITY_2021_OR_NEW
+static void __Invoke_instance_{method.CreateCallSigName()}(Il2CppMethodPointer __methodPtr, const MethodInfo* __method, void* __this, void** __args, void* __ret)
+{{
+    StackObject args[{totalQuadWordNum + 1}] = {{ (uint64_t)__this }};
+    ConvertInvokeArgs(args+1, __method, __args);
+    Interpreter::Execute(__method, args, __ret);
+}}
+
+static void __Invoke_static_{method.CreateCallSigName()}(Il2CppMethodPointer __methodPtr, const MethodInfo* __method, void* __this, void** __args, void* __ret)
+{{
+    StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{ }};
+    ConvertInvokeArgs(args, __method, __args);
+    Interpreter::Execute(__method, args, __ret);
+}}
+#else
+static void* __Invoke_instance_{method.CreateCallSigName()}(Il2CppMethodPointer __methodPtr, const MethodInfo* __method, void* __this, void** __args)
+{{
+    StackObject args[{totalQuadWordNum + 1}] = {{ (uint64_t)AdjustValueTypeSelfPointer(({ConstStrings.typeObjectPtr})__this, __method)}};
+    ConvertInvokeArgs(args+1, __method, __args);
+    StackObject* ret = {(!method.ReturnInfo.IsVoid ? "args + " + (method.ParamInfos.Count + 1) : "nullptr")};
+    Interpreter::Execute(__method, args, ret);
+    return {(!method.ReturnInfo.IsVoid ? $"TranslateNativeValueToBoxValue(__method->return_type, ret)" : "nullptr")};
+}}
+
+static void* __Invoke_static_{method.CreateCallSigName()}(Il2CppMethodPointer __methodPtr, const MethodInfo* __method, void* __this, void** __args)
+{{
+    StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{ }};
+    ConvertInvokeArgs(args, __method, __args);
+    StackObject* ret = {(!method.ReturnInfo.IsVoid ? "args + " + method.ParamInfos.Count : "nullptr")};
+    Interpreter::Execute(__method, args, ret);
+    return {(!method.ReturnInfo.IsVoid ? $"TranslateNativeValueToBoxValue(__method->return_type, ret)" : "nullptr")};
+}}
+#endif
+");
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 19 - 0
GameClient/Assets/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.Generators.MethodBridge
+{
+    [AttributeUsage(AttributeTargets.Method)]
+    public class SignatureProviderAttribute : Attribute
+    {
+        public List<PlatformABI> Platforms { get; }
+
+        public SignatureProviderAttribute(params PlatformABI[] platforms)
+        {
+            Platforms = new List<PlatformABI>(platforms);
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 132 - 0
GameClient/Assets/Editor/HybridCLR/Generators/MethodBridge/TypeInfo.cs

@@ -0,0 +1,132 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using UnityEngine;
+
+namespace HybridCLR.Generators.MethodBridge
+{
+    public class TypeInfo : IEquatable<TypeInfo>
+    {
+
+        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()
+        {
+            return PorType switch
+            {
+                ParamOrReturnType.VOID => "v",
+                ParamOrReturnType.I1_U1 => "i1",
+                ParamOrReturnType.I2_U2 => "i2",
+                ParamOrReturnType.I4_U4 => "i4",
+                ParamOrReturnType.I8_U8 => "i8",
+                ParamOrReturnType.R4 => "r4",
+                ParamOrReturnType.R8 => "r8",
+                ParamOrReturnType.I16 => "i16",
+                ParamOrReturnType.STRUCTURE_AS_REF_PARAM => "sr",
+                ParamOrReturnType.ARM64_HFA_FLOAT_2 => "vf2",
+                ParamOrReturnType.ARM64_HFA_FLOAT_3 => "vf3",
+                ParamOrReturnType.ARM64_HFA_FLOAT_4 => "vf4",
+                ParamOrReturnType.ARM64_HFA_DOUBLE_2 => "vd2",
+                ParamOrReturnType.ARM64_HFA_DOUBLE_3 => "vd3",
+                ParamOrReturnType.ARM64_HFA_DOUBLE_4 => "vd4",
+                ParamOrReturnType.STRUCTURE_ALIGN1 => "S" + Size,
+                ParamOrReturnType.STRUCTURE_ALIGN2 => "A" + Size,
+                ParamOrReturnType.STRUCTURE_ALIGN4 => "B" + Size,
+                ParamOrReturnType.STRUCTURE_ALIGN8 => "C" + Size,
+                _ => throw new NotSupportedException(PorType.ToString()),
+            };
+        }
+
+        public string GetTypeName()
+        {
+            return PorType switch
+            {
+                ParamOrReturnType.VOID => "void",
+                ParamOrReturnType.I1_U1 => "int8_t",
+                ParamOrReturnType.I2_U2 => "int16_t",
+                ParamOrReturnType.I4_U4 => "int32_t",
+                ParamOrReturnType.I8_U8 => "int64_t",
+                ParamOrReturnType.R4 => "float",
+                ParamOrReturnType.R8 => "double",
+                ParamOrReturnType.I16 => "ValueTypeSize16",
+                ParamOrReturnType.STRUCTURE_AS_REF_PARAM => "uint64_t",
+                ParamOrReturnType.ARM64_HFA_FLOAT_2 => "HtVector2f",
+                ParamOrReturnType.ARM64_HFA_FLOAT_3 => "HtVector3f",
+                ParamOrReturnType.ARM64_HFA_FLOAT_4 => "HtVector4f",
+                ParamOrReturnType.ARM64_HFA_DOUBLE_2 => "HtVector2d",
+                ParamOrReturnType.ARM64_HFA_DOUBLE_3 => "HtVector3d",
+                ParamOrReturnType.ARM64_HFA_DOUBLE_4 => "HtVector4d",
+                ParamOrReturnType.STRUCTURE_ALIGN1 => $"ValueTypeSize<{Size}>",
+                ParamOrReturnType.STRUCTURE_ALIGN2 => $"ValueTypeSizeAlign2<{Size}>",
+                ParamOrReturnType.STRUCTURE_ALIGN4 => $"ValueTypeSizeAlign4<{Size}>",
+                ParamOrReturnType.STRUCTURE_ALIGN8 => $"ValueTypeSizeAlign8<{Size}>",
+                _ => 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;
+                    }
+            }
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 148 - 0
GameClient/Assets/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.Generators.MethodBridge
+{
+
+
+	public class ValueTypeSizeAligmentCalculator
+	{
+		private static Dictionary<string, int> s_primitives = new Dictionary<string, int>(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<FieldOffsetAttribute>().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);
+		}
+	}
+}

+ 11 - 0
GameClient/Assets/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: 

+ 38 - 0
GameClient/Assets/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.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;
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 8 - 0
GameClient/Assets/Editor/HybridCLR/Generators/Templates.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3a1563e7820e5b648a6a6691677f564c
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 22 - 0
GameClient/Assets/Editor/HybridCLR/Generators/Templates/MethodBridge_Arm64.cpp

@@ -0,0 +1,22 @@
+#include "MethodBridge.h"
+
+#include <codegen/il2cpp-codegen-metadata.h>
+#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

+ 27 - 0
GameClient/Assets/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: 

+ 22 - 0
GameClient/Assets/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal32.cpp

@@ -0,0 +1,22 @@
+#include "MethodBridge.h"
+
+#include <codegen/il2cpp-codegen-metadata.h>
+#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

+ 27 - 0
GameClient/Assets/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: 

+ 22 - 0
GameClient/Assets/Editor/HybridCLR/Generators/Templates/MethodBridge_Universal64.cpp

@@ -0,0 +1,22 @@
+#include "MethodBridge.h"
+
+#include <codegen/il2cpp-codegen-metadata.h>
+#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

+ 27 - 0
GameClient/Assets/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: 

+ 117 - 0
GameClient/Assets/Editor/HybridCLR/MethodBridgeHelper.cs

@@ -0,0 +1,117 @@
+using HybridCLR.Generators;
+using HybridCLR.Generators.MethodBridge;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEditor;
+using UnityEngine;
+
+namespace HybridCLR
+{
+    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<Assembly> CollectDependentAssemblies(Dictionary<string, Assembly> allAssByName, List<Assembly> 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<Assembly> GetScanAssembiles()
+        {
+            var allAssByName = new Dictionary<string, Assembly>();
+            foreach(var ass in AppDomain.CurrentDomain.GetAssemblies())
+            {
+                allAssByName[ass.GetName().Name] = ass;
+            }
+            //CompileDllHelper.CompileDllActiveBuildTarget();
+
+            var rootAssemblies = BuildConfig.AllHotUpdateDllNames
+                .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)
+        {
+            string outputFile = $"{BuildConfig.MethodBridgeCppDir}/{fileName}.cpp";
+            var g = new MethodBridgeGenerator(new MethodBridgeGeneratorOptions()
+            {
+                CallConvention = platform,
+                Assemblies = GetScanAssembiles(),
+                OutputFile = outputFile,
+            });
+
+            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");
+        }
+
+        [MenuItem("HybridCLR/MethodBridge/All")]
+        public static void MethodBridge_All()
+        {
+            GenerateMethodBridgeCppFile(PlatformABI.Arm64, "MethodBridge_Arm64");
+            GenerateMethodBridgeCppFile(PlatformABI.Universal64, "MethodBridge_Universal64");
+            GenerateMethodBridgeCppFile(PlatformABI.Universal32, "MethodBridge_Universal32");
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/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: 

+ 8 - 0
GameClient/Assets/Editor/HybridCLR/UnityBinFileReader.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e52fb09e14efee949ae80ae8aa9f9d44
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 107 - 0
GameClient/Assets/Editor/HybridCLR/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
+{
+    /// <summary>
+    /// Unity 生成的二进制文件(本代码不支持5.x之前的版本)
+    /// </summary>
+    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<long, ObjectInfo> newObjInfos = new Dictionary<long, ObjectInfo>();
+            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();
+        }
+    }
+
+}

+ 11 - 0
GameClient/Assets/Editor/HybridCLR/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: 

+ 397 - 0
GameClient/Assets/Editor/HybridCLR/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<long, ObjectInfo> 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<long, ObjectInfo>();
+            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<string> dllNames;
+        public List<int> 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<string>(count);
+                for (var i = 0; i < count; i++)
+                    dllNames.Add(br.ReadSizeString());
+            }
+            {
+                int count = br.ReadInt32();
+                dllTypes = new List<int>(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;
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/Editor/HybridCLR/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: 

+ 78 - 0
GameClient/Assets/Editor/HybridCLR/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);
+        }
+    }
+}
+

+ 11 - 0
GameClient/Assets/Editor/HybridCLR/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: 

+ 8 - 0
GameClient/Assets/Editor/HybridCLRExtension.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d5bbd9914301c1c468f85eac21ecf29c
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 45 - 0
GameClient/Assets/Editor/HybridCLRExtension/DllHelper.cs

@@ -0,0 +1,45 @@
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+using HybridCLR;
+
+namespace GFGEditor
+{
+    public static class DllHelper
+    {
+        public static void BuildDll(string codeDir, BuildTarget target)
+        {
+            Directory.CreateDirectory(codeDir);
+            CompileDllHelper.CompileDll(target);
+
+            string hotfixDllSrcDir = BuildConfig.GetHotFixDllsOutputDirByTarget(target);
+            foreach (var dll in BuildConfig.AllHotUpdateDllNames)
+            {
+                string dllPath = $"{hotfixDllSrcDir}/{dll}";
+                string dllBytesPath = $"{codeDir}/{dll}.bytes";
+                File.Copy(dllPath, dllBytesPath, true);
+            }
+
+            AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
+        }
+        public static void CopyAOTDll(string codeDir, BuildTarget target)
+        {
+            Directory.CreateDirectory(codeDir);
+
+            string aotDllDir = BuildConfig.GetAssembliesPostIl2CppStripDir(target);
+            foreach (var dll in BuildConfig.AOTMetaDlls)
+            {
+                string dllPath = $"{aotDllDir}/{dll}";
+                if (!File.Exists(dllPath))
+                {
+                    Debug.LogError($"ab中添加AOT补充元数据dll:{dllPath} 时发生错误,文件不存在。裁剪后的AOT dll在BuildPlayer时才能生成,因此需要你先构建一次游戏App后再打包。");
+                    continue;
+                }
+                string dllBytesPath = $"{codeDir}/{dll}.bytes";
+                File.Copy(dllPath, dllBytesPath, true);
+            }
+
+            AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/Editor/HybridCLRExtension/DllHelper.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ac11ce918afbf234d8d8d011dbd76639
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 3 - 0
GameClient/Assets/Editor/Xasset/Builds/BuildTask.cs

@@ -4,6 +4,7 @@ using System.IO;
 using GFGEditor;
 using UnityEditor;
 using UnityEngine;
+using GFGGame;
 
 namespace VEngine.Editor.Builds
 {
@@ -77,6 +78,8 @@ namespace VEngine.Editor.Builds
 
         public void BuildCustomBundles(string[] resRootDirNames, string setName)
         {
+            DllHelper.BuildDll(LauncherConfig.DllDirHotfix, EditorUserBuildSettings.activeBuildTarget);
+            DllHelper.CopyAOTDll(LauncherConfig.DllDirAOT, EditorUserBuildSettings.activeBuildTarget);
             foreach (var resRootDirName in resRootDirNames)
             {
                 CreateBundles(resRootDirName, setName);

+ 0 - 1
GameClient/Assets/Editor/Xasset/Builds/Settings.cs

@@ -25,7 +25,6 @@ namespace VEngine.Editor.Builds
 
         public bool offlineMode;
         public ScriptPlayMode scriptPlayMode = ScriptPlayMode.Simulation;
-        public bool ILRuntimeMode;
 
         public static string PlatformBuildPath
         {

+ 0 - 2
GameClient/Assets/Editor/Xasset/Initializer.cs

@@ -40,8 +40,6 @@ namespace VEngine.Editor
                 default:
                     throw new ArgumentOutOfRangeException();
             }
-            //ILRuntime
-            LauncherConfig.ILRuntimeMode = settings.ILRuntimeMode;
         }
     }
 }

+ 1 - 3
GameClient/Assets/Game/HotUpdate/Data/InstanceZonesDataManager.cs

@@ -1,7 +1,5 @@
-using ET;
-using System;
+using System;
 using System.Collections.Generic;
-using static UnityEditor.ShaderData;
 
 namespace GFGGame
 {

+ 0 - 4
GameClient/Assets/Game/HotUpdate/Data/VO/ItemData.cs

@@ -1,8 +1,4 @@
-using Codice.Client.Common;
-using System;
 using System.Collections.Generic;
-using System.Diagnostics;
-using System.Reflection;
 
 namespace GFGGame
 {

+ 1 - 3
GameClient/Assets/Game/HotUpdate/ETCodes/Hotfix/App/ServerInfo/ServerInfosComponentSystem.cs

@@ -1,6 +1,4 @@
-using static Codice.Client.Common.Servers.RecentlyUsedServers;
-
-namespace ET
+namespace ET
 {
     public class ServerInfosComponentDestroySystem : DestroySystem<ServerInfosComponent>
     {

+ 1 - 3
GameClient/Assets/Game/HotUpdate/Game.HotUpdate.asmdef

@@ -6,9 +6,7 @@
         "GUID:7a41fac89c3ce014e99efb3723e6a98e",
         "GUID:7b430a36dc40f416cbc65566155a0e56"
     ],
-    "includePlatforms": [
-        "Editor"
-    ],
+    "includePlatforms": [],
     "excludePlatforms": [],
     "allowUnsafeCode": true,
     "overrideReferences": false,

+ 47 - 0
GameClient/Assets/Game/HotUpdate/HotUpdateEntry.cs

@@ -2,6 +2,7 @@
 using ET;
 using FairyGUI;
 using System;
+using System.Collections.Generic;
 using UnityEngine;
 namespace GFGGame.HotUpdate
 {
@@ -10,6 +11,11 @@ namespace GFGGame.HotUpdate
 
         public static void Start()
         {
+            Log.Debug("HotUpdateEntry Start 1");
+#if !UNITY_EDITOR
+            LoadMetadataForAOTAssembly();
+#endif
+            Log.Debug("HotUpdateEntry Start 2");
             VEngine.Logger.Loggable = false;
             //ET
             try
@@ -27,7 +33,48 @@ namespace GFGGame.HotUpdate
             {
                 Log.Error(e);
             }
+            Log.Debug("HotUpdateEntry Start 3");
             GameController.Start();
+            Log.Debug("HotUpdateEntry Start 4");
+        }
+
+        /// <summary>
+        /// 为aot assembly加载原始metadata, 这个代码放aot或者热更新都行。
+        /// 一旦加载后,如果AOT泛型函数对应native实现不存在,则自动替换为解释模式执行
+        /// </summary>
+        public static unsafe void LoadMetadataForAOTAssembly()
+        {
+            // 可以加载任意aot assembly的对应的dll。但要求dll必须与unity build过程中生成的裁剪后的dll一致,而不能直接使用原始dll。
+            // 我们在BuildProcessor_xxx里添加了处理代码,这些裁剪后的dll在打包时自动被复制到 {项目目录}/HybridCLRData/AssembliesPostIl2CppStrip/{Target} 目录。
+
+            /// 注意,补充元数据是给AOT dll补充元数据,而不是给热更新dll补充元数据。
+            /// 热更新dll不缺元数据,不需要补充,如果调用LoadMetadataForAOTAssembly会返回错误
+            /// 
+            List<string> aotDllList = new List<string>
+            {
+                "mscorlib.dll",
+                "System.dll",
+                "System.Core.dll", // 如果使用了Linq,需要这个
+                "ThirdParty.dll",
+                "Game.Launcher.dll",
+                // "Newtonsoft.Json.dll",
+                // "protobuf-net.dll",
+                // "Google.Protobuf.dll",
+                // "MongoDB.Bson.dll",
+                // "DOTween.Modules.dll",
+                // "UniTask.dll",
+            };
+
+            foreach (var aotDllName in aotDllList)
+            {
+                byte[] dllBytes = GFGAsset.Load<TextAsset>($"{LauncherConfig.DllDirAOT}{aotDllName}.bytes").bytes;
+                fixed (byte* ptr = dllBytes)
+                {
+                    // 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码
+                    int err = HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly((IntPtr)ptr, dllBytes.Length);
+                    Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. ret:{err}");
+                }
+            }
         }
 
     }

+ 0 - 1
GameClient/Assets/Game/HotUpdate/Views/CommonGame/GetSuitItemVIew.cs

@@ -1,7 +1,6 @@
 using UI.CommonGame;
 using FairyGUI;
 using UnityEngine;
-using static UnityEditor.Progress;
 
 
 namespace GFGGame

+ 0 - 1
GameClient/Assets/Game/HotUpdate/Views/Loading/LoadingView.cs

@@ -1,6 +1,5 @@
 using FairyGUI;
 using UI.Loading;
-using Unity.Plastic.Antlr3.Runtime;
 using UnityEngine;
 
 namespace GFGGame

+ 0 - 1
GameClient/Assets/Game/HotUpdate/Views/Log/LogView.cs

@@ -3,7 +3,6 @@ using UI.Common;
 using FairyGUI;
 using System.Collections.Generic;
 using UnityEngine;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
 
 namespace GFGGame
 {

+ 0 - 5
GameClient/Assets/Game/HotUpdate/Views/MainStory/StoryController.cs

@@ -1,8 +1,3 @@
-using ET;
-using log4net.Core;
-using System.Collections.Generic;
-using static GFGGame.StoryController;
-
 namespace GFGGame
 {
     //主线剧情专用类

+ 0 - 2
GameClient/Assets/Game/HotUpdate/Views/MainUI/MainUIView.cs

@@ -1,10 +1,8 @@
 using FairyGUI;
 using UI.Main;
-using UI.CommonGame;
 using UnityEngine;
 using System.Collections.Generic;
 using ET;
-using static UnityEditor.Progress;
 
 namespace GFGGame
 {

+ 25 - 21
GameClient/Assets/Game/Launcher/HotUpdateProxy/HotUpdateCodeLoader.cs

@@ -3,6 +3,7 @@ using System.Collections;
 using System.Reflection;
 using UnityEngine;
 using GFGGame.Launcher;
+using System.Linq;
 
 namespace GFGGame
 {
@@ -21,38 +22,41 @@ namespace GFGGame
         }
 
 
+        private System.Reflection.Assembly gameAss;
         IEnumerator StartLoadAssemblyHotfix()
         {
             LogServerHelperHttp.SendNodeLog((int)LogNode.StartLoadGameDll);
             //ET.Log.Debug("ILRuntimeLauncher StartLoadAssemblyHotfix");
             yield return new WaitForSeconds(0.1f);
-            var dllPath = "Assets/Res/Code/Game.HotUpdate.dll.bytes";
+#if !UNITY_EDITOR
+            LoadAssemblyJustInTime();
+#else
+            gameAss = AppDomain.CurrentDomain.GetAssemblies().First(assembly => assembly.GetName().Name == "Game.HotUpdate");
+#endif
+
+            RunMain();
+        }
+
+        private void LoadAssemblyJustInTime()
+        {
+            var dllPath = $"{LauncherConfig.DllDirHotfix}Game.HotUpdate.dll.bytes";
             var asset = GFGAsset.Load<TextAsset>(dllPath);
             byte[] assBytes = asset.bytes;
-            var pdbPath = "Assets/Res/Code/Game.HotUpdate.pdb.bytes";
-            asset = GFGAsset.Load<TextAsset>(pdbPath);
-            byte[] pdbBytes = asset.bytes;
-            if (LauncherConfig.ILRuntimeMode)
-            {
-                
-            }
-            else
-            {
-                StartCoroutine(LoadAssemblyJustInTime(assBytes, pdbBytes));
-            }
+            gameAss = Assembly.Load(assBytes);
             GFGAsset.Release(dllPath);
-            GFGAsset.Release(pdbPath);
         }
 
-        IEnumerator LoadAssemblyJustInTime(byte[] assBytes, byte[] pdbBytes)
+        public void RunMain()
         {
-            //mono模式
-            var assembly = Assembly.Load(assBytes, pdbBytes);
-            this.allTypes = assembly.GetTypes();
-            System.Type type = assembly.GetType("GFGGame.HotUpdate.HotUpdateEntry");
-            type.GetMethod("Start").Invoke(type, null);
-            yield break;
+            if (gameAss == null)
+            {
+                UnityEngine.Debug.LogError("dll未加载");
+                return;
+            }
+            this.allTypes = gameAss.GetTypes();
+            var appType = gameAss.GetType("GFGGame.HotUpdate.HotUpdateEntry");
+            var mainMethod = appType.GetMethod("Start");
+            mainMethod.Invoke(null, null);
         }
-
     }
 }

+ 8 - 0
GameClient/Assets/Game/Launcher/HybridCLR.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0b7c61fc13b3ce643a4566a850ea20b9
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 274 - 0
GameClient/Assets/Game/Launcher/HybridCLR/RefTypes.cs

@@ -0,0 +1,274 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using UnityEngine;
+using UnityEngine.Scripting;
+using System.IO;
+
+[assembly: Preserve]
+enum IntEnum : int
+{
+    A,
+    B,
+}
+
+public class MyComparer<T> : Comparer<T>
+{
+    public override int Compare(T x, T y)
+    {
+        return 0;
+    }
+}
+
+class MyStateMachine : IAsyncStateMachine
+{
+    public void MoveNext()
+    {
+        throw new NotImplementedException();
+    }
+
+    public void SetStateMachine(IAsyncStateMachine stateMachine)
+    {
+        throw new NotImplementedException();
+    }
+}
+
+public class RefTypes : MonoBehaviour
+{
+    List<Type> GetTypes()
+    {
+        return new List<Type>
+        {
+            typeof(SpriteMask)
+        };
+    }
+
+    // Start is called before the first frame update
+    void Start()
+    {
+        Debug.Log(GetTypes());
+        GameObject.Instantiate<GameObject>(null);
+        Instantiate<GameObject>(null, null);
+        Instantiate<GameObject>(null, null, false);
+        Instantiate<GameObject>(null, new Vector3(), new Quaternion());
+        Instantiate<GameObject>(null, new Vector3(), new Quaternion(), null);
+    }
+
+    public void RefNumerics()
+    {
+        var a = new System.Numerics.BigInteger();
+        a.ToString();
+    }
+
+
+    void RefMisc()
+    {
+
+    }
+
+    void RefComparers()
+    {
+        var a = new object[]
+        {
+            new MyComparer<int>(),
+            new MyComparer<long>(),
+            new MyComparer<float>(),
+            new MyComparer<double>(),
+            new MyComparer<object>(),
+        };
+
+        new MyComparer<int>().Compare(default, default);
+        new MyComparer<long>().Compare(default, default);
+        new MyComparer<float>().Compare(default, default);
+        new MyComparer<double>().Compare(default, default);
+        new MyComparer<object>().Compare(default, default);
+
+        object b = EqualityComparer<int>.Default;
+        b = EqualityComparer<long>.Default;
+        b = EqualityComparer<float>.Default;
+        b = EqualityComparer<double>.Default;
+        b = EqualityComparer<object>.Default;
+    }
+
+
+    void RefNullable()
+    {
+        // nullable
+        object b = null;
+        int? a = 5;
+        b = a;
+        int d = (int?)b ?? 7;
+        int e = (int)b;
+        a = d;
+        b = a;
+        b = Enumerable.Range(0, 1).Reverse().Take(1).TakeWhile(x => true).Skip(1).All(x => true);
+        b = new WaitForSeconds(1f);
+        b = new WaitForSecondsRealtime(1f);
+        b = new WaitForFixedUpdate();
+        b = new WaitForEndOfFrame();
+        b = new WaitWhile(() => true);
+        b = new WaitUntil(() => true);
+    }
+
+    void RefContainer()
+    {
+        //int, long,float,double, IntEnum,object
+        List<object> b = new List<object>()
+        {
+
+        };
+    }
+
+    void RefAsyncMethod()
+    {
+        var stateMachine = new MyStateMachine();
+
+        TaskAwaiter aw = default;
+        var c0 = new AsyncTaskMethodBuilder();
+        c0.Start(ref stateMachine);
+        c0.AwaitUnsafeOnCompleted(ref aw, ref stateMachine);
+        c0.SetException(null);
+        c0.SetResult();
+
+        var c1 = new AsyncTaskMethodBuilder();
+        c1.Start(ref stateMachine);
+        c1.AwaitUnsafeOnCompleted(ref aw, ref stateMachine);
+        c1.SetException(null);
+        c1.SetResult();
+
+        var c2 = new AsyncTaskMethodBuilder<bool>();
+        c2.Start(ref stateMachine);
+        c2.AwaitUnsafeOnCompleted(ref aw, ref stateMachine);
+        c2.SetException(null);
+        c2.SetResult(default);
+
+        var c3 = new AsyncTaskMethodBuilder<int>();
+        c3.Start(ref stateMachine);
+        c3.AwaitUnsafeOnCompleted(ref aw, ref stateMachine);
+        c3.SetException(null);
+        c3.SetResult(default);
+
+        var c4 = new AsyncTaskMethodBuilder<long>();
+        c4.Start(ref stateMachine);
+        c4.AwaitUnsafeOnCompleted(ref aw, ref stateMachine);
+        c4.SetException(null);
+
+        var c5 = new AsyncTaskMethodBuilder<float>();
+        c5.Start(ref stateMachine);
+        c5.AwaitUnsafeOnCompleted(ref aw, ref stateMachine);
+        c5.SetException(null);
+        c5.SetResult(default);
+
+        var c6 = new AsyncTaskMethodBuilder<double>();
+        c6.Start(ref stateMachine);
+        c6.AwaitUnsafeOnCompleted(ref aw, ref stateMachine);
+        c6.SetException(null);
+        c6.SetResult(default);
+
+        var c7 = new AsyncTaskMethodBuilder<object>();
+        c7.Start(ref stateMachine);
+        c7.AwaitUnsafeOnCompleted(ref aw, ref stateMachine);
+        c7.SetException(null);
+        c7.SetResult(default);
+
+        var c8 = new AsyncTaskMethodBuilder<IntEnum>();
+        c8.Start(ref stateMachine);
+        c8.AwaitUnsafeOnCompleted(ref aw, ref stateMachine);
+        c8.SetException(null);
+        c8.SetResult(default);
+
+        var c9 = new AsyncVoidMethodBuilder();
+        var b = AsyncVoidMethodBuilder.Create();
+        c9.Start(ref stateMachine);
+        c9.AwaitUnsafeOnCompleted(ref aw, ref stateMachine);
+        c9.SetException(null);
+        c9.SetResult();
+        Debug.Log(b);
+    }
+
+    void RefNewtonsoftJson()
+    {
+        //AotHelper.EnsureList<int>();
+        //AotHelper.EnsureList<long>();
+        //AotHelper.EnsureList<float>();
+        //AotHelper.EnsureList<double>();
+        //AotHelper.EnsureList<string>();
+        //AotHelper.EnsureDictionary<int, int>();
+        //AotHelper.EnsureDictionary<int, string>();
+    }
+
+    public void RefProtobufNet()
+    {
+        
+    }
+
+    public void RefGoogleProtobuf()
+    {
+    }
+
+    class TestTable
+    {
+        public int Id { get; set; }
+
+        public string Name { get; set; }
+    }
+
+    public void RefSQLite()
+    {
+    }
+
+    public static async void TestAsync3()
+    {
+        Debug.Log("async task 1");
+        await Task.Delay(10);
+        Debug.Log("async task 2");
+    }
+
+    public static int Main_1()
+    {
+        Debug.Log("hello,hybridclr");
+
+        var task = Task.Run(async () =>
+        {
+            await TestAsync2();
+        });
+
+        task.Wait();
+
+        Debug.Log("async task end");
+        Debug.Log("async task end2");
+
+        return 0;
+    }
+
+    public static async Task TestAsync2()
+    {
+        Debug.Log("async task 1");
+        await Task.Delay(3000);
+        Debug.Log("async task 2");
+    }
+
+    // Update is called once per frame
+    void Update()
+    {
+        TestAsync();
+    }
+
+    public static int TestAsync()
+    {
+        var t0 = Task.Run(async () =>
+        {
+            await Task.Delay(10);
+        });
+        t0.Wait();
+        var task = Task.Run(async () =>
+        {
+            await Task.Delay(10);
+            return 100;
+        });
+        Debug.Log(task.Result);
+        return 0;
+    }
+}

+ 11 - 0
GameClient/Assets/Game/Launcher/HybridCLR/RefTypes.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 17ed08ce9aa3e1f449ab4f2f79ecb0cb
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 36 - 0
GameClient/Assets/Game/Launcher/HybridCLR/RuntimeApi.cs

@@ -0,0 +1,36 @@
+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
+{
+    public static class RuntimeApi
+    {
+#if UNITY_STANDALONE_WIN
+        private const string dllName = "GameAssembly";
+#elif UNITY_IOS || UNITY_STANDALONE_OSX || UNITY_WEBGL
+    private const string dllName = "__Internal";
+#else
+    private const string dllName = "il2cpp";
+#endif
+
+        [DllImport(dllName, EntryPoint = "RuntimeApi_LoadMetadataForAOTAssembly")]
+        public static extern int LoadMetadataForAOTAssembly(IntPtr dllBytes, int dllSize);
+
+        [DllImport(dllName, EntryPoint = "RuntimeApi_GetInterpreterThreadObjectStackSize")]
+        public static extern int GetInterpreterThreadObjectStackSize();
+
+        [DllImport(dllName, EntryPoint = "RuntimeApi_SetInterpreterThreadObjectStackSize")]
+        public static extern void SetInterpreterThreadObjectStackSize(int size);
+
+        [DllImport(dllName, EntryPoint = "RuntimeApi_GetInterpreterThreadFrameStackSize")]
+        public static extern int GetInterpreterThreadFrameStackSize();
+
+        [DllImport(dllName, EntryPoint = "RuntimeApi_SetInterpreterThreadFrameStackSize")]
+        public static extern void SetInterpreterThreadFrameStackSize(int size);
+    }
+}

+ 11 - 0
GameClient/Assets/Game/Launcher/HybridCLR/RuntimeApi.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3c8b35876046d1747ae7d62244ec693f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 4 - 2
GameClient/Assets/Game/Launcher/LauncherConfig.cs

@@ -7,8 +7,10 @@ namespace GFGGame
         public enum EnumNetType { DEV, LOCAL, TEMP }
         public static EnumNetType netType = EnumNetType.LOCAL;
         public static string cfgName;
-        public static bool ILRuntimeMode;
 
+        //Èȸü´úÂë´æ·ÅλÖÃ
+        public const string DllDirHotfix = "Assets/ResIn/Dll/Update/";
+        public const string DllDirAOT = "Assets/ResIn/Dll/AOT/";
         public const int HTTP_GET_TIME_OUT = 3;
         public const int HTTP_POST_TIME_OUT = 15;
         public static string SOUND_KEY = "sound";
@@ -62,7 +64,7 @@ namespace GFGGame
             ET.Log.Debug($"ptcfg \n{json}");
             var result = JsonMapper.ToObject<Result>(json);
             LauncherConfig.CDN_ROOT = result.cdnRoot;
-            //CDN_ROOT = "http://10.108.64.127/";
+            CDN_ROOT = "http://10.108.64.127/";
             LauncherConfig.loginApiUrl = result.loginApiUrl;
             LauncherConfig.logApiUrl = result.logApiUrl;
             LauncherConfig.logKey = result.logKey;

BIN
GameClient/Assets/Plugins/Android/libs/arm64-v8a/libsqlite3.so


+ 8 - 8
GameClient/Assets/Plugins/System.Numerics.Vectors.dll.meta → GameClient/Assets/Plugins/Android/libs/arm64-v8a/libsqlite3.so.meta

@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 6bc5f51c376a66848aacd70d21e8340f
+guid: 0c89716d6b83e384c8f54b333b2b3bfe
 PluginImporter:
   externalObjects: {}
   serializedVersion: 2
@@ -12,22 +12,22 @@ PluginImporter:
   validateReferences: 1
   platformData:
   - first:
-      Any: 
+      Android: Android
     second:
       enabled: 1
-      settings: {}
+      settings:
+        CPU: ARM64
   - first:
-      Editor: Editor
+      Any: 
     second:
       enabled: 0
-      settings:
-        DefaultValueInitialized: true
+      settings: {}
   - first:
-      Windows Store Apps: WindowsStoreApps
+      Editor: Editor
     second:
       enabled: 0
       settings:
-        CPU: AnyCPU
+        DefaultValueInitialized: true
   userData: 
   assetBundleName: 
   assetBundleVariant: 

+ 21 - 22
GameClient/Assets/Plugins/Android/libs/armeabi-v7a/libkcp.so.meta

@@ -1,34 +1,33 @@
 fileFormatVersion: 2
 guid: 8e03e31ef66b1d340bfd9de539878633
-timeCreated: 1530266293
-licenseType: Pro
 PluginImporter:
+  externalObjects: {}
   serializedVersion: 2
   iconMap: {}
   executionOrder: {}
+  defineConstraints: []
   isPreloaded: 0
   isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
   platformData:
-    data:
-      first:
-        Android: Android
-      second:
-        enabled: 1
-        settings:
-          CPU: ARMv7
-    data:
-      first:
-        Any: 
-      second:
-        enabled: 0
-        settings: {}
-    data:
-      first:
-        Editor: Editor
-      second:
-        enabled: 0
-        settings:
-          DefaultValueInitialized: true
+  - first:
+      Android: Android
+    second:
+      enabled: 1
+      settings:
+        CPU: ARMv7
+  - first:
+      Any: 
+    second:
+      enabled: 0
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        DefaultValueInitialized: true
   userData: 
   assetBundleName: 
   assetBundleVariant: 

BIN
GameClient/Assets/Plugins/System.Numerics.Vectors.dll


+ 5 - 2
GameClient/Assets/Plugins/Windows/x86/Live2DCubismCore.dll.meta

@@ -5,11 +5,14 @@ PluginImporter:
   serializedVersion: 2
   iconMap: {}
   executionOrder: {}
+  defineConstraints: []
   isPreloaded: 0
   isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
   platformData:
   - first:
-      '': Any
+      : Any
     second:
       enabled: 0
       settings:
@@ -66,7 +69,7 @@ PluginImporter:
     second:
       enabled: 1
       settings:
-        CPU: x86_64
+        CPU: AnyCPU
   - first:
       Standalone: LinuxUniversal
     second:

+ 8 - 0
GameClient/Assets/ResIn/Dll.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 245d660d0740f254aa5fbfc8ad44f173
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
GameClient/Assets/ResIn/Dll/AOT.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8fd1a18c740608242ad09903e84c264e
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно