Files
aibis-dream/Assets/Scripts/Game Loop/GameLoopManager.cs
T
2025-03-17 16:04:13 +08:00

294 lines
9.3 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
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<GameLoopManager>
{
private const int MaxSaveNum = 200;
#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)
{
StartMenu.Instance.HideStartMenu();
StartSingleSceneTest();
}
else if (runMode == RunMode.SaveFile)
{
// MainUIController.Instance.TVFadeOut(1);
StartMenu.Instance.HideStartMenu();
StartCoroutine(LoadSaveFile($"{TestSaveFilePath}/{saveFileName}"));
}
else
{
StartCoroutine(LoadClinicOut());
}
#else
StartCoroutine(LoadClinicOut());
runMode = RunMode.Product;
#endif
}
private IEnumerator LoadClinicOut()
{
yield return SceneLoader.Instance.LoadSceneAsync("ClinicOut");
FindObjectOfType<EnvironmentManager>().SetTimeOfDayCommand("day");
}
public void StartWithTalkSceneSO(TalkSceneSO sceneSO)
{
_currentTalkSceneSo = sceneSO;
StartCoroutine(LoadScene());
}
public void StartWithSaveFile(string saveFileName)
{
StartMenu.Instance.HideStartMenu();
StartCoroutine(LoadSaveFile(saveFileName));
}
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);
}
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 重新开始游戏功能
/// <summary>
/// 重新开始游戏,重新加载当前场景
/// </summary>
public void RestartGame()
{
// 确保场景正在加载或卸载前,先重置相关状态
StartCoroutine(RestartGameCoroutine());
}
private IEnumerator RestartGameCoroutine()
{
yield return SceneLoader.Instance.UnloadSceneAsync();
yield return MainUIController.Instance.FadeInSync(1);
yield return LoadClinicOut();
MainUIController.Instance.ShowMainUI();
StartMenu.Instance.showStartMenu();
StartMenu.Instance.HideEndMenu();
yield return MainUIController.Instance.FadeOutSync(1);
}
#endregion
#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<VariableStorageBehaviour>();
}
/// <summary>
/// 当前场景自行更新
/// </summary>
/// <param name="sceneName">当前scene</param>
public void UpdateCurScene(string sceneName)
{
_curSceneKey = sceneName;
}
/// <summary>
/// 状态机状态更新
/// </summary>
/// <param name="curState"></param>
/// <param name="curArgs"></param>
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<Dictionary<string, float>>();
var stringDict = saveFile["stringDict"]?.ToObject<Dictionary<string, string>>();
var boolDict = saveFile["boolDict"]?.ToObject<Dictionary<string, bool>>();
_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<FixState>();
_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());
#if !UNITY_EDITOR
DeleteOldSave();
#endif
}
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}/{DateTime.Now:yyyyMMdd_HHmmss}_{_currentTalkSceneSo.name}_{gameStageStr}";
}
private void DeleteOldSave()
{
var fileList = Directory.GetFiles(SaveFilePath);
if (fileList.Length > MaxSaveNum)
{
var sorted = fileList.OrderByDescending(f => f).ToArray();
for (var i = MaxSaveNum; i < fileList.Length; i++)
{
File.Delete(sorted[i]);
}
}
}
#endregion
}
public enum RunMode
{
Product,
SingleScene,
SaveFile
}
public static class GameLoopYarnCommand
{
[YarnCommand("auto_save")]
public static void AutoSave()
{
GameLoopManager.Instance.Save();
}
}
}