using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using AibisDream.FixSystem; using AibisDream.Framework; using AibisDream.Kit; using AibisDream.Utility; using Newtonsoft.Json.Linq; using UnityEngine; using Yarn.Unity; namespace AibisDream { public class GameLoopManager : Singleton { #region 运行模式相关 [Header("可用so合集")] public TalkSceneSO[] totalSceneSos; public RunMode runMode; [Header("生产环境数据(一般不动)")] public TalkSceneSO firstTalkSo; [Header("单场景测试")] public TalkSceneSO testTalkSo; [Header("存档测试")] public string saveFileName; #endregion private TalkSceneSO _currentTalkSceneSo; public void Start() { #if UNITY_EDITOR if (runMode == RunMode.SingleScene) { MainUIController.Instance.TVFadeOut(1); GameObject.Find("Menu Canvas").SetActive(false); StartSingleSceneTest(); } else if (runMode == RunMode.SaveFile) { MainUIController.Instance.TVFadeOut(1); GameObject.Find("Menu Canvas").SetActive(false); StartCoroutine(LoadSaveFile($"{TestSaveFilePath}/{saveFileName}")); } #else runMode = RunMode.Product; #endif } public void StartWithTalkSceneSO(TalkSceneSO sceneSO) { _currentTalkSceneSo = sceneSO; StartCoroutine(LoadScene()); } public void StartNewGame() { _currentTalkSceneSo = firstTalkSo; StartCoroutine(LoadClinicScene()); } private void StartSingleSceneTest() { _currentTalkSceneSo = testTalkSo; StartCoroutine(LoadClinicScene()); } private IEnumerator LoadClinicScene() { yield return SceneLoader.Instance.LoadSceneAsync(_currentTalkSceneSo.firstSceneName); StartMenu.Instance.HideStartMenu(); DialogController.Instance.StartDialog(_currentTalkSceneSo.yarnProject); } private IEnumerator LoadScene() { yield return SceneLoader.Instance.LoadSceneAsync(_currentTalkSceneSo.firstSceneName); StartMenu.Instance.HideStartMenu(); DialogController.Instance.StartDialog(_currentTalkSceneSo.yarnProject); MainUIController.Instance.HideMainUI(); } public IEnumerator NextSceneSo() { if (_currentTalkSceneSo && _currentTalkSceneSo.nextScene) { _currentTalkSceneSo = _currentTalkSceneSo.nextScene; yield return MainUIController.Instance.FadeInSync(1); yield return LoadClinicScene(); yield return MainUIController.Instance.FadeOutSync(1); } else { yield return null; Debug.Log("没有下个场景了"); } } #region 存档相关 private static readonly string SaveFilePath = Application.streamingAssetsPath + "/SaveFiles"; private static readonly string TestSaveFilePath = Application.streamingAssetsPath + "/TestSaveFiles"; // 维修系统相关数据 public static readonly DataContainer FixDataContainer = new(); // 对话变量存储 private VariableStorageBehaviour _dialogStorage; // 当前场景 private string _curSceneKey; // 状态机 private string _fixStateArgs; private FixState _fixState; public override void OnSingletonInit() { _dialogStorage = FindObjectOfType(); } /// /// 当前场景自行更新 /// /// 当前scene public void UpdateCurScene(string sceneName) { _curSceneKey = sceneName; } /// /// 状态机状态更新 /// /// /// public void UpdateFixState(FixState curState, string curArgs) { _fixState = curState; _fixStateArgs = curArgs; } private IEnumerator LoadSaveFile(string savePath) { var saveFile = JsonUtil.ReadJObject(savePath); // 先加载对话数据 var floatDict = saveFile["floatDict"]?.ToObject>(); var stringDict = saveFile["stringDict"]?.ToObject>(); var boolDict = saveFile["boolDict"]?.ToObject>(); _dialogStorage.SetAllVariables(floatDict, stringDict, boolDict); // 再加载场景 _currentTalkSceneSo = Array.Find(totalSceneSos, so => so.name == saveFile["curTalkSceneSo"]?.ToString()); yield return SceneLoader.Instance.LoadSceneAsync(saveFile["curSceneKey"]?.ToString()); if (saveFile["fixDataContainer"] is not JObject fixDataJson) { Debug.Log("维修数据读取问题"); yield break; } // 场景加载完成之后把数据填回去 FixDataContainer.LoadByJson(fixDataJson); // 初始化维修状态机 _fixState = saveFile["fixState"]!.ToObject(); _fixStateArgs = saveFile["fixStateArgs"]!.ToString(); yield return FixSystemCenter.StateMachine.SwitchState(_fixState, _fixStateArgs); // 开启对话 DialogController.Instance.LoadDialog(_currentTalkSceneSo.yarnProject); } public void Save() { JObject saveFile = new JObject(); // 场景维修相关数据保存 var fixData = FixDataContainer.SaveAsJson(); saveFile["fixDataContainer"] = fixData; // 保存对话变量 var (floatDict, stringDict, boolDict) = _dialogStorage.GetAllVariables(); saveFile["floatDict"] = JObject.FromObject(floatDict); saveFile["stringDict"] = JObject.FromObject(stringDict); saveFile["boolDict"] = JObject.FromObject(boolDict); // 保存场景数据 saveFile["curSceneKey"] = _curSceneKey; saveFile["curTalkSceneSo"] = _currentTalkSceneSo.name; // 保存状态机数据 saveFile["fixState"] = (int) _fixState; saveFile["fixStateArgs"] = _fixStateArgs; // 存为Json JsonUtil.SaveJObject(saveFile, GetSavePath()); } private string GetSavePath() { string gameStageStr; try { _dialogStorage.TryGetValue("$gameStage", out float gameStage); gameStageStr = gameStage.ToString(CultureInfo.InvariantCulture); } catch (Exception) { _dialogStorage.TryGetValue("$gameStage", out string gameStage); gameStageStr = gameStage; } return $"{SaveFilePath}/{_currentTalkSceneSo.name}_{gameStageStr}_{DateTime.Now:yyyyMMdd_HHmmss}"; } #endregion } public enum RunMode { Product, SingleScene, SaveFile } public static class GameLoopYarnCommand { [YarnCommand("auto_save")] public static void AutoSave() { GameLoopManager.Instance.Save(); } } }