From 517a03bbc3410b9a9184f2f8f6569544552cd741 Mon Sep 17 00:00:00 2001
From: Ding Yuntian <1491671119@qq.com>
Date: Thu, 2 Jul 2026 19:15:11 +0800
Subject: [PATCH] =?UTF-8?q?perf(save):=20=E4=BC=98=E5=8C=96=E5=AD=98?=
=?UTF-8?q?=E6=A1=A3=E5=86=99=E5=85=A5=E6=80=A7=E8=83=BD=E5=B9=B6=E6=94=AF?=
=?UTF-8?q?=E6=8C=81=E5=85=B3=E9=97=AD=E7=BC=A9=E7=95=A5=E5=9B=BE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Assets/Scripts/AssetRefs/ConstRef.cs | 2 +
.../SaveSystem/SaveRestoreOrchestrator.cs | 68 ++++++++++---------
Assets/Scripts/SaveSystem/SlotManager.cs | 21 ++++--
.../SaveSystem/SlotThumbnailCapture.cs | 7 +-
Assets/Scripts/SaveSystem/SnapshotCapture.cs | 1 +
.../Scripts/SaveSystem/SnapshotPersistence.cs | 5 +-
6 files changed, 63 insertions(+), 41 deletions(-)
diff --git a/Assets/Scripts/AssetRefs/ConstRef.cs b/Assets/Scripts/AssetRefs/ConstRef.cs
index 2d9b8f360..509042502 100644
--- a/Assets/Scripts/AssetRefs/ConstRef.cs
+++ b/Assets/Scripts/AssetRefs/ConstRef.cs
@@ -29,6 +29,8 @@ namespace AibisDream.Utility
/// P2 槽位相关常量。
public const int SaveSlotCount = 8;
+ /// 存档槽位缩略图;关闭可避免主相机 Render + ReadPixels 的性能开销。
+ public const bool SaveThumbnailEnabled = false;
public const int SaveThumbnailWidth = 640;
public const int SaveThumbnailHeight = 360;
public const string SaveSlotDirPrefix = "slot_";
diff --git a/Assets/Scripts/SaveSystem/SaveRestoreOrchestrator.cs b/Assets/Scripts/SaveSystem/SaveRestoreOrchestrator.cs
index 6e702e76e..6441a5175 100644
--- a/Assets/Scripts/SaveSystem/SaveRestoreOrchestrator.cs
+++ b/Assets/Scripts/SaveSystem/SaveRestoreOrchestrator.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Threading.Tasks;
using AibisDream.Framework;
using AibisDream.UI;
using UnityEngine;
@@ -45,7 +46,7 @@ namespace AibisDream.SaveSystem
DialogController.Instance.StartCoroutine(AutoSaveRoutine(triggerNodeName));
}
- /// 自动存档协程:settle 一帧 → 主线程 Capture → 异步写盘。
+ /// 自动存档协程:settle 一帧 → 主线程 Capture → 后台序列化写盘(不阻塞主线程)。
/// 见 ;显式 save 传 null。
/// 为 true 时不写入 Yarn 节点 anchor。
public static IEnumerator AutoSaveRoutine(string triggerNodeName = null, bool omitAnchor = false)
@@ -68,47 +69,52 @@ namespace AibisDream.SaveSystem
var infoPanel = UIManager.Instance.GetPanel();
infoPanel?.ShowSaveLoading();
+ SaveSnapshot snapshot;
+ byte[] thumbnail;
+
try
{
- SaveSnapshot snapshot;
- byte[] thumbnail;
-
using (new CodeTimer("SaveSnapshot"))
{
snapshot = SnapshotService.Capture(triggerNodeName, omitAnchor);
thumbnail = SlotThumbnailCapture.CapturePng();
}
-
- if (TestSaveArchive.IsEnabled)
- {
- TestSaveArchive.Archive(snapshot, thumbnail);
- Debug.Log("[SaveRestoreOrchestrator] 测试存档模式:已写入 testsavs(不覆盖 slot_0)。");
- }
- else
- {
- var writeTask = SlotManager.SaveToAutoSlotAsync(snapshot, thumbnail);
- while (!writeTask.IsCompleted)
- {
- yield return null;
- }
-
- if (writeTask.IsFaulted)
- {
- Debug.LogError(
- $"[SaveRestoreOrchestrator] 自动存档失败: {writeTask.Exception?.GetBaseException()}");
- yield break;
- }
- }
-
- if (omitAnchor || (snapshot?.anchor != null && string.IsNullOrEmpty(snapshot.anchor.nodeName)))
- {
- Debug.Log("[SaveRestoreOrchestrator] 已保存无 Yarn 节点 anchor 的状态。");
- }
}
- finally
+ catch (Exception ex)
{
+ Debug.LogError($"[SaveRestoreOrchestrator] 自动存档 Capture 失败: {ex}");
infoPanel?.HideSaveLoading();
_isAutoSaving = false;
+ yield break;
+ }
+
+ infoPanel?.HideSaveLoading();
+
+ if (TestSaveArchive.IsEnabled)
+ {
+ TestSaveArchive.Archive(snapshot, thumbnail);
+ Debug.Log("[SaveRestoreOrchestrator] 测试存档模式:已写入 testsavs(不覆盖 slot_0)。");
+ _isAutoSaving = false;
+ }
+ else
+ {
+ _ = SlotManager.SaveToAutoSlotAsync(snapshot, thumbnail).ContinueWith(
+ writeTask =>
+ {
+ if (writeTask.IsFaulted)
+ {
+ Debug.LogError(
+ $"[SaveRestoreOrchestrator] 自动存档写盘失败: {writeTask.Exception?.GetBaseException()}");
+ }
+
+ _isAutoSaving = false;
+ },
+ TaskContinuationOptions.ExecuteSynchronously);
+ }
+
+ if (omitAnchor || (snapshot?.anchor != null && string.IsNullOrEmpty(snapshot.anchor.nodeName)))
+ {
+ Debug.Log("[SaveRestoreOrchestrator] 已保存无 Yarn 节点 anchor 的状态。");
}
}
diff --git a/Assets/Scripts/SaveSystem/SlotManager.cs b/Assets/Scripts/SaveSystem/SlotManager.cs
index 174dc2c42..64957229b 100644
--- a/Assets/Scripts/SaveSystem/SlotManager.cs
+++ b/Assets/Scripts/SaveSystem/SlotManager.cs
@@ -33,17 +33,18 @@ namespace AibisDream.SaveSystem
}
///
- /// 主线程完成序列化后,在后台线程写入自动档(slot 0)。
- /// 调用方须已在主线程完成 。
+ /// 主线程 Capture 后,在后台线程序列化并写入自动档(slot 0)。
///
public static async Task SaveToAutoSlotAsync(SaveSnapshot snapshot, byte[] thumbnailPng)
{
EnsureMigrated();
- var json = SnapshotPersistence.Serialize(snapshot);
- var meta = BuildSlotMeta(SlotIndex.Auto, snapshot);
-
- await Task.Run(() => WriteSlotFiles(SlotIndex.Auto, json, meta, thumbnailPng));
+ await Task.Run(() =>
+ {
+ var json = SnapshotPersistence.Serialize(snapshot);
+ var meta = BuildSlotMeta(SlotIndex.Auto, snapshot);
+ WriteSlotFiles(SlotIndex.Auto, json, meta, thumbnailPng);
+ });
SetLatestSlotIndex(SlotIndex.Auto);
CloudSaveManager.OnSlotWritten(SlotIndex.Auto);
@@ -147,6 +148,14 @@ namespace AibisDream.SaveSystem
}
}
+ /// 是否存在可用的自动档(slot_0 meta + snapshot)。
+ public static bool HasAutoSave()
+ {
+ EnsureMigrated();
+ return SlotDirectory.Exists(SlotIndex.Auto)
+ && File.Exists(SlotDirectory.GetSnapshotPath(SlotIndex.Auto));
+ }
+
/// 读取槽位元数据。
public static SlotMeta LoadMeta(int slotIndex)
{
diff --git a/Assets/Scripts/SaveSystem/SlotThumbnailCapture.cs b/Assets/Scripts/SaveSystem/SlotThumbnailCapture.cs
index 3d4b3561d..1001e0fec 100644
--- a/Assets/Scripts/SaveSystem/SlotThumbnailCapture.cs
+++ b/Assets/Scripts/SaveSystem/SlotThumbnailCapture.cs
@@ -12,9 +12,14 @@ namespace AibisDream.SaveSystem
///
public static class SlotThumbnailCapture
{
- /// 捕获当前画面的 PNG 字节数组。
+ /// 捕获当前画面的 PNG 字节数组;禁用时返回 null,不阻塞存档流程。
public static byte[] CapturePng()
{
+ if (!ConstRef.SaveThumbnailEnabled)
+ {
+ return null;
+ }
+
var cam = Camera.main;
if (cam == null)
{
diff --git a/Assets/Scripts/SaveSystem/SnapshotCapture.cs b/Assets/Scripts/SaveSystem/SnapshotCapture.cs
index 37d949a13..2abde22dc 100644
--- a/Assets/Scripts/SaveSystem/SnapshotCapture.cs
+++ b/Assets/Scripts/SaveSystem/SnapshotCapture.cs
@@ -45,6 +45,7 @@ namespace AibisDream.SaveSystem
snapshot.sections[provider.SaveId] = dto;
}
+ snapshot.schemaVersion = SaveSnapshotSchema.CurrentVersion;
return snapshot;
}
diff --git a/Assets/Scripts/SaveSystem/SnapshotPersistence.cs b/Assets/Scripts/SaveSystem/SnapshotPersistence.cs
index 8c18377db..102d1e227 100644
--- a/Assets/Scripts/SaveSystem/SnapshotPersistence.cs
+++ b/Assets/Scripts/SaveSystem/SnapshotPersistence.cs
@@ -40,11 +40,10 @@ namespace AibisDream.SaveSystem
return SlotManager.LoadSnapshot(slotIndex);
}
- /// 将快照序列化为 JSON 字符串。
+ /// 将快照序列化为 JSON 字符串(紧凑格式)。
public static string Serialize(SaveSnapshot snapshot)
{
- snapshot.schemaVersion = SaveSnapshotSchema.CurrentVersion;
- return JsonConvert.SerializeObject(snapshot, Formatting.Indented, Settings);
+ return JsonConvert.SerializeObject(snapshot, Formatting.None, Settings);
}
/// 从 JSON 字符串反序列化为快照。