feat(save): 验证工具增加运行时自动存档历史
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -20,6 +20,8 @@ namespace AibisDream.SaveSystem.Editor
|
||||
private const string MenuPath = "AIBIS/存档系统验证工具";
|
||||
private const string WindowTitle = "SaveSystem Validator";
|
||||
|
||||
private const float SaveHistoryBoxMinHeight = 400f;
|
||||
|
||||
private Vector2 _scrollPosition;
|
||||
private string _lastLog = string.Empty;
|
||||
private int _manualSlotIndex = 1;
|
||||
@@ -27,10 +29,109 @@ namespace AibisDream.SaveSystem.Editor
|
||||
private string _testNodeName = "SomeNode";
|
||||
private string _testTags = "";
|
||||
|
||||
private readonly List<SaveHistoryEntry> _saveHistory = new();
|
||||
private string _lastObservedSavedAt;
|
||||
|
||||
/// <summary>运行时自动存档历史条目,仅内存缓存。</summary>
|
||||
private class SaveHistoryEntry
|
||||
{
|
||||
public string SavedAt;
|
||||
public string NodeName;
|
||||
public string SceneName;
|
||||
}
|
||||
|
||||
[MenuItem(MenuPath)]
|
||||
public static void Open()
|
||||
{
|
||||
GetWindow<SaveSystemValidationWindow>(WindowTitle);
|
||||
var window = GetWindow<SaveSystemValidationWindow>(WindowTitle);
|
||||
window.minSize = new Vector2(420, 640);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
EditorApplication.update += OnEditorUpdate;
|
||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||
InitializeLastObservedSavedAt();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
EditorApplication.update -= OnEditorUpdate;
|
||||
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
||||
}
|
||||
|
||||
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||
{
|
||||
if (state == PlayModeStateChange.EnteredPlayMode)
|
||||
{
|
||||
_saveHistory.Clear();
|
||||
InitializeLastObservedSavedAt();
|
||||
TrySeedHistoryFromCurrentAutoSlot();
|
||||
Repaint();
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == PlayModeStateChange.ExitingPlayMode)
|
||||
{
|
||||
_saveHistory.Clear();
|
||||
_lastObservedSavedAt = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void TrySeedHistoryFromCurrentAutoSlot()
|
||||
{
|
||||
var meta = SlotManager.LoadMeta(SlotIndex.Auto);
|
||||
if (meta == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_saveHistory.Add(CreateHistoryEntry(meta));
|
||||
_lastObservedSavedAt = meta.savedAt;
|
||||
}
|
||||
|
||||
private static SaveHistoryEntry CreateHistoryEntry(SlotMeta meta)
|
||||
{
|
||||
return new SaveHistoryEntry
|
||||
{
|
||||
SavedAt = meta.savedAt,
|
||||
NodeName = string.IsNullOrEmpty(meta.nodeName) ? "(无节点)" : meta.nodeName,
|
||||
SceneName = meta.sceneName
|
||||
};
|
||||
}
|
||||
|
||||
private void InitializeLastObservedSavedAt()
|
||||
{
|
||||
var meta = SlotManager.LoadMeta(SlotIndex.Auto);
|
||||
_lastObservedSavedAt = meta?.savedAt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 监听 slot_0 的 meta 变化,运行时每次自动存档都会记录到内存列表中。
|
||||
/// 纯 Editor 行为,不侵入运行时代码。
|
||||
/// </summary>
|
||||
private void OnEditorUpdate()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var meta = SlotManager.LoadMeta(SlotIndex.Auto);
|
||||
if (meta == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(_lastObservedSavedAt) && _lastObservedSavedAt == meta.savedAt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lastObservedSavedAt = meta.savedAt;
|
||||
_saveHistory.Add(CreateHistoryEntry(meta));
|
||||
|
||||
Repaint();
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
@@ -40,6 +141,8 @@ namespace AibisDream.SaveSystem.Editor
|
||||
DrawHeader();
|
||||
DrawSlotOverview();
|
||||
GUILayout.Space(12);
|
||||
DrawSaveHistorySection();
|
||||
GUILayout.Space(12);
|
||||
DrawDirectCaptureSection();
|
||||
GUILayout.Space(12);
|
||||
DrawAutoSaveSimulationSection();
|
||||
@@ -131,6 +234,51 @@ namespace AibisDream.SaveSystem.Editor
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSaveHistorySection()
|
||||
{
|
||||
EditorGUILayout.LabelField("自动存档历史 (运行时)", EditorStyles.boldLabel);
|
||||
|
||||
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox, GUILayout.MinHeight(SaveHistoryBoxMinHeight)))
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
"进入 Play Mode 后,每次 slot_0 自动存档都会在此记录节点名与时间。\n" +
|
||||
"数据仅保存在当前窗口内存中,退出 Play Mode 后清空。",
|
||||
MessageType.Info);
|
||||
}
|
||||
else if (_saveHistory.Count == 0)
|
||||
{
|
||||
EditorGUILayout.LabelField("等待自动存档…", EditorStyles.wordWrappedLabel);
|
||||
EditorGUILayout.LabelField(
|
||||
"触发 content / hub / linear 节点,或点击下方 TryAutoSave。",
|
||||
EditorStyles.miniLabel);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField($"共 {_saveHistory.Count} 条记录", EditorStyles.miniLabel);
|
||||
|
||||
for (var i = 0; i < _saveHistory.Count; i++)
|
||||
{
|
||||
var entry = _saveHistory[i];
|
||||
EditorGUILayout.LabelField(
|
||||
$"{i + 1}. [{entry.SavedAt}] {entry.NodeName}",
|
||||
EditorStyles.wordWrappedLabel);
|
||||
EditorGUILayout.LabelField(
|
||||
$" 场景: {entry.SceneName ?? "N/A"}",
|
||||
EditorStyles.miniLabel);
|
||||
}
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
if (GUILayout.Button("清空历史记录"))
|
||||
{
|
||||
_saveHistory.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawManualSlotSection()
|
||||
{
|
||||
EditorGUILayout.LabelField("手动档操作", EditorStyles.boldLabel);
|
||||
@@ -243,7 +391,16 @@ namespace AibisDream.SaveSystem.Editor
|
||||
var beforeLatest = SlotManager.GetLatestSlotIndex();
|
||||
var beforeSnapshot = SlotManager.LoadSnapshot(0);
|
||||
|
||||
SaveRestoreOrchestrator.TryAutoSave();
|
||||
if (!SavePointEvaluator.CanAutoSave(out var rejectReason))
|
||||
{
|
||||
Log($"CanAutoSave 拒绝: {rejectReason}");
|
||||
return;
|
||||
}
|
||||
|
||||
var routine = SaveRestoreOrchestrator.AutoSaveRoutine();
|
||||
while (routine.MoveNext())
|
||||
{
|
||||
}
|
||||
|
||||
var afterSnapshot = SlotManager.LoadSnapshot(0);
|
||||
var afterLatest = SlotManager.GetLatestSlotIndex();
|
||||
|
||||
Reference in New Issue
Block a user