/// <summary> /// 脚本加载入口 /// </summary> /// <param name="loadPathTypeType"></param> /// <param name="runMode"></param> /// <param name="mainProjectTypes">UPM隔离了dll,需要手动传入</param> static public void Init(AssetLoadPathType loadPathTypeType, HotfixCodeRunMode runMode, Type[] mainProjectTypes, Action <bool> clrBindingAction) { CLRBindAction = clrBindingAction; if (loadPathTypeType == AssetLoadPathType.Editor) { BDebug.Log("【ScriptLaunch】Editor(非热更)模式!"); //反射调用,防止编译报错 var assembly = Assembly.GetExecutingAssembly(); var type = assembly.GetType("BDLauncherBridge"); var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); //添加框架部分的type,热更下不需要,打包会把框架的部分打进去 var list = new List <Type>(); list.AddRange(mainProjectTypes); list.AddRange(typeof(BDLauncher).Assembly.GetTypes()); method.Invoke(null, new object[] { list.ToArray(), null }); } else { BDebug.Log("【ScriptLaunch】热更模式!"); var path = GameConfig.GetLoadPath(loadPathTypeType); path = Path.Combine(path, BApplication.GetRuntimePlatformPath()); //加载dll var dllPath = Path.Combine(path, DLL_PATH); LoadHotfixDLL(dllPath, runMode, mainProjectTypes); } }
/// <summary> /// 加载 /// </summary> /// <param name="source"></param> /// <param name="copyto"></param> /// <returns></returns> static IEnumerator IE_LoadScript(string root, HotfixCodeRunMode mode) { string dllPath = ""; if (Application.isEditor) { dllPath = root + "/" + BDUtils.GetPlatformPath(Application.platform) + "/hotfix/hotfix.dll"; } else { //这里情况比较复杂,Mobile上基本认为Persistent才支持File操作, //可寻址目录也只有 StreamingAsset var firstPath = Application.persistentDataPath + "/" + BDUtils.GetPlatformPath(Application.platform) + "/hotfix/hotfix.dll"; var secondPath = Application.streamingAssetsPath + "/" + BDUtils.GetPlatformPath(Application.platform) + "/hotfix/hotfix.dll"; if (!File.Exists(firstPath)) { var www = new WWW(secondPath); yield return(www); if (www.isDone && www.error == null) { FileHelper.WriteAllBytes(firstPath, www.bytes); } } dllPath = firstPath; } //反射执行 if (mode == HotfixCodeRunMode.ByReflection) { var bytes = File.ReadAllBytes(dllPath); var mdb = dllPath + ".mdb"; if (File.Exists(mdb)) { var bytes2 = File.ReadAllBytes(mdb); Assembly = Assembly.Load(bytes, bytes2); } else { Assembly = Assembly.Load(bytes); } var type = Assembly.GetType("BDLauncherBridge"); var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); method.Invoke(null, new object[] { false, true }); } //解释执行 else if (mode == HotfixCodeRunMode.ByILRuntime) { //解释执行模式 ILRuntimeHelper.LoadHotfix(dllPath); ILRuntimeHelper.AppDomain.Invoke("BDLauncherBridge", "Start", null, new object[] { true, false }); } }
/// <summary> /// 开始热更脚本逻辑 /// </summary> static public void Load(string root, HotfixCodeRunMode mode) { if (root != "") { IEnumeratorTool.StartCoroutine(IE_LoadScript(root, mode)); } else { #if UNITY_EDITOR BDebug.Log("内置code模式!"); BDLauncherBridge.Start(); #endif } }
/// <summary> /// 更新服务器配置 /// </summary> /// <param name="callback"></param> /// <returns></returns> private IEnumerator UpdateServerConfig(Action callback) { var url = string.Format("{0}/{1}/{2}", FileServerUrl, BDUtils.GetPlatformPath(Application.platform), "GameConfig.json"); Debug.Log(url); UnityWebRequest uwq = UnityWebRequest.Get(url); GameConfig gconfig = null; yield return(uwq.SendWebRequest()); if (uwq.isDone && uwq.error == null) { var text = uwq.downloadHandler.text; if (!string.IsNullOrEmpty(text)) { gconfig = JsonMapper.ToObject <GameConfig>(text); BDebug.Log("使用服务器配置:\n" + text); } } else { BDebug.LogError("Game配置无法更新,使用本地"); } //TODO 未来改成反射实现,暂时用这一版 if (gconfig != null) { this.CodeRoot = (AssetLoadPath)gconfig.CodeRoot; this.SQLRoot = (AssetLoadPath)gconfig.SQLRoot; this.ArtRoot = (AssetLoadPath)gconfig.ArtRoot; // this.CodeRunMode = (HotfixCodeRunMode)gconfig.CodeRunMode; //ip相关 this.FileServerUrl = gconfig.FileServerUrl; this.IsHotfix = gconfig.IsHotfix; this.GateServerIp = gconfig.GateServerIp; this.Port = gconfig.Port; if (!Application.isEditor) { this.IsHotfix = this.IsNeedNet = true; } } if (callback != null) { callback(); } }
/// <summary> /// 脚本加载入口 /// </summary> /// <param name="loadPath"></param> /// <param name="runMode"></param> /// <param name="mainProjectTypes">UPM隔离了dll,需要手动传入</param> static public void Load(AssetLoadPath loadPath, HotfixCodeRunMode runMode, Type[] mainProjectTypes, Action <bool> clrBindingAction) { CLRBindAction = clrBindingAction; if (loadPath == AssetLoadPath.Editor) { BDebug.Log("Editor code模式!"); //反射调用,防止编译报错 var assembly = Assembly.GetExecutingAssembly(); var type = assembly.GetType("BDLauncherBridge"); var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); //添加框架部分的type,热更下不需要,打包会把框架的部分打进去 var list = new List <Type>(); list.AddRange(mainProjectTypes); list.AddRange(typeof(BDLauncher).Assembly.GetTypes()); method.Invoke(null, new object[] { list.ToArray(), null }); } else { var path = ""; if (Application.isEditor) { if (loadPath == AssetLoadPath.Persistent) { path = Path.Combine(Application.persistentDataPath, BDApplication.GetPlatformPath(Application.platform)); } else if (loadPath == AssetLoadPath.StreamingAsset) { path = Path.Combine(Application.streamingAssetsPath, BDApplication.GetPlatformPath(Application.platform)); } } else { //真机环境,代码在persistent下,因为需要io path = Path.Combine(Application.persistentDataPath, BDApplication.GetPlatformPath(Application.platform)); } //加载dll var dllPath = Path.Combine(path, DLLPATH); LoadHotfixDLL(dllPath, runMode, mainProjectTypes); } }
/// <summary> /// 开始热更脚本逻辑 /// </summary> static public void Load(string root, HotfixCodeRunMode mode) { if (root != "") { IEnumeratorTool.StartCoroutine(IE_LoadScript(root, mode)); } else { BDebug.Log("内置code模式!"); //反射调用,防止编译报错 var assembly = Assembly.GetExecutingAssembly(); var type = assembly.GetType("BDLauncherBridge"); var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); method.Invoke(null, new object[] { false, false }); } }
/// <summary> /// 加载 /// </summary> /// <param name="source"></param> /// <param name="copyto"></param> /// <returns></returns> static void LoadHotfixDLL(string dllPath, HotfixCodeRunMode mode, Type[] mainProjecTypes) { //反射执行 if (mode == HotfixCodeRunMode.Huatuo) { new NotSupportedException("暂未实现"); // BDebug.Log("【ScriptLaunch】反射Dll路径:" + dllPath, "red"); // Assembly Assembly; // var dllBytes = File.ReadAllBytes(dllPath); // var pdbPath = dllPath + ".pdb"; // if (File.Exists(pdbPath)) // { // var pdbBytes = File.ReadAllBytes(pdbPath); // Assembly = Assembly.Load(dllBytes, pdbBytes); // } // else // { // Assembly = Assembly.Load(dllBytes); // } // // BDebug.Log("【ScriptLaunch】反射加载成功,开始执行Start"); // var type = typeof(ScriptLoder).Assembly.GetType("BDLauncherBridge"); // var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); // // method.Invoke(null, new object[] {mainProjecTypes, Assembly.GetTypes()}); } //解释执行 else if (mode == HotfixCodeRunMode.ILRuntime) { BDebug.Log("【ScriptLaunch】热更Dll路径:" + dllPath, "red"); //解释执行模式 ILRuntimeHelper.LoadHotfix(dllPath, CLRBindAction); var hotfixTypes = ILRuntimeHelper.GetHotfixTypes().ToArray(); ILRuntimeHelper.AppDomain.Invoke("BDLauncherBridge", "Start", null, new object[] { mainProjecTypes, hotfixTypes }); } else { BDebug.Log("【ScriptLaunch】Dll路径:内置", "red"); } }
/// <summary> /// 使用新的配置 /// </summary> /// <param name="newConfig"></param> private void SetNewConfig(GameConfig newConfig) { //TODO 未来改成反射实现,暂时用这一版 if (newConfig != null) { this.CodeRoot = (AssetLoadPath)newConfig.CodeRoot; this.SQLRoot = (AssetLoadPath)newConfig.SQLRoot; this.ArtRoot = (AssetLoadPath)newConfig.ArtRoot; // this.CodeRunMode = (HotfixCodeRunMode)newConfig.CodeRunMode; //ip相关 this.FileServerUrl = newConfig.FileServerUrl; this.IsHotfix = newConfig.IsHotfix; this.GateServerIp = newConfig.GateServerIp; this.Port = newConfig.Port; if (!Application.isEditor) { this.IsHotfix = this.IsNeedNet = true; } } }
/// <summary> /// 加载 /// </summary> /// <param name="source"></param> /// <param name="copyto"></param> /// <returns></returns> static void LoadHotfixDLL(string dllPath, HotfixCodeRunMode mode, Type[] mainProjecTypes) { //反射执行 if (mode == HotfixCodeRunMode.ByReflection) { BDebug.Log("反射Dll路径:" + dllPath, "red"); Assembly Assembly; var dllBytes = File.ReadAllBytes(dllPath); var pdbPath = dllPath + ".pdb"; if (File.Exists(pdbPath)) { var pdbBytes = File.ReadAllBytes(pdbPath); Assembly = Assembly.Load(dllBytes, pdbBytes); } else { Assembly = Assembly.Load(dllBytes); } BDebug.Log("反射加载成功,开始执行Start"); var type = typeof(ScriptLoder).Assembly.GetType("BDLauncherBridge"); var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); method.Invoke(null, new object[] { mainProjecTypes, Assembly.GetTypes() }); } //解释执行 else if (mode == HotfixCodeRunMode.ByILRuntime) { BDebug.Log("热更Dll路径:" + dllPath, "red"); //解释执行模式 ILRuntimeHelper.LoadHotfix(dllPath, GamelogicILRBindAction); var hotfixTypes = ILRuntimeHelper.GetHotfixTypes().ToArray(); ILRuntimeHelper.AppDomain.Invoke("BDLauncherBridge", "Start", null, new object[] { mainProjecTypes, hotfixTypes }); } else { BDebug.Log("Dll路径:内置", "red"); } }
/// <summary> /// 加载 /// </summary> /// <param name="source"></param> /// <param name="copyto"></param> /// <returns></returns> static void LoadDLL(string dllPath, HotfixCodeRunMode mode) { //反射执行 if (mode == HotfixCodeRunMode.ByReflection) { BDebug.Log("Dll路径:" + dllPath, "red"); var dllBytes = File.ReadAllBytes(dllPath); var pdbPath = dllPath + ".pdb"; if (File.Exists(pdbPath)) { var pdbBytes = File.ReadAllBytes(pdbPath); Assembly = Assembly.Load(dllBytes, pdbBytes); } else { Assembly = Assembly.Load(dllBytes); } BDebug.Log("代码加载成功,开始执行Start"); var type = Assembly.GetType("BDLauncherBridge"); var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); method.Invoke(null, new object[] { false, true }); } //解释执行 else if (mode == HotfixCodeRunMode.ByILRuntime) { BDebug.Log("Dll路径:" + dllPath, "red"); //解释执行模式 ILRuntimeHelper.LoadHotfix(dllPath); ILRuntimeHelper.AppDomain.Invoke("BDLauncherBridge", "Start", null, new object[] { true, false }); } else { BDebug.Log("Dll路径:内置", "red"); } }
/// <summary> /// 开始热更脚本逻辑 /// </summary> static public void Load(AssetLoadPath loadPath, HotfixCodeRunMode runMode) { if (loadPath == AssetLoadPath.Editor) { BDebug.Log("内置code模式!"); //反射调用,防止编译报错 var assembly = Assembly.GetExecutingAssembly(); var type = assembly.GetType("BDLauncherBridge"); var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); method.Invoke(null, new object[] { false, false }); } else { var path = ""; if (Application.isEditor) { if (loadPath == AssetLoadPath.Persistent) { path = Path.Combine(Application.persistentDataPath, BDApplication.GetPlatformPath(Application.platform)); } else if (loadPath == AssetLoadPath.StreamingAsset) { path = Path.Combine(Application.streamingAssetsPath, BDApplication.GetPlatformPath(Application.platform)); } } else { //真机环境,代码在persistent下,因为需要io path = Path.Combine(Application.persistentDataPath, BDApplication.GetPlatformPath(Application.platform)); } //加载dll var dllPath = Path.Combine(path, DLLPATH); LoadDLL(dllPath, runMode); } }
/// <summary> /// 加载Dll热更脚本 /// </summary> /// <param name="root">路径</param> /// <param name="mode"></param> /// <returns></returns> public IEnumerator IE_LoadScript(HotfixCodeRunMode mode) { string dllPath = ""; if (Application.isEditor) { //这里情况比较复杂,Mobile上基本认为Persistent才支持File操作, dllPath = Application.streamingAssetsPath + "/Hotfix/" + LWUtility.HotfixFileName; } else { //这里情况比较复杂,Mobile上基本认为Persistent才支持File操作, //可寻址目录也只有 StreamingAsset var firstPath = FileTool.CombinePaths(LWUtility.updatePath, LWUtility.HotfixFileName); //LWUtility.updatePath + "/" + LWUtility.HotfixFileName; var secondPath = FileTool.CombinePaths(Application.streamingAssetsPath, LWUtility.AssetBundles, LWUtility.GetPlatform(), LWUtility.HotfixFileName); // Application.streamingAssetsPath + "/" + LWUtility.AssetBundles + "/" + LWUtility.GetPlatform() + "/" + LWUtility.HotfixFileName; if (!File.Exists(firstPath)) { var request = UnityWebRequest.Get(secondPath); LWDebug.Log("firstPath:" + firstPath); LWDebug.Log("secondPath:" + secondPath); yield return(request.SendWebRequest()); if (request.isDone && request.error == null) { LWDebug.Log("request.downloadHandler.data:" + request.downloadHandler.data.Length); LWDebug.Log("拷贝dll成功:" + firstPath); byte[] results = request.downloadHandler.data; FileTool.WriteByteToFile(firstPath, results, ""); } } dllPath = firstPath; } LWDebug.Log("Dll路径:" + dllPath); //反射执行 if (mode == HotfixCodeRunMode.ByReflection) { var bytes = File.ReadAllBytes(dllPath); var mdb = dllPath + ".mdb"; if (File.Exists(mdb)) { var bytes2 = File.ReadAllBytes(mdb); Assembly = Assembly.Load(bytes, bytes2); } else { Assembly = Assembly.Load(bytes); } //Debug.Log("反射模式,开始执行Start"); //var type = Assembly.GetType("StartupBridge_Hotfix"); //var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); //method.Invoke(null, new object[] { false }); StartupBridge_Hotfix.StartReflection(Assembly); } #if ILRUNTIME //解释执行 else if (mode == HotfixCodeRunMode.ByILRuntime) { //解释执行模式 // ILRuntimeHelper.LoadHotfix(dllPath); // ILRuntimeHelper.AppDomain.Invoke("StartupBridge_Hotfix", "Start", null, new object[] { true }); } #endif else if (mode == HotfixCodeRunMode.ByCode) { LWDebug.Log("内置code模式!", LogColor.green); StartupBridge_Hotfix.StartCode(); //反射调用,防止编译报错 //Assembly assembly = Assembly.GetExecutingAssembly(); //var type = assembly.GetType("StartupBridge_Hotfix"); //var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); //method.Invoke(null, new object[] { false }); } }
/// <summary> /// 开始热更脚本逻辑 /// </summary> static public void Load(string root, HotfixCodeRunMode mode) { if (root != "") { string dllPath = root + "/" + BDUtils.GetPlatformPath(Application.platform) + "/hotfix/hotfix.dll"; //反射 if (mode == HotfixCodeRunMode.ByReflection && (Application.isEditor || Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.WindowsPlayer)) { //反射模式只支持Editor PC Android if (File.Exists(dllPath)) //支持File操作 或者存在 { var bytes = File.ReadAllBytes(dllPath); var bytes2 = File.ReadAllBytes(dllPath + ".mdb"); var assembly = Assembly.Load(bytes, bytes2); var type = assembly.GetType("BDLauncherBridge"); var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); method.Invoke(null, new object[] { false, true }); } else { //不支持file操作 或者不存在,继续尝试 IEnumeratorTool.StartCoroutine(IE_LoadDLL_AndroidOrPC(dllPath)); } } //ILR else { // //ILRuntime基于文件流,所以不支持file操作的,得拷贝到支持File操作的目录 //这里情况比较复杂,Mobile上基本认为Persistent才支持File操作, //可寻址目录也只有 StreamingAsset var firstPath = Application.persistentDataPath + "/" + BDUtils.GetPlatformPath(Application.platform) + "/hotfix/hotfix.dll"; var secondPath = Application.streamingAssetsPath + "/" + BDUtils.GetPlatformPath(Application.platform) + "/hotfix/hotfix.dll"; if (!File.Exists(dllPath)) //仅当指定的路径不存在(或者不支持File操作)时,再进行可寻址 { dllPath = firstPath; if (!File.Exists(firstPath)) { //验证 可寻址目录2 IEnumeratorTool.StartCoroutine(IE_CopyDLL_WhithLaunch(secondPath, firstPath)); return; } } //解释执行模式 ILRuntimeHelper.LoadHotfix(dllPath); ILRuntimeHelper.AppDomain.Invoke("BDLauncherBridge", "Start", null, new object[] { true, false }); } } else { //PC模式 //这里用反射是为了 不访问逻辑模块的具体类,防止编译失败 var assembly = Assembly.GetExecutingAssembly(); // var type = assembly.GetType("BDLauncherBridge"); var method = type.GetMethod("Start", BindingFlags.Public | BindingFlags.Static); method.Invoke(null, new object[] { false, false }); } }