mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-14 16:51:28 +00:00
升级HybridCLR 1.1.20
升级HybridCLR 1.1.20
This commit is contained in:
@@ -72,7 +72,7 @@ namespace TEngineCore.Editor
|
||||
/// <summary>
|
||||
/// 文件过滤
|
||||
/// </summary>
|
||||
private string[] fileExcludeFilter = new[] { ".cs", ".meta", ".dll", ".DS_Store", ".unity" };
|
||||
private string[] fileExcludeFilter = new[] { ".cs", ".meta", ".dll", ".DS_Store"/*, ".unity" */};
|
||||
|
||||
/// <summary>
|
||||
/// 资源环信息初始化
|
||||
|
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using TEngine;
|
||||
using TEngine.Editor;
|
||||
using TEngine.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using Object = UnityEngine.Object;
|
||||
using Type = System.Type;
|
||||
|
||||
namespace TEngineCore.Editor
|
||||
{
|
||||
@@ -222,7 +224,7 @@ namespace TEngineCore.Editor
|
||||
#endregion
|
||||
|
||||
#region 打包按钮
|
||||
[BuilderEditor("Copy And Encrpt DLL", ContentType.Button, ",CB:CopyDLL,FlowA:disPlayType:1")]
|
||||
[BuilderEditor("Generate DLL", ContentType.Button, ",CB:GenerateDLL,FlowA:disPlayType:1")]
|
||||
private int copydll;
|
||||
|
||||
[BuilderEditor("Build AssetBundle", ContentType.Button, ",CB:BuildAssetBundle,FlowA:disPlayType:1")]
|
||||
@@ -649,6 +651,24 @@ namespace TEngineCore.Editor
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateDLL(string args)
|
||||
{
|
||||
if (EditorApplication.isCompiling)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Build AssetBundle", "请等待编译完成", "ok");
|
||||
return;
|
||||
}
|
||||
|
||||
ApplyArgs("");
|
||||
|
||||
BuildAssetsCommand.BuildAndCopyABAOTHotUpdateDlls();
|
||||
|
||||
TLogger.LogInfoSuccessd("1.生成DLL的bytes成功");
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
private void CopyDLL(string args)
|
||||
{
|
||||
|
8
Assets/TEngine/Scripts/Editor/HybridCLR.meta
Normal file
8
Assets/TEngine/Scripts/Editor/HybridCLR.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 027adf2a5b5352a498cfa2ad92dda120
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
147
Assets/TEngine/Scripts/Editor/HybridCLR/BuildAssetsCommand.cs
Normal file
147
Assets/TEngine/Scripts/Editor/HybridCLR/BuildAssetsCommand.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using HybridCLR.Editor.Commands;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using HybridCLR.Editor;
|
||||
using TEngine.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
public static class BuildAssetsCommand
|
||||
{
|
||||
public static string HybridCLRBuildCacheDir => Application.dataPath + "/HybridCLRBuildCache";
|
||||
|
||||
public static string AssetBundleOutputDir => $"{HybridCLRBuildCacheDir}/AssetBundleOutput";
|
||||
|
||||
public static string AssetBundleSourceDataTempDir => $"{HybridCLRBuildCacheDir}/AssetBundleSourceData";
|
||||
|
||||
|
||||
public static string GetAssetBundleOutputDirByTarget(BuildTarget target)
|
||||
{
|
||||
return $"{AssetBundleOutputDir}/{target}";
|
||||
}
|
||||
|
||||
public static string GetAssetBundleTempDirByTarget(BuildTarget target)
|
||||
{
|
||||
return $"{AssetBundleSourceDataTempDir}/{target}";
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
List<AssetBundleBuild> abs = new List<AssetBundleBuild>();
|
||||
|
||||
{
|
||||
var prefabAssets = new List<string>();
|
||||
string testPrefab = $"{Application.dataPath}/Prefabs/HotUpdatePrefab.prefab";
|
||||
prefabAssets.Add(testPrefab);
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
|
||||
abs.Add(new AssetBundleBuild
|
||||
{
|
||||
assetBundleName = "prefabs",
|
||||
assetNames = prefabAssets.Select(s => ToRelativeAssetPath(s)).ToArray(),
|
||||
});
|
||||
}
|
||||
|
||||
BuildPipeline.BuildAssetBundles(outputDir, abs.ToArray(), BuildAssetBundleOptions.None, target);
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
|
||||
}
|
||||
|
||||
public static void BuildAssetBundleByTarget(BuildTarget target)
|
||||
{
|
||||
BuildAssetBundles(GetAssetBundleTempDirByTarget(target), GetAssetBundleOutputDirByTarget(target), target);
|
||||
}
|
||||
|
||||
[MenuItem("HybridCLR/Build/BuildAssetsAndCopyToStreamingAssets")]
|
||||
public static void BuildAndCopyABAOTHotUpdateDlls()
|
||||
{
|
||||
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
|
||||
BuildAssetBundleByTarget(target);
|
||||
CompileDllCommand.CompileDll(target);
|
||||
CopyABAOTHotUpdateDlls(target);
|
||||
}
|
||||
|
||||
public static void CopyABAOTHotUpdateDlls(BuildTarget target)
|
||||
{
|
||||
CopyAssetBundlesToStreamingAssets(target);
|
||||
CopyAOTAssembliesToStreamingAssets();
|
||||
CopyHotUpdateAssembliesToStreamingAssets();
|
||||
}
|
||||
|
||||
|
||||
//[MenuItem("HybridCLR/Build/BuildAssetbundle")]
|
||||
public static void BuildSceneAssetBundleActiveBuildTargetExcludeAOT()
|
||||
{
|
||||
BuildAssetBundleByTarget(EditorUserBuildSettings.activeBuildTarget);
|
||||
}
|
||||
|
||||
public static void CopyAOTAssembliesToStreamingAssets()
|
||||
{
|
||||
var target = EditorUserBuildSettings.activeBuildTarget;
|
||||
string aotAssembliesSrcDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
|
||||
string aotAssembliesDstDir = Application.streamingAssetsPath+"/../TResources/DLL/";
|
||||
|
||||
foreach (var dll in ProcedureCodeInit.AOTMetaAssemblyNames)
|
||||
{
|
||||
string srcDllPath = $"{aotAssembliesSrcDir}/{dll}";
|
||||
if (!File.Exists(srcDllPath))
|
||||
{
|
||||
Debug.LogError($"ab中添加AOT补充元数据dll:{srcDllPath} 时发生错误,文件不存在。裁剪后的AOT dll在BuildPlayer时才能生成,因此需要你先构建一次游戏App后再打包。");
|
||||
continue;
|
||||
}
|
||||
string dllBytesPath = $"{aotAssembliesDstDir}/{dll}.bytes";
|
||||
File.Copy(srcDllPath, dllBytesPath, true);
|
||||
Debug.Log($"[CopyAOTAssembliesToStreamingAssets] copy AOT dll {srcDllPath} -> {dllBytesPath}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void CopyHotUpdateAssembliesToStreamingAssets()
|
||||
{
|
||||
var target = EditorUserBuildSettings.activeBuildTarget;
|
||||
|
||||
string hotfixDllSrcDir = SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target);
|
||||
string hotfixAssembliesDstDir = Application.streamingAssetsPath+"/../TResources/DLL/";
|
||||
foreach (var dll in SettingsUtil.HotUpdateAssemblyFilesExcludePreserved)
|
||||
{
|
||||
string dllPath = $"{hotfixDllSrcDir}/{dll}";
|
||||
string dllBytesPath = $"{hotfixAssembliesDstDir}/{dll}.bytes";
|
||||
File.Copy(dllPath, dllBytesPath, true);
|
||||
Debug.Log($"[CopyHotUpdateAssembliesToStreamingAssets] copy hotfix dll {dllPath} -> {dllBytesPath}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void CopyAssetBundlesToStreamingAssets(BuildTarget target)
|
||||
{
|
||||
string streamingAssetPathDst = Application.streamingAssetsPath+"/../TResources/DLL/";
|
||||
Directory.CreateDirectory(streamingAssetPathDst);
|
||||
string outputDir = GetAssetBundleOutputDirByTarget(target);
|
||||
var abs = new string[] { "prefabs" };
|
||||
foreach (var ab in abs)
|
||||
{
|
||||
string srcAb = ToRelativeAssetPath($"{outputDir}/{ab}");
|
||||
string dstAb = ToRelativeAssetPath($"{streamingAssetPathDst}/{ab}");
|
||||
Debug.Log($"[CopyAssetBundlesToStreamingAssets] copy assetbundle {srcAb} -> {dstAb}");
|
||||
AssetDatabase.CopyAsset( srcAb, dstAb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1a8357532218e6f49a9bb9401382d6d4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,68 @@
|
||||
using HybridCLR.Editor.Commands;
|
||||
using HybridCLR.Editor.Installer;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using HybridCLR.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine.Editor
|
||||
{
|
||||
public class BuildPlayerCommand
|
||||
{
|
||||
public static void CopyAssets(string outputDir)
|
||||
{
|
||||
Directory.CreateDirectory(outputDir);
|
||||
|
||||
foreach(var srcFile in Directory.GetFiles(Application.streamingAssetsPath))
|
||||
{
|
||||
string dstFile = $"{outputDir}/{Path.GetFileName(srcFile)}";
|
||||
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 = $"{SettingsUtil.ProjectDir}/Release-Win64";
|
||||
|
||||
var buildOptions = BuildOptions.CompressWithLz4;
|
||||
|
||||
string location = $"{outputPath}/HybridCLRTrial.exe";
|
||||
|
||||
PrebuildCommand.GenerateAll();
|
||||
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("====> 复制热更新资源和代码");
|
||||
BuildAssetsCommand.BuildAndCopyABAOTHotUpdateDlls();
|
||||
BashUtil.CopyDir(Application.streamingAssetsPath, $"{outputPath}/HybridCLRTrial_Data/StreamingAssets", true);
|
||||
#if UNITY_EDITOR
|
||||
Application.OpenURL($"file:///{location}");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7796c8df856ac4a4a9d644329c1f0958
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -1,7 +1,10 @@
|
||||
{
|
||||
"name": "TEngine.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:f4ecd6f7bd8993043b6cec60dd0cf2b2"
|
||||
"GUID:f4ecd6f7bd8993043b6cec60dd0cf2b2",
|
||||
"GUID:13ba8ce62aa80c74598530029cb2d649",
|
||||
"GUID:2373f786d14518f44b0f475db77ba4de"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
|
@@ -13,6 +13,7 @@ namespace TEngine.Editor
|
||||
{
|
||||
"TEngine.Runtime",
|
||||
"Assembly-CSharp",
|
||||
"HotFix",
|
||||
};
|
||||
|
||||
private static readonly string[] RuntimeOrEditorAssemblyNames =
|
||||
@@ -21,6 +22,7 @@ namespace TEngine.Editor
|
||||
"Assembly-CSharp",
|
||||
"TEngine.Editor",
|
||||
"Assembly-CSharp-Editor",
|
||||
"HotFix",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
3
Assets/TEngine/Scripts/Runtime/Core/LoadJob.meta
Normal file
3
Assets/TEngine/Scripts/Runtime/Core/LoadJob.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16c2d564e2614539ae1ce24761808e86
|
||||
timeCreated: 1675252193
|
26
Assets/TEngine/Scripts/Runtime/Core/LoadJob/LoadJob.cs
Normal file
26
Assets/TEngine/Scripts/Runtime/Core/LoadJob/LoadJob.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载任务抽象基类。
|
||||
/// </summary>
|
||||
public abstract class LoadJob
|
||||
{
|
||||
protected bool _isDone;
|
||||
|
||||
/// <summary>
|
||||
/// 任务是否完成,LoadJobManager会根据该标志判断是否加载下一个任务。
|
||||
/// </summary>
|
||||
public bool IsDone => _isDone;
|
||||
|
||||
/// <summary>
|
||||
/// 开始任务执行,一次性初始化工作可放在其中。
|
||||
/// </summary>
|
||||
public abstract void Start();
|
||||
|
||||
/// <summary>
|
||||
/// 任务处理。
|
||||
/// </summary>
|
||||
/// <returns>执行进入(0 - 1)。</returns>
|
||||
public abstract float Process();
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6604789763448b7afa669c2cd352cfc
|
||||
timeCreated: 1675252202
|
105
Assets/TEngine/Scripts/Runtime/Core/LoadJob/LoadJobManager.cs
Normal file
105
Assets/TEngine/Scripts/Runtime/Core/LoadJob/LoadJobManager.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载器,处理场景加载、对象预生成等需要在加载期处理的事务.
|
||||
/// </summary>
|
||||
public class LoadJobManager : UnitySingleton<LoadJobManager>
|
||||
{
|
||||
System.Action<float> _progressCallback;
|
||||
System.Action _onFinishCallback;
|
||||
Queue<LoadJob> _jobQueue = new Queue<LoadJob>();
|
||||
LoadJob _curJob = null;
|
||||
int _doneJobCount;
|
||||
int _jobCount;
|
||||
float _progress;
|
||||
|
||||
/// <summary>
|
||||
/// 添加任务.
|
||||
/// </summary>
|
||||
/// <param name="job"></param>
|
||||
public void AddJob(LoadJob job)
|
||||
{
|
||||
_jobQueue.Enqueue(job);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动执行任务队列.
|
||||
/// </summary>
|
||||
/// <param name="progressCallback">处理进度回调,参数为0-1进度</param>
|
||||
/// <param name="onFinishCallback">完成回调。</param>
|
||||
public void Launch(System.Action<float> progressCallback, System.Action onFinishCallback)
|
||||
{
|
||||
_progress = 0f;
|
||||
_doneJobCount = 0;
|
||||
_jobCount = _jobQueue.Count;
|
||||
_progressCallback = progressCallback;
|
||||
_onFinishCallback = onFinishCallback;
|
||||
_curJob = _jobQueue.Dequeue();
|
||||
_curJob.Start();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_curJob != null)
|
||||
{
|
||||
_progress = (_doneJobCount + _curJob.Process()) / _jobCount;
|
||||
if (_curJob.IsDone)
|
||||
{
|
||||
if (_jobQueue.Count > 0)
|
||||
{
|
||||
_curJob = _jobQueue.Dequeue();
|
||||
_curJob.Start();
|
||||
}
|
||||
else
|
||||
_curJob = null;
|
||||
|
||||
++_doneJobCount;
|
||||
}
|
||||
|
||||
if (_progressCallback != null)
|
||||
_progressCallback(_progress);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingletonMgr.Release(gameObject);
|
||||
_progressCallback = null;
|
||||
|
||||
if (_onFinishCallback != null)
|
||||
_onFinishCallback();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步加载场景。
|
||||
/// </summary>
|
||||
/// <param name="sceneName">场景名称。</param>
|
||||
/// <param name="progressCallback">加载函数回调。</param>
|
||||
/// <param name="callback">加载完成回调。</param>
|
||||
/// <param name="mode">场景加载模式。</param>
|
||||
public void LoadSceneAsync(string sceneName, System.Action<float> progressCallback = null, System.Action callback = null, LoadSceneMode mode = LoadSceneMode.Single)
|
||||
{
|
||||
MonoUtility.StartCoroutine(LoadJobManager.Instance.LoadJobManagerLoadScene(sceneName, progressCallback, callback, mode));
|
||||
}
|
||||
|
||||
private IEnumerator LoadJobManagerLoadScene(string sceneName, System.Action<float> progressCallback = null, System.Action callback = null,
|
||||
LoadSceneMode mode = LoadSceneMode.Single)
|
||||
{
|
||||
bool isLoadEnd = false;
|
||||
Instance.AddJob(new SceneLoadJob(sceneName, LoadSceneMode.Single));
|
||||
Instance.Launch(progressCallback, () =>
|
||||
{
|
||||
callback?.Invoke();
|
||||
isLoadEnd = true;
|
||||
});
|
||||
yield return null;
|
||||
while (!isLoadEnd)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5bbbf8a8cdf4a1fb239ddbc8fd855f2
|
||||
timeCreated: 1675252202
|
56
Assets/TEngine/Scripts/Runtime/Core/LoadJob/SceneLoadJob.cs
Normal file
56
Assets/TEngine/Scripts/Runtime/Core/LoadJob/SceneLoadJob.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 场景加载任务
|
||||
/// </summary>
|
||||
public class SceneLoadJob : LoadJob
|
||||
{
|
||||
AsyncOperation _asyncOp;
|
||||
string _sceneName;
|
||||
LoadSceneMode _loadMode;
|
||||
|
||||
/// <summary>
|
||||
/// 构造方法
|
||||
/// </summary>
|
||||
/// <param name="sceneName">场景名</param>
|
||||
public SceneLoadJob(string sceneName, LoadSceneMode mode = LoadSceneMode.Single)
|
||||
{
|
||||
_sceneName = sceneName;
|
||||
_loadMode = mode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始执行加载任务,强制卸载未引用的AB资源,开始LoadScene
|
||||
/// </summary>
|
||||
public override void Start()
|
||||
{
|
||||
//经讨论对象池清理策略交由项目组控制更合理
|
||||
ResMgr.Instance.UnloadUnusedAssetBundle();
|
||||
_asyncOp = ResMgr.Instance.LoadScene(_sceneName, _loadMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理加载任务
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override float Process()
|
||||
{
|
||||
if (_asyncOp != null)
|
||||
{
|
||||
if (_asyncOp.isDone)
|
||||
{
|
||||
_isDone = true;
|
||||
|
||||
return 1f;
|
||||
}
|
||||
else
|
||||
return _asyncOp.progress / 0.9f;
|
||||
}
|
||||
else
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d14939b3184744598b90eebd67b4bf5f
|
||||
timeCreated: 1675252346
|
@@ -56,6 +56,7 @@ namespace TEngine.Runtime
|
||||
{
|
||||
assetPaths[j] = reader.ReadString();
|
||||
_assetPath2BundleDatas.Add(assetPaths[j], bundleName);
|
||||
Log.Error($"Init Ab {assetPaths[j]} bundleName {bundleName}");
|
||||
}
|
||||
depCount = reader.ReadInt32();
|
||||
if (!_bundleDatas.TryGetValue(bundleName, out assetBundleData))
|
||||
|
@@ -1,15 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
internal class SceneAssetData
|
||||
{
|
||||
public AssetData _assetData;
|
||||
public LoadSceneMode _loadSceneMode = LoadSceneMode.Single;
|
||||
}
|
||||
|
||||
internal class ResMgr : TSingleton<ResMgr>
|
||||
{
|
||||
AssetConfig _assetConfig = new AssetConfig();
|
||||
private Dictionary<ScriptableObject, AssetData> _scriptableObjects = new Dictionary<ScriptableObject, AssetData>();
|
||||
public ResMgr()
|
||||
{
|
||||
MonoUtility.AddUpdateListener(Update);
|
||||
_assetConfig.Load();
|
||||
}
|
||||
|
||||
@@ -27,6 +35,15 @@ namespace TEngine.Runtime
|
||||
_assetConfig.MaxUnloadNumPerFrame = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 资源更新重载。
|
||||
/// </summary>
|
||||
public void ReLoad()
|
||||
{
|
||||
_assetConfig.Unload();
|
||||
_assetConfig.Load();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载无用资源
|
||||
/// </summary>
|
||||
@@ -355,5 +372,131 @@ namespace TEngine.Runtime
|
||||
return $"{Application.dataPath}/TResources/{rawPath}";
|
||||
#endif
|
||||
}
|
||||
|
||||
#region Scene
|
||||
//已经加载好的场景
|
||||
private List<SceneAssetData> _loadedScenes = new List<SceneAssetData>();
|
||||
|
||||
//加载中的场景
|
||||
private List<SceneAssetData> _loadingScenes = new List<SceneAssetData>();
|
||||
|
||||
private List<SceneAssetData> _cachedDeleteFromLoadingScenes = new List<SceneAssetData>();
|
||||
/// <summary>
|
||||
/// 场景加载
|
||||
/// </summary>
|
||||
/// <param name="sceneName">场景名</param>
|
||||
/// /// <param name="mode">加载模式</param>
|
||||
/// <returns>异步操作对象</returns>
|
||||
/// <seealso>SceneLoader</seealso>提供了加载进度展示,也可以自定义包装来加载场景
|
||||
public AsyncOperation LoadScene(string sceneName, LoadSceneMode mode = LoadSceneMode.Single)
|
||||
{
|
||||
AssetData assetData = _assetConfig.GetSceneAsset(sceneName, mode);
|
||||
SceneAssetData sData = new SceneAssetData();
|
||||
sData._assetData = assetData;
|
||||
sData._loadSceneMode = mode;
|
||||
if(assetData != null)
|
||||
{
|
||||
_loadingScenes.Add(sData);
|
||||
assetData.AddRef();
|
||||
|
||||
return assetData.AsyncOp;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 场景是否已经加载过了
|
||||
/// </summary>
|
||||
/// <param name="sceneName"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsSceneLoaded(string sceneName)
|
||||
{
|
||||
foreach (SceneAssetData loadedScene in _loadedScenes)
|
||||
{
|
||||
if (loadedScene != null
|
||||
&& loadedScene._assetData != null
|
||||
&& !string.IsNullOrEmpty(loadedScene._assetData.Name)
|
||||
&& loadedScene._assetData.Name.Equals(sceneName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 场景是否在加载过程中
|
||||
/// </summary>
|
||||
/// <param name="sceneName"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsSceneLoading(string sceneName)
|
||||
{
|
||||
foreach (SceneAssetData loadingScene in _loadingScenes)
|
||||
{
|
||||
if (loadingScene._assetData != null
|
||||
&& !string.IsNullOrEmpty(loadingScene._assetData.Name)
|
||||
&& loadingScene._assetData.Name.Equals(sceneName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理掉已经加载的场景
|
||||
/// </summary>
|
||||
void UnloadLoadedScenes()
|
||||
{
|
||||
foreach (SceneAssetData loadedScene in _loadedScenes)
|
||||
{
|
||||
if (loadedScene != null && loadedScene._assetData != null)
|
||||
{
|
||||
loadedScene._assetData.DecRef(true);
|
||||
}
|
||||
}
|
||||
_loadedScenes.Clear();
|
||||
Resources.UnloadUnusedAssets();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 轮询资源。
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
_assetConfig.Update(Time.deltaTime);
|
||||
|
||||
foreach (SceneAssetData loadingScene in _loadingScenes)
|
||||
{
|
||||
if (loadingScene._assetData != null &&loadingScene._assetData.AsyncOp != null)
|
||||
{
|
||||
if (!loadingScene._assetData.AsyncOp.isDone)
|
||||
{
|
||||
if (loadingScene._assetData.AsyncOp.progress >= 0.9f)
|
||||
{
|
||||
if (loadingScene._loadSceneMode == LoadSceneMode.Single)
|
||||
{
|
||||
UnloadLoadedScenes();
|
||||
}
|
||||
// 激活新场景
|
||||
loadingScene._assetData.AsyncOp.allowSceneActivation = true;
|
||||
_cachedDeleteFromLoadingScenes.Add(loadingScene);
|
||||
_loadedScenes.Add(loadingScene);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//从Loading队列中删除掉加载完成的场景
|
||||
foreach (SceneAssetData deleteScene in _cachedDeleteFromLoadingScenes)
|
||||
{
|
||||
_loadingScenes.Remove(deleteScene);
|
||||
}
|
||||
_cachedDeleteFromLoadingScenes.Clear();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -64,9 +64,7 @@ namespace TEngine.Runtime
|
||||
if (configContent == string.Empty)
|
||||
{
|
||||
#if !UNITY_EDITOR
|
||||
#if RELEASE_BUILD || _DEVELOPMENT_BUILD_
|
||||
TLogger.LogError($"version config not find in InnerPath,please check it");
|
||||
#endif
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@@ -146,6 +144,10 @@ namespace TEngine.Runtime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_versionConfig.ResVersion))
|
||||
{
|
||||
return "0";
|
||||
}
|
||||
return _versionConfig.ResVersion;
|
||||
}
|
||||
set
|
||||
|
@@ -29,6 +29,7 @@
|
||||
{
|
||||
if (s_VersionHelper == null)
|
||||
{
|
||||
Log.Fatal("s_VersionHelper is null GameVersion");
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
@@ -45,6 +46,7 @@
|
||||
{
|
||||
if (s_VersionHelper == null)
|
||||
{
|
||||
Log.Fatal("s_VersionHelper is null InternalGameVersion");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
8
Assets/TEngine/Scripts/Runtime/GameProcedure.meta
Normal file
8
Assets/TEngine/Scripts/Runtime/GameProcedure.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39615847fdccd4b42a6be39d1d6824ad
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,350 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TEngine.Runtime.HotUpdate;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 流程加载器 - 检查版本更新
|
||||
/// </summary>
|
||||
public class ProcedureCheckVersion:ProcedureBase
|
||||
{
|
||||
private bool m_CheckVersionComplete = false;
|
||||
private bool m_NeedUpdateVersion = false;
|
||||
private OnlineVersionInfo m_VersionInfo = null;
|
||||
private UnityWebRequest m_UnityWebRequest;
|
||||
private UnityWebRequestAsyncOperation m_result;
|
||||
private int _curTryCount;
|
||||
private const int MaxTryCount = 3;
|
||||
|
||||
private void PreLoadHotUpdate()
|
||||
{
|
||||
//热更新阶段文本初始化
|
||||
LoadText.Instance.InitConfigData(null);
|
||||
//热更新UI初始化
|
||||
UILoadMgr.Initialize();
|
||||
|
||||
UILoadMgr.Show(UIDefine.UILoadUpdate);
|
||||
}
|
||||
|
||||
protected internal override void OnEnter(IFsm<IProcedureManager> procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
m_CheckVersionComplete = false;
|
||||
m_NeedUpdateVersion = false;
|
||||
m_VersionInfo = null;
|
||||
Log.Warning("On Enter ProcedureCheckVersion");
|
||||
PreLoadHotUpdate();
|
||||
|
||||
RequestVersion();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求热更数据
|
||||
/// </summary>
|
||||
private void RequestVersion()
|
||||
{
|
||||
Log.Warning("On RequestVersion");
|
||||
_curTryCount++;
|
||||
|
||||
if (_curTryCount > MaxTryCount)
|
||||
{
|
||||
LoaderUtilities.ShowMessageBox(LoadText.Instance.Label_Net_Error, MessageShowType.TwoButton,
|
||||
LoadStyle.StyleEnum.Style_Retry,
|
||||
() => {
|
||||
_curTryCount = 0;
|
||||
RequestVersion();
|
||||
}, () =>
|
||||
{
|
||||
Application.Quit();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var checkVersionUrl = Utility.Text.Format(HotUpdateMgr.Instance.BuildInfo.CheckVersionUrl,
|
||||
GetPlatformPath());
|
||||
|
||||
UILoadMgr.Show(UIDefine.UILoadUpdate, string.Format(LoadText.Instance.Label_Load_Checking, _curTryCount));
|
||||
if (string.IsNullOrEmpty(checkVersionUrl))
|
||||
{
|
||||
TLogger.LogError("LoadMgr.RequestVersion, remote url is empty or null");
|
||||
LoaderUtilities.ShowMessageBox(LoadText.Instance.Label_RemoteUrlisNull, MessageShowType.OneButton,
|
||||
LoadStyle.StyleEnum.Style_QuitApp,
|
||||
Application.Quit);
|
||||
return;
|
||||
}
|
||||
Log.Warning("LoadMgr.RequestVersion, proxy:" + checkVersionUrl);
|
||||
|
||||
Log.Warning($"Check Version Url=>{checkVersionUrl}");
|
||||
|
||||
m_UnityWebRequest = UnityWebRequest.Get(checkVersionUrl);
|
||||
|
||||
m_result = m_UnityWebRequest.SendWebRequest();
|
||||
}
|
||||
|
||||
private LoadData GenLoadData()
|
||||
{
|
||||
var onlineResListUrl = m_VersionInfo.UpdatePrefixUri + "/" + m_VersionInfo.ResourceVersion +"/";
|
||||
Log.Warning(onlineResListUrl);
|
||||
string resListStr = string.Empty;
|
||||
try
|
||||
{
|
||||
resListStr = LoaderUtilities.HttpGet(onlineResListUrl + "Md5List.json");
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LoaderUtilities.ShowMessageBox(LoadText.Instance.Label_Net_Error+e.Message, MessageShowType.TwoButton,
|
||||
LoadStyle.StyleEnum.Style_Retry,
|
||||
() => {
|
||||
RequestVersion();
|
||||
}, () =>
|
||||
{
|
||||
Application.Quit();
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
var resDic = (Dictionary<string, object>)MiniJSON.Json.Deserialize(resListStr);
|
||||
List<object> resList = (List<object>)resDic["_target"];
|
||||
var data = new LoadData();
|
||||
|
||||
data.Type = UpdateType.ResourceUpdate;
|
||||
data.Style = UpdateStyle.Optional;
|
||||
data.Notice = UpdateNotice.Notice;
|
||||
data.Type = m_VersionInfo.UpdateType;
|
||||
|
||||
if (GameConfig.Instance.ResId == m_VersionInfo.ResourceVersion.ToString())
|
||||
{
|
||||
TLogger.LogInfo("GameConfig.Instance.ResId 匹配,无需更新");
|
||||
|
||||
UILoadMgr.Show(UIDefine.UILoadUpdate, "校验资源版中...");
|
||||
|
||||
LoaderUtilities.DelayFun((() =>
|
||||
{
|
||||
UILoadMgr.Show(UIDefine.UILoadUpdate, "资源版校验完成!!!");
|
||||
}), new WaitForSeconds(1f));
|
||||
|
||||
LoaderUtilities.DelayFun((() =>
|
||||
{
|
||||
UILoadMgr.HideAll();
|
||||
}),new WaitForSeconds(2f));
|
||||
|
||||
data.Type = UpdateType.None;
|
||||
}
|
||||
if (data.Type != UpdateType.PackageUpdate)
|
||||
{
|
||||
data.Style = m_VersionInfo.UpdateStyle;
|
||||
data.Notice = m_VersionInfo.UpdateNotice;
|
||||
}
|
||||
|
||||
data.List = new List<LoadResource>();
|
||||
data.All = new List<LoadResource>();
|
||||
|
||||
if (resList != null)
|
||||
{
|
||||
for (int i = 0; i < resList.Count; i++)
|
||||
{
|
||||
var item = (Dictionary<string, object>)resList[i];
|
||||
string fileName = item["fileName"].ToString();
|
||||
var itemTemp = new LoadResource
|
||||
{
|
||||
RemoteUrl = onlineResListUrl + fileName,
|
||||
Md5 = item["md5"].ToString(),
|
||||
Size = (long)item["fileSize"],
|
||||
Url = fileName,
|
||||
};
|
||||
data.List.Add(itemTemp);
|
||||
data.All.Add(itemTemp);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
protected internal override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
if (m_result == null || !m_result.isDone)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckWebRequest();
|
||||
}
|
||||
|
||||
if (!m_CheckVersionComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_NeedUpdateVersion)
|
||||
{
|
||||
var data = GenLoadData();
|
||||
if (data == null)
|
||||
{
|
||||
m_UnityWebRequest.Dispose();
|
||||
m_result = null;
|
||||
m_UnityWebRequest = null;
|
||||
return;
|
||||
}
|
||||
procedureOwner.SetData<LoadData>("LoadData", data);
|
||||
procedureOwner.SetData<OnlineVersionInfo>("OnlineVersionInfo", m_VersionInfo);
|
||||
ChangeState<ProcedureResourcesUpdate>(procedureOwner);
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = GenLoadData();
|
||||
if (data == null)
|
||||
{
|
||||
m_UnityWebRequest.Dispose();
|
||||
m_result = null;
|
||||
m_UnityWebRequest = null;
|
||||
return;
|
||||
}
|
||||
procedureOwner.SetData<LoadData>("LoadData", data);
|
||||
procedureOwner.SetData<OnlineVersionInfo>("OnlineVersionInfo", m_VersionInfo);
|
||||
ChangeState<ProcedureCodeInit>(procedureOwner);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测版本检查网络请求
|
||||
/// </summary>
|
||||
private void CheckWebRequest()
|
||||
{
|
||||
if (m_result == null || !m_result.isDone)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_UnityWebRequest != null && m_UnityWebRequest.isDone)
|
||||
{
|
||||
if (m_UnityWebRequest.error == null)
|
||||
{
|
||||
byte[] versionInfoBytes = m_UnityWebRequest.downloadHandler.data;
|
||||
string versionInfoString = Utility.Converter.GetString(versionInfoBytes);
|
||||
m_VersionInfo = Utility.Json.ToObject<OnlineVersionInfo>(versionInfoString);
|
||||
Log.Error("m_VersionInfo.ToString()" + m_VersionInfo.ToString());
|
||||
if (m_VersionInfo == null)
|
||||
{
|
||||
Log.Fatal("Parse VersionInfo failure.");
|
||||
return;
|
||||
}
|
||||
Log.Error(" m_VersionInfo.GameVersion" + m_VersionInfo.GameVersion);
|
||||
Log.Error(" m_VersionInfo.InternalResourceVersion" + m_VersionInfo.InternalResourceVersion);
|
||||
Log.Error(" m_VersionInfo.GameVersion" + Version.GameVersion);
|
||||
Log.Error(" m_VersionInfo.InternalGameVersion" + Version.InternalGameVersion);
|
||||
Log.Error("Latest game version is '{0} ({1})', local game version is '{2} ({3})'.",
|
||||
m_VersionInfo.GameVersion,
|
||||
m_VersionInfo.InternalResourceVersion.ToString(),
|
||||
Version.GameVersion,
|
||||
Version.InternalGameVersion.ToString());
|
||||
|
||||
Log.Warning("GameConfig.Instance.ResId " + GameConfig.Instance.ResId);
|
||||
Log.Warning("Version.ResourceVersion " + m_VersionInfo.ResourceVersion);
|
||||
|
||||
if (string.Equals(GameConfig.Instance.ResId, m_VersionInfo.ResourceVersion.ToString()))
|
||||
{
|
||||
m_NeedUpdateVersion = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_NeedUpdateVersion = true;
|
||||
}
|
||||
m_CheckVersionComplete = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Fatal($"Check version failure :{m_UnityWebRequest.error}");
|
||||
m_UnityWebRequest.Dispose();
|
||||
m_result = null;
|
||||
m_UnityWebRequest = null;
|
||||
|
||||
LoaderUtilities.DelayFun(RequestVersion, new WaitForSeconds(1f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 跳转到APP下载路径
|
||||
/// </summary>
|
||||
/// <param name="userData"></param>
|
||||
private void GotoUpdateApp(object userData)
|
||||
{
|
||||
string url = null;
|
||||
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
|
||||
url = HotUpdateMgr.Instance.BuildInfo.WindowsAppUrl;
|
||||
#elif UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
|
||||
url = HotUpdateMgr.Instance.BuildInfo.MacOSAppUrl;
|
||||
#elif UNITY_IOS
|
||||
url = HotUpdateMgr.Instance.BuildInfo.IOSAppUrl;
|
||||
#elif UNITY_ANDROID
|
||||
url = HotUpdateMgr.Instance.BuildInfo.AndroidAppUrl;
|
||||
#endif
|
||||
if (!string.IsNullOrEmpty(url))
|
||||
{
|
||||
Application.OpenURL(url);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取不同平台的资源检测路径
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private string GetPlatformPath()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
#if UNITY_STANDALONE_WIN
|
||||
return "Windows";
|
||||
#elif UNITY_EDITOR_OSX
|
||||
return "IOS";
|
||||
#elif UNITY_IOS
|
||||
return "IOS";
|
||||
#elif UNITY_ANDROID
|
||||
return "Android";
|
||||
#else
|
||||
return "Unknow"
|
||||
#endif
|
||||
#else
|
||||
// 这里和 PlatformUtility.GetPlatformPath() 对应。由 Unity.RuntimePlatform 得到 平台标识符
|
||||
switch (Application.platform)
|
||||
{
|
||||
case RuntimePlatform.WindowsEditor:
|
||||
case RuntimePlatform.WindowsPlayer:
|
||||
return "Windows";
|
||||
|
||||
case RuntimePlatform.OSXEditor:
|
||||
case RuntimePlatform.OSXPlayer:
|
||||
return "MacOS";
|
||||
|
||||
case RuntimePlatform.IPhonePlayer:
|
||||
return "IOS";
|
||||
|
||||
case RuntimePlatform.Android:
|
||||
return "Android";
|
||||
|
||||
case RuntimePlatform.WSAPlayerX64:
|
||||
case RuntimePlatform.WSAPlayerX86:
|
||||
case RuntimePlatform.WSAPlayerARM:
|
||||
return "WSA";
|
||||
|
||||
case RuntimePlatform.WebGLPlayer:
|
||||
return "WebGL";
|
||||
|
||||
case RuntimePlatform.LinuxEditor:
|
||||
case RuntimePlatform.LinuxPlayer:
|
||||
return "Linux";
|
||||
|
||||
default:
|
||||
Log.Fatal(Application.platform.ToString());
|
||||
throw new System.NotSupportedException(Utility.Text.Format("Platform '{0}' is not supported.", Application.platform));
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4174e49b2cd17241878ed96673b9785
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using HybridCLR;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 流程加载器 - 代码初始化
|
||||
/// </summary>
|
||||
public class ProcedureCodeInit : ProcedureBase
|
||||
{
|
||||
|
||||
public static List<string> AOTMetaAssemblyNames { get; } = new List<string>()
|
||||
{
|
||||
"mscorlib.dll",
|
||||
"System.dll",
|
||||
"System.Core.dll",
|
||||
"HotFix.dll",
|
||||
};
|
||||
|
||||
private static Dictionary<string, byte[]> _AssetDatas = new Dictionary<string, byte[]>();
|
||||
|
||||
public static byte[] GetAssetData(string dllName)
|
||||
{
|
||||
return _AssetDatas[dllName];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为aot assembly加载原始metadata, 这个代码放aot或者热更新都行。
|
||||
/// 一旦加载后,如果AOT泛型函数对应native实现不存在,则自动替换为解释模式执行
|
||||
/// </summary>
|
||||
private static void LoadMetadataForAOTAssemblies()
|
||||
{
|
||||
// 可以加载任意aot assembly的对应的dll。但要求dll必须与unity build过程中生成的裁剪后的dll一致,而不能直接使用原始dll。
|
||||
// 我们在BuildProcessors里添加了处理代码,这些裁剪后的dll在打包时自动被复制到 {项目目录}/HybridCLRData/AssembliesPostIl2CppStrip/{Target} 目录。
|
||||
|
||||
// 注意,补充元数据是给AOT dll补充元数据,而不是给热更新dll补充元数据。
|
||||
// 热更新dll不缺元数据,不需要补充,如果调用LoadMetadataForAOTAssembly会返回错误
|
||||
HomologousImageMode mode = HomologousImageMode.SuperSet;
|
||||
|
||||
foreach (var aotDllName in AOTMetaAssemblyNames)
|
||||
{
|
||||
var path = "DLL/" + aotDllName + ".bytes";
|
||||
Log.Warning(path);
|
||||
byte[] dllBytes = TResources.Load<TextAsset>(path)?.bytes;
|
||||
if (dllBytes == null)
|
||||
{
|
||||
Log.Fatal($"{aotDllName} is null");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
_AssetDatas[aotDllName+".bytes"] = dllBytes;
|
||||
}
|
||||
|
||||
// 加载assembly对应的dll,会自动为它hook。一旦aot泛型函数的native函数不存在,用解释器版本代码
|
||||
LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes,mode);
|
||||
Log.Info($"LoadMetadataForAOTAssembly:{aotDllName}. ret:{err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否需要加载热更新DLL
|
||||
/// </summary>
|
||||
public bool NeedLoadDll => ResourceComponent.Instance.ResourceMode == ResourceMode.Updatable || ResourceComponent.Instance.ResourceMode == ResourceMode.UpdatableWhilePlaying;
|
||||
|
||||
private IFsm<IProcedureManager> m_procedureOwner;
|
||||
|
||||
protected internal override void OnEnter(IFsm<IProcedureManager> procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
LoadJobManager.Instance.LoadSceneAsync("L2Scene");
|
||||
|
||||
m_procedureOwner = procedureOwner;
|
||||
|
||||
if (!NeedLoadDll)
|
||||
{
|
||||
ChangeState<ProcedureStartGame>(procedureOwner);
|
||||
return;
|
||||
}
|
||||
|
||||
LoadMetadataForAOTAssemblies();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
Assembly hotfixAssembly = System.AppDomain.CurrentDomain.GetAssemblies().First(assembly => assembly.GetName().Name == "HotFix");
|
||||
StartHotfixEntry(hotfixAssembly);
|
||||
#else
|
||||
try
|
||||
{
|
||||
Assembly hotfixAssembly =System.Reflection.Assembly.Load(GetAssetData("HotFix.dll.bytes"));
|
||||
StartHotfixEntry(hotfixAssembly);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
OnLoadAssetFail();
|
||||
Log.Error(e.Message);
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private void OnLoadAssetSuccess(TextAsset asset)
|
||||
{
|
||||
TextAsset dll = (TextAsset)asset;
|
||||
Assembly hotfixAssembly = System.Reflection.Assembly.Load(dll.bytes);
|
||||
Log.Info("Load hotfix dll OK.");
|
||||
StartHotfixEntry(hotfixAssembly);
|
||||
}
|
||||
|
||||
private void OnLoadAssetFail()
|
||||
{
|
||||
Log.Error("Load hotfix dll failed. ");
|
||||
}
|
||||
|
||||
private void StartHotfixEntry(Assembly hotfixAssembly)
|
||||
{
|
||||
var hotfixEntry = hotfixAssembly.GetType("HotFix.GameHotfixEntry");
|
||||
var start = hotfixEntry.GetMethod("Start");
|
||||
start?.Invoke(null, null);
|
||||
ChangeState<ProcedureStartGame>(m_procedureOwner);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 727c047191bf562408cd171d83ba3d61
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,20 @@
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 流程加载器 - 开始起点
|
||||
/// </summary>
|
||||
public class ProcedureLaunch : ProcedureBase
|
||||
{
|
||||
protected internal override void OnEnter(IFsm<IProcedureManager> procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
ResMgr.Instance.Active();
|
||||
}
|
||||
|
||||
protected internal override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
ChangeState<ProcedureSplash>(procedureOwner);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31acbba6c65c0314985944275895f1c0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,49 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 流程加载器 - 资源初始化
|
||||
/// </summary>
|
||||
public class ProcedureResourcesInit : ProcedureBase
|
||||
{
|
||||
public static int OnInitResourceCompleteEvent = StringId.StringToHash("OnInitResourceComplete");
|
||||
|
||||
private bool m_initResourceComplete = false;
|
||||
|
||||
protected internal override void OnEnter(IFsm<IProcedureManager> procedureOwner)
|
||||
{
|
||||
|
||||
base.OnEnter(procedureOwner);
|
||||
GameEvent.AddEventListener(OnInitResourceCompleteEvent, OnInitResourceComplete);
|
||||
m_initResourceComplete = false;
|
||||
LoaderUtilities.DelayFun((() =>
|
||||
{
|
||||
GameEvent.Send(OnInitResourceCompleteEvent);
|
||||
}),new WaitForSeconds(1f));
|
||||
}
|
||||
|
||||
protected internal override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
if (m_initResourceComplete)
|
||||
{
|
||||
ChangeState<ProcedureCodeInit>(procedureOwner);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected internal override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
|
||||
{
|
||||
base.OnLeave(procedureOwner, isShutdown);
|
||||
GameEvent.RemoveEventListener(OnInitResourceCompleteEvent, OnInitResourceComplete);
|
||||
}
|
||||
|
||||
private void OnInitResourceComplete()
|
||||
{
|
||||
m_initResourceComplete = true;
|
||||
Log.Info("OnInitResourceComplete 初始化资源完成");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22e55cee812c74f4d9e831d604e3fa33
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,201 @@
|
||||
using System;
|
||||
using TEngine.Runtime.HotUpdate;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 流程加载器 - 资源下载/资源热更新/资源校验
|
||||
/// </summary>
|
||||
internal class ProcedureResourcesUpdate : ProcedureBase
|
||||
{
|
||||
private LoadData _currentData;
|
||||
private OnlineVersionInfo _onlineVersionInfo;
|
||||
private IFsm<IProcedureManager> _procedureOwner;
|
||||
private bool _dllLoad = false;
|
||||
|
||||
protected internal override void OnEnter(IFsm<IProcedureManager> procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
GameEvent.AddEventListener<bool>(LoadMgr.DownLoadFinish,AllDownLoaded);
|
||||
|
||||
_procedureOwner = procedureOwner;
|
||||
|
||||
_currentData = procedureOwner.GetData<LoadData>("LoadData");
|
||||
_onlineVersionInfo = procedureOwner.GetData<OnlineVersionInfo>("OnlineVersionInfo");
|
||||
|
||||
_currentData.List = LoadMgr.Instance.CheckLocalExitResource(_currentData.List);
|
||||
|
||||
if (_currentData.List.Count <= 0)
|
||||
{
|
||||
LoadMgr.Instance.DownLoadCallBack((int)DownLoadResult.AllDownLoaded, GameStatus.AssetLoad, _currentData.All);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowUpdateType(_currentData);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示更新方式
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool ShowUpdateType(LoadData data)
|
||||
{
|
||||
UILoadMgr.Show(UIDefine.UILoadUpdate, LoadText.Instance.Label_Load_Checked);
|
||||
//底包更新
|
||||
if (data.Type == UpdateType.PackageUpdate)
|
||||
{
|
||||
LoaderUtilities.ShowMessageBox(LoadText.Instance.Label_Load_Package, MessageShowType.OneButton,
|
||||
LoadStyle.StyleEnum.Style_DownLoadApk,
|
||||
() =>
|
||||
{
|
||||
LoadMgr.Instance.StartUpdate(data.List);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
//资源更新
|
||||
else if (data.Type == UpdateType.ResourceUpdate)
|
||||
{
|
||||
//强制
|
||||
if (data.Style == UpdateStyle.Froce)
|
||||
{
|
||||
//提示
|
||||
if (data.Notice == UpdateNotice.Notice)
|
||||
{
|
||||
NetworkReachability n = Application.internetReachability;
|
||||
string desc = LoadText.Instance.Label_Load_Force_WIFI;
|
||||
if (n == NetworkReachability.ReachableViaCarrierDataNetwork)
|
||||
{
|
||||
desc = LoadText.Instance.Label_Load_Force_NO_WIFI;
|
||||
}
|
||||
|
||||
long totalSize = 0;
|
||||
foreach (var item in data.List)
|
||||
{
|
||||
totalSize += item.Size;
|
||||
}
|
||||
|
||||
desc = string.Format(desc, LoaderUtilities.FormatData(totalSize));
|
||||
LoaderUtilities.ShowMessageBox(desc, MessageShowType.TwoButton,
|
||||
LoadStyle.StyleEnum.Style_StartUpdate_Notice,
|
||||
() =>
|
||||
{
|
||||
LoadMgr.Instance.StartUpdate(data.List);
|
||||
}, () =>
|
||||
{
|
||||
ProcedureCodeInit();
|
||||
});
|
||||
}
|
||||
//不提示
|
||||
else if (data.Notice == UpdateNotice.NoNotice)
|
||||
{
|
||||
LoadMgr.Instance.StartUpdate(data.List);
|
||||
}
|
||||
}
|
||||
//非强制
|
||||
else if (data.Style == UpdateStyle.Optional)
|
||||
{
|
||||
//提示
|
||||
if (data.Notice == UpdateNotice.Notice)
|
||||
{
|
||||
LoaderUtilities.ShowMessageBox(LoadText.Instance.Label_Load_Notice, MessageShowType.TwoButton,
|
||||
LoadStyle.StyleEnum.Style_StartUpdate_Notice,
|
||||
() =>
|
||||
{
|
||||
LoadMgr.Instance.StartUpdate(data.List);
|
||||
}, () =>
|
||||
{
|
||||
ProcedureCodeInit();
|
||||
});
|
||||
}
|
||||
//不提示
|
||||
else if (data.Notice == UpdateNotice.NoNotice)
|
||||
{
|
||||
LoadMgr.Instance.StartUpdate(data.List);
|
||||
}
|
||||
}
|
||||
else
|
||||
TLogger.LogError("LoadMgr._CheckUpdate, style is error,code:" + data.Style);
|
||||
return true;
|
||||
}
|
||||
//没有更新
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ProcedureCodeInit()
|
||||
{
|
||||
ChangeState<ProcedureCodeInit>(_procedureOwner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 全部下载完成回调
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
private void AllDownLoaded(bool result)
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(_onlineVersionInfo.ResourceVersion.ToString()))
|
||||
{
|
||||
_onlineVersionInfo.ResourceVersion = int.Parse(GameConfig.Instance.ResId);
|
||||
}
|
||||
GameConfig.Instance.WriteResVersion(_onlineVersionInfo.ResourceVersion.ToString());
|
||||
ResMgr.Instance.ReLoad();
|
||||
UILoadMgr.Show(UIDefine.UILoadUpdate, "所有资源下载完成,稍后进入游戏!");
|
||||
LoaderUtilities.DelayFun((() =>
|
||||
{
|
||||
UILoadMgr.HideAll();
|
||||
}), new WaitForSeconds(2));
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TLogger.LogError(e.StackTrace);
|
||||
LoaderUtilities.ShowMessageBox(LoadText.Instance.Label_Load_UnPackError, MessageShowType.OneButton,
|
||||
LoadStyle.StyleEnum.Style_RestartApp,
|
||||
() =>
|
||||
{
|
||||
Application.Quit();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (_dllLoad == false)
|
||||
{
|
||||
ProcedureCodeInit();
|
||||
}
|
||||
else
|
||||
{
|
||||
LoaderUtilities.ShowMessageBox(LoadText.Instance.Label_RestartApp, MessageShowType.OneButton,
|
||||
LoadStyle.StyleEnum.Style_RestartApp,
|
||||
() =>
|
||||
{
|
||||
Application.Quit();
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in _currentData.List)
|
||||
{
|
||||
if (item.Url == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LoaderUtilities.DeleteFile(FileSystem.ResourceRoot + "/" + item.Url);
|
||||
}
|
||||
|
||||
LoaderUtilities.ShowMessageBox(LoadText.Instance.Label_Load_UnPackError, MessageShowType.OneButton,
|
||||
LoadStyle.StyleEnum.Style_QuitApp,
|
||||
() => {
|
||||
Application.Quit();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b4949e6ae6db604e8e24cd52f27889f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,29 @@
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 流程加载器 - 资源校验(暂无)
|
||||
/// </summary>
|
||||
internal class ProcedureResourcesVerify:ProcedureBase
|
||||
{
|
||||
private bool m_VerifyResourcesComplete = false;
|
||||
|
||||
protected internal override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
if (!m_VerifyResourcesComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChangeState<ProcedureCodeInit>(procedureOwner);
|
||||
}
|
||||
|
||||
private void OnVerifyResourcesComplete(bool result)
|
||||
{
|
||||
m_VerifyResourcesComplete = true;
|
||||
Log.Info("Verify resources complete, result is '{0}'.", result);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7e515393a43f24f459c7d87a50d78084
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 流程加载器 - 闪屏
|
||||
/// </summary>
|
||||
public class ProcedureSplash : ProcedureBase
|
||||
{
|
||||
protected internal override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds,
|
||||
float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
// TODO: 这里可以播放一个 Splash 动画
|
||||
// ...
|
||||
if (ResourceComponent.Instance.ResourceMode == ResourceMode.Package)
|
||||
{
|
||||
Log.Info("单机模式 ChangeState<ProcedureInitResources>");
|
||||
ChangeState<ProcedureResourcesInit>(procedureOwner);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Info("可更新模式 ChangeState<ProcedureCheckVersion>");
|
||||
ChangeState<ProcedureCheckVersion>(procedureOwner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cea4ebefaac8fbd468eb0b3591277ec6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,19 @@
|
||||
namespace TEngine.Runtime
|
||||
{
|
||||
public static partial class TEngineEvent
|
||||
{
|
||||
public static readonly int OnStartGame = StringId.StringToHash("TEngineEvent.OnStartGame");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流程加载器 - 终点StartGame
|
||||
/// </summary>
|
||||
public class ProcedureStartGame : ProcedureBase
|
||||
{
|
||||
protected internal override void OnEnter(IFsm<IProcedureManager> procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
GameEvent.Send(TEngineEvent.OnStartGame);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7fd9e9398439a34197e5e3c73094987
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -1,6 +1,9 @@
|
||||
{
|
||||
"name": "TEngine.Runtime",
|
||||
"references": [],
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:13ba8ce62aa80c74598530029cb2d649"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
|
Reference in New Issue
Block a user