From cc3e1dd138a711481efa3aa9823d73ba737edb63 Mon Sep 17 00:00:00 2001 From: Ding Yuntian <1491671119@qq.com> Date: Fri, 12 Jun 2026 17:40:36 +0800 Subject: [PATCH] =?UTF-8?q?refactor(save):=20=E5=90=88=E5=B9=B6=20SaveSyst?= =?UTF-8?q?em=20=E8=BF=87=E5=BA=A6=E6=8B=86=E5=88=86=E7=9A=84=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将以下小文件合并到相关核心类中,减少文件数量并保持职责清晰: - SaveSnapshotSummary -> SaveSnapshot - SnapshotProviderIds + SnapshotBootstrap -> SnapshotRegistry - SnapshotSectionDeserializer -> SnapshotRestore - SnapshotSerializer -> SnapshotPersistence 同步更新 SnapshotService 与 YarnVariableStorage 的调用点。 --- .../Scripts/Game Loop/YarnVariableStorage.cs | 2 +- Assets/Scripts/SaveSystem/SaveSnapshot.cs | 41 +++++++ .../Scripts/SaveSystem/SaveSnapshotSummary.cs | 43 ------- .../SaveSystem/SaveSnapshotSummary.cs.meta | 11 -- .../Scripts/SaveSystem/SnapshotBootstrap.cs | 26 ---- .../SaveSystem/SnapshotBootstrap.cs.meta | 11 -- .../Scripts/SaveSystem/SnapshotPersistence.cs | 62 +++++++++- .../Scripts/SaveSystem/SnapshotProviderIds.cs | 26 ---- .../SaveSystem/SnapshotProviderIds.cs.meta | 11 -- Assets/Scripts/SaveSystem/SnapshotRegistry.cs | 41 ++++++- Assets/Scripts/SaveSystem/SnapshotRestore.cs | 26 +++- .../SaveSystem/SnapshotSectionDeserializer.cs | 31 ----- .../SnapshotSectionDeserializer.cs.meta | 11 -- .../Scripts/SaveSystem/SnapshotSerializer.cs | 115 ------------------ .../SaveSystem/SnapshotSerializer.cs.meta | 11 -- Assets/Scripts/SaveSystem/SnapshotService.cs | 4 +- 16 files changed, 165 insertions(+), 307 deletions(-) delete mode 100644 Assets/Scripts/SaveSystem/SaveSnapshotSummary.cs delete mode 100644 Assets/Scripts/SaveSystem/SaveSnapshotSummary.cs.meta delete mode 100644 Assets/Scripts/SaveSystem/SnapshotBootstrap.cs delete mode 100644 Assets/Scripts/SaveSystem/SnapshotBootstrap.cs.meta delete mode 100644 Assets/Scripts/SaveSystem/SnapshotProviderIds.cs delete mode 100644 Assets/Scripts/SaveSystem/SnapshotProviderIds.cs.meta delete mode 100644 Assets/Scripts/SaveSystem/SnapshotSectionDeserializer.cs delete mode 100644 Assets/Scripts/SaveSystem/SnapshotSectionDeserializer.cs.meta delete mode 100644 Assets/Scripts/SaveSystem/SnapshotSerializer.cs delete mode 100644 Assets/Scripts/SaveSystem/SnapshotSerializer.cs.meta diff --git a/Assets/Scripts/Game Loop/YarnVariableStorage.cs b/Assets/Scripts/Game Loop/YarnVariableStorage.cs index 35b2dfe04..4891c22c9 100644 --- a/Assets/Scripts/Game Loop/YarnVariableStorage.cs +++ b/Assets/Scripts/Game Loop/YarnVariableStorage.cs @@ -211,7 +211,7 @@ namespace AibisDream } Instance = this; - SnapshotBootstrap.EnsureInitialized(); + SnapshotRegistry.EnsureInitialized(); } #endregion diff --git a/Assets/Scripts/SaveSystem/SaveSnapshot.cs b/Assets/Scripts/SaveSystem/SaveSnapshot.cs index af381c5e4..121b7a2f0 100644 --- a/Assets/Scripts/SaveSystem/SaveSnapshot.cs +++ b/Assets/Scripts/SaveSystem/SaveSnapshot.cs @@ -198,4 +198,45 @@ namespace AibisDream.SaveSystem } #endregion + + /// + /// 从 根对象直接读取的宏观摘要(场景 / 章节 SO / YarnProject)。 + /// + /// scene 与 anchor 已提升到根对象,无需再从 sections 字典派生。 + /// 槽位 / 「继续游戏」等 UI 在需要展示时调用 即可。 + /// + /// + public readonly struct SaveSnapshotSummary + { + /// Addressable 场景 key(来自 )。 + public readonly string SceneName; + + /// 当前 TalkSceneSO 的 asset 名称(来自 )。 + public readonly string SceneSoName; + + /// 当前 YarnProject 的 name(来自 )。 + public readonly string YarnProjectId; + + public SaveSnapshotSummary(string sceneName, string sceneSoName, string yarnProjectId) + { + SceneName = sceneName; + SceneSoName = sceneSoName; + YarnProjectId = yarnProjectId; + } + + /// 从快照根对象直接读取宏观摘要。 + public static SaveSnapshotSummary From(SaveSnapshot snapshot) + { + if (snapshot == null) + { + return new SaveSnapshotSummary(null, null, null); + } + + var sceneName = snapshot.scene?.sceneName; + var sceneSoName = snapshot.anchor?.sceneSoName; + var yarnProjectId = snapshot.anchor?.yarnProjectId; + + return new SaveSnapshotSummary(sceneName, sceneSoName, yarnProjectId); + } + } } diff --git a/Assets/Scripts/SaveSystem/SaveSnapshotSummary.cs b/Assets/Scripts/SaveSystem/SaveSnapshotSummary.cs deleted file mode 100644 index 203dc1961..000000000 --- a/Assets/Scripts/SaveSystem/SaveSnapshotSummary.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace AibisDream.SaveSystem -{ - /// - /// 从 根对象直接读取的宏观摘要(场景 / 章节 SO / YarnProject)。 - /// - /// scene 与 anchor 已提升到根对象,无需再从 sections 字典派生。 - /// 槽位 / 「继续游戏」等 UI 在需要展示时调用 即可。 - /// - /// - public readonly struct SaveSnapshotSummary - { - /// Addressable 场景 key(来自 )。 - public readonly string SceneName; - - /// 当前 TalkSceneSO 的 asset 名称(来自 )。 - public readonly string SceneSoName; - - /// 当前 YarnProject 的 name(来自 )。 - public readonly string YarnProjectId; - - public SaveSnapshotSummary(string sceneName, string sceneSoName, string yarnProjectId) - { - SceneName = sceneName; - SceneSoName = sceneSoName; - YarnProjectId = yarnProjectId; - } - - /// 从快照根对象直接读取宏观摘要。 - public static SaveSnapshotSummary From(SaveSnapshot snapshot) - { - if (snapshot == null) - { - return new SaveSnapshotSummary(null, null, null); - } - - var sceneName = snapshot.scene?.sceneName; - var sceneSoName = snapshot.anchor?.sceneSoName; - var yarnProjectId = snapshot.anchor?.yarnProjectId; - - return new SaveSnapshotSummary(sceneName, sceneSoName, yarnProjectId); - } - } -} diff --git a/Assets/Scripts/SaveSystem/SaveSnapshotSummary.cs.meta b/Assets/Scripts/SaveSystem/SaveSnapshotSummary.cs.meta deleted file mode 100644 index 1da3b3180..000000000 --- a/Assets/Scripts/SaveSystem/SaveSnapshotSummary.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5b1c9a2f7d3e4c8a9b6f0d1e2a3c4b5d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/SaveSystem/SnapshotBootstrap.cs b/Assets/Scripts/SaveSystem/SnapshotBootstrap.cs deleted file mode 100644 index 1662efd48..000000000 --- a/Assets/Scripts/SaveSystem/SnapshotBootstrap.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace AibisDream.SaveSystem -{ - /// - /// 一次性注册 P1 所需的全部 。 - /// 由 在首次使用时调用。 - /// - public static class SnapshotBootstrap - { - private static bool _initialized; - - /// 幂等;重复调用无副作用。 - public static void EnsureInitialized() - { - if (_initialized) return; - _initialized = true; - - SnapshotRegistry.Register(new EnvironmentSnapshotProvider()); - SnapshotRegistry.Register(new ActorSnapshotProvider()); - SnapshotRegistry.Register(new AudioSnapshotProvider()); - SnapshotRegistry.Register(new TimelineSnapshotProvider()); - SnapshotRegistry.Register(new FixSnapshotProvider()); - SnapshotRegistry.Register(new ScreenSnapshotProvider()); - } - - } -} diff --git a/Assets/Scripts/SaveSystem/SnapshotBootstrap.cs.meta b/Assets/Scripts/SaveSystem/SnapshotBootstrap.cs.meta deleted file mode 100644 index f5858fb00..000000000 --- a/Assets/Scripts/SaveSystem/SnapshotBootstrap.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 8deaa7a6856bb384fba9e42453a06e1d -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/SaveSystem/SnapshotPersistence.cs b/Assets/Scripts/SaveSystem/SnapshotPersistence.cs index d1c9fea55..8c18377db 100644 --- a/Assets/Scripts/SaveSystem/SnapshotPersistence.cs +++ b/Assets/Scripts/SaveSystem/SnapshotPersistence.cs @@ -1,34 +1,84 @@ using System.IO; using AibisDream.Utility; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using UnityEngine; namespace AibisDream.SaveSystem { /// - /// 快照与磁盘的边界:读写 JSON 文件、检测旧档格式。 + /// 快照与磁盘的边界:序列化、读写 JSON 文件、检测旧档格式。 /// - /// P1 使用固定测试路径(); - /// P2 将扩展为槽位目录、原子写、sidecar,接口可保持不变。 + /// P2 起,业务存档统一通过 写入槽位目录; + /// 本类保留按路径读写的低级接口,供旧档兼容、迁移和外部调试使用。 /// /// public static class SnapshotPersistence { - /// P1 自测落盘:SnapshotTestPath/latest_snapshot.json + private static readonly JsonSerializerSettings Settings = new() + { + TypeNameHandling = TypeNameHandling.None, + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + NullValueHandling = NullValueHandling.Ignore + }; + + /// P1 自测落盘:SnapshotTestPath/latest_snapshot.json(P2 迁移源)。 public static string GetTestFilePath() { return Path.Combine(ConstRef.SnapshotTestPath, ConstRef.SnapshotTestFileName); } + /// 将快照序列化并写入指定槽位。 + public static void SaveToSlot(int slotIndex, SaveSnapshot snapshot) + { + SlotManager.SaveToSlot(slotIndex, snapshot, null); + } + + /// 从指定槽位读取快照。 + public static SaveSnapshot LoadFromSlot(int slotIndex) + { + return SlotManager.LoadSnapshot(slotIndex); + } + + /// 将快照序列化为 JSON 字符串。 + public static string Serialize(SaveSnapshot snapshot) + { + snapshot.schemaVersion = SaveSnapshotSchema.CurrentVersion; + return JsonConvert.SerializeObject(snapshot, Formatting.Indented, Settings); + } + + /// 从 JSON 字符串反序列化为快照。 + public static SaveSnapshot Deserialize(string json) + { + var snapshot = JsonConvert.DeserializeObject(json, Settings); + if (snapshot != null && snapshot.schemaVersion != SaveSnapshotSchema.CurrentVersion) + { + Debug.LogWarning( + $"[SnapshotPersistence] schemaVersion {snapshot.schemaVersion} != {SaveSnapshotSchema.CurrentVersion},按当前结构读取。"); + } + + return snapshot; + } + /// 将快照序列化并写入 path(自动补 .json 后缀)。 public static void Save(SaveSnapshot snapshot, string pathWithoutExtension) { - SnapshotSerializer.SaveToFile(snapshot, pathWithoutExtension); + var json = Serialize(snapshot); + var path = JsonUtil.FormatAsJsonPath(pathWithoutExtension); + var dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir)) + { + Directory.CreateDirectory(dir); + } + + File.WriteAllText(path, json); } /// 从 path 读取并反序列化为 public static SaveSnapshot Load(string pathWithoutExtension) { - return SnapshotSerializer.LoadFromFile(pathWithoutExtension); + var json = File.ReadAllText(JsonUtil.FormatAsJsonPath(pathWithoutExtension)); + return Deserialize(json); } /// diff --git a/Assets/Scripts/SaveSystem/SnapshotProviderIds.cs b/Assets/Scripts/SaveSystem/SnapshotProviderIds.cs deleted file mode 100644 index 4173e1172..000000000 --- a/Assets/Scripts/SaveSystem/SnapshotProviderIds.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace AibisDream.SaveSystem -{ - /// - /// 快照 section 的稳定字符串 id。 - /// 用于 JSON key、Provider 注册与反序列化,避免使用 AssemblyQualifiedName。 - /// - public static class SnapshotProviderIds - { - public const string Environment = "env"; - public const string Actor = "actor"; - public const string Audio = "audio"; - public const string Timeline = "timeline"; - public const string Screen = "screen"; - public const string Fix = "fix"; - - /// - /// P1 应参与 Capture 的 provider 清单。 - /// 据此告警缺失项;不含深度维修。 - /// scene 与 macro 已提升到 根对象,由框架直管。 - /// - public static readonly string[] RequiredForCapture = - { - Environment, Actor, Audio, Timeline, Fix, Screen - }; - } -} diff --git a/Assets/Scripts/SaveSystem/SnapshotProviderIds.cs.meta b/Assets/Scripts/SaveSystem/SnapshotProviderIds.cs.meta deleted file mode 100644 index 041c1bf2a..000000000 --- a/Assets/Scripts/SaveSystem/SnapshotProviderIds.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 961a9f94f713b334388b4d1a0b1018c4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/SaveSystem/SnapshotRegistry.cs b/Assets/Scripts/SaveSystem/SnapshotRegistry.cs index 7f2d5fdfe..eaedfc5c0 100644 --- a/Assets/Scripts/SaveSystem/SnapshotRegistry.cs +++ b/Assets/Scripts/SaveSystem/SnapshotRegistry.cs @@ -1,9 +1,33 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using UnityEngine; namespace AibisDream.SaveSystem { + /// + /// 快照 section 的稳定字符串 id。 + /// 用于 JSON key、Provider 注册与反序列化,避免使用 AssemblyQualifiedName。 + /// + public static class SnapshotProviderIds + { + public const string Environment = "env"; + public const string Actor = "actor"; + public const string Audio = "audio"; + public const string Timeline = "timeline"; + public const string Screen = "screen"; + public const string Fix = "fix"; + + /// + /// P1 应参与 Capture 的 provider 清单。 + /// 据此告警缺失项;不含深度维修。 + /// scene 与 macro 已提升到 根对象,由框架直管。 + /// + public static readonly string[] RequiredForCapture = + { + Environment, Actor, Audio, Timeline, Fix, Screen + }; + } + /// /// 运行时登记全部 。 /// Capture/Restore 时按 迭代; @@ -12,6 +36,21 @@ namespace AibisDream.SaveSystem public static class SnapshotRegistry { private static readonly Dictionary Providers = new(); + private static bool _initialized; + + /// 幂等初始化:注册 P1 所需的全部 Provider。 + public static void EnsureInitialized() + { + if (_initialized) return; + _initialized = true; + + Register(new EnvironmentSnapshotProvider()); + Register(new ActorSnapshotProvider()); + Register(new AudioSnapshotProvider()); + Register(new TimelineSnapshotProvider()); + Register(new FixSnapshotProvider()); + Register(new ScreenSnapshotProvider()); + } /// 注册 provider;同 SaveId 后者覆盖前者。 public static void Register(ISnapshotProvider provider) diff --git a/Assets/Scripts/SaveSystem/SnapshotRestore.cs b/Assets/Scripts/SaveSystem/SnapshotRestore.cs index 3eba9c504..40c83d92c 100644 --- a/Assets/Scripts/SaveSystem/SnapshotRestore.cs +++ b/Assets/Scripts/SaveSystem/SnapshotRestore.cs @@ -1,4 +1,5 @@ using System.Collections; +using Newtonsoft.Json.Linq; using UnityEngine; namespace AibisDream.SaveSystem @@ -34,7 +35,7 @@ namespace AibisDream.SaveSystem continue; } - dto = SnapshotSectionDeserializer.Coerce(provider.SaveId, dto); + dto = CoerceSectionDto(provider.SaveId, dto); yield return provider.Restore(dto); } @@ -129,5 +130,28 @@ namespace AibisDream.SaveSystem gameManager.SetSceneSoByName(snapshot.anchor.sceneSoName); } + + /// + /// 读盘后 中的值常为 ; + /// 按 SaveId 转回各 Provider 所需的强类型 DTO。 + /// + private static object CoerceSectionDto(string saveId, object dto) + { + if (dto is not JObject jobj) + { + return dto; + } + + return saveId switch + { + SnapshotProviderIds.Environment => jobj.ToObject(), + SnapshotProviderIds.Actor => jobj.ToObject(), + SnapshotProviderIds.Audio => jobj.ToObject(), + SnapshotProviderIds.Timeline => jobj.ToObject(), + SnapshotProviderIds.Fix => jobj.ToObject(), + SnapshotProviderIds.Screen => jobj.ToObject(), + _ => jobj + }; + } } } diff --git a/Assets/Scripts/SaveSystem/SnapshotSectionDeserializer.cs b/Assets/Scripts/SaveSystem/SnapshotSectionDeserializer.cs deleted file mode 100644 index 6352d80ae..000000000 --- a/Assets/Scripts/SaveSystem/SnapshotSectionDeserializer.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Newtonsoft.Json.Linq; - -namespace AibisDream.SaveSystem -{ - /// - /// 读盘后 中的值常为 ; - /// 本类按 SaveId 转回各 Provider 所需的强类型 DTO。 - /// - public static class SnapshotSectionDeserializer - { - /// 若 dto 已是强类型则原样返回;若为 JObject 则 ToObject 到对应 DTO。 - public static object Coerce(string saveId, object dto) - { - if (dto is not JObject jobj) - { - return dto; - } - - return saveId switch - { - SnapshotProviderIds.Environment => jobj.ToObject(), - SnapshotProviderIds.Actor => jobj.ToObject(), - SnapshotProviderIds.Audio => jobj.ToObject(), - SnapshotProviderIds.Timeline => jobj.ToObject(), - SnapshotProviderIds.Fix => jobj.ToObject(), - SnapshotProviderIds.Screen => jobj.ToObject(), - _ => jobj - }; - } - } -} diff --git a/Assets/Scripts/SaveSystem/SnapshotSectionDeserializer.cs.meta b/Assets/Scripts/SaveSystem/SnapshotSectionDeserializer.cs.meta deleted file mode 100644 index a62a9a546..000000000 --- a/Assets/Scripts/SaveSystem/SnapshotSectionDeserializer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d7def29588434ab48b6f6768daf76635 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/SaveSystem/SnapshotSerializer.cs b/Assets/Scripts/SaveSystem/SnapshotSerializer.cs deleted file mode 100644 index dc3ffdc00..000000000 --- a/Assets/Scripts/SaveSystem/SnapshotSerializer.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System; - -using AibisDream.Utility; - -using Newtonsoft.Json; - -using UnityEngine; - - - -namespace AibisDream.SaveSystem - -{ - - /// - - /// 与 JSON 互转;写入时带上 。 - - /// 被 调用,业务层通常不直接使用。 - - /// - - public static class SnapshotSerializer - - { - - private static readonly JsonSerializerSettings Settings = new() - - { - - TypeNameHandling = TypeNameHandling.None, - - ReferenceLoopHandling = ReferenceLoopHandling.Ignore, - - NullValueHandling = NullValueHandling.Ignore - - }; - - - - public static string Serialize(SaveSnapshot snapshot) - - { - - snapshot.schemaVersion = SaveSnapshotSchema.CurrentVersion; - - return JsonConvert.SerializeObject(snapshot, Formatting.Indented, Settings); - - } - - - - public static SaveSnapshot Deserialize(string json) - - { - - var snapshot = JsonConvert.DeserializeObject(json, Settings); - - if (snapshot.schemaVersion != SaveSnapshotSchema.CurrentVersion) - - { - - Debug.LogWarning( - - $"[SnapshotSerializer] schemaVersion {snapshot.schemaVersion} != {SaveSnapshotSchema.CurrentVersion},按当前结构读取。"); - - } - - - - return snapshot; - - } - - - - public static void SaveToFile(SaveSnapshot snapshot, string pathWithoutExtension) - - { - - var json = Serialize(snapshot); - - var dir = System.IO.Path.GetDirectoryName(JsonUtil.FormatAsJsonPath(pathWithoutExtension)); - - if (!string.IsNullOrEmpty(dir)) - - { - - System.IO.Directory.CreateDirectory(dir); - - } - - - - System.IO.File.WriteAllText(JsonUtil.FormatAsJsonPath(pathWithoutExtension), json); - - } - - - - public static SaveSnapshot LoadFromFile(string pathWithoutExtension) - - { - - var json = System.IO.File.ReadAllText(JsonUtil.FormatAsJsonPath(pathWithoutExtension)); - - return Deserialize(json); - - } - - } - -} - - diff --git a/Assets/Scripts/SaveSystem/SnapshotSerializer.cs.meta b/Assets/Scripts/SaveSystem/SnapshotSerializer.cs.meta deleted file mode 100644 index 12a8127fb..000000000 --- a/Assets/Scripts/SaveSystem/SnapshotSerializer.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f57d93779e83c064f9ba2490e623e5b4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/SaveSystem/SnapshotService.cs b/Assets/Scripts/SaveSystem/SnapshotService.cs index 7e6d6b4b1..1dd22cd32 100644 --- a/Assets/Scripts/SaveSystem/SnapshotService.cs +++ b/Assets/Scripts/SaveSystem/SnapshotService.cs @@ -11,7 +11,7 @@ namespace AibisDream.SaveSystem /// 捕获当前运行时快照。 public static SaveSnapshot Capture() { - SnapshotBootstrap.EnsureInitialized(); + SnapshotRegistry.EnsureInitialized(); return SnapshotCapture.Capture(YarnVariableStorage.Instance); } @@ -26,7 +26,7 @@ namespace AibisDream.SaveSystem yield break; } - SnapshotBootstrap.EnsureInitialized(); + SnapshotRegistry.EnsureInitialized(); yield return SnapshotRestore.Restore(YarnVariableStorage.Instance, snapshot); if (restoreAnchor)