diff --git a/Assets/GameScripts/Main/Procedure.meta b/Assets/GameScripts/Main/Procedure.meta new file mode 100644 index 00000000..4d988b6c --- /dev/null +++ b/Assets/GameScripts/Main/Procedure.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6fb918d22aa59c84895bd15208a930b8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameScripts/Main/Procedure/ProcedureBase.cs b/Assets/GameScripts/Main/Procedure/ProcedureBase.cs new file mode 100644 index 00000000..d35cea5c --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureBase.cs @@ -0,0 +1,14 @@ +namespace GameMain +{ + public abstract class ProcedureBase : TEngine.ProcedureBase + { + /// + /// 获取流程是否使用原生对话框 + /// 在一些特殊的流程(如游戏逻辑对话框资源更新完成前的流程)中,可以考虑调用原生对话框进行消息提示行为 + /// + public abstract bool UseNativeDialog + { + get; + } + } +} diff --git a/Assets/GameScripts/Main/Procedure/ProcedureBase.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureBase.cs.meta new file mode 100644 index 00000000..bb301525 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureBase.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 531a832bf8dfd734395de52f4141082f +timeCreated: 1528026158 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameScripts/Main/Procedure/ProcedureClearCache.cs b/Assets/GameScripts/Main/Procedure/ProcedureClearCache.cs new file mode 100644 index 00000000..0faf0c1e --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureClearCache.cs @@ -0,0 +1,31 @@ +using TEngine; +using ProcedureOwner = TEngine.IFsm; + +namespace GameMain +{ + public class ProcedureClearCache:ProcedureBase + { + public override bool UseNativeDialog { get; } + + private ProcedureOwner _procedureOwner; + + protected override void OnEnter(ProcedureOwner procedureOwner) + { + _procedureOwner = procedureOwner; + Log.Info("清理未使用的缓存文件!"); + + UILoadMgr.Show(UIDefine.UILoadUpdate,$"清理未使用的缓存文件..."); + + var operation = GameModule.Resource.ClearUnusedCacheFilesAsync(); + operation.Completed += Operation_Completed; + } + + + private void Operation_Completed(YooAsset.AsyncOperationBase obj) + { + UILoadMgr.Show(UIDefine.UILoadUpdate,$"清理完成 即将进入游戏..."); + + ChangeState(_procedureOwner); + } + } +} \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureClearCache.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureClearCache.cs.meta new file mode 100644 index 00000000..00653ae7 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureClearCache.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b9e990ba01f24ac584014438abc7f3b7 +timeCreated: 1679635352 \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureCreateDownloader.cs b/Assets/GameScripts/Main/Procedure/ProcedureCreateDownloader.cs new file mode 100644 index 00000000..2116f9ad --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureCreateDownloader.cs @@ -0,0 +1,57 @@ +using System; +using Cysharp.Threading.Tasks; +using TEngine; +using ProcedureOwner = TEngine.IFsm; + +namespace GameMain +{ + public class ProcedureCreateDownloader : ProcedureBase + { + public override bool UseNativeDialog { get; } + + protected override void OnEnter(ProcedureOwner procedureOwner) + { + Log.Info("创建补丁下载器"); + + UILoadMgr.Show(UIDefine.UILoadUpdate,$"创建补丁下载器..."); + + CreateDownloader(procedureOwner).Forget(); + } + + private async UniTaskVoid CreateDownloader(ProcedureOwner procedureOwner) + { + await UniTask.Delay(TimeSpan.FromSeconds(0.5f)); + + var downloader = GameModule.Resource.CreateResourceDownloader(); + + if (downloader.TotalDownloadCount == 0) + { + Log.Info("Not found any download files !"); + ChangeState(procedureOwner); + } + else + { + //A total of 10 files were found that need to be downloaded + Log.Info($"Found total {downloader.TotalDownloadCount} files that need download !"); + + // 发现新更新文件后,挂起流程系统 + // 注意:开发者需要在下载前检测磁盘空间不足 + int totalDownloadCount = downloader.TotalDownloadCount; + long totalDownloadBytes = downloader.TotalDownloadBytes; + + float sizeMb = totalDownloadBytes / 1048576f; + sizeMb = UnityEngine.Mathf.Clamp(sizeMb, 0.1f, float.MaxValue); + string totalSizeMb = sizeMb.ToString("f1"); + + UILoadTip.ShowMessageBox($"Found update patch files, Total count {totalDownloadCount} Total size {totalSizeMb}MB", MessageShowType.TwoButton, + LoadStyle.StyleEnum.Style_StartUpdate_Notice + , () => { StartDownFile(procedureOwner: procedureOwner); }, UnityEngine.Application.Quit); + } + } + + void StartDownFile(ProcedureOwner procedureOwner) + { + ChangeState(procedureOwner); + } + } +} \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureCreateDownloader.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureCreateDownloader.cs.meta new file mode 100644 index 00000000..5a42e45f --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureCreateDownloader.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2323d6b64e5a4a1195b9ed1795a64bdd +timeCreated: 1679634708 \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureDownloadFile.cs b/Assets/GameScripts/Main/Procedure/ProcedureDownloadFile.cs new file mode 100644 index 00000000..1412cec5 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureDownloadFile.cs @@ -0,0 +1,76 @@ +using System; +using Cysharp.Threading.Tasks; +using TEngine; +using YooAsset; +using ProcedureOwner = TEngine.IFsm; + +namespace GameMain +{ + public class ProcedureDownloadFile:ProcedureBase + { + public override bool UseNativeDialog { get; } + + private ProcedureOwner _procedureOwner; + protected override void OnEnter(ProcedureOwner procedureOwner) + { + _procedureOwner = procedureOwner; + + Log.Info("开始下载更新文件!"); + + UILoadMgr.Show(UIDefine.UILoadUpdate,$"开始下载更新文件..."); + + BeginDownload().Forget(); + } + + private async UniTaskVoid BeginDownload() + { + var downloader = GameModule.Resource.Downloader; + + // 注册下载回调 + downloader.OnDownloadErrorCallback = OnDownloadErrorCallback; + downloader.OnDownloadProgressCallback = OnDownloadProgressCallback; + downloader.BeginDownload(); + await downloader; + + // 检测下载结果 + if (downloader.Status != EOperationStatus.Succeed) + return; + + ChangeState(_procedureOwner); + } + + private void OnDownloadErrorCallback(string fileName, string error) + { + UILoadTip.ShowMessageBox($"Failed to download file : {fileName}", MessageShowType.TwoButton, + LoadStyle.StyleEnum.Style_Default + , () => { ChangeState(_procedureOwner); }, UnityEngine.Application.Quit); + } + + private void OnDownloadProgressCallback(int totalDownloadCount, int currentDownloadCount, long totalDownloadBytes, long currentDownloadBytes) + { + string currentSizeMb = (currentDownloadBytes / 1048576f).ToString("f1"); + string totalSizeMb = (totalDownloadBytes / 1048576f).ToString("f1"); + // UILoadMgr.Show(UIDefine.UILoadUpdate,$"{currentDownloadCount}/{totalDownloadCount} {currentSizeMb}MB/{totalSizeMb}MB"); + string descriptionText = Utility.Text.Format("正在更新,已更新{0},总更新{1},已更新大小{2},总更新大小{3},更新进度{4},当前网速{5}/s", + currentDownloadCount.ToString(), + totalDownloadCount.ToString(), + Utility.File.GetByteLengthString(currentDownloadBytes), + Utility.File.GetByteLengthString(totalDownloadBytes), + GameModule.Resource.Downloader.Progress, + Utility.File.GetByteLengthString((int)GameModule.Resource.Downloader.CurrentSpeed)); + LoadUpdateLogic.Instance.DownProgressAction?.Invoke(GameModule.Resource.Downloader.Progress); + UILoadMgr.Show(UIDefine.UILoadUpdate,descriptionText); + + int needTime = 0; + if (GameModule.Resource.Downloader.CurrentSpeed > 0) + { + needTime = (int)((totalDownloadBytes - currentDownloadBytes) / GameModule.Resource.Downloader.CurrentSpeed); + } + + TimeSpan ts = new TimeSpan(0, 0, needTime); + string timeStr = ts.ToString(@"mm\:ss"); + string updateProgress = Utility.Text.Format("剩余时间 {0}({1}/s)", timeStr, Utility.File.GetLengthString((int)GameModule.Resource.Downloader.CurrentSpeed)); + Log.Info(updateProgress); + } + } +} \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureDownloadFile.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureDownloadFile.cs.meta new file mode 100644 index 00000000..32b827ad --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureDownloadFile.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 19b2799aad474898b96d8551856e6b40 +timeCreated: 1679642638 \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureDownloadOver.cs b/Assets/GameScripts/Main/Procedure/ProcedureDownloadOver.cs new file mode 100644 index 00000000..abd525e9 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureDownloadOver.cs @@ -0,0 +1,22 @@ +using TEngine; +using ProcedureOwner = TEngine.IFsm; + +namespace GameMain +{ + public class ProcedureDownloadOver:ProcedureBase + { + public override bool UseNativeDialog { get; } + + protected override void OnEnter(ProcedureOwner procedureOwner) + { + Log.Info("下载完成!!!"); + + UILoadMgr.Show(UIDefine.UILoadUpdate,$"下载完成..."); + } + + protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds) + { + ChangeState(procedureOwner); + } + } +} \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureDownloadOver.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureDownloadOver.cs.meta new file mode 100644 index 00000000..8b59b07a --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureDownloadOver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b3998cede0874b49afc170062e554c34 +timeCreated: 1679635148 \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureInitPackage.cs b/Assets/GameScripts/Main/Procedure/ProcedureInitPackage.cs new file mode 100644 index 00000000..9d01b371 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureInitPackage.cs @@ -0,0 +1,84 @@ +using System; +using Cysharp.Threading.Tasks; +using TEngine; +using YooAsset; +using ProcedureOwner = TEngine.IFsm; + +namespace GameMain +{ + /// + /// 流程 => 初始化Package。 + /// + public class ProcedureInitPackage : ProcedureBase + { + public override bool UseNativeDialog { get; } + + protected override void OnEnter(ProcedureOwner procedureOwner) + { + base.OnEnter(procedureOwner); + + //Fire Forget立刻触发UniTask初始化Package + InitPackage(procedureOwner).Forget(); + } + + private async UniTaskVoid InitPackage(ProcedureOwner procedureOwner) + { + var initializationOperation = GameModule.Resource.InitPackage(); + + await UniTask.Delay(TimeSpan.FromSeconds(1f)); + + await initializationOperation.ToUniTask(); + + if (initializationOperation.Status == EOperationStatus.Succeed) + { + // 编辑器模式。 + if (GameModule.Resource.playMode == EPlayMode.EditorSimulateMode) + { + Log.Info("Editor resource mode detected."); + ChangeState(procedureOwner); + } + // 单机模式。 + else if (GameModule.Resource.playMode == EPlayMode.OfflinePlayMode) + { + Log.Info("Package resource mode detected."); + ChangeState(procedureOwner); + } + // 可更新模式。 + else if (GameModule.Resource.playMode == EPlayMode.HostPlayMode) + { + // 打开启动UI。 + UILoadMgr.Show(UIDefine.UILoadUpdate); + + Log.Info("Updatable resource mode detected."); + ChangeState(procedureOwner); + } + else + { + Log.Error("UnKnow resource mode detected Please check???"); + } + } + else + { + // 打开启动UI。 + UILoadMgr.Show(UIDefine.UILoadUpdate); + + Log.Error($"{initializationOperation.Error}"); + + // 打开启动UI。 + UILoadMgr.Show(UIDefine.UILoadUpdate, $"资源初始化失败!"); + + UILoadTip.ShowMessageBox($"资源初始化失败!点击确认重试 \n \n 原因{initializationOperation.Error}", MessageShowType.TwoButton, + LoadStyle.StyleEnum.Style_Retry + , () => { Retry(procedureOwner); }, UnityEngine.Application.Quit); + } + } + + private void Retry(ProcedureOwner procedureOwner) + { + // 打开启动UI。 + UILoadMgr.Show(UIDefine.UILoadUpdate, $"重新初始化资源中..."); + + InitPackage(procedureOwner).Forget(); + } + } +} \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureInitPackage.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureInitPackage.cs.meta new file mode 100644 index 00000000..6c5d486d --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureInitPackage.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0fc41b358bdc498681a63f72ad8942c8 +timeCreated: 1679639147 \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureInitResources.cs b/Assets/GameScripts/Main/Procedure/ProcedureInitResources.cs new file mode 100644 index 00000000..2a9f88f9 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureInitResources.cs @@ -0,0 +1,49 @@ +using TEngine; +using ProcedureOwner = TEngine.IFsm; + +namespace GameMain +{ + public class ProcedureInitResources : ProcedureBase + { + private bool m_InitResourcesComplete = false; + + public override bool UseNativeDialog + { + get + { + return true; + } + } + + protected override void OnEnter(ProcedureOwner procedureOwner) + { + base.OnEnter(procedureOwner); + + m_InitResourcesComplete = false; + + UILoadMgr.Show(UIDefine.UILoadUpdate,"初始化资源中..."); + + // 注意:使用单机模式并初始化资源前,需要先构建 AssetBundle 并复制到 StreamingAssets 中,否则会产生 HTTP 404 错误 + OnInitResourcesComplete(); + } + + protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds) + { + base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds); + + if (!m_InitResourcesComplete) + { + // 初始化资源未完成则继续等待 + return; + } + + ChangeState(procedureOwner); + } + + private void OnInitResourcesComplete() + { + m_InitResourcesComplete = true; + Log.Info("Init resources complete."); + } + } +} diff --git a/Assets/GameScripts/Main/Procedure/ProcedureInitResources.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureInitResources.cs.meta new file mode 100644 index 00000000..0747cce9 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureInitResources.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 49285f361d08436aab23bdf729c10ea0 +timeCreated: 1679635748 \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureLaunch.cs b/Assets/GameScripts/Main/Procedure/ProcedureLaunch.cs new file mode 100644 index 00000000..50e375a3 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureLaunch.cs @@ -0,0 +1,91 @@ +using System; +using TEngine; +using TEngine.Localization; +using YooAsset; +using ProcedureOwner = TEngine.IFsm; + +namespace GameMain +{ + /// + /// 流程 => 启动器。 + /// + public class ProcedureLaunch : ProcedureBase + { + public override bool UseNativeDialog => true; + + protected override void OnEnter(ProcedureOwner procedureOwner) + { + base.OnEnter(procedureOwner); + + // 构建信息:发布版本时,把一些数据以 Json 的格式写入 Assets/GameMain/Configs/BuildInfo.txt,供游戏逻辑读取 + // GameModule.BuiltinData.InitBuildInfo(); + + // 语言配置:设置当前使用的语言,如果不设置,则默认使用操作系统语言 + InitLanguageSettings(); + + // 声音配置:根据用户配置数据,设置即将使用的声音选项 + InitSoundSettings(); + + // 默认字典:加载默认字典文件 Assets/GameMain/Configs/DefaultDictionary.xml + // 此字典文件记录了资源更新前使用的各种语言的字符串,会随 App 一起发布,故不可更新 + // GameModule.BuiltinData.InitDefaultDictionary(); + } + + protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds) + { + base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds); + + // 运行一帧即切换到 Splash 展示流程 + ChangeState(procedureOwner); + } + + private void InitLanguageSettings() + { + if (GameModule.Resource.playMode == EPlayMode.EditorSimulateMode && GameModule.Base.EditorLanguage != Language.Unspecified) + { + // 编辑器资源模式直接使用 Inspector 上设置的语言 + return; + } + + // Language language = GameModule.Localization.Language; + // if (GameModule.Setting.HasSetting(Constant.Setting.Language)) + // { + // try + // { + // string languageString = GameModule.Setting.GetString(Constant.Setting.Language); + // language = (Language)Enum.Parse(typeof(Language), languageString); + // } + // catch(Exception exception) + // { + // Log.Error("Init language error, reason {0}",exception.ToString()); + // } + // } + + // if (language != Language.English + // && language != Language.ChineseSimplified + // && language != Language.ChineseTraditional + // && language != Language.Korean) + // { + // // 若是暂不支持的语言,则使用英语 + // language = Language.English; + // + // GameModule.Setting.SetString(Constant.Setting.Language, language.ToString()); + // GameModule.Setting.Save(); + // } + // + // GameModule.Localization.Language = language; + // Log.Info("Init language settings complete, current language is '{0}'.", language.ToString()); + } + + private void InitSoundSettings() + { + // GameModule.Sound.Mute("Music", GameModule.Setting.GetBool(Constant.Setting.MusicMuted, false)); + // GameModule.Sound.SetVolume("Music", GameModule.Setting.GetFloat(Constant.Setting.MusicVolume, 0.3f)); + // GameModule.Sound.Mute("Sound", GameModule.Setting.GetBool(Constant.Setting.SoundMuted, false)); + // GameModule.Sound.SetVolume("Sound", GameModule.Setting.GetFloat(Constant.Setting.SoundVolume, 1f)); + // GameModule.Sound.Mute("UISound", GameModule.Setting.GetBool(Constant.Setting.UISoundMuted, false)); + // GameModule.Sound.SetVolume("UISound", GameModule.Setting.GetFloat(Constant.Setting.UISoundVolume, 1f)); + Log.Info("Init sound settings complete."); + } + } +} diff --git a/Assets/GameScripts/Main/Procedure/ProcedureLaunch.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureLaunch.cs.meta new file mode 100644 index 00000000..7ae84b24 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureLaunch.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: d6c3d65d0c3a2104383e82700116b3d1 +timeCreated: 1528026159 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameScripts/Main/Procedure/ProcedureLoadAssembly.cs b/Assets/GameScripts/Main/Procedure/ProcedureLoadAssembly.cs new file mode 100644 index 00000000..7ab2c23b --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureLoadAssembly.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections.Generic; +using System.IO; +#if HybridCLR_Enable +using HybridCLR; +#endif +using UnityEngine; +using TEngine; +using System.Reflection; +using YooAsset; + +namespace GameMain +{ + /// + /// 流程加载器 - 代码初始化 + /// + public class ProcedureLoadAssembly : ProcedureBase + { + /// + /// 是否需要加载热更新DLL + /// + public bool NeedLoadDll => GameModule.Resource.playMode == EPlayMode.HostPlayMode || GameModule.Resource.playMode == EPlayMode.OfflinePlayMode; + + public override bool UseNativeDialog => true; +// private int m_LoadAssetCount; +// private int m_LoadMetadataAssetCount; +// private int m_FailureAssetCount; +// private int m_FailureMetadataAssetCount; +// private bool m_LoadAssemblyComplete; +// private bool m_LoadMetadataAssemblyComplete; +// private bool m_LoadAssemblyWait; +// private bool m_LoadMetadataAssemblyWait; +// private System.Reflection.Assembly m_MainLogicAssembly; +// private List m_HotfixAssemblys; +// private IFsm m_procedureOwner; +// +// protected override void OnEnter(IFsm procedureOwner) +// { +// base.OnEnter(procedureOwner); +// Log.Debug("HyBridCLR ProcedureLoadAssembly OnEnter"); +// m_procedureOwner = procedureOwner; +// m_LoadAssemblyComplete = false; +// m_HotfixAssemblys = new List(); +// +// if (!NeedLoadDll || GameModule.Resource.playMode == EPlayMode.EditorSimulateMode) +// { +// m_MainLogicAssembly = GetMainLogicAssembly(); +// } +// else +// { +// if (SettingsUtils.HybridCLRCustomGlobalSettings.Enable) +// { +// m_LoadAssetCallbacks ??= new LoadAssetCallbacks(LoadAssetSuccess, LoadAssetFailure); +// foreach (var hotUpdateDllName in SettingsUtils.HybridCLRCustomGlobalSettings.HotUpdateAssemblies) +// { +// var assetPath = Utility.Path.GetRegularPath( +// Path.Combine( +// "Assets", +// SettingsUtils.HybridCLRCustomGlobalSettings.AssemblyTextAssetPath, +// $"{hotUpdateDllName}{SettingsUtils.HybridCLRCustomGlobalSettings.AssemblyTextAssetExtension}")); +// Log.Debug($"LoadAsset: [ {assetPath} ]"); +// m_LoadAssetCount++; +// GameModule.Resource.LoadAssetAsync(assetPath,typeof(UnityEngine.TextAsset), m_LoadAssetCallbacks, hotUpdateDllName); +// } +// +// m_LoadAssemblyWait = true; +// } +// else +// { +// m_MainLogicAssembly = GetMainLogicAssembly(); +// } +// } +// +// if (SettingsUtils.HybridCLRCustomGlobalSettings.Enable) +// { +// #if !UNITY_EDITOR +// m_LoadMetadataAssemblyComplete = false; +// LoadMetadataForAOTAssembly(); +// #else +// m_LoadMetadataAssemblyComplete = true; +// #endif +// } +// else +// { +// m_LoadMetadataAssemblyComplete = true; +// } +// +// if (m_LoadAssetCount == 0) +// { +// m_LoadAssemblyComplete = true; +// } +// } +// +// protected override void OnUpdate(IFsm procedureOwner, float elapseSeconds, float realElapseSeconds) +// { +// base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds); +// if (!m_LoadAssemblyComplete) +// { +// return; +// } +// if (!m_LoadMetadataAssemblyComplete) +// { +// return; +// } +// AllAssemblyLoadComplete(); +// } +// +// private void AllAssemblyLoadComplete() +// { +// if (GameModule.Resource.playMode == EPlayMode.EditorSimulateMode) +// { +// ChangeState(m_procedureOwner); +// return; +// } +// if (m_MainLogicAssembly == null) +// { +// Log.Fatal($"Main logic assembly missing."); +// return; +// } +// var appType = m_MainLogicAssembly.GetType("GameMain"); +// if (appType == null) +// { +// Log.Fatal($"Main logic type 'GameMain' missing."); +// return; +// } +// var entryMethod = appType.GetMethod("Entrance"); +// if (entryMethod == null) +// { +// Log.Fatal($"Main logic entry method 'Entrance' missing."); +// return; +// } +// object[] objects = new object[] { new object[] { m_HotfixAssemblys } }; +// entryMethod.Invoke(appType, objects); +// ChangeState(m_procedureOwner); +// } +// +// private Assembly GetMainLogicAssembly() +// { +// Assembly mainLogicAssembly = null; +// foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) +// { +// if (string.Compare(SettingsUtils.HybridCLRCustomGlobalSettings.LogicMainDllName, $"{assembly.GetName().Name}.dll", +// StringComparison.Ordinal) == 0) +// { +// mainLogicAssembly = assembly; +// } +// +// foreach (var hotUpdateDllName in SettingsUtils.HybridCLRCustomGlobalSettings.HotUpdateAssemblies) +// { +// if (hotUpdateDllName == $"{assembly.GetName().Name}.dll") +// { +// m_HotfixAssemblys.Add(assembly); +// } +// } +// +// if (mainLogicAssembly != null && m_HotfixAssemblys.Count == SettingsUtils.HybridCLRCustomGlobalSettings.HotUpdateAssemblies.Count) +// { +// break; +// } +// } +// +// return mainLogicAssembly; +// } +// +// /// +// /// 加载代码资源成功回调。 +// /// +// /// 资源名称。 +// /// 资源实例。 +// /// 加载耗时。 +// /// 用户数据。 +// private void LoadAssetSuccess(string assetName, object asset, float duration, object userData) +// { +// m_LoadAssetCount--; +// Log.Debug($"LoadAssetSuccess, assetName: [ {assetName} ], duration: [ {duration} ], userData: [ {userData} ]"); +// var textAsset = asset as TextAsset; +// if (textAsset == null) +// { +// Log.Warning($"Load text asset [ {assetName} ] failed."); +// return; +// } +// +// try +// { +// var assembly = Assembly.Load(textAsset.bytes); +// if (string.Compare(SettingsUtils.HybridCLRCustomGlobalSettings.LogicMainDllName, userData as string, StringComparison.Ordinal) == 0) +// { +// m_MainLogicAssembly = assembly; +// } +// m_HotfixAssemblys.Add(assembly); +// Log.Debug($"Assembly [ {assembly.GetName().Name} ] loaded"); +// } +// catch (Exception e) +// { +// m_FailureAssetCount++; +// Log.Fatal(e); +// throw; +// } +// finally +// { +// m_LoadAssemblyComplete = m_LoadAssemblyWait && 0 == m_LoadAssetCount; +// } +// } +// +// /// +// /// 加载代码资源失败回调。 +// /// +// /// 资源名称。 +// /// 加载状态。 +// /// 错误信息。 +// /// 自定义数据。 +// private void LoadAssetFailure(string assetName, LoadResourceStatus status, string errorMessage, object userData) +// { +// Log.Fatal($"LoadAssetFailure, assetName: [ {assetName} ], status: [ {status} ], errorMessage: [ {errorMessage} ], userData: [ {userData} ]"); +// m_LoadAssetCount--; +// m_FailureAssetCount++; +// } +// +// /// +// /// 为Aot Assembly加载原始metadata, 这个代码放Aot或者热更新都行。 +// /// 一旦加载后,如果AOT泛型函数对应native实现不存在,则自动替换为解释模式执行。 +// /// +// public void LoadMetadataForAOTAssembly() +// { +// // 可以加载任意aot assembly的对应的dll。但要求dll必须与unity build过程中生成的裁剪后的dll一致,而不能直接使用原始dll。 +// // 我们在BuildProcessor_xxx里添加了处理代码,这些裁剪后的dll在打包时自动被复制到 {项目目录}/HybridCLRData/AssembliesPostIl2CppStrip/{Target} 目录。 +// +// // 注意,补充元数据是给AOT dll补充元数据,而不是给热更新dll补充元数据。 +// // 热更新dll不缺元数据,不需要补充,如果调用LoadMetadataForAOTAssembly会返回错误 +// if (SettingsUtils.HybridCLRCustomGlobalSettings.AOTMetaAssemblies.Count == 0) +// { +// m_LoadMetadataAssemblyComplete = true; +// return; +// } +// m_LoadMetadataAssetCallbacks ??= new LoadAssetCallbacks(LoadMetadataAssetSuccess, LoadMetadataAssetFailure); +// foreach (var aotDllName in SettingsUtils.HybridCLRCustomGlobalSettings.AOTMetaAssemblies) +// { +// var assetPath = Utility.Path.GetRegularPath( +// Path.Combine( +// "Assets", +// SettingsUtils.HybridCLRCustomGlobalSettings.AssemblyTextAssetPath, +// $"{aotDllName}{SettingsUtils.HybridCLRCustomGlobalSettings.AssemblyTextAssetExtension}")); +// Log.Debug($"LoadMetadataAsset: [ {assetPath} ]"); +// m_LoadMetadataAssetCount++; +// GameModule.Resource.LoadAssetAsync(assetPath,typeof(UnityEngine.TextAsset), m_LoadMetadataAssetCallbacks, aotDllName); +// } +// m_LoadMetadataAssemblyWait = true; +// } +// +// /// +// /// 加载元数据资源成功回调。 +// /// +// /// 资源名称。 +// /// 资源实例。 +// /// 加载耗时。 +// /// 用户数据。 +// private unsafe void LoadMetadataAssetSuccess(string assetName, object asset, float duration, object userData) +// { +// m_LoadMetadataAssetCount--; +// Log.Debug($"LoadMetadataAssetSuccess, assetName: [ {assetName} ], duration: [ {duration} ], userData: [ {userData} ]"); +// var textAsset = asset as TextAsset; +// if (null == textAsset) +// { +// Log.Debug($"LoadMetadataAssetSuccess:Load text asset [ {assetName} ] failed."); +// return; +// } +// +// try +// { +// byte[] dllBytes = textAsset.bytes; +// fixed (byte* ptr = dllBytes) +// { +// #if HybridCLR_Enable +// // 加载assembly对应的dll,会自动为它hook。一旦Aot泛型函数的native函数不存在,用解释器版本代码 +// HomologousImageMode mode = HomologousImageMode.SuperSet; +// LoadImageErrorCode err = (LoadImageErrorCode)HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(dllBytes,mode); +// Log.Warning($"LoadMetadataForAOTAssembly:{userData as string}. mode:{mode} ret:{err}"); +// #endif +// } +// } +// catch (Exception e) +// { +// m_FailureMetadataAssetCount++; +// Log.Fatal(e.Message); +// throw; +// } +// finally +// { +// m_LoadMetadataAssemblyComplete = m_LoadMetadataAssemblyWait && 0 == m_LoadMetadataAssetCount; +// } +// } +// +// /// +// /// 加载元数据资源失败回调。 +// /// +// /// 资源名称。 +// /// 加载状态。 +// /// 错误信息。 +// /// 自定义数据。 +// private void LoadMetadataAssetFailure(string assetName, LoadResourceStatus status, string errorMessage, object userData) +// { +// Log.Warning($"LoadAssetFailure, assetName: [ {assetName} ], status: [ {status} ], errorMessage: [ {errorMessage} ], userData: [ {userData} ]"); +// m_LoadMetadataAssetCount--; +// m_FailureMetadataAssetCount++; +// } + } +} \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureLoadAssembly.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureLoadAssembly.cs.meta new file mode 100644 index 00000000..37b228fd --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureLoadAssembly.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 38e1de092fdb401c955859d7d60d1b5a +timeCreated: 1675668724 \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedurePreload.cs b/Assets/GameScripts/Main/Procedure/ProcedurePreload.cs new file mode 100644 index 00000000..f4df9efa --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedurePreload.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using TEngine; +using YooAsset; +using ProcedureOwner = TEngine.IFsm; + +namespace GameMain +{ + /// + /// 预加载流程 + /// + public class ProcedurePreload : ProcedureBase + { + private Dictionary m_LoadedFlag = new Dictionary(); + + public override bool UseNativeDialog + { + get { return true; } + } + + private bool m_needProLoadConfig = false; + + private bool m_InitConfigXml = false; + + protected override void OnEnter(ProcedureOwner procedureOwner) + { + base.OnEnter(procedureOwner); + + m_LoadedFlag.Clear(); + + if (GameModule.Resource.playMode == EPlayMode.EditorSimulateMode) + { + m_InitConfigXml = true; + } + + UILoadMgr.Show(UIDefine.UILoadUpdate, Utility.Text.Format(LoadText.Instance.Label_Load_Load_Progress, 0)); + + PreloadResources(); + } + + protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds) + { + base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds); + + var totalCount = m_LoadedFlag.Count <= 0 ? 1 : m_LoadedFlag.Count; + + var loadCount = m_LoadedFlag.Count <= 0 ? 1 : 0; + + foreach (KeyValuePair loadedFlag in m_LoadedFlag) + { + if (!loadedFlag.Value) + { + break; + } + else + { + loadCount++; + } + } + + UILoadMgr.Show(UIDefine.UILoadUpdate, Utility.Text.Format(LoadText.Instance.Label_Load_Load_Progress, (float)loadCount / totalCount * 100)); + + if (loadCount < totalCount) + { + return; + } + + if (m_InitConfigXml == false) + { + return; + } + + UILoadMgr.HideAll(); + + ChangeState(procedureOwner); + } + + private void PreloadResources() + { + if (m_needProLoadConfig) + { + LoadAllConfig(); + } + else + { + m_InitConfigXml = true; + } + } + + private void LoadAllConfig() + { + if (GameModule.Resource.playMode == EPlayMode.EditorSimulateMode) + { + m_InitConfigXml = true; + return; + } + } + } +} \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedurePreload.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedurePreload.cs.meta new file mode 100644 index 00000000..e6c61063 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedurePreload.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3510902f458c4bd48422c40d10138549 +timeCreated: 1665578910 \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureSplash.cs b/Assets/GameScripts/Main/Procedure/ProcedureSplash.cs new file mode 100644 index 00000000..ec777ef5 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureSplash.cs @@ -0,0 +1,27 @@ +using UnityEngine; +using ProcedureOwner = TEngine.IFsm; + +namespace GameMain +{ + /// + /// 流程 => 闪屏。 + /// + public class ProcedureSplash : ProcedureBase + { + public override bool UseNativeDialog => true; + + protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds) + { + base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds); + + // 播放 Splash 动画 + //Splash.Active(splashTime:3f); + //热更新阶段文本初始化 + LoadText.Instance.InitConfigData(null); + //热更新UI初始化 + UILoadMgr.Initialize(); + //初始化资源包 + ChangeState(procedureOwner); + } + } +} diff --git a/Assets/GameScripts/Main/Procedure/ProcedureSplash.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureSplash.cs.meta new file mode 100644 index 00000000..f9480a6a --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureSplash.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 139ec26f4972a8147a39d4bb34d5fcaa +timeCreated: 1528026159 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/GameScripts/Main/Procedure/ProcedureStartGame.cs b/Assets/GameScripts/Main/Procedure/ProcedureStartGame.cs new file mode 100644 index 00000000..9c962303 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureStartGame.cs @@ -0,0 +1,23 @@ +using System; +using Cysharp.Threading.Tasks; +using TEngine; + +namespace GameMain +{ + public class ProcedureStartGame : ProcedureBase + { + public override bool UseNativeDialog { get; } + + protected override void OnEnter(IFsm procedureOwner) + { + base.OnEnter(procedureOwner); + StartGame().Forget(); + } + + private async UniTaskVoid StartGame() + { + await UniTask.Delay(TimeSpan.FromSeconds(2f)); + UILoadMgr.HideAll(); + } + } +} \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureStartGame.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureStartGame.cs.meta new file mode 100644 index 00000000..ddb8910f --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureStartGame.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: db61ddc0f5f34d639fae224363a3ac49 +timeCreated: 1665628052 \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureUpdateManifest.cs b/Assets/GameScripts/Main/Procedure/ProcedureUpdateManifest.cs new file mode 100644 index 00000000..9a4a365d --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureUpdateManifest.cs @@ -0,0 +1,47 @@ +using System; +using Cysharp.Threading.Tasks; +using TEngine; +using YooAsset; +using ProcedureOwner = TEngine.IFsm; + +namespace GameMain +{ + /// + /// 流程 => 用户尝试更新清单 + /// + public class ProcedureUpdateManifest: ProcedureBase + { + public override bool UseNativeDialog { get; } + + protected override void OnEnter(ProcedureOwner procedureOwner) + { + Log.Info("更新资源清单!!!"); + + UILoadMgr.Show(UIDefine.UILoadUpdate,$"更新清单文件..."); + + UpdateManifest(procedureOwner).Forget(); + } + + private async UniTaskVoid UpdateManifest(ProcedureOwner procedureOwner) + { + await UniTask.Delay(TimeSpan.FromSeconds(0.5f)); + + var operation = GameModule.Resource.UpdatePackageManifestAsync(GameModule.Resource.PackageVersion); + + await operation.ToUniTask(); + + if(operation.Status == EOperationStatus.Succeed) + { + ChangeState(procedureOwner); + } + else + { + Log.Error(operation.Error); + + UILoadTip.ShowMessageBox($"用户尝试更新清单失败!点击确认重试 \n \n 原因{operation.Error}", MessageShowType.TwoButton, + LoadStyle.StyleEnum.Style_Retry + , () => { ChangeState(procedureOwner); }, UnityEngine.Application.Quit); + } + } + } +} \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureUpdateManifest.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureUpdateManifest.cs.meta new file mode 100644 index 00000000..10ed0770 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureUpdateManifest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3f0ff55ed6ee4711a65cc396946bb43f +timeCreated: 1679634395 \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureUpdateVersion.cs b/Assets/GameScripts/Main/Procedure/ProcedureUpdateVersion.cs new file mode 100644 index 00000000..375d0b48 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureUpdateVersion.cs @@ -0,0 +1,74 @@ +using System; +using Cysharp.Threading.Tasks; +using UnityEngine; +using TEngine; +using YooAsset; +using ProcedureOwner = TEngine.IFsm; + +namespace GameMain +{ + /// + /// 流程 => 用户尝试更新静态版本 + /// + public class ProcedureUpdateVersion : ProcedureBase + { + public override bool UseNativeDialog + { + get { return true; } + } + + private ProcedureOwner _procedureOwner; + + protected override void OnEnter(ProcedureOwner procedureOwner) + { + _procedureOwner = procedureOwner; + + base.OnEnter(procedureOwner); + + UILoadMgr.Show(UIDefine.UILoadUpdate,$"更新静态版本文件..."); + + //检查设备是否能够访问互联网 + if (Application.internetReachability == NetworkReachability.NotReachable) + { + Log.Warning("The device is not connected to the network"); + UILoadMgr.Show(UIDefine.UILoadUpdate, LoadText.Instance.Label_Net_UnReachable); + UILoadTip.ShowMessageBox(LoadText.Instance.Label_Net_UnReachable, MessageShowType.TwoButton, + LoadStyle.StyleEnum.Style_Retry, + GetStaticVersion().Forget, + () => { ChangeState(procedureOwner); }); + } + UILoadMgr.Show(UIDefine.UILoadUpdate, LoadText.Instance.Label_RequestVersionIng); + + // 用户尝试更新静态版本。 + GetStaticVersion().Forget(); + } + + /// + /// 向用户尝试更新静态版本。 + /// + private async UniTaskVoid GetStaticVersion() + { + await UniTask.Delay(TimeSpan.FromSeconds(0.5f)); + + var operation = GameModule.Resource.UpdatePackageVersionAsync(); + + await operation.ToUniTask(); + + if (operation.Status == EOperationStatus.Succeed) + { + //线上最新版本operation.PackageVersion + GameModule.Resource.PackageVersion = operation.PackageVersion; + + ChangeState(_procedureOwner); + } + else + { + Log.Error(operation.Error); + + UILoadTip.ShowMessageBox($"用户尝试更新静态版本失败!点击确认重试 \n \n 原因{operation.Error}", MessageShowType.TwoButton, + LoadStyle.StyleEnum.Style_Retry + , () => { ChangeState(_procedureOwner); }, UnityEngine.Application.Quit); + } + } + } +} \ No newline at end of file diff --git a/Assets/GameScripts/Main/Procedure/ProcedureUpdateVersion.cs.meta b/Assets/GameScripts/Main/Procedure/ProcedureUpdateVersion.cs.meta new file mode 100644 index 00000000..f29a92a0 --- /dev/null +++ b/Assets/GameScripts/Main/Procedure/ProcedureUpdateVersion.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6f0ff5df84e44adcb8064f46662a1b10 +timeCreated: 1665651883 \ No newline at end of file