using UnityEngine;
|
using Cysharp.Threading;
|
using Cysharp.Threading.Tasks;
|
using System;
|
using DG.Tweening;
|
using System.Collections;
|
using System.Collections.Generic;
|
using System.IO;
|
using System.Linq;
|
using System.Reflection;
|
using UnityEngine.Networking;
|
using LaunchCommon;
|
using HybridCLR;
|
|
public class Launch : MonoBehaviour
|
{
|
|
private static Assembly _hotUpdateAss;
|
|
//网络获取
|
private static List<string> AOTMetaAssemblyFiles { get; } = new List<string>();
|
|
private static Dictionary<string, byte[]> s_assetDatas = new Dictionary<string, byte[]>();
|
|
public static Launch Instance
|
{
|
get
|
{
|
return m_Instance;
|
}
|
}
|
|
private GameObject launchExWin = null;
|
|
private static Launch m_Instance;
|
private void Awake()
|
{
|
if (m_Instance != null)
|
{
|
Debug.LogError("Launch Instance is not null");
|
return;
|
}
|
|
m_Instance = this;
|
|
#if !UNITY_EDITOR
|
if (File.Exists(Directory.GetParent(Application.persistentDataPath) + "/Debug") ||
|
LocalSave.GetString("#@#BrancH") != string.Empty)
|
{
|
Debug.unityLogger.logEnabled = true;
|
}
|
else
|
{
|
Debug.unityLogger.logEnabled = false;
|
}
|
|
#endif
|
|
}
|
|
// 启动入口
|
async void Start()
|
{
|
Debug.Log("Launch Start");
|
|
InitPlugins();
|
InitSetting();
|
|
// 1. 打开加载界面
|
}
|
|
private void InitSetting()
|
{
|
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CreateSpecificCulture("en-US");
|
System.Globalization.CultureInfo.CurrentCulture = culture;
|
System.Globalization.CultureInfo.CurrentUICulture = culture;
|
System.Globalization.CultureInfo.DefaultThreadCurrentCulture = culture;
|
System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = culture;
|
System.Net.ServicePointManager.DefaultConnectionLimit = 100;
|
|
#if UNITY_EDITOR
|
//内网下载测试
|
_hotUpdateAss = System.AppDomain.CurrentDomain.GetAssemblies().First(a => a.GetName().Name == "Main");
|
Type type = _hotUpdateAss.GetType("InGameDownTestUtility");
|
LocalResManager.Instance.isPCTestDownLoad = (bool)type.GetMethod("GetReadVerionEx").Invoke(null, null);
|
#endif
|
SDKInit();
|
LocalResManager.Instance.Init();
|
LocalResManager.Instance.InitTable(() =>
|
{
|
LocalResManager.Instance.InitDefaultLanguage();
|
launchExWin = LaunchExWin.OpenWindow();
|
// LocalResManager.Instance.OpenWindow("LaunchExWin", m_UICanvas);
|
#if !UNITY_EDITOR
|
LocalResManager.step = LocalResManager.LoadDllStep.RequestVersion;
|
#else
|
if (LocalResManager.Instance.isPCTestDownLoad)
|
{
|
LocalResManager.step = LocalResManager.LoadDllStep.RequestVersion;
|
}
|
else
|
{
|
StartGame();
|
}
|
#endif
|
});
|
}
|
|
private void InitPlugins()
|
{
|
DOTween.Init();
|
}
|
|
private void SDKInit()
|
{
|
|
}
|
|
/// <summary>
|
/// 为aot assembly加载原始metadata, 这个代码放aot或者热更新都行。
|
/// 一旦加载后,如果AOT泛型函数对应native实现不存在,则自动替换为解释模式执行
|
/// </summary>
|
private void LoadMetadataForAOTAssemblies()
|
{
|
/// 注意,补充元数据是给AOT dll补充元数据,而不是给热更新dll补充元数据。
|
/// 热更新dll不缺元数据,不需要补充,如果调用LoadMetadataForAOTAssembly会返回错误
|
///
|
HomologousImageMode mode = HomologousImageMode.SuperSet;
|
foreach (var aotDllName in AOTMetaAssemblyFiles)
|
{
|
if (aotDllName == "Main.dll.bytes")
|
continue;
|
// 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码
|
LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(ReadBytesFromStreamingAssets(aotDllName), mode);
|
Debug.Log($"LoadMetadataForAOTAssembly:{aotDllName}. mode:{mode} ret:{err}");
|
}
|
}
|
|
public static byte[] ReadBytesFromStreamingAssets(string dllName)
|
{
|
return s_assetDatas[dllName];
|
}
|
|
private void StartGame()
|
{
|
#if !UNITY_EDITOR
|
LoadMetadataForAOTAssemblies();
|
_hotUpdateAss = Assembly.Load(ReadBytesFromStreamingAssets("Main.dll.bytes"));
|
s_assetDatas = null;
|
#else
|
if (_hotUpdateAss == null)
|
_hotUpdateAss = System.AppDomain.CurrentDomain.GetAssemblies().First(a => a.GetName().Name == "Main");
|
#endif
|
LocalResManager.step = LocalResManager.LoadDllStep.None;
|
// m_UICanvas.gameObject.SetActive(false);
|
DestroySingleton();
|
Type type = _hotUpdateAss.GetType("LaunchInHot").BaseType;
|
|
var getInstance = type.GetMethod("get_Instance", BindingFlags.Public | BindingFlags.Static);
|
if (getInstance != null)
|
{
|
getInstance.Invoke(null, null);
|
}
|
else
|
{
|
Debug.LogError("无法找到get_Instance方法");
|
}
|
|
Debug.Log("进入游戏流程");
|
}
|
|
private void DestroySingleton()
|
{
|
if (LocalResManager.IsValid())
|
{
|
LocalResManager.Destroy();
|
}
|
if (DownloadMgr.IsValid())
|
{
|
Destroy(DownloadMgr.Instance);
|
}
|
if (LogicEngine.IsValid())
|
{
|
Destroy(LogicEngine.Instance);
|
}
|
if (HttpRequest.IsValid())
|
{
|
Destroy(HttpRequest.Instance);
|
}
|
if (DownLoadAndDiscompressTask.IsValid())
|
{
|
DownLoadAndDiscompressTask.Destroy();
|
}
|
|
if (null != launchExWin)
|
{
|
Destroy(launchExWin);
|
launchExWin = null;
|
}
|
|
stop = true;
|
}
|
|
bool stop = false;
|
|
void Update()
|
{
|
if (stop)
|
return;
|
if (LocalResManager.step == LocalResManager.LoadDllStep.None || LocalResManager.step == LocalResManager.LoadDllStep.Wait)
|
return;
|
else if (LocalResManager.step == LocalResManager.LoadDllStep.RequestVersion)
|
{
|
LocalResManager.step = LocalResManager.LoadDllStep.Wait;
|
LocalResManager.Instance.RequestVersionCheck();
|
}
|
else if (LocalResManager.step == LocalResManager.LoadDllStep.PrepareDownLoad)
|
{
|
LocalResManager.step = LocalResManager.LoadDllStep.Wait;
|
//下载前准备,读表判断是否需要多语言不同下载路径
|
PrepareDownLoad();
|
}
|
else if (LocalResManager.step == LocalResManager.LoadDllStep.DownLoad)
|
{
|
LocalResManager.step = LocalResManager.LoadDllStep.Wait;
|
BeginDownload();
|
}
|
else if (LocalResManager.step == LocalResManager.LoadDllStep.ReadBytes)
|
{
|
LocalResManager.step = LocalResManager.LoadDllStep.Wait;
|
ReadDllBytes(this.StartGame);
|
}
|
//else if (LocalResManager.step == LocalResManager.LoadDllStep.Completed)
|
//{
|
// LocalResManager.step = LocalResManager.LoadDllStep.None;
|
// m_UICanvas.gameObject.SetActive(false);
|
// DestroySingleton();
|
//}
|
}
|
|
|
private string GetWebRequestPath(string asset)
|
{
|
var path = LocalResManager.Instance.GetAssetFilePath(string.Concat(LocalResManager.bytesFolderName, asset));
|
|
if (!path.Contains("file:"))
|
{
|
//ExternalStorePath 路径需要添加
|
path = "file://" + path;
|
}
|
return path;
|
}
|
|
private async void ReadDllBytes(Action callback)
|
{
|
foreach (var assetVersion in LocalResManager.Instance.assetVersions.Values)
|
{
|
if (assetVersion.localValid)
|
{
|
AOTMetaAssemblyFiles.Add(string.Concat(assetVersion.fileName, assetVersion.extersion));
|
}
|
else
|
{
|
Debug.LogErrorFormat("文件无效 {0}", assetVersion.fileName);
|
}
|
}
|
|
foreach (var asset in AOTMetaAssemblyFiles)
|
{
|
string dllPath = GetWebRequestPath(asset);
|
Debug.Log($"dllPath:{dllPath}");
|
UnityWebRequest www = UnityWebRequest.Get(dllPath);
|
await www.SendWebRequest();
|
|
#if UNITY_2020_1_OR_NEWER
|
if (www.result != UnityWebRequest.Result.Success)
|
{
|
Debug.Log(www.error);
|
}
|
#else
|
if (www.isHttpError || www.isNetworkError)
|
{
|
Debug.Log(www.error);
|
}
|
#endif
|
else
|
{
|
// 特殊处理
|
byte[] assetData;
|
if (asset == "Main.dll.bytes")
|
{
|
assetData = new byte[www.downloadHandler.data.Length - 3];
|
Array.Copy(www.downloadHandler.data, 3, assetData, 0, assetData.Length);
|
}
|
else
|
{
|
assetData = www.downloadHandler.data;
|
}
|
|
Debug.Log($"dll:{asset} size:{assetData.Length}");
|
s_assetDatas[asset] = assetData;
|
}
|
}
|
|
callback?.Invoke();
|
}
|
|
private void PrepareDownLoad()
|
{
|
if (LocalResManager.downLoadCount > 3)
|
{
|
LocalResManager.step = LocalResManager.LoadDllStep.None;
|
stop = true;
|
HttpBehaviour.ConnectAllTimes = 9999;
|
return;
|
}
|
|
LocalResManager.Instance.RequestLogicBytes();
|
}
|
|
private void BeginDownload()
|
{
|
List<AssetVersion> priorDownLoadAssetVersions = new List<AssetVersion>();
|
foreach (var assetVersion in LocalResManager.Instance.assetVersions.Values)
|
{
|
AssetVersion localAssetVersion = null;
|
LocalResManager.Instance.localAssetVersions.TryGetValue(assetVersion.relativePath, out localAssetVersion);
|
if (!assetVersion.CheckLocalFileValid(localAssetVersion))
|
{
|
priorDownLoadAssetVersions.Add(assetVersion);
|
assetVersion.localValid = false;
|
}
|
else
|
{
|
assetVersion.localValid = true;
|
}
|
}
|
|
Debug.LogFormat("需要下载的文件数量:{0}", priorDownLoadAssetVersions.Count);
|
if (priorDownLoadAssetVersions.Count == 0)
|
{
|
DownloadComplete();
|
return;
|
}
|
var targetDirectory = LocalResManager.Instance.ExternalStorePath;
|
if (!Directory.Exists(targetDirectory))
|
{
|
Directory.CreateDirectory(targetDirectory);
|
}
|
|
DownLoadAndDiscompressTask.Instance.Prepare(priorDownLoadAssetVersions, DownloadComplete);
|
}
|
|
void DownloadComplete()
|
{
|
LocalResManager.step = LocalResManager.LoadDllStep.ReadBytes;
|
}
|
}
|
|