Merge branch 'bugfix/问题修复' into 'develop'
fix: 任务面板重构 See merge request aibis-dream/aibis-dream!788
This commit is contained in:
@@ -3329,6 +3329,8 @@ Transform:
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 895638590458225172}
|
||||
- {fileID: 910000000000000002}
|
||||
- {fileID: 910000000000000004}
|
||||
- {fileID: 2161354415544340870}
|
||||
- {fileID: 930245164819552547}
|
||||
- {fileID: 1768036090393189231}
|
||||
@@ -3347,7 +3349,74 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
taskRoot: {fileID: 895638590458225172}
|
||||
hiddenAnchor: {fileID: 910000000000000002}
|
||||
shownAnchor: {fileID: 910000000000000004}
|
||||
taskListParent: {fileID: 2078109273994026669}
|
||||
taskItemPrefab: {fileID: 910000000000000005, guid: 63913c6ee20b38644bf16a505dd300f2, type: 3}
|
||||
animationDuration: 1
|
||||
animationEase: 6
|
||||
--- !u!1 &910000000000000001
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 910000000000000002}
|
||||
m_Layer: 0
|
||||
m_Name: TaskPanelHiddenAnchor
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &910000000000000002
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 910000000000000001}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -10.32, y: 3.6511626, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 4912059846133439537}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &910000000000000003
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 910000000000000004}
|
||||
m_Layer: 0
|
||||
m_Name: TaskPanelShownAnchor
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &910000000000000004
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 910000000000000003}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -7.12, y: 3.6511626, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 4912059846133439537}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &2080789105181032567
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -11,6 +11,7 @@ GameObject:
|
||||
- component: {fileID: 4156240678385147197}
|
||||
- component: {fileID: 3152720343440710739}
|
||||
- component: {fileID: 351969066121265812}
|
||||
- component: {fileID: 910000000000000005}
|
||||
m_Layer: 0
|
||||
m_Name: TaskItem
|
||||
m_TagString: Untagged
|
||||
@@ -171,3 +172,16 @@ MonoBehaviour:
|
||||
m_hasFontAssetChanged: 0
|
||||
m_renderer: {fileID: 3152720343440710739}
|
||||
m_maskType: 0
|
||||
--- !u!114 &910000000000000005
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5370176113195622641}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4fe106c891d8f8b448b72b805e707075, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
label: {fileID: 351969066121265812}
|
||||
|
||||
@@ -56,7 +56,6 @@ namespace AibisDream.Utility
|
||||
|
||||
public const string CutLinePrefabName = "Prefab/CutLine";
|
||||
|
||||
public const string TaskItemName = "Prefab/TaskItem";
|
||||
|
||||
public const string ActorPrefabName = "Prefab/ActorAnima";
|
||||
public const string SpriteActorPrefabName = "Prefab/SpriteActor";
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace AibisDream.FixSystem
|
||||
isStartupPrepared = true;
|
||||
targetLightState = LightState.Normal;
|
||||
ApplySystemOnImmediate(false);
|
||||
taskPanel?.HidePanelImmediate();
|
||||
taskPanel?.SetVisible(false, immediate: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -205,7 +205,7 @@ namespace AibisDream.FixSystem
|
||||
|
||||
if (taskPanel != null)
|
||||
{
|
||||
taskPanel.CaptureSnapshot(out dto.isTaskPanelVisible, dto.tasks);
|
||||
taskPanel.CaptureSnapshot(out dto.isTaskPanelRequestedVisible, dto.tasks);
|
||||
}
|
||||
|
||||
return dto;
|
||||
@@ -235,7 +235,7 @@ namespace AibisDream.FixSystem
|
||||
|
||||
GetRepairPanel<CablePanel>()?.ApplyCableSnapshot(dto.isCableRetracted, dto.pluggedModuleName);
|
||||
|
||||
taskPanel?.ApplySnapshot(dto.isTaskPanelVisible, dto.tasks, immediate: true);
|
||||
taskPanel?.ApplySnapshot(dto.isTaskPanelRequestedVisible, dto.tasks);
|
||||
}
|
||||
|
||||
/// <summary>读档终态:跳过 StartAllSystems 动画,直接写面板壳层状态。</summary>
|
||||
|
||||
@@ -1,121 +1,153 @@
|
||||
using System.Collections.Generic;
|
||||
using AibisDream.Framework;
|
||||
using System.Collections.Generic;
|
||||
using AibisDream.SaveSystem;
|
||||
using AibisDream.Utility;
|
||||
using TMPro;
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using DG.Tweening;
|
||||
|
||||
namespace AibisDream.FixSystem
|
||||
{
|
||||
public class TaskPanel : MonoBehaviour, ILineView
|
||||
{
|
||||
private const float HiddenLocalX = -10.32f;
|
||||
private const float ShownLocalX = -7.12f;
|
||||
|
||||
#region 索引
|
||||
|
||||
[Header("面板位置")]
|
||||
[SerializeField] private Transform taskRoot;
|
||||
[SerializeField] private Transform taskListParent;
|
||||
private GameObject _taskItemPrefab;
|
||||
private readonly Dictionary<string, GameObject> _taskDict = new();
|
||||
[SerializeField] private Transform hiddenAnchor;
|
||||
[SerializeField] private Transform shownAnchor;
|
||||
|
||||
#endregion
|
||||
[Header("任务列表")]
|
||||
[SerializeField] private RectTransform taskListParent;
|
||||
[SerializeField] private TaskItem taskItemPrefab;
|
||||
|
||||
[Header("动画")]
|
||||
[SerializeField, Min(0f)] private float animationDuration = 1f;
|
||||
[SerializeField] private Ease animationEase = Ease.OutQuad;
|
||||
|
||||
private readonly List<TaskEntry> _tasks = new();
|
||||
private Tween _moveTween;
|
||||
private bool _requestedVisible;
|
||||
private bool _temporarilyHidden;
|
||||
|
||||
public bool RequestedVisible => _requestedVisible;
|
||||
public bool EffectiveVisible => _requestedVisible && !_temporarilyHidden;
|
||||
|
||||
private sealed class TaskEntry
|
||||
{
|
||||
public string LineId;
|
||||
public string Text;
|
||||
public TaskItem View;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_taskItemPrefab = ResourceKit.LoadAssetSync<GameObject>(ConstRef.TaskItemName);
|
||||
ValidateConfiguration();
|
||||
}
|
||||
|
||||
public bool IsPanelVisible => Mathf.Approximately(taskRoot.localPosition.x, ShownLocalX);
|
||||
|
||||
public void ShowPanel()
|
||||
private void OnEnable()
|
||||
{
|
||||
taskRoot.DOLocalMoveX(ShownLocalX, 1f);
|
||||
RefreshVisual(immediate: true);
|
||||
}
|
||||
|
||||
/// <summary>动画收起面板(与 ShowPanel 对称)。</summary>
|
||||
public void HidePanel()
|
||||
private void OnDisable()
|
||||
{
|
||||
taskRoot.DOKill();
|
||||
taskRoot.DOLocalMoveX(HiddenLocalX, 1f);
|
||||
KillMoveTween();
|
||||
}
|
||||
|
||||
public void HidePanelImmediate()
|
||||
public void SetVisible(bool visible, bool immediate = false)
|
||||
{
|
||||
taskRoot.DOKill();
|
||||
SetPanelVisibleImmediate(false);
|
||||
if (_requestedVisible == visible)
|
||||
{
|
||||
if (immediate)
|
||||
{
|
||||
RefreshVisual(immediate: true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var wasEffectivelyVisible = EffectiveVisible;
|
||||
_requestedVisible = visible;
|
||||
|
||||
if (wasEffectivelyVisible != EffectiveVisible || immediate)
|
||||
{
|
||||
RefreshVisual(immediate);
|
||||
}
|
||||
}
|
||||
|
||||
private bool _restoreVisibleAfterCollapse;
|
||||
|
||||
/// <summary>临时收起面板(如进入 Memory 模式),记录之前是否展开,供 RestoreCollapsedPanel 恢复。</summary>
|
||||
public void CollapsePanelTemporary(bool immediate = false)
|
||||
public void SetTemporarilyHidden(bool hidden, bool immediate = false)
|
||||
{
|
||||
_restoreVisibleAfterCollapse = IsPanelVisible;
|
||||
if (!_restoreVisibleAfterCollapse) return;
|
||||
if (immediate) HidePanelImmediate();
|
||||
else HidePanel();
|
||||
}
|
||||
if (_temporarilyHidden == hidden)
|
||||
{
|
||||
if (immediate)
|
||||
{
|
||||
RefreshVisual(immediate: true);
|
||||
}
|
||||
|
||||
/// <summary>按 CollapsePanelTemporary 记录的状态恢复面板(之前未展开则不做任何事)。</summary>
|
||||
public void RestoreCollapsedPanel()
|
||||
{
|
||||
if (!_restoreVisibleAfterCollapse) return;
|
||||
_restoreVisibleAfterCollapse = false;
|
||||
ShowPanel();
|
||||
return;
|
||||
}
|
||||
|
||||
var wasEffectivelyVisible = EffectiveVisible;
|
||||
_temporarilyHidden = hidden;
|
||||
|
||||
if (wasEffectivelyVisible != EffectiveVisible || immediate)
|
||||
{
|
||||
RefreshVisual(immediate);
|
||||
}
|
||||
}
|
||||
|
||||
public void CompleteTask(string lineId)
|
||||
{
|
||||
if (_taskDict.Remove(lineId, out var taskItem))
|
||||
var index = FindTaskIndex(lineId);
|
||||
if (index < 0)
|
||||
{
|
||||
Destroy(taskItem);
|
||||
return;
|
||||
}
|
||||
|
||||
DestroyTaskView(_tasks[index].View);
|
||||
_tasks.RemoveAt(index);
|
||||
MarkTaskLayoutDirty();
|
||||
}
|
||||
|
||||
public void ClearTasks()
|
||||
{
|
||||
foreach (var task in _taskDict)
|
||||
foreach (var task in _tasks)
|
||||
{
|
||||
Destroy(task.Value);
|
||||
DestroyTaskView(task.View);
|
||||
}
|
||||
_taskDict.Clear();
|
||||
|
||||
_tasks.Clear();
|
||||
MarkTaskLayoutDirty();
|
||||
}
|
||||
|
||||
public void RunLine(LineSyncToken token)
|
||||
{
|
||||
if (_taskDict.ContainsKey(token.lineInfo.lineId))
|
||||
var lineId = token.lineInfo.lineId;
|
||||
if (string.IsNullOrWhiteSpace(lineId))
|
||||
{
|
||||
EnumEventSystem.Global.Send(DialogEventEnum.LineShown);
|
||||
token.ForceAdvance();
|
||||
return;
|
||||
Debug.LogWarning($"[{nameof(TaskPanel)}] 忽略缺少 lineId 的任务文本。", this);
|
||||
}
|
||||
else if (FindTaskIndex(lineId) < 0)
|
||||
{
|
||||
AddTaskItem(lineId, token.lineInfo.lineText);
|
||||
}
|
||||
|
||||
AddTaskItem(token.lineInfo.lineId, $"\u25cf {token.lineInfo.lineText}");
|
||||
token.TextStart();
|
||||
token.TextShown();
|
||||
token.ForceAdvance();
|
||||
CompleteLineImmediately(token);
|
||||
}
|
||||
|
||||
public void CaptureSnapshot(out bool isPanelVisible, List<TaskEntrySnapshotDto> tasks)
|
||||
public void CaptureSnapshot(out bool requestedVisible, List<TaskEntrySnapshotDto> tasks)
|
||||
{
|
||||
isPanelVisible = IsPanelVisible;
|
||||
requestedVisible = RequestedVisible;
|
||||
tasks.Clear();
|
||||
|
||||
foreach (var kv in _taskDict)
|
||||
foreach (var task in _tasks)
|
||||
{
|
||||
var text = kv.Value.GetComponent<TMP_Text>()?.text ?? string.Empty;
|
||||
tasks.Add(new TaskEntrySnapshotDto
|
||||
{
|
||||
lineId = kv.Key,
|
||||
text = text
|
||||
lineId = task.LineId,
|
||||
text = task.Text
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplySnapshot(bool isPanelVisible, List<TaskEntrySnapshotDto> tasks, bool immediate)
|
||||
public void ApplySnapshot(bool requestedVisible, List<TaskEntrySnapshotDto> tasks)
|
||||
{
|
||||
ClearTasks();
|
||||
|
||||
@@ -123,40 +155,208 @@ namespace AibisDream.FixSystem
|
||||
{
|
||||
foreach (var entry in tasks)
|
||||
{
|
||||
if (string.IsNullOrEmpty(entry.lineId))
|
||||
if (entry == null || string.IsNullOrWhiteSpace(entry.lineId))
|
||||
{
|
||||
Debug.LogWarning($"[{nameof(TaskPanel)}] 跳过缺少 lineId 的任务快照。", this);
|
||||
continue;
|
||||
}
|
||||
|
||||
AddTaskItem(entry.lineId, entry.text);
|
||||
if (FindTaskIndex(entry.lineId) >= 0)
|
||||
{
|
||||
Debug.LogWarning($"[{nameof(TaskPanel)}] 跳过重复任务快照 '{entry.lineId}'。", this);
|
||||
continue;
|
||||
}
|
||||
|
||||
AddTaskItem(entry.lineId, entry.text ?? string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
if (immediate)
|
||||
SetVisible(requestedVisible, immediate: true);
|
||||
}
|
||||
|
||||
private void RefreshVisual(bool immediate)
|
||||
{
|
||||
KillMoveTween();
|
||||
|
||||
var visible = EffectiveVisible;
|
||||
if (visible)
|
||||
{
|
||||
taskRoot.DOKill();
|
||||
SetPanelVisibleImmediate(isPanelVisible);
|
||||
SetTaskTextVisible(true);
|
||||
MarkTaskLayoutDirty();
|
||||
}
|
||||
else if (isPanelVisible)
|
||||
|
||||
if (taskRoot == null || hiddenAnchor == null || shownAnchor == null)
|
||||
{
|
||||
ShowPanel();
|
||||
if (!visible)
|
||||
{
|
||||
SetTaskTextVisible(false);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var targetPosition = visible
|
||||
? shownAnchor.localPosition
|
||||
: hiddenAnchor.localPosition;
|
||||
|
||||
if (immediate || animationDuration <= 0f)
|
||||
{
|
||||
taskRoot.localPosition = targetPosition;
|
||||
if (!visible)
|
||||
{
|
||||
SetTaskTextVisible(false);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var tween = taskRoot
|
||||
.DOLocalMove(targetPosition, animationDuration)
|
||||
.SetEase(animationEase);
|
||||
|
||||
_moveTween = tween;
|
||||
tween.OnComplete(() =>
|
||||
{
|
||||
if (_moveTween != tween)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_moveTween = null;
|
||||
if (!EffectiveVisible)
|
||||
{
|
||||
SetTaskTextVisible(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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>());
|
||||
TaskItem view = null;
|
||||
if (taskItemPrefab == null || taskListParent == null)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"[{nameof(TaskPanel)}] 无法创建任务 '{lineId}':TaskItem Prefab 或任务列表父节点未配置。",
|
||||
this);
|
||||
}
|
||||
else
|
||||
{
|
||||
view = Instantiate(taskItemPrefab, taskListParent);
|
||||
view.SetText(text);
|
||||
}
|
||||
|
||||
_tasks.Add(new TaskEntry
|
||||
{
|
||||
LineId = lineId,
|
||||
Text = text,
|
||||
View = view
|
||||
});
|
||||
|
||||
MarkTaskLayoutDirty();
|
||||
}
|
||||
|
||||
private void SetPanelVisibleImmediate(bool visible)
|
||||
private int FindTaskIndex(string lineId)
|
||||
{
|
||||
var pos = taskRoot.localPosition;
|
||||
pos.x = visible ? ShownLocalX : HiddenLocalX;
|
||||
taskRoot.localPosition = pos;
|
||||
if (string.IsNullOrEmpty(lineId))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (var i = 0; i < _tasks.Count; i++)
|
||||
{
|
||||
if (_tasks[i].LineId == lineId)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static void CompleteLineImmediately(LineSyncToken token)
|
||||
{
|
||||
token.TextStart();
|
||||
token.TextShown();
|
||||
token.ForceAdvance();
|
||||
}
|
||||
|
||||
private static void DestroyTaskView(TaskItem view)
|
||||
{
|
||||
if (view == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
view.gameObject.SetActive(false);
|
||||
Destroy(view.gameObject);
|
||||
}
|
||||
|
||||
private void SetTaskTextVisible(bool visible)
|
||||
{
|
||||
if (taskListParent != null && taskListParent.gameObject.activeSelf != visible)
|
||||
{
|
||||
taskListParent.gameObject.SetActive(visible);
|
||||
}
|
||||
}
|
||||
|
||||
private void MarkTaskLayoutDirty()
|
||||
{
|
||||
if (taskListParent != null)
|
||||
{
|
||||
LayoutRebuilder.MarkLayoutForRebuild(taskListParent);
|
||||
}
|
||||
}
|
||||
|
||||
private void KillMoveTween()
|
||||
{
|
||||
if (_moveTween == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tween = _moveTween;
|
||||
_moveTween = null;
|
||||
tween.Kill();
|
||||
}
|
||||
|
||||
private void ValidateConfiguration()
|
||||
{
|
||||
if (taskRoot == null)
|
||||
{
|
||||
Debug.LogError($"[{nameof(TaskPanel)}] {name} 未配置 Task Root。", this);
|
||||
}
|
||||
|
||||
if (hiddenAnchor == null)
|
||||
{
|
||||
Debug.LogError($"[{nameof(TaskPanel)}] {name} 未配置 Hidden Anchor。", this);
|
||||
}
|
||||
|
||||
if (shownAnchor == null)
|
||||
{
|
||||
Debug.LogError($"[{nameof(TaskPanel)}] {name} 未配置 Shown Anchor。", this);
|
||||
}
|
||||
|
||||
if (taskRoot != null
|
||||
&& hiddenAnchor != null
|
||||
&& shownAnchor != null
|
||||
&& (taskRoot.parent != hiddenAnchor.parent || taskRoot.parent != shownAnchor.parent))
|
||||
{
|
||||
Debug.LogError($"[{nameof(TaskPanel)}] {name} 的 Task Root 与两个 Anchor 必须拥有同一个父节点。", this);
|
||||
}
|
||||
|
||||
if (taskListParent == null)
|
||||
{
|
||||
Debug.LogError($"[{nameof(TaskPanel)}] {name} 未配置任务列表父节点。", this);
|
||||
}
|
||||
|
||||
if (taskItemPrefab == null)
|
||||
{
|
||||
Debug.LogError($"[{nameof(TaskPanel)}] {name} 未配置 TaskItem Prefab。", this);
|
||||
}
|
||||
else if (!taskItemPrefab.IsConfigured)
|
||||
{
|
||||
Debug.LogError($"[{nameof(TaskPanel)}] {name} 的 TaskItem Prefab 未绑定文本组件。", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace AibisDream
|
||||
[YarnCommand("show_task_panel")]
|
||||
public static void ShowTaskPanel()
|
||||
{
|
||||
TaskPanel.ShowPanel();
|
||||
TaskPanel?.SetVisible(true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
namespace AibisDream.FixSystem
|
||||
{
|
||||
public class TaskItem : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TMP_Text label;
|
||||
|
||||
public bool IsConfigured => label != null;
|
||||
|
||||
public void SetText(string value)
|
||||
{
|
||||
GetComponent<TMP_Text>().text = $"\u25cf {value}";
|
||||
if (label == null)
|
||||
{
|
||||
Debug.LogError($"[{nameof(TaskItem)}] {name} 未绑定文本组件。", this);
|
||||
return;
|
||||
}
|
||||
|
||||
label.text = $"\u25cf {value}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace AibisDream.FixSystem
|
||||
float duration = 0.5f;
|
||||
var memorySystem = FixSystemCenter.SystemDic.Get<MemoryProcess>();
|
||||
// 进入Memory前收起Task面板
|
||||
FixPanelSystem.Instance.TaskPanel?.CollapsePanelTemporary();
|
||||
FixPanelSystem.Instance.TaskPanel?.SetTemporarilyHidden(true);
|
||||
// 先切BodyModule
|
||||
if (!CameraKit.Instance.EqualToCameraState(CameraEnum.BodyModule))
|
||||
{
|
||||
@@ -126,7 +126,7 @@ namespace AibisDream.FixSystem
|
||||
{
|
||||
var memorySystem = FixSystemCenter.SystemDic.Get<MemoryProcess>();
|
||||
|
||||
FixPanelSystem.Instance.TaskPanel?.CollapsePanelTemporary(immediate: true);
|
||||
FixPanelSystem.Instance.TaskPanel?.SetTemporarilyHidden(true, immediate: true);
|
||||
yield return memorySystem.DropMemoryProjector();
|
||||
FixPanelSystem.GetRepairPanel<CablePanel>()?.PullUpCable();
|
||||
yield return CameraKit.Instance.SwitchCamera(CameraEnum.Memory, true);
|
||||
@@ -145,7 +145,7 @@ namespace AibisDream.FixSystem
|
||||
yield return CameraKit.Instance.SwitchCamera(CameraEnum.BodyModule);
|
||||
memorySystem.PullMemoryProjector();
|
||||
// 退出Memory后恢复Task面板
|
||||
FixPanelSystem.Instance.TaskPanel?.RestoreCollapsedPanel();
|
||||
FixPanelSystem.Instance.TaskPanel?.SetTemporarilyHidden(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ Postflight 校验
|
||||
|
||||
Provider 使用 `ISyncSnapshotProvider` 或 `IAsyncSnapshotProvider` 显式声明同步/异步恢复;异步 Provider 必须把等待过程返回给编排层,禁止内部 fire-and-forget。
|
||||
|
||||
## 快照 JSON 结构(schemaVersion = 1)
|
||||
## 快照 JSON 结构(schemaVersion = 2)
|
||||
|
||||
| 字段 | 含义 |
|
||||
| --- | --- |
|
||||
@@ -191,11 +191,11 @@ Fix 场景各 State 的 `Enter()` 通常包含相机过渡、Timeline 播放、F
|
||||
| --- | --- | --- | --- |
|
||||
| `punchTape` | `PunchTapeSnapshotDto` | 63 | 打孔带收藏 |
|
||||
| `fix` | `FixSnapshotDto` | 65 | FixSceneDirector 宏观模式(state + args) |
|
||||
| `fixPanel` | `FixPanelSnapshotDto` | 66 | FixPanel 壳层 + 线缆/插头 + TaskPanel(展开状态与任务列表) |
|
||||
| `fixPanel` | `FixPanelSnapshotDto` | 66 | FixPanel 壳层 + 线缆/插头 + TaskPanel(请求展开状态与任务列表) |
|
||||
| `bodyModule` | `BodyModuleSnapshotDto` | 67 | 插线模块物理态 |
|
||||
| `eye` | `EyeSnapshotDto` | 68 | Eye 叙事阶段 |
|
||||
|
||||
**还原顺序**:punchTape → fix(cue)→ fixPanel → bodyModule → eye → showcase → day2SleepPresentation → playTool → screen。`fixPanel` 须在 `fix` 之后,以覆盖 Cue `EnterImmediate` 中的 `ResetPlug`;D2 动态表现须在通用 Showcase 图片之后恢复,才能叠加虚焦、缩放或场景专属动画。
|
||||
**还原顺序**:punchTape → fix(cue)→ fixPanel → bodyModule → eye → showcase → day2SleepPresentation → playTool → screen。`fixPanel` 须在 `fix` 之后,以覆盖 Cue `EnterImmediate` 中的 `ResetPlug`,并让 Memory Cue 先建立 TaskPanel 临时隐藏状态;D2 动态表现须在通用 Showcase 图片之后恢复,才能叠加虚焦、缩放或场景专属动画。
|
||||
|
||||
**维修场景门控**(`FixSceneSnapshotHelper`):上述 section 仅在 `FixSystemCenter.Instance != null` 时 Capture/Restore。
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace AibisDream.SaveSystem
|
||||
/// </summary>
|
||||
public static class SaveSnapshotSchema
|
||||
{
|
||||
public const int CurrentVersion = 1;
|
||||
public const int CurrentVersion = 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -269,7 +269,7 @@ namespace AibisDream.SaveSystem
|
||||
/// <summary>Yarn 行 id,如 <c>line:01dade5</c>。</summary>
|
||||
public string lineId;
|
||||
|
||||
/// <summary>存档时 UI 显示的完整文本(含 <c>● </c> 前缀)。</summary>
|
||||
/// <summary>存档时已完成 substitutions 的本地化文本,不含 UI 圆点前缀。</summary>
|
||||
public string text;
|
||||
}
|
||||
|
||||
@@ -290,8 +290,8 @@ namespace AibisDream.SaveSystem
|
||||
/// <summary>插头插入的 BodyModule 名(data.moduleName);null/空 = 未插入。</summary>
|
||||
public string pluggedModuleName;
|
||||
|
||||
/// <summary>TaskPanel 是否处于展开位(<c>show_task_panel</c> 后)。</summary>
|
||||
public bool isTaskPanelVisible;
|
||||
/// <summary>剧情是否要求 TaskPanel 展开;Memory 等临时隐藏状态不写入存档。</summary>
|
||||
public bool isTaskPanelRequestedVisible;
|
||||
|
||||
/// <summary>TaskPanel 当前未完成任务列表(保持插入顺序)。</summary>
|
||||
public List<TaskEntrySnapshotDto> tasks = new();
|
||||
|
||||
Reference in New Issue
Block a user