using AibisDream.Framework; using AibisDream.Kit; using AibisDream.SaveSystem; using UnityEngine; using System.Collections; using DG.Tweening; namespace AibisDream.FixSystem { public enum SystemStartupMode { AutoOnHead, Deferred } /// /// 维修面板系统 - 统一管理所有侧边栏面板 /// 包括常驻面板(对话、任务)和随状态切换的游戏面板 /// public class FixPanelSystem : Singleton { private void Start() { InitLight(); } private void OnEnable() { RegisterCanvasCamera(); RegisterPanels(); RegisterScreenView(); } private void OnDisable() { UnRegisterCanvasCamera(); _panelContainer.Clear(); UnRegisterScreenView(); } #region 维修面板 private static IOCContainer _panelContainer = new(); public static T GetRepairPanel() where T : class { return _panelContainer.Get(); } public void RegisterPanels() { var panels = GetComponentsInChildren(true); foreach (var panel in panels) { _panelContainer.RegisterByInstance(panel); } } #endregion #region 维修管理扩展 [Header("光照系统")] [SerializeField] private bool isSystemOn = false; public bool IsSystemOn => isSystemOn; public bool ShouldAutoStartOnHeadEntry => !isSystemOn && (!isStartupPrepared || startupMode == SystemStartupMode.AutoOnHead); [SerializeField] private FixPanelLight panelLight; public FixPanelLight PanelLight => panelLight; private bool isStarting; private bool isStartupPrepared; private SystemStartupMode startupMode = SystemStartupMode.AutoOnHead; private LightState targetLightState = LightState.Normal; [Header("维修切换管理")] [SerializeField] private RepairSystemManager repairSystemManager; public RepairSystemManager RepairSystemManager => repairSystemManager; private void InitLight() { panelLight.Initialize(isSystemOn, targetLightState); GetRepairPanel().InitLight(isSystemOn); // 无光环境下屏幕也不能亮 if (!isSystemOn) { screenPanel.gameObject.SetActive(false); } } #endregion #region 系统启动协调 /// /// 为指定剧情准备一次系统启动。只有显式调用该接口的 YarnProject 会改变默认表现。 /// public void PrepareSystemStartup(SystemStartupMode mode) { startupMode = mode; isStartupPrepared = true; targetLightState = LightState.Normal; ApplySystemOnImmediate(false); taskPanel?.SetVisible(false, immediate: true); } /// /// 启动所有系统(协调灯光系统和 CablePanel 的启动顺序) /// public IEnumerator StartAllSystems() { if (isSystemOn) yield break; if (isStarting) { while (isStarting) { yield return null; } yield break; } isStarting = true; // 1. 先启动 CablePanel 的系统自检 var cablePanel = GetRepairPanel(); if (cablePanel != null) { yield return cablePanel.StartSystem(); } // 2. 再启动灯光序列 if (panelLight != null) { yield return panelLight.PanelLightStartSequence(); } // 3. 再启动屏幕面板 screenPanel.gameObject.SetActive(true); isSystemOn = true; isStarting = false; isStartupPrepared = false; // 开机动画使用 Normal 表现,完成后再进入 Yarn 在关机期间缓存的目标状态。 ApplyLightState(targetLightState); } /// /// 设置灯光状态,并同步更新相关面板的灯光效果 /// public void SetLightState(LightState newState) { targetLightState = newState; // 关机时只缓存目标状态,避免序章的 Warning 提前点亮面板。 if (!isSystemOn) return; ApplyLightState(newState); } private void ApplyLightState(LightState newState) { // 1. 更新主灯光系统 if (panelLight != null) { panelLight.SetLightState(newState); } // 2. 同步更新 CablePanel 的灯光效果 var cablePanel = GetRepairPanel(); if (cablePanel != null) { cablePanel.UpdateBreathingLight(newState); cablePanel.UpdateECGWave(newState); } } #endregion #region 快照 Capture / Restore public FixPanelSnapshotDto CapturePanelSnapshot() { var cablePanel = GetRepairPanel(); var dto = new FixPanelSnapshotDto { isSystemOn = isSystemOn, lightState = targetLightState.ToString(), currentRepairSystemType = repairSystemManager?.GetCurrentSystemType()?.Name, isCableRetracted = cablePanel != null && cablePanel.isCableRetracted }; if (cablePanel != null && cablePanel.TryGetPluggedModuleName(out var moduleName)) { dto.pluggedModuleName = moduleName; } if (dto.isCableRetracted && !string.IsNullOrEmpty(dto.pluggedModuleName)) { Debug.LogWarning("[FixPanelSystem] Capture: isCableRetracted 与 pluggedModuleName 冲突,忽略 pluggedModuleName。"); dto.pluggedModuleName = null; } if (taskPanel != null) { taskPanel.CaptureSnapshot(out dto.isTaskPanelRequestedVisible, dto.tasks); } return dto; } public void ApplyPanelSnapshot(FixPanelSnapshotDto dto) { if (dto == null) return; // 读档恢复的是稳定终态,不继承可能仍留在场景中的待启动模式。 isStartupPrepared = false; startupMode = SystemStartupMode.AutoOnHead; targetLightState = LightState.Normal; if (!string.IsNullOrEmpty(dto.lightState) && !System.Enum.TryParse(dto.lightState, true, out targetLightState)) { Debug.LogWarning($"[FixPanelSystem] Unknown saved light state '{dto.lightState}'; using Normal."); targetLightState = LightState.Normal; } ApplySystemOnImmediate(dto.isSystemOn); if (repairSystemManager != null) { repairSystemManager.RestoreSystemType(dto.currentRepairSystemType); } GetRepairPanel()?.ApplyCableSnapshot(dto.isCableRetracted, dto.pluggedModuleName); taskPanel?.ApplySnapshot(dto.isTaskPanelRequestedVisible, dto.tasks); } /// 读档终态:跳过 StartAllSystems 动画,直接写面板壳层状态。 public void ApplySystemOnImmediate(bool isOn) { isSystemOn = isOn; isStarting = false; if (panelLight != null) { panelLight.Initialize(isOn, targetLightState); } var cablePanel = GetRepairPanel(); cablePanel?.InitLight(isOn); if (screenPanel != null) { screenPanel.gameObject.SetActive(isOn); } } #endregion #region 屏幕相关操作 [Header("默认画布")] [SerializeField] private Canvas canvas; [Header("全景遮罩")] [SerializeField] private SpriteRenderer mask; [Header("任务面板")] [SerializeField] private TaskPanel taskPanel; public TaskPanel TaskPanel => taskPanel; [Header("屏幕面板")] [SerializeField] private ScreenPanel screenPanel; public ScreenPanel ScreenPanel => screenPanel; private void RegisterScreenView() { DialogUIManager.Instance.RegisterScreenView(DialogViewType.Screen, screenPanel); DialogUIManager.Instance.RegisterScreenView(DialogViewType.Task, taskPanel); } private void UnRegisterScreenView() { DialogUIManager.Instance.UnRegisterScreenView(DialogViewType.Screen); DialogUIManager.Instance.UnRegisterScreenView(DialogViewType.Task); } private void RegisterCanvasCamera() { canvas.worldCamera = Camera.main; } private void UnRegisterCanvasCamera() { canvas.worldCamera = null; } /// /// 遮罩淡入(从当前透明度过渡到不透明) /// /// 淡入时长(秒) public IEnumerator MaskFadeIn(float duration = 1f) { if (mask == null) yield break; yield return mask.DOFade(1f, duration).WaitForCompletion(); } /// /// 遮罩淡出(从当前透明度过渡到透明) /// /// 淡出时长(秒) public IEnumerator MaskFadeOut(float duration = 1f) { if (mask == null) yield break; yield return mask.DOFade(0f, duration).WaitForCompletion(); } #endregion } }