2023-10-19 15:00:19 +08:00
|
|
|
|
using HybridCLR;
|
|
|
|
|
|
using Sirenix.Utilities;
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.AddressableAssets;
|
|
|
|
|
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
2024-01-26 19:55:40 +08:00
|
|
|
|
using UnityEngine.ResourceManagement.ResourceLocations;
|
2023-10-19 15:00:19 +08:00
|
|
|
|
using UnityEngine.ResourceManagement.ResourceProviders;
|
|
|
|
|
|
using UnityEngine.SceneManagement;
|
|
|
|
|
|
|
|
|
|
|
|
public class GameLauncher : MonoBehaviour
|
|
|
|
|
|
{
|
|
|
|
|
|
private class MethodExecutionInfo
|
|
|
|
|
|
{
|
|
|
|
|
|
public MethodInfo method;
|
|
|
|
|
|
public int sequnence;
|
|
|
|
|
|
|
|
|
|
|
|
public MethodExecutionInfo(MethodInfo method, int sequnence)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.method = method;
|
|
|
|
|
|
this.sequnence = sequnence;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-01-30 19:42:52 +08:00
|
|
|
|
[Serializable]
|
|
|
|
|
|
private class DownloadContent
|
|
|
|
|
|
{
|
|
|
|
|
|
public List<string> catalogs = new();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
const string START_SCENE_NAME = "Assets/Scenes/StartScene.unity";
|
|
|
|
|
|
|
|
|
|
|
|
const string META_DATA_DLL_PATH = "Assets/HotUpdateDlls/MetaDataDll/";
|
|
|
|
|
|
const string HOT_UPDATE_DLL_PATH = "Assets/HotUpdateDlls/HotUpdateDll/";
|
|
|
|
|
|
const string PHXH_DLL_NAME = "Phxh.dll";
|
|
|
|
|
|
const string FRAMEWORK_DLL_NAME = "FrameWork.dll";
|
|
|
|
|
|
const string GAMEPLAY_DLL_NAME = "GamePlay.dll";
|
|
|
|
|
|
|
2024-01-30 19:42:52 +08:00
|
|
|
|
//记录在playerPres里的需要下载的catalogs的ID
|
|
|
|
|
|
const string DOWNLOAD_CATALOGS_ID = "DownloadCatalogs";
|
|
|
|
|
|
|
|
|
|
|
|
//最大能容忍的下载卡住时长,一旦超过则重新开始下载
|
|
|
|
|
|
private const float DOWNLOAD_STUCK_TIME_MAX = 10;
|
|
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
private Coroutine _launchCoroutine;
|
|
|
|
|
|
private byte[] _dllBytes;
|
|
|
|
|
|
|
|
|
|
|
|
private Dictionary<string, Assembly> _allHotUpdateAssemblies = new();
|
|
|
|
|
|
|
|
|
|
|
|
//version update
|
|
|
|
|
|
private AsyncOperationHandle _downloadOP;
|
2023-11-08 19:04:23 +08:00
|
|
|
|
private UI_VersionUpdate _versionUpdateUI;
|
2023-10-19 15:00:19 +08:00
|
|
|
|
private Type _versionUpdaterType;
|
2024-01-30 19:42:52 +08:00
|
|
|
|
private float _downloadProgress;
|
|
|
|
|
|
private float _downloadStuckTime;
|
|
|
|
|
|
|
|
|
|
|
|
private List<object> _KeysNeedToDownload = new();
|
|
|
|
|
|
|
|
|
|
|
|
//此对象里保存了需要下载的catalog,每次获取新的catalog会将此对象保存到手机上,如果在下载的过程中关闭了游戏,下次打开还能拿到catalog继续下载
|
|
|
|
|
|
private DownloadContent _downloadContent = new();
|
|
|
|
|
|
|
|
|
|
|
|
private bool HasContentToDownload => _downloadContent != null && _downloadContent.catalogs != null &&
|
|
|
|
|
|
_downloadContent.catalogs.Count > 0;
|
2023-10-19 15:00:19 +08:00
|
|
|
|
|
|
|
|
|
|
private readonly List<string> _phxhDependencyDlls = new List<string>()
|
|
|
|
|
|
{
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
private readonly List<string> _frameWorkDependencyDlls = new List<string>()
|
|
|
|
|
|
{
|
|
|
|
|
|
//不要随意改顺序!
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
private readonly List<string> _gamePlayDependencyDlls = new List<string>()
|
|
|
|
|
|
{
|
2023-11-08 19:04:23 +08:00
|
|
|
|
//不要随意改顺序!
|
2023-10-19 15:00:19 +08:00
|
|
|
|
"BehaviorDesigner.Runtime.dll",
|
2023-12-18 15:28:27 +08:00
|
|
|
|
//"BestHTTP.dll",
|
2023-10-19 15:00:19 +08:00
|
|
|
|
"DOTweenCSharp.dll",
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//所有使用了RuntimeInitializeOnLoadMethod attribute的程序集
|
|
|
|
|
|
private readonly List<string> _hasRuntimeInitializeOnLoadMethodAssemblies = new List<string>()
|
|
|
|
|
|
{
|
|
|
|
|
|
"BehaviorDesigner.Runtime",
|
2023-12-18 15:28:27 +08:00
|
|
|
|
//"BestHTTP",
|
2023-10-19 15:00:19 +08:00
|
|
|
|
"GamePlay",
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
public bool enableHotUpdate = true;
|
|
|
|
|
|
|
|
|
|
|
|
private void Start()
|
|
|
|
|
|
{
|
|
|
|
|
|
_launchCoroutine = StartCoroutine(Launch());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void OnDestroy()
|
|
|
|
|
|
{
|
|
|
|
|
|
StopCoroutine(_launchCoroutine);
|
|
|
|
|
|
_launchCoroutine = null;
|
|
|
|
|
|
}
|
2024-01-30 19:42:52 +08:00
|
|
|
|
|
2023-12-15 19:40:57 +08:00
|
|
|
|
// private void _SafeProtect()
|
|
|
|
|
|
// {
|
|
|
|
|
|
// var typeList = new List<Type>();
|
|
|
|
|
|
// typeList.Add(typeof(BestHTTP.HTTPRequest));
|
|
|
|
|
|
// typeList.Add(typeof(BestHTTP.HTTPResponse));
|
|
|
|
|
|
// for (int i = 0; i < typeList.Count; i++)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// var type = typeList[i];
|
|
|
|
|
|
// DebugUtil.LogError("type = {0}", type);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
2023-10-19 15:00:19 +08:00
|
|
|
|
|
|
|
|
|
|
private IEnumerator Launch()
|
|
|
|
|
|
{
|
2023-12-15 19:40:57 +08:00
|
|
|
|
// _SafeProtect();
|
2023-10-19 15:00:19 +08:00
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
|
enableHotUpdate = false;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
Debug.Log($"Launch Game! enableHotUpdate:{enableHotUpdate}");
|
|
|
|
|
|
yield return VersionCheck();
|
2024-01-30 19:42:52 +08:00
|
|
|
|
if (HasContentToDownload)
|
2023-10-19 15:00:19 +08:00
|
|
|
|
yield return VersionUpdate();
|
|
|
|
|
|
if (enableHotUpdate)
|
|
|
|
|
|
yield return LoadAssemblies();
|
|
|
|
|
|
yield return EnterGame();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private IEnumerator VersionCheck()
|
|
|
|
|
|
{
|
|
|
|
|
|
//todo 如果包体版本不一致则提示用户去app store重新下载
|
|
|
|
|
|
var checkUpdateOP = Addressables.CheckForCatalogUpdates(false);
|
|
|
|
|
|
yield return checkUpdateOP;
|
|
|
|
|
|
if (checkUpdateOP.Status == AsyncOperationStatus.Succeeded)
|
|
|
|
|
|
{
|
2024-01-30 19:42:52 +08:00
|
|
|
|
_downloadContent.catalogs = checkUpdateOP.Result;
|
|
|
|
|
|
if (HasContentToDownload)
|
2023-10-19 15:00:19 +08:00
|
|
|
|
{
|
2024-01-30 19:42:52 +08:00
|
|
|
|
//如果服务器上的catalog和本地不一致,则覆盖上一次需要下载的被内容
|
2024-01-30 20:08:53 +08:00
|
|
|
|
var jsonStr = JsonUtility.ToJson(_downloadContent);
|
|
|
|
|
|
Debug.Log($"set download json:{jsonStr}");
|
|
|
|
|
|
PlayerPrefs.SetString(DOWNLOAD_CATALOGS_ID, jsonStr);
|
|
|
|
|
|
PlayerPrefs.Save();
|
2024-01-30 19:42:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2024-01-30 20:08:53 +08:00
|
|
|
|
Debug.Log($"try to get last download json");
|
2024-01-30 19:42:52 +08:00
|
|
|
|
if (PlayerPrefs.HasKey(DOWNLOAD_CATALOGS_ID))
|
|
|
|
|
|
{
|
2024-01-30 20:08:53 +08:00
|
|
|
|
var jsonStr = PlayerPrefs.GetString(DOWNLOAD_CATALOGS_ID);
|
|
|
|
|
|
Debug.Log($"try to get last download json:{jsonStr}");
|
|
|
|
|
|
JsonUtility.FromJsonOverwrite(jsonStr, _downloadContent);
|
|
|
|
|
|
Debug.Log($"catalog count:{_downloadContent.catalogs.Count}");
|
2024-01-30 19:42:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (HasContentToDownload)
|
|
|
|
|
|
{
|
|
|
|
|
|
var updateCatalogOP = Addressables.UpdateCatalogs(_downloadContent.catalogs, false);
|
2023-10-19 15:00:19 +08:00
|
|
|
|
yield return updateCatalogOP;
|
|
|
|
|
|
if (updateCatalogOP.Status == AsyncOperationStatus.Succeeded)
|
|
|
|
|
|
{
|
2024-01-30 19:42:52 +08:00
|
|
|
|
_KeysNeedToDownload.Clear();
|
2023-10-19 15:00:19 +08:00
|
|
|
|
foreach (var resourceLocator in updateCatalogOP.Result)
|
|
|
|
|
|
{
|
2024-01-30 19:42:52 +08:00
|
|
|
|
_KeysNeedToDownload.AddRange(resourceLocator.Keys);
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"Update catalog failed!exception:{updateCatalogOP.OperationException.Message}");
|
|
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
Addressables.Release(updateCatalogOP);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"CheckUpdate failed!exception:{checkUpdateOP.OperationException.Message}");
|
|
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
Addressables.Release(checkUpdateOP);
|
|
|
|
|
|
yield return ReloadAddressableCatalog();
|
2024-01-30 19:42:52 +08:00
|
|
|
|
Debug.Log($"版本检查结束,是否有需要下载的内容:{HasContentToDownload}");
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private IEnumerator VersionUpdate()
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return OpenVersionUpdateUI();
|
|
|
|
|
|
yield return Download();
|
|
|
|
|
|
Debug.Log($"版本更新结束!");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private IEnumerator LoadAssemblies()
|
|
|
|
|
|
{
|
2023-11-08 19:04:23 +08:00
|
|
|
|
yield return LoadPhxhDependencyAssemblies();
|
|
|
|
|
|
yield return LoadPhxhAssembies();
|
|
|
|
|
|
yield return LoadFrameworkDependencyAssemblies();
|
|
|
|
|
|
yield return LoadFrameWorkAssemblies();
|
|
|
|
|
|
yield return LoadMetadataForAOTAssemblies();
|
2023-10-19 15:00:19 +08:00
|
|
|
|
yield return LoadGamePlayDependencyAssemblies();
|
|
|
|
|
|
yield return LoadGamePlayAssemblies();
|
|
|
|
|
|
yield return ReloadAddressableCatalog();
|
|
|
|
|
|
ExecuteRuntimeInitializeOnLoadMethodAttribute();
|
|
|
|
|
|
Debug.Log("加载程序集结束!");
|
|
|
|
|
|
yield return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//补充元数据
|
|
|
|
|
|
private IEnumerator LoadMetadataForAOTAssemblies()
|
|
|
|
|
|
{
|
2023-11-27 19:53:34 +08:00
|
|
|
|
var aotAssemblies = AOTGenericReferences.PatchedAOTAssemblyList;
|
|
|
|
|
|
if (aotAssemblies == null)
|
2023-10-19 15:00:19 +08:00
|
|
|
|
{
|
2023-11-27 19:53:34 +08:00
|
|
|
|
Debug.LogError($"LoadMetadataForAOTAssemblies failed, PatchedAOTAssemblyList is null!");
|
2023-10-19 15:00:19 +08:00
|
|
|
|
yield break;
|
|
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
foreach (var aotDllName in aotAssemblies)
|
|
|
|
|
|
{
|
|
|
|
|
|
var path = $"{META_DATA_DLL_PATH}{aotDllName}.bytes";
|
|
|
|
|
|
yield return ReadDllBytes(path);
|
|
|
|
|
|
if (_dllBytes != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var err = HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(_dllBytes, HomologousImageMode.SuperSet);
|
|
|
|
|
|
Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. ret:{err}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-11-08 19:04:23 +08:00
|
|
|
|
Debug.Log("补充元数据结束!");
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private IEnumerator LoadPhxhDependencyAssemblies()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var dllName in _phxhDependencyDlls)
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return LoadSingleHotUpdateAssembly(dllName);
|
|
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
Debug.Log("加载Phxh依赖程序集结束!");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private IEnumerator LoadPhxhAssembies()
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return LoadSingleHotUpdateAssembly(PHXH_DLL_NAME);
|
|
|
|
|
|
Debug.Log("加载Phxh程序集结束!");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//加载FrameWork依赖的第三方热更序集
|
|
|
|
|
|
private IEnumerator LoadFrameworkDependencyAssemblies()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var dllName in _frameWorkDependencyDlls)
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return LoadSingleHotUpdateAssembly(dllName);
|
|
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
Debug.Log("加载Framework依赖程序集结束!");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//加载Framework程序集
|
|
|
|
|
|
private IEnumerator LoadFrameWorkAssemblies()
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return LoadSingleHotUpdateAssembly(FRAMEWORK_DLL_NAME);
|
|
|
|
|
|
Debug.Log("加载Framework程序集结束!");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//通过加载场景打开版本更新界面
|
|
|
|
|
|
private IEnumerator OpenVersionUpdateUI()
|
|
|
|
|
|
{
|
2024-01-30 19:42:52 +08:00
|
|
|
|
_versionUpdateUI = FindObjectOfType<UI_VersionUpdate>(true);
|
2023-11-08 19:04:23 +08:00
|
|
|
|
if (_versionUpdateUI == null)
|
2023-10-19 15:00:19 +08:00
|
|
|
|
{
|
2023-11-08 19:04:23 +08:00
|
|
|
|
Debug.LogError("cant find UI_VersionUpdate");
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-01-30 19:42:52 +08:00
|
|
|
|
_versionUpdateUI.gameObject.SetActive(true);
|
2023-11-08 19:04:23 +08:00
|
|
|
|
return null;
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//下载资源
|
|
|
|
|
|
private IEnumerator Download()
|
|
|
|
|
|
{
|
2024-01-30 19:42:52 +08:00
|
|
|
|
var downloadSizeOp = Addressables.GetDownloadSizeAsync((IEnumerable)_KeysNeedToDownload);
|
2023-10-19 15:00:19 +08:00
|
|
|
|
yield return downloadSizeOp;
|
|
|
|
|
|
Debug.Log($"download size:{downloadSizeOp.Result / (1024f * 1024f)}MB");
|
|
|
|
|
|
|
|
|
|
|
|
if (downloadSizeOp.Result > 0)
|
|
|
|
|
|
{
|
2024-01-30 19:42:52 +08:00
|
|
|
|
_downloadStuckTime = 0;
|
|
|
|
|
|
Addressables.Release(downloadSizeOp);
|
2024-01-26 19:55:40 +08:00
|
|
|
|
//下载经常在100%的时候卡住,参考:https://forum.unity.com/threads/addressables-1-14-2-downloaddependenciesasync-does-not-complete-randomly.966671/
|
|
|
|
|
|
//倒数第二个回答
|
2024-01-30 19:42:52 +08:00
|
|
|
|
var asyncLoadResources = Addressables.LoadResourceLocationsAsync((IEnumerable)_KeysNeedToDownload,
|
|
|
|
|
|
Addressables.MergeMode.Union, null);
|
2024-01-26 19:55:40 +08:00
|
|
|
|
IList<IResourceLocation> dependencyLoadList = new List<IResourceLocation>();
|
|
|
|
|
|
yield return asyncLoadResources;
|
|
|
|
|
|
foreach (var item in asyncLoadResources.Result)
|
|
|
|
|
|
{
|
|
|
|
|
|
dependencyLoadList.Add(item);
|
|
|
|
|
|
}
|
2024-01-30 19:42:52 +08:00
|
|
|
|
|
2023-11-08 19:04:23 +08:00
|
|
|
|
_downloadOP =
|
2024-01-26 19:55:40 +08:00
|
|
|
|
Addressables.DownloadDependenciesAsync(dependencyLoadList);
|
2023-11-08 19:04:23 +08:00
|
|
|
|
_versionUpdateUI.SetParams(_downloadOP);
|
|
|
|
|
|
|
2024-01-30 19:42:52 +08:00
|
|
|
|
while (_downloadOP.IsDone)
|
|
|
|
|
|
{
|
|
|
|
|
|
RefreshDownLoadStatus();
|
|
|
|
|
|
if (!CheckIfNeedReDownload())
|
|
|
|
|
|
yield return 0;
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
//说明下载卡住了,重启下载
|
|
|
|
|
|
Debug.LogError($"下载卡住超过时间上限,重新启动下载!");
|
|
|
|
|
|
Addressables.Release(_downloadOP);
|
|
|
|
|
|
yield return Download();
|
|
|
|
|
|
yield break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (_downloadOP.IsDone && _downloadOP.Status != AsyncOperationStatus.Succeeded)
|
2023-10-19 15:00:19 +08:00
|
|
|
|
{
|
2023-11-08 19:04:23 +08:00
|
|
|
|
Debug.LogError(
|
|
|
|
|
|
$"Download Update Content Failed! exception:{_downloadOP.OperationException.Message} \r\n {_downloadOP.OperationException.StackTrace}");
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
Addressables.Release(_downloadOP);
|
|
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
|
2024-01-30 19:42:52 +08:00
|
|
|
|
//清除需要下载的内容
|
2024-01-30 20:08:53 +08:00
|
|
|
|
Debug.Log($"delete key:{DOWNLOAD_CATALOGS_ID}");
|
2024-01-30 19:42:52 +08:00
|
|
|
|
PlayerPrefs.DeleteKey(DOWNLOAD_CATALOGS_ID);
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-01-30 19:42:52 +08:00
|
|
|
|
private void RefreshDownLoadStatus()
|
|
|
|
|
|
{
|
|
|
|
|
|
var currDownloadProgress = _downloadOP.GetDownloadStatus().Percent;
|
|
|
|
|
|
if (Math.Abs(currDownloadProgress - _downloadProgress) < float.Epsilon)
|
|
|
|
|
|
_downloadStuckTime += Time.deltaTime;
|
|
|
|
|
|
else
|
|
|
|
|
|
_downloadStuckTime = 0;
|
|
|
|
|
|
_downloadProgress = currDownloadProgress;
|
|
|
|
|
|
Debug.Log($"下载进度:{_downloadProgress} 下载卡顿时间:{_downloadStuckTime}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool CheckIfNeedReDownload() => _downloadStuckTime >= DOWNLOAD_STUCK_TIME_MAX;
|
|
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
//加载GamePlay依赖的第三方程序集
|
|
|
|
|
|
private IEnumerator LoadGamePlayDependencyAssemblies()
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var dllName in _gamePlayDependencyDlls)
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return LoadSingleHotUpdateAssembly(dllName);
|
|
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
Debug.Log("加载GamePlay依赖程序集结束!");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//加载GamePlay程序集
|
|
|
|
|
|
private IEnumerator LoadGamePlayAssemblies()
|
|
|
|
|
|
{
|
|
|
|
|
|
yield return LoadSingleHotUpdateAssembly(GAMEPLAY_DLL_NAME);
|
|
|
|
|
|
Debug.Log("加载GamePlay程序集结束!");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Addressable初始化时热更新代码所对应的ScriptableObject的类型会被识别为System.Object,需要在热更新dll加载完后重新加载一下Addressable的Catalog
|
|
|
|
|
|
/// https://hybridclr.doc.code-philosophy.com/docs/help/commonerrors
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private IEnumerator ReloadAddressableCatalog()
|
|
|
|
|
|
{
|
|
|
|
|
|
var op = Addressables.LoadContentCatalogAsync($"{Addressables.RuntimePath}/catalog.json");
|
|
|
|
|
|
yield return op;
|
|
|
|
|
|
if (op.Status != AsyncOperationStatus.Succeeded)
|
|
|
|
|
|
{
|
2023-11-08 19:04:23 +08:00
|
|
|
|
Debug.LogError(
|
|
|
|
|
|
$"load content catalog failed, exception:{op.OperationException.Message} \r\n {op.OperationException.StackTrace}");
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 反射执行被RuntimeInitializeOnLoadMethod attribute标注的函数,HybirdCLR不支持该attribute
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void ExecuteRuntimeInitializeOnLoadMethodAttribute()
|
|
|
|
|
|
{
|
|
|
|
|
|
var runtimeInitializedAttribute = typeof(RuntimeInitializeOnLoadMethodAttribute);
|
|
|
|
|
|
List<MethodExecutionInfo> runtimeMethods = new();
|
|
|
|
|
|
foreach (var assemblyName in _hasRuntimeInitializeOnLoadMethodAssemblies)
|
|
|
|
|
|
{
|
|
|
|
|
|
var assembly = GetAssembly(assemblyName);
|
|
|
|
|
|
if (assembly == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError($"找不到使用过RuntimeInitializeOnLoadMethod的assembly,name:{assemblyName}");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
foreach (var type in assembly.GetTypes())
|
|
|
|
|
|
{
|
|
|
|
|
|
type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).ForEach(method =>
|
2023-11-08 19:04:23 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (!method.IsStatic)
|
|
|
|
|
|
return;
|
|
|
|
|
|
var attri = method.GetCustomAttribute(runtimeInitializedAttribute);
|
|
|
|
|
|
if (attri == null)
|
|
|
|
|
|
return;
|
|
|
|
|
|
var sequence = (int)(attri as RuntimeInitializeOnLoadMethodAttribute).loadType;
|
|
|
|
|
|
var methodInfo = new MethodExecutionInfo(method, sequence);
|
|
|
|
|
|
runtimeMethods.Add(methodInfo);
|
|
|
|
|
|
});
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
runtimeMethods.Sort((a, b) => b.sequnence.CompareTo(a.sequnence));
|
|
|
|
|
|
foreach (var methodInfo in runtimeMethods)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.Log($"call method methodName:{methodInfo.method.Name} sequnence:{methodInfo.sequnence}");
|
|
|
|
|
|
methodInfo.method.Invoke(null, null);
|
|
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
Debug.Log("调用RuntimeInitializeOnLoadMethod结束!");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private IEnumerator ReadDllBytes(string path)
|
|
|
|
|
|
{
|
|
|
|
|
|
var op = Addressables.LoadAssetAsync<TextAsset>(path);
|
|
|
|
|
|
yield return op;
|
|
|
|
|
|
if (op.Status == AsyncOperationStatus.Succeeded)
|
|
|
|
|
|
{
|
|
|
|
|
|
_dllBytes = op.Result.bytes;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2023-11-08 19:04:23 +08:00
|
|
|
|
Debug.LogError(
|
|
|
|
|
|
$"cant load dll,exception:{op.OperationException.Message}\r\n{op.OperationException.StackTrace}");
|
2023-10-19 15:00:19 +08:00
|
|
|
|
_dllBytes = null;
|
|
|
|
|
|
yield break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private IEnumerator LoadSingleHotUpdateAssembly(string dllName)
|
|
|
|
|
|
{
|
|
|
|
|
|
var path = $"{HOT_UPDATE_DLL_PATH}{dllName}.bytes";
|
|
|
|
|
|
yield return ReadDllBytes(path);
|
|
|
|
|
|
if (_dllBytes != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var assembly = Assembly.Load(_dllBytes);
|
|
|
|
|
|
_allHotUpdateAssemblies.Add(assembly.FullName, assembly);
|
|
|
|
|
|
Debug.Log($"Load Assembly success,assembly Name:{assembly.FullName}");
|
2024-01-30 19:42:52 +08:00
|
|
|
|
// foreach (var type in GetAssembly(dllName).GetTypes())
|
|
|
|
|
|
// {
|
|
|
|
|
|
// Debug.Log($"type:{type} in assembly:{GAMEPLAY_DLL_NAME}");
|
|
|
|
|
|
// }
|
2023-10-19 15:00:19 +08:00
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
|
2023-10-19 15:00:19 +08:00
|
|
|
|
yield return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private IEnumerator EnterGame()
|
|
|
|
|
|
{
|
|
|
|
|
|
var op = Addressables.LoadSceneAsync(START_SCENE_NAME, LoadSceneMode.Single);
|
|
|
|
|
|
yield return op;
|
|
|
|
|
|
if (op.Status != AsyncOperationStatus.Succeeded)
|
|
|
|
|
|
{
|
2023-11-08 19:04:23 +08:00
|
|
|
|
Debug.LogError(
|
|
|
|
|
|
$"load scene failed,exception:{op.OperationException.Message} \r\n {op.OperationException.StackTrace}");
|
2023-10-19 15:00:19 +08:00
|
|
|
|
yield break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private Assembly GetAssembly(string assemblyName)
|
|
|
|
|
|
{
|
2024-01-19 20:05:16 +08:00
|
|
|
|
assemblyName = assemblyName.Replace(".dll", "");
|
2023-11-08 19:04:23 +08:00
|
|
|
|
IEnumerable<Assembly> allAssemblies =
|
|
|
|
|
|
enableHotUpdate ? _allHotUpdateAssemblies.Values : AppDomain.CurrentDomain.GetAssemblies();
|
2023-10-19 15:00:19 +08:00
|
|
|
|
return allAssemblies.First(assembly => assembly.FullName.Contains(assemblyName));
|
|
|
|
|
|
}
|
2023-11-08 19:04:23 +08:00
|
|
|
|
}
|