feat(fix-system): 支持 Fix 系统任务面板与身体模块状态读档恢复

This commit is contained in:
2026-06-29 15:58:35 +08:00
parent 0f681b518e
commit 2d43af4827
7 changed files with 164 additions and 27 deletions
@@ -72,7 +72,7 @@ namespace AibisDream.FixSystem
RepairSystemManager.Register(this);
}
/// <summary>捕获插线模块持久状态(分组 + UF + Chip)。</summary>
/// <summary>捕获插线模块持久状态(分组 + UF + Chip + 高亮/报警)。</summary>
public BodyModuleSnapshotDto CaptureBodyModuleSnapshot()
{
var dto = new BodyModuleSnapshotDto
@@ -86,6 +86,13 @@ namespace AibisDream.FixSystem
var chipModule = FindBodyModuleByName("Color")?.GetComponent<ChipModule>();
chipModule?.CaptureState(dto);
foreach (var module in EnumerateAllBodyModules())
{
var name = module.data.moduleName;
if (module.IsHighlighted) dto.highlightedModules.Add(name);
if (module.IsAlarmed) dto.alarmedModules.Add(name);
}
return dto;
}
@@ -105,6 +112,31 @@ namespace AibisDream.FixSystem
var chipModule = FindBodyModuleByName("Color")?.GetComponent<ChipModule>();
chipModule?.ApplyState(dto);
var highlighted = new HashSet<string>(dto.highlightedModules ?? Enumerable.Empty<string>());
var alarmed = new HashSet<string>(dto.alarmedModules ?? Enumerable.Empty<string>());
foreach (var module in EnumerateAllBodyModules())
{
var name = module.data.moduleName;
module.Highlight(highlighted.Contains(name));
module.Alarm(alarmed.Contains(name));
}
}
private IEnumerable<BodyModule> EnumerateAllBodyModules()
{
if (_bodyModuleGroup != null)
{
foreach (var module in _bodyModuleGroup.GetComponentsInChildren<BodyModule>(true))
yield return module;
}
if (_headModuleGroup != null)
{
foreach (var module in _headModuleGroup.GetComponentsInChildren<BodyModule>(true))
yield return module;
}
}
/// <summary>
@@ -28,6 +28,10 @@ namespace AibisDream.FixSystem
/// Yarn 可能在 Start 里异步加载材质完成前就调用 ModuleHightLight,需记下来待加载后再套材质。
/// </summary>
private bool _wantsHighlight;
private bool _wantsAlarm;
public bool IsHighlighted => _wantsHighlight;
public bool IsAlarmed => _wantsAlarm;
[SerializeField]
private SpriteRenderer targetSpriteRenderer; // 目标的 SpriteRenderer
@@ -99,7 +103,7 @@ namespace AibisDream.FixSystem
else
Debug.LogError("[BodyModule] Failed to load AlarmMaterial");
ApplyHighlightVisual();
ApplyModuleVisual();
}
#region
@@ -165,23 +169,25 @@ namespace AibisDream.FixSystem
public void Highlight(bool enable)
{
_wantsHighlight = enable;
ApplyHighlightVisual();
}
private void ApplyHighlightVisual()
{
if (targetSpriteRenderer == null || _highlightMaterial == null) return;
if (_alarmMaterial != null && targetSpriteRenderer.material == _alarmMaterial) return;
targetSpriteRenderer.material = _wantsHighlight ? _highlightMaterial : _originalMaterial;
ApplyModuleVisual();
}
public void Alarm(bool enable)
{
if (targetSpriteRenderer != null && _alarmMaterial != null)
{
targetSpriteRenderer.material = enable ? _alarmMaterial : _originalMaterial;
}
_wantsAlarm = enable;
ApplyModuleVisual();
}
private void ApplyModuleVisual()
{
if (targetSpriteRenderer == null) return;
if (_wantsAlarm && _alarmMaterial != null)
targetSpriteRenderer.material = _alarmMaterial;
else if (_wantsHighlight && _highlightMaterial != null)
targetSpriteRenderer.material = _highlightMaterial;
else
targetSpriteRenderer.material = _originalMaterial;
}
#endregion
@@ -22,6 +22,15 @@ namespace AibisDream.FixSystem
SystemDic ??= new IOCContainer();
Context = new FixSceneContext(SystemDic);
Director = new FixSceneDirector();
}
private void Start()
{
if (SaveRestoreOrchestrator.IsRestoring)
{
return;
}
StartCoroutine(Director.Init(defaultMode));
}
@@ -149,6 +149,11 @@ namespace AibisDream.FixSystem
dto.pluggedModuleName = null;
}
if (taskPanel != null)
{
taskPanel.CaptureSnapshot(out dto.isTaskPanelVisible, dto.tasks);
}
return dto;
}
@@ -164,6 +169,8 @@ namespace AibisDream.FixSystem
}
GetRepairPanel<CablePanel>()?.ApplyCableSnapshot(dto.isCableRetracted, dto.pluggedModuleName);
taskPanel?.ApplySnapshot(dto.isTaskPanelVisible, dto.tasks, immediate: true);
}
/// <summary>读档终态:跳过 StartAllSystems 动画,直接写面板壳层状态。</summary>
@@ -111,6 +111,17 @@ namespace AibisDream.FixSystem
if (retracted)
{
if (ShouldSkipRetractOnRestore())
{
if (isCableRetracted)
{
DropDownCableImmediate();
}
curSocket = null;
return;
}
SetRetractCable();
curSocket = null;
return;
@@ -153,6 +164,7 @@ namespace AibisDream.FixSystem
var socketPos = module.GetSocketPos();
PlugRef.RestoreInsertedAt(socketPos);
CableRef.SetEndPos(socketPos);
SetCableMode(CableMode.Visual);
BodyModuleSystem.CloseModuleSlots(null);
}
@@ -166,6 +178,13 @@ namespace AibisDream.FixSystem
PlugRef.SetSpriteVisible(true);
}
private static bool ShouldSkipRetractOnRestore()
{
return FixSystemCenter.Instance != null
&& FixSystemCenter.Director.HasMode
&& FixSystemCenter.Director.CurrentMode == FixSceneMode.BodyModule;
}
private void Update()
{
// 获取线缆方向并更新转盘旋转
@@ -177,10 +196,14 @@ namespace AibisDream.FixSystem
public void ResetPlug()
{
// 不在初始插孔里,就从当前插孔拔出来,插回初始插孔
PlugRef.PullUpSocket();
if (IsPlugInSocket())
{
PlugRef.PullUpSocket();
}
BodyModuleSystem.CloseModuleSlots(null);
PlugRef.ReturnToStartPosition();
DropDownCableImmediate();
AudioManager.Instance.PlaySfx("event:/ActionFB/mods_close");
AudioManager.Instance.PlaySfx("event:/FollowInput/plugdrop");
}
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using AibisDream.Framework;
using AibisDream.SaveSystem;
using AibisDream.Utility;
using TMPro;
using UnityEngine;
@@ -10,6 +11,9 @@ namespace AibisDream.FixSystem
{
public class TaskPanel : MonoBehaviour, ILineView
{
private const float HiddenLocalX = -10.32f;
private const float ShownLocalX = -7.12f;
#region
[SerializeField] private Transform taskRoot;
@@ -26,8 +30,9 @@ namespace AibisDream.FixSystem
public void ShowPanel()
{
taskRoot.DOLocalMoveX(-7.12f, 1f);
taskRoot.DOLocalMoveX(ShownLocalX, 1f);
}
public void CompleteTask(string lineId)
{
if (_taskDict.Remove(lineId, out var taskItem))
@@ -54,15 +59,70 @@ namespace AibisDream.FixSystem
return;
}
var taskItem = Instantiate(_taskItemPrefab, taskListParent);
var task = taskItem.GetComponent<TMP_Text>();
task.text = $"\u25cf {token.lineInfo.lineText}";
AddTaskItem(token.lineInfo.lineId, $"\u25cf {token.lineInfo.lineText}");
token.TextStart();
_taskDict[token.lineInfo.lineId] = taskItem;
token.TextShown();
token.ForceAdvance();
}
public void CaptureSnapshot(out bool isPanelVisible, List<TaskEntrySnapshotDto> tasks)
{
isPanelVisible = Mathf.Approximately(taskRoot.localPosition.x, ShownLocalX);
tasks.Clear();
foreach (var kv in _taskDict)
{
var text = kv.Value.GetComponent<TMP_Text>()?.text ?? string.Empty;
tasks.Add(new TaskEntrySnapshotDto
{
lineId = kv.Key,
text = text
});
}
}
public void ApplySnapshot(bool isPanelVisible, List<TaskEntrySnapshotDto> tasks, bool immediate)
{
ClearTasks();
if (tasks != null)
{
foreach (var entry in tasks)
{
if (string.IsNullOrEmpty(entry.lineId))
{
continue;
}
AddTaskItem(entry.lineId, entry.text);
}
}
if (immediate)
{
taskRoot.DOKill();
SetPanelVisibleImmediate(isPanelVisible);
}
else if (isPanelVisible)
{
ShowPanel();
}
}
private void AddTaskItem(string lineId, string text)
{
var taskItem = Instantiate(_taskItemPrefab, taskListParent);
var task = taskItem.GetComponent<TMP_Text>();
task.text = text;
_taskDict[lineId] = taskItem;
LayoutRebuilder.ForceRebuildLayoutImmediate(taskListParent.GetComponent<RectTransform>());
}
private void SetPanelVisibleImmediate(bool visible)
{
var pos = taskRoot.localPosition;
pos.x = visible ? ShownLocalX : HiddenLocalX;
taskRoot.localPosition = pos;
}
}
}
}
@@ -1,9 +1,9 @@
using UnityEngine;
using UnityEngine;
namespace AibisDream.SaveSystem
{
/// <summary>
/// sections["fixPanel"]FixPanel 壳层 + 线缆/插头。RestoreOrder=66,在 fix 之后、bodyModule 之前
/// sections["fixPanel"]FixPanel 壳层 + 线缆/插头 + TaskPanel。RestoreOrder=66,在 fix(65) 之后写回面板/线缆/任务快照
/// </summary>
public class FixPanelSnapshotProvider : ISyncSnapshotProvider
{