perf(save): 优化存档写入性能并支持关闭缩略图
This commit is contained in:
@@ -29,6 +29,8 @@ namespace AibisDream.Utility
|
||||
|
||||
/// <summary>P2 槽位相关常量。</summary>
|
||||
public const int SaveSlotCount = 8;
|
||||
/// <summary>存档槽位缩略图;关闭可避免主相机 Render + ReadPixels 的性能开销。</summary>
|
||||
public const bool SaveThumbnailEnabled = false;
|
||||
public const int SaveThumbnailWidth = 640;
|
||||
public const int SaveThumbnailHeight = 360;
|
||||
public const string SaveSlotDirPrefix = "slot_";
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/// <summary>自动存档协程:settle 一帧 → 主线程 Capture → 异步写盘。</summary>
|
||||
/// <summary>自动存档协程:settle 一帧 → 主线程 Capture → 后台序列化写盘(不阻塞主线程)。</summary>
|
||||
/// <param name="triggerNodeName">见 <see cref="SnapshotCapture.Capture"/>;显式 save 传 null。</param>
|
||||
/// <param name="omitAnchor">为 true 时不写入 Yarn 节点 anchor。</param>
|
||||
public static IEnumerator AutoSaveRoutine(string triggerNodeName = null, bool omitAnchor = false)
|
||||
@@ -68,47 +69,52 @@ namespace AibisDream.SaveSystem
|
||||
var infoPanel = UIManager.Instance.GetPanel<InfoPanel>();
|
||||
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 的状态。");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,17 +33,18 @@ namespace AibisDream.SaveSystem
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 主线程完成序列化后,在后台线程写入自动档(slot 0)。
|
||||
/// 调用方须已在主线程完成 <see cref="SnapshotService.Capture"/>。
|
||||
/// 主线程 Capture 后,在后台线程序列化并写入自动档(slot 0)。
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>是否存在可用的自动档(slot_0 meta + snapshot)。</summary>
|
||||
public static bool HasAutoSave()
|
||||
{
|
||||
EnsureMigrated();
|
||||
return SlotDirectory.Exists(SlotIndex.Auto)
|
||||
&& File.Exists(SlotDirectory.GetSnapshotPath(SlotIndex.Auto));
|
||||
}
|
||||
|
||||
/// <summary>读取槽位元数据。</summary>
|
||||
public static SlotMeta LoadMeta(int slotIndex)
|
||||
{
|
||||
|
||||
@@ -12,9 +12,14 @@ namespace AibisDream.SaveSystem
|
||||
/// </summary>
|
||||
public static class SlotThumbnailCapture
|
||||
{
|
||||
/// <summary>捕获当前画面的 PNG 字节数组。</summary>
|
||||
/// <summary>捕获当前画面的 PNG 字节数组;禁用时返回 null,不阻塞存档流程。</summary>
|
||||
public static byte[] CapturePng()
|
||||
{
|
||||
if (!ConstRef.SaveThumbnailEnabled)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var cam = Camera.main;
|
||||
if (cam == null)
|
||||
{
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace AibisDream.SaveSystem
|
||||
snapshot.sections[provider.SaveId] = dto;
|
||||
}
|
||||
|
||||
snapshot.schemaVersion = SaveSnapshotSchema.CurrentVersion;
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,11 +40,10 @@ namespace AibisDream.SaveSystem
|
||||
return SlotManager.LoadSnapshot(slotIndex);
|
||||
}
|
||||
|
||||
/// <summary>将快照序列化为 JSON 字符串。</summary>
|
||||
/// <summary>将快照序列化为 JSON 字符串(紧凑格式)。</summary>
|
||||
public static string Serialize(SaveSnapshot snapshot)
|
||||
{
|
||||
snapshot.schemaVersion = SaveSnapshotSchema.CurrentVersion;
|
||||
return JsonConvert.SerializeObject(snapshot, Formatting.Indented, Settings);
|
||||
return JsonConvert.SerializeObject(snapshot, Formatting.None, Settings);
|
||||
}
|
||||
|
||||
/// <summary>从 JSON 字符串反序列化为快照。</summary>
|
||||
|
||||
Reference in New Issue
Block a user