初始化仓库
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 584905d0498e8ef4e8ca565415c454a9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
namespace Procedure
|
||||
{
|
||||
public abstract class ProcedureBase : GameFramework.Procedure.ProcedureBase
|
||||
{
|
||||
// 获取流程是否使用原生对话框
|
||||
// 在一些特殊的流程(如游戏逻辑对话框资源更新完成前的流程)中,可以考虑调用原生对话框进行消息提示行为
|
||||
public abstract bool UseNativeDialog
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 531a832bf8dfd734395de52f4141082f
|
||||
timeCreated: 1528026158
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,151 @@
|
||||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using GameFramework.DataTable;
|
||||
using GameFramework.Event;
|
||||
using Scene;
|
||||
using StarForce;
|
||||
using UnityGameFramework.Runtime;
|
||||
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
|
||||
|
||||
namespace Procedure
|
||||
{
|
||||
public class ProcedureChangeScene : ProcedureBase
|
||||
{
|
||||
private int _nextSceneId = 0;
|
||||
private bool _isChangeSceneComplete = false;
|
||||
private int _backgroundMusicId = 0;
|
||||
|
||||
public override bool UseNativeDialog => false;
|
||||
|
||||
protected override void OnEnter(ProcedureOwner procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
_isChangeSceneComplete = false;
|
||||
|
||||
GameEntry.Event.Subscribe(LoadSceneSuccessEventArgs.EventId, OnLoadSceneSuccess);
|
||||
GameEntry.Event.Subscribe(LoadSceneFailureEventArgs.EventId, OnLoadSceneFailure);
|
||||
GameEntry.Event.Subscribe(LoadSceneUpdateEventArgs.EventId, OnLoadSceneUpdate);
|
||||
GameEntry.Event.Subscribe(LoadSceneDependencyAssetEventArgs.EventId, OnLoadSceneDependencyAsset);
|
||||
|
||||
// 停止所有声音
|
||||
GameEntry.Sound.StopAllLoadingSounds();
|
||||
GameEntry.Sound.StopAllLoadedSounds();
|
||||
|
||||
// 隐藏所有实体
|
||||
GameEntry.Entity.HideAllLoadingEntities();
|
||||
GameEntry.Entity.HideAllLoadedEntities();
|
||||
|
||||
// 卸载所有场景
|
||||
string[] loadedSceneAssetNames = GameEntry.Scene.GetLoadedSceneAssetNames();
|
||||
for (int i = 0; i < loadedSceneAssetNames.Length; i++)
|
||||
{
|
||||
GameEntry.Scene.UnloadScene(loadedSceneAssetNames[i]);
|
||||
}
|
||||
|
||||
// 还原游戏速度
|
||||
GameEntry.Base.ResetNormalGameSpeed();
|
||||
|
||||
_nextSceneId = procedureOwner.GetData<VarInt32>("NextSceneId");
|
||||
|
||||
IDataTable<DRScene> dtScene = GameEntry.DataTable.GetDataTable<DRScene>();
|
||||
DRScene drScene = dtScene.GetDataRow(_nextSceneId);
|
||||
if (drScene == null)
|
||||
{
|
||||
Log.Warning("Can not load scene '{0}' from data table.", _nextSceneId.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Scene.LoadScene(AssetUtility.GetSceneAsset(drScene.AssetName), Constant.AssetPriority.SceneAsset, this);
|
||||
_backgroundMusicId = drScene.BackgroundMusicId;
|
||||
}
|
||||
|
||||
protected override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
|
||||
{
|
||||
GameEntry.Event.Unsubscribe(LoadSceneSuccessEventArgs.EventId, OnLoadSceneSuccess);
|
||||
GameEntry.Event.Unsubscribe(LoadSceneFailureEventArgs.EventId, OnLoadSceneFailure);
|
||||
GameEntry.Event.Unsubscribe(LoadSceneUpdateEventArgs.EventId, OnLoadSceneUpdate);
|
||||
GameEntry.Event.Unsubscribe(LoadSceneDependencyAssetEventArgs.EventId, OnLoadSceneDependencyAsset);
|
||||
|
||||
base.OnLeave(procedureOwner, isShutdown);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
if (!_isChangeSceneComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SceneId sceneId = (SceneId)_nextSceneId;
|
||||
switch (sceneId)
|
||||
{
|
||||
case SceneId.GameplayA:
|
||||
ChangeState<ProcedureCombine>(procedureOwner);
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.Debug($"Scene {sceneId.ToString()} don't configure a procedure");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLoadSceneSuccess(object sender, GameEventArgs e)
|
||||
{
|
||||
LoadSceneSuccessEventArgs ne = (LoadSceneSuccessEventArgs)e;
|
||||
if (ne.UserData != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Info("Load scene '{0}' OK.", ne.SceneAssetName);
|
||||
|
||||
if (_backgroundMusicId > 0)
|
||||
{
|
||||
GameEntry.Sound.PlayMusic(_backgroundMusicId);
|
||||
}
|
||||
|
||||
_isChangeSceneComplete = true;
|
||||
}
|
||||
|
||||
private void OnLoadSceneFailure(object sender, GameEventArgs e)
|
||||
{
|
||||
LoadSceneFailureEventArgs ne = (LoadSceneFailureEventArgs)e;
|
||||
if (ne.UserData != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Error("Load scene '{0}' failure, error message '{1}'.", ne.SceneAssetName, ne.ErrorMessage);
|
||||
}
|
||||
|
||||
private void OnLoadSceneUpdate(object sender, GameEventArgs e)
|
||||
{
|
||||
LoadSceneUpdateEventArgs ne = (LoadSceneUpdateEventArgs)e;
|
||||
if (ne.UserData != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Info("Load scene '{0}' update, progress '{1}'.", ne.SceneAssetName, ne.Progress.ToString("P2"));
|
||||
}
|
||||
|
||||
private void OnLoadSceneDependencyAsset(object sender, GameEventArgs e)
|
||||
{
|
||||
LoadSceneDependencyAssetEventArgs ne = (LoadSceneDependencyAssetEventArgs)e;
|
||||
if (ne.UserData != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Info("Load scene '{0}' dependency asset '{1}', count '{2}/{3}'.", ne.SceneAssetName, ne.DependencyAssetName, ne.LoadedCount.ToString(), ne.TotalCount.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c40f93285f4afc949bb907e33a909042
|
||||
timeCreated: 1528026158
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,57 @@
|
||||
using UnityGameFramework.Runtime;
|
||||
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
|
||||
|
||||
namespace Procedure
|
||||
{
|
||||
public class ProcedureCheckResources : ProcedureBase
|
||||
{
|
||||
private bool m_CheckResourcesComplete = false;
|
||||
private bool m_NeedUpdateResources = false;
|
||||
private int m_UpdateResourceCount = 0;
|
||||
private long m_UpdateResourceTotalCompressedLength = 0L;
|
||||
|
||||
public override bool UseNativeDialog => true;
|
||||
|
||||
protected override void OnEnter(ProcedureOwner procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
m_CheckResourcesComplete = false;
|
||||
m_NeedUpdateResources = false;
|
||||
m_UpdateResourceCount = 0;
|
||||
m_UpdateResourceTotalCompressedLength = 0L;
|
||||
|
||||
GameEntry.Resource.CheckResources(OnCheckResourcesComplete);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
if (!m_CheckResourcesComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_NeedUpdateResources)
|
||||
{
|
||||
procedureOwner.SetData<VarInt32>("UpdateResourceCount", m_UpdateResourceCount);
|
||||
procedureOwner.SetData<VarInt64>("UpdateResourceTotalCompressedLength", m_UpdateResourceTotalCompressedLength);
|
||||
ChangeState<ProcedureUpdateResources>(procedureOwner);
|
||||
}
|
||||
else
|
||||
{
|
||||
ChangeState<ProcedurePreload>(procedureOwner);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCheckResourcesComplete(int movedCount, int removedCount, int updateCount, long updateTotalLength, long updateTotalCompressedLength)
|
||||
{
|
||||
m_CheckResourcesComplete = true;
|
||||
m_NeedUpdateResources = updateCount > 0;
|
||||
m_UpdateResourceCount = updateCount;
|
||||
m_UpdateResourceTotalCompressedLength = updateTotalCompressedLength;
|
||||
Log.Info("Check resources complete, '{0}' resources need to update, compressed length is '{1}', uncompressed length is '{2}'.", updateCount.ToString(), updateTotalCompressedLength.ToString(), updateTotalLength.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44ab7d7cd1160a64ca7b3ca50e89f0a3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,169 @@
|
||||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using GameFramework;
|
||||
using GameFramework.Event;
|
||||
using GameFramework.Resource;
|
||||
using StarForce;
|
||||
using UI;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
|
||||
|
||||
namespace Procedure
|
||||
{
|
||||
public class ProcedureCheckVersion : ProcedureBase
|
||||
{
|
||||
private bool m_CheckVersionComplete = false;
|
||||
private bool m_NeedUpdateVersion = false;
|
||||
private VersionInfo m_VersionInfo = null;
|
||||
|
||||
public override bool UseNativeDialog => true;
|
||||
|
||||
protected override void OnEnter(ProcedureOwner procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
m_CheckVersionComplete = false;
|
||||
m_NeedUpdateVersion = false;
|
||||
m_VersionInfo = null;
|
||||
|
||||
GameEntry.Event.Subscribe(WebRequestSuccessEventArgs.EventId, OnWebRequestSuccess);
|
||||
GameEntry.Event.Subscribe(WebRequestFailureEventArgs.EventId, OnWebRequestFailure);
|
||||
|
||||
// 向服务器请求版本信息
|
||||
GameEntry.WebRequest.AddWebRequest(Utility.Text.Format(GameEntry.BuiltinData.BuildInfo.CheckVersionUrl, GetPlatformPath()), this);
|
||||
}
|
||||
|
||||
protected override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
|
||||
{
|
||||
GameEntry.Event.Unsubscribe(WebRequestSuccessEventArgs.EventId, OnWebRequestSuccess);
|
||||
GameEntry.Event.Unsubscribe(WebRequestFailureEventArgs.EventId, OnWebRequestFailure);
|
||||
|
||||
base.OnLeave(procedureOwner, isShutdown);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
if (!m_CheckVersionComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_NeedUpdateVersion)
|
||||
{
|
||||
procedureOwner.SetData<VarInt32>("VersionListLength", m_VersionInfo.VersionListLength);
|
||||
procedureOwner.SetData<VarInt32>("VersionListHashCode", m_VersionInfo.VersionListHashCode);
|
||||
procedureOwner.SetData<VarInt32>("VersionListCompressedLength", m_VersionInfo.VersionListCompressedLength);
|
||||
procedureOwner.SetData<VarInt32>("VersionListCompressedHashCode", m_VersionInfo.VersionListCompressedHashCode);
|
||||
ChangeState<ProcedureUpdateVersion>(procedureOwner);
|
||||
}
|
||||
else
|
||||
{
|
||||
ChangeState<ProcedureVerifyResources>(procedureOwner);
|
||||
}
|
||||
}
|
||||
|
||||
private void GotoUpdateApp(object userData)
|
||||
{
|
||||
string url = null;
|
||||
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
|
||||
url = GameEntry.BuiltinData.BuildInfo.WindowsAppUrl;
|
||||
#elif UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
|
||||
url = GameEntry.BuiltinData.BuildInfo.MacOSAppUrl;
|
||||
#elif UNITY_IOS
|
||||
url = GameEntry.BuiltinData.BuildInfo.IOSAppUrl;
|
||||
#elif UNITY_ANDROID
|
||||
url = GameEntry.BuiltinData.BuildInfo.AndroidAppUrl;
|
||||
#endif
|
||||
if (!string.IsNullOrEmpty(url))
|
||||
{
|
||||
Application.OpenURL(url);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWebRequestSuccess(object sender, GameEventArgs e)
|
||||
{
|
||||
WebRequestSuccessEventArgs ne = (WebRequestSuccessEventArgs)e;
|
||||
if (ne.UserData != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 解析版本信息
|
||||
byte[] versionInfoBytes = ne.GetWebResponseBytes();
|
||||
string versionInfoString = Utility.Converter.GetString(versionInfoBytes);
|
||||
m_VersionInfo = Utility.Json.ToObject<VersionInfo>(versionInfoString);
|
||||
if (m_VersionInfo == null)
|
||||
{
|
||||
Log.Error("Parse VersionInfo failure.");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Info("Latest game version is '{0} ({1})', local game version is '{2} ({3})'.", m_VersionInfo.LatestGameVersion, m_VersionInfo.InternalGameVersion.ToString(), Version.GameVersion, Version.InternalGameVersion.ToString());
|
||||
|
||||
if (m_VersionInfo.ForceUpdateGame)
|
||||
{
|
||||
// 需要强制更新游戏应用
|
||||
GameEntry.UI.OpenDialog(new DialogParams
|
||||
{
|
||||
Mode = 2,
|
||||
Title = GameEntry.Localization.GetString("ForceUpdate.Title"),
|
||||
Message = GameEntry.Localization.GetString("ForceUpdate.Message"),
|
||||
ConfirmText = GameEntry.Localization.GetString("ForceUpdate.UpdateButton"),
|
||||
OnClickConfirm = GotoUpdateApp,
|
||||
CancelText = GameEntry.Localization.GetString("ForceUpdate.QuitButton"),
|
||||
OnClickCancel = delegate (object userData) { UnityGameFramework.Runtime.GameEntry.Shutdown(ShutdownType.Quit); },
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置资源更新下载地址
|
||||
GameEntry.Resource.UpdatePrefixUri = Utility.Path.GetRegularPath(m_VersionInfo.UpdatePrefixUri);
|
||||
|
||||
m_CheckVersionComplete = true;
|
||||
m_NeedUpdateVersion = GameEntry.Resource.CheckVersionList(m_VersionInfo.InternalResourceVersion) == CheckVersionListResult.NeedUpdate;
|
||||
}
|
||||
|
||||
private void OnWebRequestFailure(object sender, GameEventArgs e)
|
||||
{
|
||||
WebRequestFailureEventArgs ne = (WebRequestFailureEventArgs)e;
|
||||
if (ne.UserData != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Warning("Check version failure, error message is '{0}'.", ne.ErrorMessage);
|
||||
}
|
||||
|
||||
private string GetPlatformPath()
|
||||
{
|
||||
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";
|
||||
|
||||
default:
|
||||
throw new System.NotSupportedException(Utility.Text.Format("Platform '{0}' is not supported.", Application.platform));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05e2f8f675c85954b808765c1f046d70
|
||||
timeCreated: 1528026158
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using UnityGameFramework.Runtime;
|
||||
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
|
||||
|
||||
namespace Procedure
|
||||
{
|
||||
public class ProcedureInitResources : ProcedureBase
|
||||
{
|
||||
private bool m_InitResourcesComplete = false;
|
||||
|
||||
public override bool UseNativeDialog => true;
|
||||
|
||||
protected override void OnEnter(ProcedureOwner procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
m_InitResourcesComplete = false;
|
||||
|
||||
// 注意:使用单机模式并初始化资源前,需要先构建 AssetBundle 并复制到 StreamingAssets 中,否则会产生 HTTP 404 错误
|
||||
GameEntry.Resource.InitResources(OnInitResourcesComplete);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
if (!m_InitResourcesComplete)
|
||||
{
|
||||
// 初始化资源未完成则继续等待
|
||||
return;
|
||||
}
|
||||
|
||||
ChangeState<ProcedurePreload>(procedureOwner);
|
||||
}
|
||||
|
||||
private void OnInitResourcesComplete()
|
||||
{
|
||||
m_InitResourcesComplete = true;
|
||||
Log.Info("Init resources complete.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 101da8cb17234f84f9746066a5f41397
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,133 @@
|
||||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using GameFramework.Localization;
|
||||
using System;
|
||||
using StarForce;
|
||||
using UnityGameFramework.Runtime;
|
||||
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
|
||||
|
||||
namespace Procedure
|
||||
{
|
||||
public class ProcedureLaunch : ProcedureBase
|
||||
{
|
||||
public override bool UseNativeDialog => true;
|
||||
|
||||
protected override void OnEnter(ProcedureOwner procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
// 构建信息:发布版本时,把一些数据以 Json 的格式写入 Assets/GameMain/Configs/BuildInfo.txt,供游戏逻辑读取
|
||||
GameEntry.BuiltinData.InitBuildInfo();
|
||||
|
||||
// 语言配置:设置当前使用的语言,如果不设置,则默认使用操作系统语言
|
||||
InitLanguageSettings();
|
||||
|
||||
// 变体配置:根据使用的语言,通知底层加载对应的资源变体
|
||||
InitCurrentVariant();
|
||||
|
||||
// 声音配置:根据用户配置数据,设置即将使用的声音选项
|
||||
InitSoundSettings();
|
||||
|
||||
// 默认字典:加载默认字典文件 Assets/GameMain/Configs/DefaultDictionary.xml
|
||||
// 此字典文件记录了资源更新前使用的各种语言的字符串,会随 App 一起发布,故不可更新
|
||||
GameEntry.BuiltinData.InitDefaultDictionary();
|
||||
}
|
||||
|
||||
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
// 运行一帧即切换到 Splash 展示流程
|
||||
ChangeState<ProcedureSplash>(procedureOwner);
|
||||
}
|
||||
|
||||
private void InitLanguageSettings()
|
||||
{
|
||||
if (GameEntry.Base.EditorResourceMode && GameEntry.Base.EditorLanguage != Language.Unspecified)
|
||||
{
|
||||
// 编辑器资源模式直接使用 Inspector 上设置的语言
|
||||
return;
|
||||
}
|
||||
|
||||
Language language = GameEntry.Localization.Language;
|
||||
if (GameEntry.Setting.HasSetting(Constant.Setting.Language))
|
||||
{
|
||||
try
|
||||
{
|
||||
string languageString = GameEntry.Setting.GetString(Constant.Setting.Language);
|
||||
language = (Language)Enum.Parse(typeof(Language), languageString);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (language != Language.English
|
||||
&& language != Language.ChineseSimplified
|
||||
&& language != Language.ChineseTraditional
|
||||
&& language != Language.Korean)
|
||||
{
|
||||
// 若是暂不支持的语言,则使用英语
|
||||
language = Language.English;
|
||||
|
||||
GameEntry.Setting.SetString(Constant.Setting.Language, language.ToString());
|
||||
GameEntry.Setting.Save();
|
||||
}
|
||||
|
||||
GameEntry.Localization.Language = language;
|
||||
Log.Info("Init language settings complete, current language is '{0}'.", language.ToString());
|
||||
}
|
||||
|
||||
private void InitCurrentVariant()
|
||||
{
|
||||
if (GameEntry.Base.EditorResourceMode)
|
||||
{
|
||||
// 编辑器资源模式不使用 AssetBundle,也就没有变体了
|
||||
return;
|
||||
}
|
||||
|
||||
string currentVariant = null;
|
||||
switch (GameEntry.Localization.Language)
|
||||
{
|
||||
case Language.English:
|
||||
currentVariant = "en-us";
|
||||
break;
|
||||
|
||||
case Language.ChineseSimplified:
|
||||
currentVariant = "zh-cn";
|
||||
break;
|
||||
|
||||
case Language.ChineseTraditional:
|
||||
currentVariant = "zh-tw";
|
||||
break;
|
||||
|
||||
case Language.Korean:
|
||||
currentVariant = "ko-kr";
|
||||
break;
|
||||
|
||||
default:
|
||||
currentVariant = "zh-cn";
|
||||
break;
|
||||
}
|
||||
|
||||
GameEntry.Resource.SetCurrentVariant(currentVariant);
|
||||
Log.Info("Init current variant complete.");
|
||||
}
|
||||
|
||||
private void InitSoundSettings()
|
||||
{
|
||||
GameEntry.Sound.Mute("Music", GameEntry.Setting.GetBool(Constant.Setting.MusicMuted, false));
|
||||
GameEntry.Sound.SetVolume("Music", GameEntry.Setting.GetFloat(Constant.Setting.MusicVolume, 0.3f));
|
||||
GameEntry.Sound.Mute("Sound", GameEntry.Setting.GetBool(Constant.Setting.SoundMuted, false));
|
||||
GameEntry.Sound.SetVolume("Sound", GameEntry.Setting.GetFloat(Constant.Setting.SoundVolume, 1f));
|
||||
GameEntry.Sound.Mute("UISound", GameEntry.Setting.GetBool(Constant.Setting.UISoundMuted, false));
|
||||
GameEntry.Sound.SetVolume("UISound", GameEntry.Setting.GetFloat(Constant.Setting.UISoundVolume, 1f));
|
||||
Log.Info("Init sound settings complete.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6c3d65d0c3a2104383e82700116b3d1
|
||||
timeCreated: 1528026159
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,224 @@
|
||||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using GameFramework;
|
||||
using GameFramework.Event;
|
||||
using GameFramework.Resource;
|
||||
using System.Collections.Generic;
|
||||
using StarForce;
|
||||
using TMPro;
|
||||
using UI;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
|
||||
|
||||
namespace Procedure
|
||||
{
|
||||
public class ProcedurePreload : ProcedureBase
|
||||
{
|
||||
public static readonly string[] DataTableNames = new string[]
|
||||
{
|
||||
"Entity",
|
||||
"Music",
|
||||
"Scene",
|
||||
"Sound",
|
||||
"UIForm",
|
||||
"UISound",
|
||||
};
|
||||
|
||||
private Dictionary<string, bool> _loadedFlag = new Dictionary<string, bool>();
|
||||
|
||||
public override bool UseNativeDialog => true;
|
||||
|
||||
protected override void OnEnter(ProcedureOwner procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
GameEntry.Event.Subscribe(LoadConfigSuccessEventArgs.EventId, OnLoadConfigSuccess);
|
||||
GameEntry.Event.Subscribe(LoadConfigFailureEventArgs.EventId, OnLoadConfigFailure);
|
||||
GameEntry.Event.Subscribe(LoadDataTableSuccessEventArgs.EventId, OnLoadDataTableSuccess);
|
||||
GameEntry.Event.Subscribe(LoadDataTableFailureEventArgs.EventId, OnLoadDataTableFailure);
|
||||
GameEntry.Event.Subscribe(LoadDictionarySuccessEventArgs.EventId, OnLoadDictionarySuccess);
|
||||
GameEntry.Event.Subscribe(LoadDictionaryFailureEventArgs.EventId, OnLoadDictionaryFailure);
|
||||
|
||||
_loadedFlag.Clear();
|
||||
|
||||
PreloadResources();
|
||||
}
|
||||
|
||||
protected override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
|
||||
{
|
||||
GameEntry.Event.Unsubscribe(LoadConfigSuccessEventArgs.EventId, OnLoadConfigSuccess);
|
||||
GameEntry.Event.Unsubscribe(LoadConfigFailureEventArgs.EventId, OnLoadConfigFailure);
|
||||
GameEntry.Event.Unsubscribe(LoadDataTableSuccessEventArgs.EventId, OnLoadDataTableSuccess);
|
||||
GameEntry.Event.Unsubscribe(LoadDataTableFailureEventArgs.EventId, OnLoadDataTableFailure);
|
||||
GameEntry.Event.Unsubscribe(LoadDictionarySuccessEventArgs.EventId, OnLoadDictionarySuccess);
|
||||
GameEntry.Event.Unsubscribe(LoadDictionaryFailureEventArgs.EventId, OnLoadDictionaryFailure);
|
||||
|
||||
base.OnLeave(procedureOwner, isShutdown);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
foreach (KeyValuePair<string, bool> loadedFlag in _loadedFlag)
|
||||
{
|
||||
if (!loadedFlag.Value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
procedureOwner.SetData<VarInt32>("NextSceneId", GameEntry.Config.GetInt("Scene.GameplayA"));
|
||||
ChangeState<ProcedureChangeScene>(procedureOwner);
|
||||
}
|
||||
|
||||
private void PreloadResources()
|
||||
{
|
||||
// Preload configs
|
||||
LoadConfig("DefaultConfig");
|
||||
|
||||
// Preload data tables
|
||||
foreach (string dataTableName in DataTableNames)
|
||||
{
|
||||
LoadDataTable(dataTableName);
|
||||
}
|
||||
|
||||
// Preload dictionaries
|
||||
LoadDictionary("Default");
|
||||
|
||||
// Preload fonts
|
||||
LoadFont("MainFont");
|
||||
LoadTMPFont("MainTMPFont");
|
||||
}
|
||||
|
||||
private void LoadConfig(string configName)
|
||||
{
|
||||
string configAssetName = AssetUtility.GetConfigAsset(configName, false);
|
||||
_loadedFlag.Add(configAssetName, false);
|
||||
GameEntry.Config.ReadData(configAssetName, this);
|
||||
}
|
||||
|
||||
private void LoadDataTable(string dataTableName)
|
||||
{
|
||||
string dataTableAssetName = AssetUtility.GetDataTableAsset(dataTableName, false);
|
||||
_loadedFlag.Add(dataTableAssetName, false);
|
||||
GameEntry.DataTable.LoadDataTable(dataTableName, dataTableAssetName, this);
|
||||
}
|
||||
|
||||
private void LoadDictionary(string dictionaryName)
|
||||
{
|
||||
string dictionaryAssetName = AssetUtility.GetDictionaryAsset(dictionaryName, false);
|
||||
_loadedFlag.Add(dictionaryAssetName, false);
|
||||
GameEntry.Localization.ReadData(dictionaryAssetName, this);
|
||||
}
|
||||
|
||||
private void LoadFont(string fontName)
|
||||
{
|
||||
_loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false);
|
||||
GameEntry.Resource.LoadAsset(AssetUtility.GetFontAsset(fontName), Constant.AssetPriority.FontAsset, new LoadAssetCallbacks(
|
||||
(assetName, asset, duration, userData) =>
|
||||
{
|
||||
_loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true;
|
||||
UGuiForm.SetMainFont((Font)asset);
|
||||
Log.Info("Load font '{0}' OK.", fontName);
|
||||
},
|
||||
|
||||
(assetName, status, errorMessage, userData) =>
|
||||
{
|
||||
Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName, errorMessage);
|
||||
}));
|
||||
}
|
||||
|
||||
private void LoadTMPFont(string fontName)
|
||||
{
|
||||
_loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false);
|
||||
GameEntry.Resource.LoadAsset(AssetUtility.GetTMPFontAsset(fontName), Constant.AssetPriority.FontAsset, new LoadAssetCallbacks(
|
||||
(assetName, asset, duration, userData) =>
|
||||
{
|
||||
_loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true;
|
||||
UGuiForm.SetMainTMPFont((TMP_FontAsset)asset);
|
||||
Log.Info("Load font '{0}' OK.", fontName);
|
||||
},
|
||||
|
||||
(assetName, status, errorMessage, userData) =>
|
||||
{
|
||||
Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName, errorMessage);
|
||||
}));
|
||||
}
|
||||
|
||||
private void OnLoadConfigSuccess(object sender, GameEventArgs e)
|
||||
{
|
||||
LoadConfigSuccessEventArgs ne = (LoadConfigSuccessEventArgs)e;
|
||||
if (ne.UserData != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_loadedFlag[ne.ConfigAssetName] = true;
|
||||
Log.Info("Load config '{0}' OK.", ne.ConfigAssetName);
|
||||
}
|
||||
|
||||
private void OnLoadConfigFailure(object sender, GameEventArgs e)
|
||||
{
|
||||
LoadConfigFailureEventArgs ne = (LoadConfigFailureEventArgs)e;
|
||||
if (ne.UserData != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Error("Can not load config '{0}' from '{1}' with error message '{2}'.", ne.ConfigAssetName, ne.ConfigAssetName, ne.ErrorMessage);
|
||||
}
|
||||
|
||||
private void OnLoadDataTableSuccess(object sender, GameEventArgs e)
|
||||
{
|
||||
LoadDataTableSuccessEventArgs ne = (LoadDataTableSuccessEventArgs)e;
|
||||
if (ne.UserData != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_loadedFlag[ne.DataTableAssetName] = true;
|
||||
Log.Info("Load data table '{0}' OK.", ne.DataTableAssetName);
|
||||
}
|
||||
|
||||
private void OnLoadDataTableFailure(object sender, GameEventArgs e)
|
||||
{
|
||||
LoadDataTableFailureEventArgs ne = (LoadDataTableFailureEventArgs)e;
|
||||
if (ne.UserData != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Error("Can not load data table '{0}' from '{1}' with error message '{2}'.", ne.DataTableAssetName, ne.DataTableAssetName, ne.ErrorMessage);
|
||||
}
|
||||
|
||||
private void OnLoadDictionarySuccess(object sender, GameEventArgs e)
|
||||
{
|
||||
LoadDictionarySuccessEventArgs ne = (LoadDictionarySuccessEventArgs)e;
|
||||
if (ne.UserData != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_loadedFlag[ne.DictionaryAssetName] = true;
|
||||
Log.Info("Load dictionary '{0}' OK.", ne.DictionaryAssetName);
|
||||
}
|
||||
|
||||
private void OnLoadDictionaryFailure(object sender, GameEventArgs e)
|
||||
{
|
||||
LoadDictionaryFailureEventArgs ne = (LoadDictionaryFailureEventArgs)e;
|
||||
if (ne.UserData != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Error("Can not load dictionary '{0}' from '{1}' with error message '{2}'.", ne.DictionaryAssetName, ne.DictionaryAssetName, ne.ErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5733d8991f6bbf8409de2830c6c67b9b
|
||||
timeCreated: 1528026159
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,45 @@
|
||||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using GameFramework.Resource;
|
||||
using UnityGameFramework.Runtime;
|
||||
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
|
||||
|
||||
namespace Procedure
|
||||
{
|
||||
public class ProcedureSplash : ProcedureBase
|
||||
{
|
||||
public override bool UseNativeDialog => true;
|
||||
|
||||
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
// TODO: 这里可以播放一个 Splash 动画
|
||||
// ...
|
||||
|
||||
if (GameEntry.Base.EditorResourceMode)
|
||||
{
|
||||
// 编辑器模式
|
||||
Log.Info("Editor resource mode detected.");
|
||||
ChangeState<ProcedurePreload>(procedureOwner);
|
||||
}
|
||||
else if (GameEntry.Resource.ResourceMode == ResourceMode.Package)
|
||||
{
|
||||
// 单机模式
|
||||
Log.Info("Package resource mode detected.");
|
||||
ChangeState<ProcedureInitResources>(procedureOwner);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 可更新模式
|
||||
Log.Info("Updatable resource mode detected.");
|
||||
ChangeState<ProcedureCheckVersion>(procedureOwner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 139ec26f4972a8147a39d4bb34d5fcaa
|
||||
timeCreated: 1528026159
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,270 @@
|
||||
using GameFramework;
|
||||
using GameFramework.Event;
|
||||
using System.Collections.Generic;
|
||||
using StarForce;
|
||||
using UI;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
|
||||
|
||||
namespace Procedure
|
||||
{
|
||||
public class ProcedureUpdateResources : ProcedureBase
|
||||
{
|
||||
private bool m_UpdateResourcesComplete = false;
|
||||
private int m_UpdateCount = 0;
|
||||
private long m_UpdateTotalCompressedLength = 0L;
|
||||
private int m_UpdateSuccessCount = 0;
|
||||
private List<UpdateLengthData> m_UpdateLengthData = new List<UpdateLengthData>();
|
||||
private UpdateResourceForm m_UpdateResourceForm = null;
|
||||
|
||||
public override bool UseNativeDialog
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnEnter(ProcedureOwner procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
m_UpdateResourcesComplete = false;
|
||||
m_UpdateCount = procedureOwner.GetData<VarInt32>("UpdateResourceCount");
|
||||
procedureOwner.RemoveData("UpdateResourceCount");
|
||||
m_UpdateTotalCompressedLength = procedureOwner.GetData<VarInt64>("UpdateResourceTotalCompressedLength");
|
||||
procedureOwner.RemoveData("UpdateResourceTotalCompressedLength");
|
||||
m_UpdateSuccessCount = 0;
|
||||
m_UpdateLengthData.Clear();
|
||||
m_UpdateResourceForm = null;
|
||||
|
||||
GameEntry.Event.Subscribe(ResourceUpdateStartEventArgs.EventId, OnResourceUpdateStart);
|
||||
GameEntry.Event.Subscribe(ResourceUpdateChangedEventArgs.EventId, OnResourceUpdateChanged);
|
||||
GameEntry.Event.Subscribe(ResourceUpdateSuccessEventArgs.EventId, OnResourceUpdateSuccess);
|
||||
GameEntry.Event.Subscribe(ResourceUpdateFailureEventArgs.EventId, OnResourceUpdateFailure);
|
||||
|
||||
if (Application.internetReachability == NetworkReachability.ReachableViaCarrierDataNetwork)
|
||||
{
|
||||
GameEntry.UI.OpenDialog(new DialogParams
|
||||
{
|
||||
Mode = 2,
|
||||
Title = GameEntry.Localization.GetString("UpdateResourceViaCarrierDataNetwork.Title"),
|
||||
Message = GameEntry.Localization.GetString("UpdateResourceViaCarrierDataNetwork.Message"),
|
||||
ConfirmText = GameEntry.Localization.GetString("UpdateResourceViaCarrierDataNetwork.UpdateButton"),
|
||||
OnClickConfirm = StartUpdateResources,
|
||||
CancelText = GameEntry.Localization.GetString("UpdateResourceViaCarrierDataNetwork.QuitButton"),
|
||||
OnClickCancel = delegate (object userData) { UnityGameFramework.Runtime.GameEntry.Shutdown(ShutdownType.Quit); },
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
StartUpdateResources(null);
|
||||
}
|
||||
|
||||
protected override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
|
||||
{
|
||||
if (m_UpdateResourceForm != null)
|
||||
{
|
||||
Object.Destroy(m_UpdateResourceForm.gameObject);
|
||||
m_UpdateResourceForm = null;
|
||||
}
|
||||
|
||||
GameEntry.Event.Unsubscribe(ResourceUpdateStartEventArgs.EventId, OnResourceUpdateStart);
|
||||
GameEntry.Event.Unsubscribe(ResourceUpdateChangedEventArgs.EventId, OnResourceUpdateChanged);
|
||||
GameEntry.Event.Unsubscribe(ResourceUpdateSuccessEventArgs.EventId, OnResourceUpdateSuccess);
|
||||
GameEntry.Event.Unsubscribe(ResourceUpdateFailureEventArgs.EventId, OnResourceUpdateFailure);
|
||||
|
||||
base.OnLeave(procedureOwner, isShutdown);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
if (!m_UpdateResourcesComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChangeState<ProcedurePreload>(procedureOwner);
|
||||
}
|
||||
|
||||
private void StartUpdateResources(object userData)
|
||||
{
|
||||
if (m_UpdateResourceForm == null)
|
||||
{
|
||||
m_UpdateResourceForm = Object.Instantiate(GameEntry.BuiltinData.UpdateResourceFormTemplate);
|
||||
}
|
||||
|
||||
Log.Info("Start update resources...");
|
||||
GameEntry.Resource.UpdateResources(OnUpdateResourcesComplete);
|
||||
}
|
||||
|
||||
private void RefreshProgress()
|
||||
{
|
||||
long currentTotalUpdateLength = 0L;
|
||||
for (int i = 0; i < m_UpdateLengthData.Count; i++)
|
||||
{
|
||||
currentTotalUpdateLength += m_UpdateLengthData[i].Length;
|
||||
}
|
||||
|
||||
float progressTotal = (float)currentTotalUpdateLength / m_UpdateTotalCompressedLength;
|
||||
string descriptionText = GameEntry.Localization.GetString("UpdateResource.Tips", m_UpdateSuccessCount.ToString(), m_UpdateCount.ToString(), GetByteLengthString(currentTotalUpdateLength), GetByteLengthString(m_UpdateTotalCompressedLength), progressTotal, GetByteLengthString((int)GameEntry.Download.CurrentSpeed));
|
||||
m_UpdateResourceForm.SetProgress(progressTotal, descriptionText);
|
||||
}
|
||||
|
||||
private string GetByteLengthString(long byteLength)
|
||||
{
|
||||
if (byteLength < 1024L) // 2 ^ 10
|
||||
{
|
||||
return Utility.Text.Format("{0} Bytes", byteLength);
|
||||
}
|
||||
|
||||
if (byteLength < 1048576L) // 2 ^ 20
|
||||
{
|
||||
return Utility.Text.Format("{0:F2} KB", byteLength / 1024f);
|
||||
}
|
||||
|
||||
if (byteLength < 1073741824L) // 2 ^ 30
|
||||
{
|
||||
return Utility.Text.Format("{0:F2} MB", byteLength / 1048576f);
|
||||
}
|
||||
|
||||
if (byteLength < 1099511627776L) // 2 ^ 40
|
||||
{
|
||||
return Utility.Text.Format("{0:F2} GB", byteLength / 1073741824f);
|
||||
}
|
||||
|
||||
if (byteLength < 1125899906842624L) // 2 ^ 50
|
||||
{
|
||||
return Utility.Text.Format("{0:F2} TB", byteLength / 1099511627776f);
|
||||
}
|
||||
|
||||
if (byteLength < 1152921504606846976L) // 2 ^ 60
|
||||
{
|
||||
return Utility.Text.Format("{0:F2} PB", byteLength / 1125899906842624f);
|
||||
}
|
||||
|
||||
return Utility.Text.Format("{0:F2} EB", byteLength / 1152921504606846976f);
|
||||
}
|
||||
|
||||
private void OnUpdateResourcesComplete(GameFramework.Resource.IResourceGroup resourceGroup, bool result)
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
m_UpdateResourcesComplete = true;
|
||||
Log.Info("Update resources complete with no errors.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("Update resources complete with errors.");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnResourceUpdateStart(object sender, GameEventArgs e)
|
||||
{
|
||||
ResourceUpdateStartEventArgs ne = (ResourceUpdateStartEventArgs)e;
|
||||
|
||||
for (int i = 0; i < m_UpdateLengthData.Count; i++)
|
||||
{
|
||||
if (m_UpdateLengthData[i].Name == ne.Name)
|
||||
{
|
||||
Log.Warning("Update resource '{0}' is invalid.", ne.Name);
|
||||
m_UpdateLengthData[i].Length = 0;
|
||||
RefreshProgress();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_UpdateLengthData.Add(new UpdateLengthData(ne.Name));
|
||||
}
|
||||
|
||||
private void OnResourceUpdateChanged(object sender, GameEventArgs e)
|
||||
{
|
||||
ResourceUpdateChangedEventArgs ne = (ResourceUpdateChangedEventArgs)e;
|
||||
|
||||
for (int i = 0; i < m_UpdateLengthData.Count; i++)
|
||||
{
|
||||
if (m_UpdateLengthData[i].Name == ne.Name)
|
||||
{
|
||||
m_UpdateLengthData[i].Length = ne.CurrentLength;
|
||||
RefreshProgress();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Log.Warning("Update resource '{0}' is invalid.", ne.Name);
|
||||
}
|
||||
|
||||
private void OnResourceUpdateSuccess(object sender, GameEventArgs e)
|
||||
{
|
||||
ResourceUpdateSuccessEventArgs ne = (ResourceUpdateSuccessEventArgs)e;
|
||||
Log.Info("Update resource '{0}' success.", ne.Name);
|
||||
|
||||
for (int i = 0; i < m_UpdateLengthData.Count; i++)
|
||||
{
|
||||
if (m_UpdateLengthData[i].Name == ne.Name)
|
||||
{
|
||||
m_UpdateLengthData[i].Length = ne.CompressedLength;
|
||||
m_UpdateSuccessCount++;
|
||||
RefreshProgress();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Log.Warning("Update resource '{0}' is invalid.", ne.Name);
|
||||
}
|
||||
|
||||
private void OnResourceUpdateFailure(object sender, GameEventArgs e)
|
||||
{
|
||||
ResourceUpdateFailureEventArgs ne = (ResourceUpdateFailureEventArgs)e;
|
||||
if (ne.RetryCount >= ne.TotalRetryCount)
|
||||
{
|
||||
Log.Error("Update resource '{0}' failure from '{1}' with error message '{2}', retry count '{3}'.", ne.Name, ne.DownloadUri, ne.ErrorMessage, ne.RetryCount.ToString());
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Info("Update resource '{0}' failure from '{1}' with error message '{2}', retry count '{3}'.", ne.Name, ne.DownloadUri, ne.ErrorMessage, ne.RetryCount.ToString());
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_UpdateLengthData.Count; i++)
|
||||
{
|
||||
if (m_UpdateLengthData[i].Name == ne.Name)
|
||||
{
|
||||
m_UpdateLengthData.Remove(m_UpdateLengthData[i]);
|
||||
RefreshProgress();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Log.Warning("Update resource '{0}' is invalid.", ne.Name);
|
||||
}
|
||||
|
||||
private class UpdateLengthData
|
||||
{
|
||||
private readonly string m_Name;
|
||||
|
||||
public UpdateLengthData(string name)
|
||||
{
|
||||
m_Name = name;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Name;
|
||||
}
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 42642b01f19746c4180a6579c098d7a9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,70 @@
|
||||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using GameFramework.Resource;
|
||||
using UnityGameFramework.Runtime;
|
||||
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
|
||||
|
||||
namespace Procedure
|
||||
{
|
||||
public class ProcedureUpdateVersion : ProcedureBase
|
||||
{
|
||||
private bool m_UpdateVersionComplete = false;
|
||||
private UpdateVersionListCallbacks m_UpdateVersionListCallbacks = null;
|
||||
|
||||
public override bool UseNativeDialog
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInit(ProcedureOwner procedureOwner)
|
||||
{
|
||||
base.OnInit(procedureOwner);
|
||||
|
||||
m_UpdateVersionListCallbacks = new UpdateVersionListCallbacks(OnUpdateVersionListSuccess, OnUpdateVersionListFailure);
|
||||
}
|
||||
|
||||
protected override void OnEnter(ProcedureOwner procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
m_UpdateVersionComplete = false;
|
||||
|
||||
GameEntry.Resource.UpdateVersionList(procedureOwner.GetData<VarInt32>("VersionListLength"), procedureOwner.GetData<VarInt32>("VersionListHashCode"), procedureOwner.GetData<VarInt32>("VersionListCompressedLength"), procedureOwner.GetData<VarInt32>("VersionListCompressedHashCode"), m_UpdateVersionListCallbacks);
|
||||
procedureOwner.RemoveData("VersionListLength");
|
||||
procedureOwner.RemoveData("VersionListHashCode");
|
||||
procedureOwner.RemoveData("VersionListCompressedLength");
|
||||
procedureOwner.RemoveData("VersionListCompressedHashCode");
|
||||
}
|
||||
|
||||
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
if (!m_UpdateVersionComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChangeState<ProcedureVerifyResources>(procedureOwner);
|
||||
}
|
||||
|
||||
private void OnUpdateVersionListSuccess(string downloadPath, string downloadUri)
|
||||
{
|
||||
m_UpdateVersionComplete = true;
|
||||
Log.Info("Update version list from '{0}' success.", downloadUri);
|
||||
}
|
||||
|
||||
private void OnUpdateVersionListFailure(string downloadUri, string errorMessage)
|
||||
{
|
||||
Log.Warning("Update version list from '{0}' failure, error message is '{1}'.", downloadUri, errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45878acf6351cb64385d78fabb8b3acc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,77 @@
|
||||
using GameFramework.Event;
|
||||
using StarForce;
|
||||
using UnityGameFramework.Runtime;
|
||||
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
|
||||
|
||||
namespace Procedure
|
||||
{
|
||||
public class ProcedureVerifyResources : ProcedureBase
|
||||
{
|
||||
private bool m_VerifyResourcesComplete = false;
|
||||
|
||||
public override bool UseNativeDialog
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnEnter(ProcedureOwner procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
GameEntry.Event.Subscribe(ResourceVerifyStartEventArgs.EventId, OnResourceVerifyStart);
|
||||
GameEntry.Event.Subscribe(ResourceVerifySuccessEventArgs.EventId, OnResourceVerifySuccess);
|
||||
GameEntry.Event.Subscribe(ResourceVerifyFailureEventArgs.EventId, OnResourceVerifyFailure);
|
||||
|
||||
m_VerifyResourcesComplete = false;
|
||||
GameEntry.Resource.VerifyResources(OnVerifyResourcesComplete);
|
||||
}
|
||||
|
||||
protected override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
|
||||
{
|
||||
base.OnLeave(procedureOwner, isShutdown);
|
||||
|
||||
GameEntry.Event.Unsubscribe(ResourceVerifyStartEventArgs.EventId, OnResourceVerifyStart);
|
||||
GameEntry.Event.Unsubscribe(ResourceVerifySuccessEventArgs.EventId, OnResourceVerifySuccess);
|
||||
GameEntry.Event.Unsubscribe(ResourceVerifyFailureEventArgs.EventId, OnResourceVerifyFailure);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
if (!m_VerifyResourcesComplete)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ChangeState<ProcedureCheckResources>(procedureOwner);
|
||||
}
|
||||
|
||||
private void OnVerifyResourcesComplete(bool result)
|
||||
{
|
||||
m_VerifyResourcesComplete = true;
|
||||
Log.Info("Verify resources complete, result is '{0}'.", result);
|
||||
}
|
||||
|
||||
private void OnResourceVerifyStart(object sender, GameEventArgs e)
|
||||
{
|
||||
ResourceVerifyStartEventArgs ne = (ResourceVerifyStartEventArgs)e;
|
||||
Log.Info("Start verify resources, verify resource count '{0}', verify resource total length '{1}'.", ne.Count, ne.TotalLength);
|
||||
}
|
||||
|
||||
private void OnResourceVerifySuccess(object sender, GameEventArgs e)
|
||||
{
|
||||
ResourceVerifySuccessEventArgs ne = (ResourceVerifySuccessEventArgs)e;
|
||||
Log.Info("Verify resource '{0}' success.", ne.Name);
|
||||
}
|
||||
|
||||
private void OnResourceVerifyFailure(object sender, GameEventArgs e)
|
||||
{
|
||||
ResourceVerifyFailureEventArgs ne = (ResourceVerifyFailureEventArgs)e;
|
||||
Log.Warning("Verify resource '{0}' failure.", ne.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ce5f594e4bf0564d992c26a44fec7c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,363 @@
|
||||
using Scene;
|
||||
using System.Collections.Generic;
|
||||
using CustomComponent;
|
||||
using Definition.Enum;
|
||||
using Event;
|
||||
using GameFramework.Event;
|
||||
using UI;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;
|
||||
|
||||
namespace Procedure
|
||||
{
|
||||
/// <summary>
|
||||
/// 斗拱拼装流程:
|
||||
/// 1. 进入流程后准备组件与事件;
|
||||
/// 2. 启动并监控拼装关卡(成功或超时);
|
||||
/// 3. 结算后短暂等待并重开场景。
|
||||
/// </summary>
|
||||
public class ProcedureCombine : ProcedureBase
|
||||
{
|
||||
#region Property
|
||||
|
||||
/// <summary>
|
||||
/// 单局超时时间(秒)。
|
||||
/// </summary>
|
||||
private const float TimeoutSeconds = 180f;
|
||||
|
||||
/// <summary>
|
||||
/// 结算后重开场景的延迟(秒)。
|
||||
/// </summary>
|
||||
private const float RestartDelaySeconds = 2f;
|
||||
|
||||
/// <summary>
|
||||
/// 统一日志前缀。
|
||||
/// </summary>
|
||||
private const string LogPrefix = "[GameplayATest]";
|
||||
|
||||
/// <summary>
|
||||
/// 当前局是否已开始。
|
||||
/// </summary>
|
||||
private bool _isStarted = false;
|
||||
|
||||
/// <summary>
|
||||
/// 当前局是否已结束。
|
||||
/// </summary>
|
||||
private bool _isFinished = false;
|
||||
|
||||
/// <summary>
|
||||
/// 当前局是否通过。
|
||||
/// </summary>
|
||||
private bool _isPassed = false;
|
||||
|
||||
/// <summary>
|
||||
/// 当前局累计耗时(秒)。
|
||||
/// </summary>
|
||||
private float _elapsed = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// 结算后的重开倒计时(秒)。
|
||||
/// </summary>
|
||||
private float _restartCountdown = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// 当前局开始时的实时时间戳。
|
||||
/// </summary>
|
||||
private float _startTimestamp = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// 拼装玩法组件入口。
|
||||
/// </summary>
|
||||
private CombineComponent _combineComponent = null;
|
||||
|
||||
/// <summary>
|
||||
/// 当前流程不使用原生对话框。
|
||||
/// </summary>
|
||||
public override bool UseNativeDialog => false;
|
||||
|
||||
#endregion
|
||||
|
||||
#region FSM
|
||||
|
||||
/// <summary>
|
||||
/// 进入流程:重置状态、订阅事件、拉取组件。
|
||||
/// </summary>
|
||||
protected override void OnEnter(ProcedureOwner procedureOwner)
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
InitializeProcedureState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 离开流程:反订阅事件、停止关卡并清理状态。
|
||||
/// </summary>
|
||||
protected override void OnLeave(ProcedureOwner procedureOwner, bool isShutdown)
|
||||
{
|
||||
ShutdownProcedureState();
|
||||
|
||||
base.OnLeave(procedureOwner, isShutdown);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 流程逐帧更新:
|
||||
/// 1. 未结算时推进关卡运行;
|
||||
/// 2. 已结算时推进重开倒计时。
|
||||
/// </summary>
|
||||
protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
|
||||
|
||||
if (TryUpdateRound(realElapseSeconds))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TryRestartScene(procedureOwner, realElapseSeconds);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Other Methods
|
||||
|
||||
/// <summary>
|
||||
/// 初始化流程级状态并订阅事件。
|
||||
/// </summary>
|
||||
private void InitializeProcedureState()
|
||||
{
|
||||
ResetRoundState();
|
||||
GameEntry.Event.Subscribe(CombineCompletedEventArgs.EventId, OnPuzzleCompleted);
|
||||
|
||||
_combineComponent = GameEntry.Combine;
|
||||
if (_combineComponent == null)
|
||||
{
|
||||
Log.Warning("{0} START failed. CombineComponent is missing.", LogPrefix);
|
||||
}
|
||||
|
||||
Log.Info("{0} START timeout={1}s restartDelay={2}s.", LogPrefix, TimeoutSeconds.ToString("F0"),
|
||||
RestartDelaySeconds.ToString("F0"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理流程级状态并反订阅事件。
|
||||
/// </summary>
|
||||
private void ShutdownProcedureState()
|
||||
{
|
||||
GameEntry.Event.Unsubscribe(CombineCompletedEventArgs.EventId, OnPuzzleCompleted);
|
||||
_combineComponent?.StopLevel();
|
||||
ResetRoundState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新当前局状态。
|
||||
/// 返回 true 表示流程仍在关卡运行阶段,不进入重开逻辑。
|
||||
/// </summary>
|
||||
private bool TryUpdateRound(float realElapseSeconds)
|
||||
{
|
||||
if (_isFinished)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_isStarted)
|
||||
{
|
||||
TryStartPuzzle();
|
||||
return true;
|
||||
}
|
||||
|
||||
UpdateTimeout(realElapseSeconds);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动拼装关卡并记录开始信息。
|
||||
/// </summary>
|
||||
private void TryStartPuzzle()
|
||||
{
|
||||
if (_combineComponent == null)
|
||||
{
|
||||
Log.Warning("{0} FAIL_NO_COMPONENT reason='CombineComponentMissing'.", LogPrefix);
|
||||
FinishAndScheduleRestart(false);
|
||||
return;
|
||||
}
|
||||
|
||||
CombineFormContext context = BuildTestOpenData();
|
||||
int? serialId = _combineComponent.StartLevel(context);
|
||||
|
||||
if (!serialId.HasValue)
|
||||
{
|
||||
Log.Warning("{0} FAIL_NO_CONTEXT reason='StartLevelFailed'.", LogPrefix);
|
||||
FinishAndScheduleRestart(false);
|
||||
return;
|
||||
}
|
||||
|
||||
_isStarted = true;
|
||||
_elapsed = 0f;
|
||||
_startTimestamp = Time.realtimeSinceStartup;
|
||||
Log.Info("{0} START uiFormId={1} serialId={2}.", LogPrefix, ((int)UIFormId.CombineForm).ToString(),
|
||||
serialId.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新超时计时;超时后按失败结算。
|
||||
/// </summary>
|
||||
private void UpdateTimeout(float realElapseSeconds)
|
||||
{
|
||||
_elapsed += realElapseSeconds;
|
||||
if (_elapsed < TimeoutSeconds)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_elapsed = TimeoutSeconds;
|
||||
Log.Warning("{0} FAIL_TIMEOUT elapsed={1:F2}s timeout={2:F2}s.", LogPrefix, _elapsed, TimeoutSeconds);
|
||||
FinishAndScheduleRestart(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结算后推进重开倒计时,到时切换到换场景流程。
|
||||
/// </summary>
|
||||
private void TryRestartScene(ProcedureOwner procedureOwner, float realElapseSeconds)
|
||||
{
|
||||
if (!_isFinished)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_restartCountdown -= realElapseSeconds;
|
||||
if (_restartCountdown > 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int nextSceneId = (int)SceneId.GameplayA;
|
||||
procedureOwner.SetData<VarInt32>("NextSceneId", nextSceneId);
|
||||
Log.Info("{0} RESTART result={1} nextSceneId={2}.", LogPrefix, _isPassed ? "PASS" : "FAIL",
|
||||
nextSceneId.ToString());
|
||||
ChangeState<ProcedureChangeScene>(procedureOwner);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建测试用关卡上下文(槽位、部件与自动开始配置)。
|
||||
/// </summary>
|
||||
private static CombineFormContext BuildTestOpenData()
|
||||
{
|
||||
List<CombineSlotContext> slots = new List<CombineSlotContext>
|
||||
{
|
||||
new CombineSlotContext
|
||||
{
|
||||
RequiredPartType = CombinePartType.Dou,
|
||||
BuildOrder = 0,
|
||||
RequireStrictOrder = true,
|
||||
AnchoredPosition = new Vector2(-320f, -160f),
|
||||
SizeDelta = new Vector2(120f, 120f),
|
||||
MechanicsExplanation = "Dou transfers upper load and works as the base node."
|
||||
},
|
||||
new CombineSlotContext
|
||||
{
|
||||
RequiredPartType = CombinePartType.Sheng,
|
||||
BuildOrder = 1,
|
||||
RequireStrictOrder = true,
|
||||
AnchoredPosition = new Vector2(-320f, -20f),
|
||||
SizeDelta = new Vector2(120f, 120f),
|
||||
MechanicsExplanation = "Sheng raises layer height to form the bracket hierarchy."
|
||||
},
|
||||
new CombineSlotContext
|
||||
{
|
||||
RequiredPartType = CombinePartType.Gong,
|
||||
BuildOrder = 2,
|
||||
RequireStrictOrder = true,
|
||||
AnchoredPosition = new Vector2(-320f, 120f),
|
||||
SizeDelta = new Vector2(120f, 120f),
|
||||
MechanicsExplanation = "Gong spreads force laterally through overhang."
|
||||
},
|
||||
new CombineSlotContext
|
||||
{
|
||||
RequiredPartType = CombinePartType.Qiao,
|
||||
BuildOrder = 3,
|
||||
RequireStrictOrder = true,
|
||||
AnchoredPosition = new Vector2(-160f, 120f),
|
||||
SizeDelta = new Vector2(120f, 120f),
|
||||
MechanicsExplanation = "Qiao continues force transfer to the outer side."
|
||||
},
|
||||
new CombineSlotContext
|
||||
{
|
||||
RequiredPartType = CombinePartType.Ang,
|
||||
BuildOrder = 4,
|
||||
RequireStrictOrder = true,
|
||||
AnchoredPosition = new Vector2(0f, 120f),
|
||||
SizeDelta = new Vector2(120f, 120f),
|
||||
MechanicsExplanation = "Ang uses leverage to redirect eave load inward."
|
||||
}
|
||||
};
|
||||
|
||||
List<CombinePartContext> parts = new List<CombinePartContext>
|
||||
{
|
||||
new CombinePartContext
|
||||
{ PartType = CombinePartType.Dou, PartDisplayName = "Dou", LockAfterPlaced = true },
|
||||
new CombinePartContext
|
||||
{ PartType = CombinePartType.Sheng, PartDisplayName = "Sheng", LockAfterPlaced = true },
|
||||
new CombinePartContext
|
||||
{ PartType = CombinePartType.Gong, PartDisplayName = "Gong", LockAfterPlaced = true },
|
||||
new CombinePartContext
|
||||
{ PartType = CombinePartType.Qiao, PartDisplayName = "Qiao", LockAfterPlaced = true },
|
||||
new CombinePartContext
|
||||
{ PartType = CombinePartType.Ang, PartDisplayName = "Ang", LockAfterPlaced = true }
|
||||
};
|
||||
|
||||
return new CombineFormContext
|
||||
{
|
||||
Slots = slots,
|
||||
Parts = parts,
|
||||
AutoStart = true
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拼装完成事件回调:记录耗时并按成功结算。
|
||||
/// </summary>
|
||||
private void OnPuzzleCompleted(object sender, GameEventArgs e)
|
||||
{
|
||||
if (!(e is CombineCompletedEventArgs))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_isFinished)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_elapsed = Mathf.Max(0f, Time.realtimeSinceStartup - _startTimestamp);
|
||||
Log.Info("{0} PASS elapsed={1:F2}s.", LogPrefix, _elapsed);
|
||||
FinishAndScheduleRestart(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标记当前局结束,并开始重开倒计时。
|
||||
/// </summary>
|
||||
private void FinishAndScheduleRestart(bool isPassed)
|
||||
{
|
||||
_isPassed = isPassed;
|
||||
_isFinished = true;
|
||||
_restartCountdown = RestartDelaySeconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置局内运行态字段。
|
||||
/// </summary>
|
||||
private void ResetRoundState()
|
||||
{
|
||||
_isStarted = false;
|
||||
_isFinished = false;
|
||||
_isPassed = false;
|
||||
_elapsed = 0f;
|
||||
_restartCountdown = 0f;
|
||||
_startTimestamp = 0f;
|
||||
_combineComponent = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b53c7f7e4bb428186cf9076c95cc484
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user