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 字符串反序列化为快照。