Files
Continentis/Assets/Scripts/MainGame/MainGameManager.cs
SoulliesOfficial ac98ec3aef 更新
2026-04-17 12:01:50 -04:00

247 lines
11 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using Continentis.MainGame.Character;
using Continentis.MainGame.Saving;
using SLSUtilities.General;
using SLSUtilities.UModAssistance;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Continentis.MainGame
{
// ── 常量与核心字段 ──────────────────────────────────────────────────────────
public partial class MainGameManager : Singleton<MainGameManager>
{
private const string CombatSceneName = "GameScene";
private const string MenuSceneName = "MenuScene";
public readonly HashSet<string> elementTags = new HashSet<string>()
{
"Wind", "Fire", "Ice", "Earth", "Storm", "Light", "Darkness", "Physics"
};
public BasePrefabs basePrefabs;
}
// ── 游戏数据字段 ────────────────────────────────────────────────────────────
public partial class MainGameManager
{
/// <summary>全关键词合并表,由各 Mod 的 KeywordData 合并而来。</summary>
public KeywordData keywordData;
/// <summary>当前跑局的存档快照既是运行时状态也是持久化来源。null 表示无进行中的跑局。</summary>
public RunSave currentRun;
/// <summary>当前战斗的玩家英雄 CharacterData 列表,由 PrepareCombat() 填充。</summary>
public List<CharacterData> playerHeroDataList = new List<CharacterData>();
/// <summary>当前战斗的敌方 CharacterData 列表,由 PrepareCombat() 填充。</summary>
public List<CharacterData> enemyDataList = new List<CharacterData>();
}
// ── 初始化 ──────────────────────────────────────────────────────────────────
public partial class MainGameManager
{
protected override void Awake()
{
base.Awake();
// 合并所有 Mod 的 KeywordData 到全局查询表
keywordData = ScriptableObject.CreateInstance<KeywordData>();
foreach (KeyValuePair<string, ScriptableObject> pair in ModManager.Database[typeof(KeywordData)])
{
KeywordData data = pair.Value as KeywordData;
foreach (var keyword in data!.interpretedKeywords)
{
keywordData.interpretedKeywords.TryAdd(keyword.Key, keyword.Value);
}
}
// 消费 InformationTransistor 中的主菜单意图
InfoTransistor transistor = InfoTransistor.Instance;
if (transistor == null)
{
Debug.LogError("[MainGame] InformationTransistor 未找到,无法确定跑局意图。");
return;
}
InfoTransistor.Menu.MenuIntent intent = transistor.menuToMainGame.menuIntent;
RunConfig config = transistor.menuToMainGame.pendingRunConfig;
Debug.Log($"[MainGame] Awake收到主菜单意图 {intent}RunConfig {(config != null ? config.name : "null")}。");
// 消费后重置,避免场景重新加载时重复执行
transistor.menuToMainGame.menuIntent = InfoTransistor.Menu.MenuIntent.None;
transistor.menuToMainGame.pendingRunConfig = null;
switch (intent)
{
case InfoTransistor.Menu.MenuIntent.StartNewRun:
StartNewRun(config);
break;
case InfoTransistor.Menu.MenuIntent.ContinueRun:
ContinueRun();
break;
default:
Debug.LogWarning("[MainGame] Awake 时未收到有效的跑局意图,跳过初始化。");
break;
}
}
}
// ── 跑局流程 API ────────────────────────────────────────────────────────────
public partial class MainGameManager
{
/// <summary>
/// 开始一次新跑局:从 RunConfig 初始化英雄和关卡序列,写入开局存档,准备首场战斗数据。
/// RunConfig 仅在此处读取一次,结果完整拷贝到 RunSave后续不再查询它。
/// 由 Awake 消费 StartNewRun 意图时调用。
/// </summary>
private void StartNewRun(RunConfig config)
{
currentRun = new RunSave(
Random.Range(int.MinValue, int.MaxValue),
config.startingGold,
new List<string>(config.encounterSequenceIDs)
);
foreach (string heroID in config.initialHeroIDs)
{
CharacterData data = CharacterData.Get(heroID);
if (data == null)
{
Debug.LogError($"[MainGame] StartNewRun找不到角色数据 '{heroID}',已跳过。");
continue;
}
int maxHP = Mathf.RoundToInt(data.generalAttributes.TryGetValue("MaximumHealth", out float hp) ? hp : 0f);
HeroSave hero = new HeroSave(heroID, maxHP, maxHP);
foreach (string cardID in data.initialDeckRef)
hero.deck.Add(new CardSave(cardID));
currentRun.heroes.Add(hero);
}
SaveManager.Instance.SaveRunSave(currentRun);
Debug.Log($"[MainGame] 新跑局开始(配置:{config.name},节点数:{currentRun.combatNodeIDs.Count},种子:{currentRun.randomSeed}");
PrepareCombat(currentRun.currentNodeIndex);
}
/// <summary>
/// 从 SaveManager 缓存恢复跑局并准备当前节点的战斗数据。
/// 由 Awake 消费 ContinueRun 意图时调用。
/// </summary>
private void ContinueRun()
{
currentRun = SaveManager.Instance.GetRunSave();
if (currentRun == null)
{
Debug.LogError("[MainGame] ContinueRunSaveManager 缓存中无进行中的跑局。");
return;
}
Debug.Log($"[MainGame] 继续跑局(节点 {currentRun.currentNodeIndex} / {currentRun.combatNodeIDs.Count}");
PrepareCombat(currentRun.currentNodeIndex);
}
/// <summary>
/// 根据节点索引填充玩家英雄和敌方角色列表。
/// 仅准备运行时数据供 CombatMainManager 使用,不涉及场景加载。
/// </summary>
private void PrepareCombat(int nodeIndex)
{
if (nodeIndex >= currentRun.combatNodeIDs.Count)
{
Debug.Log("[MainGame] 所有关卡已通关,跑局结束!");
// TODO: Phase 4 — 显示通关结算界面
return;
}
// 填充玩家英雄列表
playerHeroDataList.Clear();
foreach (HeroSave hero in currentRun.heroes)
{
CharacterData data = CharacterData.Get(hero.characterDataID);
if (data != null)
playerHeroDataList.Add(data);
else
Debug.LogError($"[MainGame] PrepareCombat找不到角色数据 '{hero.characterDataID}'。");
}
// 填充敌方列表
string nodeID = currentRun.combatNodeIDs[nodeIndex];
CombatNodeData nodeData = CombatNodeData.Get(nodeID);
if (nodeData == null)
{
Debug.LogError($"[MainGame] PrepareCombat找不到 CombatNodeData '{nodeID}'。");
return;
}
enemyDataList.Clear();
foreach (string enemyID in nodeData.enemyCharacterIDs)
{
CharacterData data = CharacterData.Get(enemyID);
if (data != null)
enemyDataList.Add(data);
else
Debug.LogError($"[MainGame] PrepareCombat找不到敌方角色数据 '{enemyID}'。");
}
}
/// <summary>
/// 战斗结束回调,由 CombatMainManager 调用。
/// 胜利时回写 HP、推进节点并存档然后通过 InfoTransistor 写入 ContinueRun 意图并重载场景。
/// 失败时清除跑局存档(保留 PlayerSave并返回主菜单。
/// 注意MainGameManager 是场景局部单例,重载场景后当前实例会被销毁,
/// 新实例的 Awake 会从 InfoTransistor 消费意图并重新初始化。
/// </summary>
public void ExitCombat(bool isVictory, IReadOnlyList<(string heroID, int currentHP)> heroResults = null)
{
if (isVictory)
{
if (heroResults != null)
{
foreach (var (heroID, hp) in heroResults)
{
HeroSave hero = currentRun.heroes.Find(h => h.characterDataID == heroID);
if (hero != null)
hero.currentHP = hp;
}
}
currentRun.currentNodeIndex++;
SaveManager.Instance.SaveRunSave(currentRun);
Debug.Log($"[MainGame] 战斗胜利,节点推进至 {currentRun.currentNodeIndex},存档已写入。");
// 检查是否所有节点已通关
if (currentRun.currentNodeIndex >= currentRun.combatNodeIDs.Count)
{
Debug.Log("[MainGame] 所有关卡已通关,跑局结束!");
// TODO: Phase 4 — 显示通关结算界面,之后返回主菜单
return;
}
// 写入 ContinueRun 意图,重载场景以启动下一场战斗
// TODO: Phase 4 — 先进入奖励选择界面,完成后再走此流程
InfoTransistor transistor = InfoTransistor.Instance;
transistor.menuToMainGame.menuIntent = InfoTransistor.Menu.MenuIntent.ContinueRun;
transistor.menuToMainGame.pendingRunConfig = null;
SceneManager.LoadScene(CombatSceneName);
}
else
{
SaveManager.Instance.DeleteRunSave();
Debug.Log("[MainGame] 战斗失败跑局存档已清除PlayerSave 保留),返回主菜单。");
SceneManager.LoadScene(MenuSceneName);
}
}
}
// ── 静态工具方法 ────────────────────────────────────────────────────────────
public partial class MainGameManager
{
public static void GenerateInfoText(string content, CombatCharacterViewBase characterView, Color color = default, float size = 1)
=> Instance.basePrefabs.GenerateInfoText(content, characterView, color, size);
}
}