From 6909c32a0c8fcf11d4b573af890a0232c1525afe Mon Sep 17 00:00:00 2001 From: walon Date: Mon, 13 Mar 2023 09:55:26 +0800 Subject: [PATCH] =?UTF-8?q?[new]=20=E6=94=AF=E6=8C=81=202021=20WebGL?= =?UTF-8?q?=E8=B5=84=E6=BA=90=E4=B8=8A=E6=8C=82=E8=BD=BD=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BuildPipeline_StripDll_HookTest.cs | 277 ++++++++++++++++++ .../BuildPipeline_StripDll_HookTest.cs.meta | 11 + .../PatchScriptingAssembliesJsonHook.cs | 55 ++++ .../PatchScriptingAssembliesJsonHook.cs.meta | 11 + Editor/3rds/UnityHook/LDasm.cs | 12 +- Editor/3rds/UnityHook/MethodHook.cs | 10 +- Editor/3rds/UnityHook/Plugins.meta | 2 +- .../PatchScriptingAssemblyList.cs | 2 +- package.json | 2 +- 9 files changed, 368 insertions(+), 14 deletions(-) create mode 100644 Editor/3rds/UnityHook/HybridCLRHooks/BuildPipeline_StripDll_HookTest.cs create mode 100644 Editor/3rds/UnityHook/HybridCLRHooks/BuildPipeline_StripDll_HookTest.cs.meta create mode 100644 Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs create mode 100644 Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs.meta diff --git a/Editor/3rds/UnityHook/HybridCLRHooks/BuildPipeline_StripDll_HookTest.cs b/Editor/3rds/UnityHook/HybridCLRHooks/BuildPipeline_StripDll_HookTest.cs new file mode 100644 index 0000000..b16c93f --- /dev/null +++ b/Editor/3rds/UnityHook/HybridCLRHooks/BuildPipeline_StripDll_HookTest.cs @@ -0,0 +1,277 @@ +#if ENABLE_HOOK_TEST_CASE +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEngine; +using System.Linq; + +namespace MonoHook.Test +{ + // 有需求时可以打开,也可以手动按需注册Hook + [InitializeOnLoad] + public class BuildPipeline_StripDll_HookTest + { + /// + /// 裁剪执行完毕的回调,可能会被调用多次,一般而言同一次打包只需要处理第一次回调 + /// + public static Action OnAssemblyStripped; + + // 尝试 Hook 4个函数,至少一个被调用就可以达到要求 + private static MethodHook _hook_PostprocessBuildPlayer_CompleteBuild; + private static MethodHook _hook_Default_PostProcess; + private static MethodHook _hook_ReportBuildResults; + private static MethodHook _hook_StripAssembliesTo; + +#region Fake Internal Structures + public struct BuildPostProcessArgs + { + public BuildTarget target; + public int subTarget; + public string stagingArea; + public string stagingAreaData; + public string stagingAreaDataManaged; + public string playerPackage; + public string installPath; + public string companyName; + public string productName; + public Guid productGUID; + public BuildOptions options; + public UnityEditor.Build.Reporting.BuildReport report; + internal /*RuntimeClassRegistry*/object usedClassRegistry; + } + + public sealed class BeeDriverResult + { + public /*NodeResult*/object[] NodeResults { get; set; } + public bool Success { get; set; } + public /*Message*/object[] BeeDriverMessages { get; set; } + public override string ToString() => Success.ToString(); + } +#endregion + + static BuildPipeline_StripDll_HookTest() + { + InstallHook(); +#if ENABLE_HOOK_TEST_CASE + OnAssemblyStripped = DemoStripCallback; +#endif + } + + /// + /// 示例裁剪回调函数 + /// + /// + /// + /// + static void DemoStripCallback(string outputFolder, BuildPostProcessArgs args, BeeDriverResult result) + { + if (outputFolder != null) + Debug.Log($"stripped outputFolder is:{outputFolder}"); + else if (args.stagingAreaDataManaged != null) + Debug.Log($"stripped staging folder is:{args.stagingAreaDataManaged}"); + else if (result != null) + Debug.Log($"stripped result is: {result.Success}"); + else + Debug.Log("stripped test called"); + } + + public static void InstallHook() + { + do + { + Type type = Type.GetType("UnityEditor.PostprocessBuildPlayer,UnityEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); + if (type == null) + { + Debug.LogError($"can not find type: UnityEditor.PostprocessBuildPlayer"); + break; + } + + MethodInfo miTarget = type.GetMethod("PostProcessCompletedBuild", BindingFlags.Static | BindingFlags.Public); + + if (miTarget == null) + { + Debug.LogError($"can not find method: UnityEditor.PostprocessBuildPlayer.PostProcessCompletedBuild"); + break; + } + + MethodInfo miReplace = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(PostprocessBuildPlayer_CompleteBuild_Replace), BindingFlags.Static | BindingFlags.NonPublic); + MethodInfo miProxy = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(PostprocessBuildPlayer_CompleteBuild_Proxy), BindingFlags.Static | BindingFlags.NonPublic); + + _hook_PostprocessBuildPlayer_CompleteBuild = new MethodHook(miTarget, miReplace, miProxy); + _hook_PostprocessBuildPlayer_CompleteBuild.Install(); + + Debug.Log("Hook BuildPipeline_StripDll_HookTest.PostprocessBuildPlayer_CompleteBuild installed"); + } while (false); + + do + { + Type type = Type.GetType("UnityEditor.Modules.DefaultBuildPostprocessor,UnityEditor.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); + if (type == null) + { + Debug.LogError($"can not find type: UnityEditor.Modules.DefaultBuildPostprocessor"); + break; + } + + MethodInfo[] miTargets = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly); + MethodInfo miTarget = (from mi in miTargets where mi.Name == "PostProcess" && mi.GetParameters().Length == 2 select mi).FirstOrDefault(); + + if (miTarget == null) + { + Debug.LogError($"can not find method: UnityEditor.Modules.DefaultBuildPostprocessor.PostProcess"); + break; + } + + MethodInfo miReplace = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(Default_PostProcess_Replace), BindingFlags.Static | BindingFlags.NonPublic); + MethodInfo miProxy = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(Default_PostProcess_Proxy), BindingFlags.Static | BindingFlags.NonPublic); + + _hook_Default_PostProcess = new MethodHook(miTarget, miReplace, miProxy); + _hook_Default_PostProcess.Install(); + + Debug.Log("Hook BuildPipeline_StripDll_HookTest.PostProcess installed"); + } while (false); + + do + { + Type type = Type.GetType("UnityEditor.Modules.BeeBuildPostprocessor,UnityEditor.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); + if (type == null) + { + Debug.LogError($"can not find type: UnityEditor.Modules.BeeBuildPostprocessor"); + break; + } + + MethodInfo miTarget = type.GetMethod("ReportBuildResults", BindingFlags.Instance | BindingFlags.NonPublic); + if (miTarget == null) + { + Debug.LogError($"can not find method: UnityEditor.Modules.BeeBuildPostprocessor.ReportBuildResults"); + break; + } + + MethodInfo miReplace = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(ReportBuildResults_Replace), BindingFlags.Static | BindingFlags.NonPublic); + MethodInfo miProxy = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(ReportBuildResults_Proxy), BindingFlags.Static | BindingFlags.NonPublic); + + _hook_ReportBuildResults = new MethodHook(miTarget, miReplace, miProxy); + _hook_ReportBuildResults.Install(); + + Debug.Log("Hook BuildPipeline_StripDll_HookTest.ReportBuildResults installed"); + } while (false); + + do + { + Type type = Type.GetType("UnityEditorInternal.AssemblyStripper,UnityEditor.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"); + if (type == null) + { + Debug.LogError($"can not find type: UnityEditorInternal.AssemblyStripper"); + break; + } + + MethodInfo miTarget = type.GetMethod("StripAssembliesTo", BindingFlags.Static | BindingFlags.NonPublic); + if (miTarget == null) + { + Debug.LogError($"can not find method: UnityEditorInternal.AssemblyStripper.StripAssembliesTo"); + break; + } + + MethodInfo miReplace = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(StripAssembliesTo_Replace), BindingFlags.Static | BindingFlags.NonPublic); + MethodInfo miProxy = typeof(BuildPipeline_StripDll_HookTest).GetMethod(nameof(StripAssembliesTo_Proxy), BindingFlags.Static | BindingFlags.NonPublic); + + _hook_StripAssembliesTo = new MethodHook(miTarget, miReplace, miProxy); + _hook_StripAssembliesTo.Install(); + + Debug.Log("Hook BuildPipeline_StripDll_HookTest.StripAssembliesTo installed"); + } while (false); + } + + public static void UninstallHook() + { + _hook_PostprocessBuildPlayer_CompleteBuild?.Uninstall(); + _hook_Default_PostProcess?.Uninstall(); + _hook_ReportBuildResults?.Uninstall(); + _hook_StripAssembliesTo?.Uninstall(); + } + + static void PostprocessBuildPlayer_CompleteBuild_Replace(BuildPostProcessArgs args) + { + Debug.Log("PostprocessBuildPlayer_CompleteBuild_Replace called"); + + OnAssemblyStripped?.Invoke(null, args, null); + PostprocessBuildPlayer_CompleteBuild_Proxy(args); + } + + static void Default_PostProcess_Replace(object obj, BuildPostProcessArgs args, out /*BuildProperties*/ object outProperties) + { + try + { + // 注意:此函数中途可能会被 Unity throw Exception + Default_PostProcess_Proxy(obj, args, out outProperties); + } + catch(Exception ex) + { + throw ex; + } + finally + { + Debug.Log("PostProcess_Replace called"); + OnAssemblyStripped?.Invoke(null, args, null); + } + } + + static void ReportBuildResults_Replace(object obj, BeeDriverResult result) + { + // TODO: 可以在这里把 Library\Bee\artifacts\WinPlayerBuildProgram\ManagedStripped 目录下的文件复制出来 + Debug.Log("ReportBuildResults_Replace called"); + + OnAssemblyStripped?.Invoke(null, default(BuildPostProcessArgs), result); + ReportBuildResults_Proxy(obj, result); + } + + static bool StripAssembliesTo_Replace(string outputFolder, out string output, out string error, IEnumerable linkXmlFiles, /*UnityLinkerRunInformation*/ object runInformation) + { + bool ret = StripAssembliesTo_Proxy(outputFolder, out output, out error, linkXmlFiles, runInformation); + + // TODO: 可以在这里把 Temp\StagingArea\Data\Managed\tempStrip 目录下的文件复制出来 + Debug.Log("StripAssembliesTo_Replace called"); + + OnAssemblyStripped?.Invoke(outputFolder, default(BuildPostProcessArgs), null); + return ret; + } + +#region Proxy Methods + [MethodImpl(MethodImplOptions.NoOptimization)] + static void PostprocessBuildPlayer_CompleteBuild_Proxy(BuildPostProcessArgs args) + { + Debug.Log("dummy code" + 200); + Debug.Log(args.companyName); + } + + [MethodImpl(MethodImplOptions.NoOptimization)] + static void Default_PostProcess_Proxy(object obj, BuildPostProcessArgs args, out /*BuildProperties*/ object outProperties) + { + Debug.Log("dummy code" + 100); + outProperties = null; + } + + [MethodImpl(MethodImplOptions.NoOptimization)] + static void ReportBuildResults_Proxy(object obj, /*BeeDriverResult*/ object result) + { + // dummy code + Debug.Log("something" + obj.ToString() + result.ToString() + 2); + } + + [MethodImpl(MethodImplOptions.NoOptimization)] + static bool StripAssembliesTo_Proxy(string outputFolder, out string output, out string error, IEnumerable linkXmlFiles, /*UnityLinkerRunInformation*/ object runInformation) + { + Debug.Log("StripAssembliesTo_Proxy called"); + output = null; + error = null; + return true; + } +#endregion + } +} + +#endif \ No newline at end of file diff --git a/Editor/3rds/UnityHook/HybridCLRHooks/BuildPipeline_StripDll_HookTest.cs.meta b/Editor/3rds/UnityHook/HybridCLRHooks/BuildPipeline_StripDll_HookTest.cs.meta new file mode 100644 index 0000000..c9a800a --- /dev/null +++ b/Editor/3rds/UnityHook/HybridCLRHooks/BuildPipeline_StripDll_HookTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed8859610137d404e87f332b7082c19b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs b/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs new file mode 100644 index 0000000..1a23d77 --- /dev/null +++ b/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs @@ -0,0 +1,55 @@ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using UnityEditor; +using System.Runtime.CompilerServices; +using MonoHook; +using HybridCLR.Editor.BuildProcessors; +using System.IO; + +namespace HybridCLR.MonoHook +{ +#if UNITY_2021_1_OR_NEWER && UNITY_WEBGL + [InitializeOnLoad] + public class PatchScriptingAssembliesJsonHook + { + private static MethodHook _hook; + + static PatchScriptingAssembliesJsonHook() + { + if (_hook == null) + { + Type type = typeof(UnityEditor.EditorApplication); + MethodInfo miTarget = type.GetMethod("BuildMainWindowTitle", BindingFlags.Static | BindingFlags.NonPublic); + + MethodInfo miReplacement = new Func(BuildMainWindowTitle).Method; + MethodInfo miProxy = new Func(BuildMainWindowTitleProxy).Method; + + _hook = new MethodHook(miTarget, miReplacement, miProxy); + _hook.Install(); + } + } + + private static string BuildMainWindowTitle() + { + string tempJsonPath = $"{Application.dataPath}/../Library/PlayerDataCache/WebGL/Data/ScriptingAssemblies.json"; + if (File.Exists(tempJsonPath)) + { + var patcher = new PatchScriptingAssemblyList(); + patcher.PathScriptingAssembilesFile(Path.GetDirectoryName(tempJsonPath)); + } + string newTitle = BuildMainWindowTitleProxy(); + return newTitle; + } + + [MethodImpl(MethodImplOptions.NoOptimization)] + private static string BuildMainWindowTitleProxy() + { + return string.Empty; + } + } +#endif +} diff --git a/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs.meta b/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs.meta new file mode 100644 index 0000000..ccf939f --- /dev/null +++ b/Editor/3rds/UnityHook/HybridCLRHooks/PatchScriptingAssembliesJsonHook.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cc89a9041ab48ac41975fbd1e00b9b98 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/3rds/UnityHook/LDasm.cs b/Editor/3rds/UnityHook/LDasm.cs index d87ab91..d766e66 100644 --- a/Editor/3rds/UnityHook/LDasm.cs +++ b/Editor/3rds/UnityHook/LDasm.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.InteropServices; namespace DotNetDetour { @@ -642,8 +641,15 @@ namespace DotNetDetour if(s_isArm.HasValue) return s_isArm.Value; - var arch = RuntimeInformation.ProcessArchitecture; - s_isArm = arch == Architecture.Arm || arch == Architecture.Arm64; + string processorType = UnityEngine.SystemInfo.processorType; + + /* + * appple M 系列 + * SystemInfo.processorType 返回值为: Apple M1 Max, Apple M2 等 + * SystemInfo.operatingSystem 返回值为: Mac OS X xx.x.x + * + */ + s_isArm = processorType.Contains("ARM") || processorType.Contains("Apple M"); return s_isArm.Value; } diff --git a/Editor/3rds/UnityHook/MethodHook.cs b/Editor/3rds/UnityHook/MethodHook.cs index e7acd0a..0c8173b 100644 --- a/Editor/3rds/UnityHook/MethodHook.cs +++ b/Editor/3rds/UnityHook/MethodHook.cs @@ -363,14 +363,8 @@ namespace MonoHook { if (s_fi_GUISkin_current.GetValue(null) != null) { - try - { - DoInstall(); - } - finally - { - EditorApplication.update -= OnEditorUpdate; - } + DoInstall(); + EditorApplication.update -= OnEditorUpdate; } } #endif diff --git a/Editor/3rds/UnityHook/Plugins.meta b/Editor/3rds/UnityHook/Plugins.meta index f6f9520..1f7f284 100644 --- a/Editor/3rds/UnityHook/Plugins.meta +++ b/Editor/3rds/UnityHook/Plugins.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 82346623158bae349a8347ae74662b12 +guid: 16b9dc031f67b4fe5ad79c230f75768c folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Editor/BuildProcessors/PatchScriptingAssemblyList.cs b/Editor/BuildProcessors/PatchScriptingAssemblyList.cs index e7c0fad..8a8c958 100644 --- a/Editor/BuildProcessors/PatchScriptingAssemblyList.cs +++ b/Editor/BuildProcessors/PatchScriptingAssemblyList.cs @@ -52,7 +52,7 @@ namespace HybridCLR.Editor.BuildProcessors #endif } - private void PathScriptingAssembilesFile(string path) + public void PathScriptingAssembilesFile(string path) { if (!SettingsUtil.Enable) { diff --git a/package.json b/package.json index a554cc9..35e8028 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.focus-creative-games.hybridclr_unity", - "version": "2.0.8", + "version": "2.0.9", "displayName": "HybridCLR", "description": "Unity package for HybridCLR. It includes editor and runtime scripts and assets for HybridCLR", "category": "Runtime",