using System.Collections.Generic; using Cielonos.MainGame.Map; using Cielonos.MainGame.UI; using SLSUtilities.General; using UnityEngine; namespace Cielonos.MainGame { public partial class RunManager { /// /// 管理一局 Run 的创建和销毁。 /// 这里只负责 RunState 初始化、事件订阅入口和返回 Hub 的清理,不处理单个节点完成或奖励结算。 /// public class RunSessionSubmodule : SubmoduleBase { public RunSessionSubmodule(RunManager owner) : base(owner) { } public void StartNewRun() { if (owner.mapConfig == null) { Debug.LogError("[RunManager] mapConfig 未配置,无法开始 Run。"); return; } owner.progressSm.UnsubscribePlayerEvents(); owner.combatSm.UnsubscribeRoomEvents(); Randomizer runRng = new Randomizer(MainGameManager.Seed); RunMapData mapData = MapGenerator.Generate(owner.mapConfig); if (mapData == null) { Debug.LogError("[RunManager] 地图生成失败,无法开始 Run。"); return; } owner.currentRun = new RunState { randomizer = runRng, mapData = mapData, currentPosition = mapData.startPosition, visitedNodes = new HashSet { mapData.startPosition }, exhaustedNodes = new HashSet(), completedNodes = new HashSet(), permanentlyRevealedNodes = new HashSet(), permanentlyRevealedTypes = new HashSet(), scoutRange = 1, elapsedTime = 0f, roomsCleared = 0, enemiesDefeated = 0, hurtCount = 0, isCompleted = false, }; owner.combatRewardSm.Clear(); Debug.Log( $"[RunManager] 新一局开始(Seed: {runRng.Seed}),地图节点数:{mapData.totalNodes}," + $"起点:{mapData.startPosition},Boss:{mapData.bossPosition}"); PlayerCanvas.MainGamePages.mapPage.Populate(mapData); owner.progressSm.SubscribePlayerEvents(); owner.combatSm.SubscribeRoomEvents(); LoadStartZone(mapData); } public void ReturnToHub() { owner.progressSm.UnsubscribePlayerEvents(); owner.combatSm.UnsubscribeRoomEvents(); owner.combatRewardSm.Clear(); owner.currentRun = null; owner.phaseSm.TransitionToPhase(RunPhase.Idle); Debug.Log("[RunManager] 已返回 Hub,RunState 已清理。"); } private void LoadStartZone(RunMapData mapData) { RunMapNode startNode = mapData.nodes[mapData.startPosition]; if (startNode.zoneData == null) { Debug.LogWarning("[RunManager] 起点节点没有配置 ZoneData,直接进入地图选择。"); owner.phaseSm.TransitionToPhase(RunPhase.MapSelection); return; } owner.phaseSm.TransitionToPhase(RunPhase.Transitioning); ZoneSetupMode setupMode = RunNodeTypeUtility.ShouldStartBattleSetup(startNode, isCompleted: false) ? ZoneSetupMode.CombatEncounter : ZoneSetupMode.EnvironmentOnly; MapManager.Instance.LoadZone(startNode.zoneData, onComplete: () => { owner.phaseSm.TransitionToPhase(RunPhase.MapSelection); }, setupMode: setupMode); } } } }