feat: 清除几个旧的混用测试存档功能
This commit is contained in:
@@ -78,9 +78,6 @@ crashlytics-build.properties
|
||||
# Local Save Files
|
||||
/[Aa]ssets/[Ss]treamingAssets/SaveFiles/*
|
||||
|
||||
# DevSaveFiles lives outside Assets; Unity metadata from the old location is not needed.
|
||||
/DevSaveFiles/**/*.meta
|
||||
|
||||
# Never ignore DLLs in the FMOD subfolder.
|
||||
!/[Aa]ssets/Plugins/FMOD/**/lib/*
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace AibisDream.DeveloperMode.Editor
|
||||
{
|
||||
private const string PrefabPath = "Assets/GameContent/Feature_MainUI/Prefabs/DeveloperModePanel.prefab";
|
||||
private const string ScenePath = "Assets/Scenes/Persistence.unity";
|
||||
private const string FontAssetPath = "Assets/Font/Assets/WenQuanYi Bitmap Song 14px SDF.asset";
|
||||
private static readonly Color Background = new(0.025f, 0.045f, 0.065f, 0.97f);
|
||||
private static readonly Color Surface = new(0.055f, 0.085f, 0.11f, 0.96f);
|
||||
private static readonly Color Accent = new(0.16f, 0.75f, 0.88f, 1f);
|
||||
@@ -82,7 +83,7 @@ namespace AibisDream.DeveloperMode.Editor
|
||||
var tabs = CreateHorizontal("Tabs", root.transform, 4f, new RectOffset(4, 4, 3, 3));
|
||||
SetAnchors(tabs.GetComponent<RectTransform>(), new Vector2(0f, 1f), new Vector2(1f, 1f),
|
||||
new Vector2(0f, -88f), new Vector2(0f, -46f));
|
||||
var tabNames = new[] { "概览", "日志", "Yarn 变量", "存档跳转", "显示与控制" };
|
||||
var tabNames = new[] { "概览", "日志", "Yarn 变量", "存档槽位", "显示与控制" };
|
||||
var tabButtons = tabNames.Select(name => CreateButton($"Tab {name}", tabs.transform, name, 0f, 34f)).ToArray();
|
||||
foreach (var button in tabButtons)
|
||||
{
|
||||
@@ -214,31 +215,17 @@ namespace AibisDream.DeveloperMode.Editor
|
||||
var page = CreateVertical("Saves Page", parent, 6f, new RectOffset(8, 8, 8, 8));
|
||||
var toolbar = CreateHorizontal("Toolbar", page.transform, 6f, new RectOffset(0, 0, 0, 0));
|
||||
AddLayout(toolbar, 38f);
|
||||
var search = CreateInput("Save Search", toolbar.transform, "搜索开发检查点...", 350f);
|
||||
var reload = CreateButton("Reload Saves", toolbar.transform, "重新扫描", 110f, 34f);
|
||||
var status = CreateText("Save Status", toolbar.transform, "Ready", 14f);
|
||||
AddFlexible(status.gameObject);
|
||||
status.alignment = TextAlignmentOptions.MidlineRight;
|
||||
|
||||
var columns = CreateHorizontal("Save Columns", page.transform, 8f, new RectOffset(0, 0, 0, 0));
|
||||
var columnsLayout = columns.AddComponent<LayoutElement>();
|
||||
columnsLayout.flexibleHeight = 1f;
|
||||
|
||||
var slotColumn = CreateVertical("Official Slots", columns.transform, 4f, new RectOffset(0, 0, 0, 0));
|
||||
var slotColumn = CreateVertical("Official Slots", page.transform, 4f, new RectOffset(0, 0, 0, 0));
|
||||
var slotLayout = slotColumn.AddComponent<LayoutElement>();
|
||||
slotLayout.preferredWidth = 330f;
|
||||
slotLayout.flexibleHeight = 1f;
|
||||
var slotTitle = CreateText("Title", slotColumn.transform, "正式槽位(点击读档)", 16f, FontStyles.Bold);
|
||||
AddLayout(slotTitle.gameObject, 28f);
|
||||
CreateList("Slot List", slotColumn.transform, 430f, out var slotContent, out var slotTemplate);
|
||||
|
||||
var devColumn = CreateVertical("Dev Saves", columns.transform, 4f, new RectOffset(0, 0, 0, 0));
|
||||
var devLayout = devColumn.AddComponent<LayoutElement>();
|
||||
devLayout.flexibleWidth = 1f;
|
||||
devLayout.flexibleHeight = 1f;
|
||||
var devTitle = CreateText("Title", devColumn.transform, "开发检查点(严格恢复)", 16f, FontStyles.Bold);
|
||||
AddLayout(devTitle.gameObject, 28f);
|
||||
CreateList("Dev Save List", devColumn.transform, 430f, out var devContent, out var devTemplate);
|
||||
CreateList("Slot List", slotColumn.transform, 500f, out var slotContent, out var slotTemplate);
|
||||
|
||||
var paths1 = CreateHorizontal("Paths 1", page.transform, 5f, new RectOffset(0, 0, 0, 0));
|
||||
AddLayout(paths1, 34f);
|
||||
@@ -246,26 +233,17 @@ namespace AibisDream.DeveloperMode.Editor
|
||||
var copySave = CreateButton("Copy Saves", paths1.transform, "复制存档路径", 130f, 30f);
|
||||
var openLog = CreateButton("Open Logs", paths1.transform, "打开日志目录", 130f, 30f);
|
||||
var copyLog = CreateButton("Copy Logs", paths1.transform, "复制日志路径", 130f, 30f);
|
||||
var paths2 = CreateHorizontal("Paths 2", page.transform, 5f, new RectOffset(0, 0, 0, 0));
|
||||
AddLayout(paths2, 34f);
|
||||
var openDev = CreateButton("Open Dev Saves", paths2.transform, "打开检查点目录", 140f, 30f);
|
||||
var copyDev = CreateButton("Copy Dev Saves", paths2.transform, "复制检查点路径", 140f, 30f);
|
||||
var openCurrent = CreateButton("Open Current Log", paths2.transform, "定位当前日志", 130f, 30f);
|
||||
var copyCurrent = CreateButton("Copy Current Log", paths2.transform, "复制当前日志", 130f, 30f);
|
||||
var openCurrent = CreateButton("Open Current Log", paths1.transform, "定位当前日志", 130f, 30f);
|
||||
var copyCurrent = CreateButton("Copy Current Log", paths1.transform, "复制当前日志", 130f, 30f);
|
||||
|
||||
refs.Add("saveSearchInput", search);
|
||||
refs.Add("reloadSavesButton", reload.GetComponent<Button>());
|
||||
refs.Add("saveStatusText", status);
|
||||
refs.Add("slotContent", slotContent);
|
||||
refs.Add("slotRowTemplate", slotTemplate);
|
||||
refs.Add("devSaveContent", devContent);
|
||||
refs.Add("devSaveRowTemplate", devTemplate);
|
||||
refs.Add("openSaveFolderButton", openSave.GetComponent<Button>());
|
||||
refs.Add("copySaveFolderButton", copySave.GetComponent<Button>());
|
||||
refs.Add("openLogFolderButton", openLog.GetComponent<Button>());
|
||||
refs.Add("copyLogFolderButton", copyLog.GetComponent<Button>());
|
||||
refs.Add("openDevSaveFolderButton", openDev.GetComponent<Button>());
|
||||
refs.Add("copyDevSaveFolderButton", copyDev.GetComponent<Button>());
|
||||
refs.Add("openCurrentLogButton", openCurrent.GetComponent<Button>());
|
||||
refs.Add("copyCurrentLogButton", copyCurrent.GetComponent<Button>());
|
||||
return page;
|
||||
@@ -407,7 +385,7 @@ namespace AibisDream.DeveloperMode.Editor
|
||||
var go = CreateUiObject(name, typeof(CanvasRenderer), typeof(TextMeshProUGUI));
|
||||
go.transform.SetParent(parent, false);
|
||||
var text = go.GetComponent<TextMeshProUGUI>();
|
||||
text.font = TMP_Settings.defaultFontAsset;
|
||||
text.font = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(FontAssetPath);
|
||||
text.text = value;
|
||||
text.fontSize = size;
|
||||
text.fontStyle = style;
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d4c5a2b82ac1ca459e228aaad3255c6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,536 +0,0 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using AibisDream.SaveSystem;
|
||||
using AibisDream.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AddressableAssets;
|
||||
using UnityEditor.AddressableAssets.Settings;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
|
||||
namespace AibisDream.EditorTools
|
||||
{
|
||||
/// <summary>从本机 testsavs 选择章节、去重排序并提升为可提交测试档。</summary>
|
||||
public sealed class DevSavePromoteWindow : EditorWindow
|
||||
{
|
||||
private readonly List<ArchiveGroup> groups = new();
|
||||
private readonly List<Candidate> preview = new();
|
||||
private int selectedGroup;
|
||||
private string sectionId = string.Empty;
|
||||
private string sectionTitle = string.Empty;
|
||||
private string status = string.Empty;
|
||||
private Vector2 scroll;
|
||||
|
||||
[MenuItem("Tools/Aibis/Dev Save Promote")]
|
||||
public static void Open()
|
||||
{
|
||||
var window = GetWindow<DevSavePromoteWindow>("Dev Save Promote");
|
||||
window.minSize = new Vector2(720f, 520f);
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private void OnEnable() => RefreshGroups();
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
EditorGUILayout.LabelField("测试存档提升与校验", EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox(
|
||||
"来源是本机 testsavs;目标是项目根目录的 DevSaveFiles。该目录可提交,但不会被 Unity 自动打包。",
|
||||
MessageType.Info);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("刷新本机归档", GUILayout.Height(26f))) RefreshGroups();
|
||||
if (GUILayout.Button("校验全部已提交测试档", GUILayout.Height(26f))) ValidateCommittedCatalog();
|
||||
}
|
||||
|
||||
if (groups.Count == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("本机没有可用 testsavs。", MessageType.Warning);
|
||||
DrawStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
var labels = groups.Select(group =>
|
||||
$"{group.SceneSoName} | {group.YarnProjectId} | {group.SceneName} ({group.Items.Count})").ToArray();
|
||||
var nextGroup = EditorGUILayout.Popup("章节归档", Mathf.Clamp(selectedGroup, 0, labels.Length - 1), labels);
|
||||
if (nextGroup != selectedGroup || preview.Count == 0)
|
||||
{
|
||||
selectedGroup = nextGroup;
|
||||
SelectGroup(groups[selectedGroup]);
|
||||
}
|
||||
|
||||
sectionId = EditorGUILayout.TextField("Section Id", sectionId);
|
||||
sectionTitle = EditorGUILayout.TextField("显示名称", sectionTitle);
|
||||
EditorGUILayout.LabelField("规则", "每个 Yarn 节点保留 savedAt 最新一份;默认按 savedAt 升序");
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button("提升当前章节", GUILayout.Width(180f), GUILayout.Height(28f))) Promote();
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(5f);
|
||||
EditorGUILayout.LabelField($"阶段预览:{preview.Count}", EditorStyles.boldLabel);
|
||||
scroll = EditorGUILayout.BeginScrollView(scroll);
|
||||
for (var i = 0; i < preview.Count; i++)
|
||||
{
|
||||
var item = preview[i];
|
||||
using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox))
|
||||
{
|
||||
EditorGUILayout.LabelField($"{i + 1:000}", GUILayout.Width(38f));
|
||||
item.Label = EditorGUILayout.TextField(item.Label, GUILayout.Width(210f));
|
||||
EditorGUILayout.LabelField(item.NodeName, GUILayout.MinWidth(180f));
|
||||
EditorGUILayout.LabelField(item.SavedAt, GUILayout.Width(140f));
|
||||
using (new EditorGUI.DisabledScope(i == 0))
|
||||
{
|
||||
if (GUILayout.Button("↑", GUILayout.Width(26f))) Move(i, i - 1);
|
||||
}
|
||||
using (new EditorGUI.DisabledScope(i == preview.Count - 1))
|
||||
{
|
||||
if (GUILayout.Button("↓", GUILayout.Width(26f))) Move(i, i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndScrollView();
|
||||
DrawStatus();
|
||||
}
|
||||
|
||||
private void DrawStatus()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(status))
|
||||
EditorGUILayout.HelpBox(status, status.StartsWith("OK", StringComparison.Ordinal) ? MessageType.Info : MessageType.Warning);
|
||||
}
|
||||
|
||||
private void RefreshGroups()
|
||||
{
|
||||
groups.Clear();
|
||||
preview.Clear();
|
||||
var root = ConstRef.TestAutoSaveArchivePath;
|
||||
if (!Directory.Exists(root))
|
||||
{
|
||||
status = $"找不到本机归档:{root}";
|
||||
return;
|
||||
}
|
||||
|
||||
var candidates = new List<Candidate>();
|
||||
foreach (var directory in Directory.GetDirectories(root))
|
||||
{
|
||||
var snapshotPath = Path.Combine(directory, $"{ConstRef.SaveSnapshotFileName}.json");
|
||||
if (!File.Exists(snapshotPath)) continue;
|
||||
try
|
||||
{
|
||||
var snapshot = SnapshotPersistence.Load(Path.Combine(directory, ConstRef.SaveSnapshotFileName));
|
||||
if (snapshot?.anchor == null || string.IsNullOrWhiteSpace(snapshot.anchor.nodeName)) continue;
|
||||
candidates.Add(new Candidate(
|
||||
snapshotPath,
|
||||
Path.Combine(directory, $"{ConstRef.SaveMetaFileName}.json"),
|
||||
snapshot.scene?.sceneName,
|
||||
snapshot.anchor.sceneSoName,
|
||||
snapshot.anchor.yarnProjectId,
|
||||
snapshot.anchor.nodeName,
|
||||
snapshot.savedAt));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[DevSavePromote] 跳过损坏归档 {snapshotPath}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
groups.AddRange(candidates
|
||||
.GroupBy(item => $"{item.SceneName}\n{item.SceneSoName}\n{item.YarnProjectId}", StringComparer.Ordinal)
|
||||
.Select(group => new ArchiveGroup(group.ToList()))
|
||||
.OrderBy(group => group.SceneSoName, StringComparer.Ordinal));
|
||||
selectedGroup = Mathf.Clamp(selectedGroup, 0, Math.Max(0, groups.Count - 1));
|
||||
if (groups.Count > 0) SelectGroup(groups[selectedGroup]);
|
||||
status = $"OK:读取 {candidates.Count} 份归档,分为 {groups.Count} 个章节。";
|
||||
}
|
||||
|
||||
private void SelectGroup(ArchiveGroup group)
|
||||
{
|
||||
preview.Clear();
|
||||
preview.AddRange(group.Items
|
||||
.GroupBy(item => item.NodeName, StringComparer.Ordinal)
|
||||
.Select(nodes => nodes.OrderByDescending(item => item.SavedAt, StringComparer.Ordinal).First())
|
||||
.OrderBy(item => item.SavedAt, StringComparer.Ordinal));
|
||||
sectionId = SanitizeIdentifier(group.SceneSoName);
|
||||
sectionTitle = group.SceneSoName;
|
||||
}
|
||||
|
||||
private void Move(int from, int to)
|
||||
{
|
||||
if (from < 0 || to < 0 || from >= preview.Count || to >= preview.Count) return;
|
||||
var item = preview[from];
|
||||
preview.RemoveAt(from);
|
||||
preview.Insert(to, item);
|
||||
GUI.FocusControl(null);
|
||||
}
|
||||
|
||||
private void Promote()
|
||||
{
|
||||
if (preview.Count == 0 || string.IsNullOrWhiteSpace(sectionId))
|
||||
{
|
||||
status = "没有可提升阶段,或 Section Id 为空。";
|
||||
return;
|
||||
}
|
||||
|
||||
var validation = ValidateCandidates(preview);
|
||||
if (validation.Count > 0)
|
||||
{
|
||||
status = string.Join("\n", validation);
|
||||
return;
|
||||
}
|
||||
|
||||
var group = groups[selectedGroup];
|
||||
var root = ConstRef.TestSaveFilePath;
|
||||
var targetSection = Path.Combine(root, sectionId);
|
||||
if (Directory.Exists(targetSection)) Directory.Delete(targetSection, true);
|
||||
Directory.CreateDirectory(targetSection);
|
||||
|
||||
var catalog = LoadCatalogForWrite();
|
||||
catalog.sections.RemoveAll(section => string.Equals(section.id, sectionId, StringComparison.OrdinalIgnoreCase));
|
||||
var sectionDto = new DevSaveCatalogSectionDto
|
||||
{
|
||||
order = FindDemoChapterOrder(group.SceneSoName),
|
||||
id = sectionId,
|
||||
title = string.IsNullOrWhiteSpace(sectionTitle) ? sectionId : sectionTitle,
|
||||
expectedSceneName = group.SceneName,
|
||||
expectedSceneSoName = group.SceneSoName,
|
||||
expectedYarnProjectId = group.YarnProjectId
|
||||
};
|
||||
|
||||
for (var i = 0; i < preview.Count; i++)
|
||||
{
|
||||
var item = preview[i];
|
||||
var folder = $"{i + 1:000}_{SanitizeIdentifier(item.NodeName)}";
|
||||
var destination = Path.Combine(targetSection, folder);
|
||||
Directory.CreateDirectory(destination);
|
||||
File.Copy(item.SnapshotPath, Path.Combine(destination, $"{ConstRef.SaveSnapshotFileName}.json"), true);
|
||||
if (File.Exists(item.MetaPath))
|
||||
File.Copy(item.MetaPath, Path.Combine(destination, $"{ConstRef.SaveMetaFileName}.json"), true);
|
||||
sectionDto.entries.Add(new DevSaveCatalogEntryDto
|
||||
{
|
||||
order = i + 1,
|
||||
label = string.IsNullOrWhiteSpace(item.Label) ? item.NodeName : item.Label,
|
||||
path = $"{sectionId}/{folder}",
|
||||
anchorNode = item.NodeName
|
||||
});
|
||||
}
|
||||
|
||||
catalog.sections.Add(sectionDto);
|
||||
catalog.sections.Sort((left, right) => left.order.CompareTo(right.order));
|
||||
WriteCatalog(catalog);
|
||||
AssetDatabase.Refresh();
|
||||
ValidateCommittedCatalog();
|
||||
}
|
||||
|
||||
private static List<string> ValidateCandidates(IEnumerable<Candidate> candidates)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
var nodes = new HashSet<string>(StringComparer.Ordinal);
|
||||
foreach (var item in candidates)
|
||||
{
|
||||
if (!nodes.Add(item.NodeName)) errors.Add($"重复节点:{item.NodeName}");
|
||||
try
|
||||
{
|
||||
var snapshot = SnapshotPersistence.Load(Path.Combine(Path.GetDirectoryName(item.SnapshotPath)!, ConstRef.SaveSnapshotFileName));
|
||||
if (snapshot.schemaVersion != SaveSnapshotSchema.CurrentVersion)
|
||||
errors.Add($"{item.NodeName}: schema {snapshot.schemaVersion} 不兼容");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errors.Add($"{item.NodeName}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
private void ValidateCommittedCatalog()
|
||||
{
|
||||
var sections = DevSaveCatalog.Load(ConstRef.TestSaveFilePath);
|
||||
var errors = new List<string>();
|
||||
if (!string.IsNullOrWhiteSpace(DevSaveCatalog.LastError)) errors.Add(DevSaveCatalog.LastError);
|
||||
foreach (var section in sections)
|
||||
{
|
||||
var orders = new HashSet<int>();
|
||||
var nodes = new HashSet<string>(StringComparer.Ordinal);
|
||||
foreach (var entry in section.Entries)
|
||||
{
|
||||
if (!orders.Add(entry.Order)) errors.Add($"{section.Id}: 重复 order {entry.Order}");
|
||||
if (!nodes.Add(entry.AnchorNode)) errors.Add($"{section.Id}: 重复节点 {entry.AnchorNode}");
|
||||
if (!entry.IsValid) errors.Add($"{section.Id}/{entry.Label}: {entry.Error}");
|
||||
}
|
||||
}
|
||||
|
||||
var dto = LoadCatalogForWrite();
|
||||
foreach (var section in dto.sections)
|
||||
{
|
||||
if (!SceneAddressExists(section.expectedSceneName))
|
||||
errors.Add($"{section.id}: Addressable 场景不存在 {section.expectedSceneName}");
|
||||
var sceneSo = FindTalkSceneSo(section.expectedSceneSoName);
|
||||
if (sceneSo == null)
|
||||
errors.Add($"{section.id}: TalkSceneSO 不存在 {section.expectedSceneSoName}");
|
||||
else if (sceneSo.yarnProject == null || sceneSo.yarnProject.name != section.expectedYarnProjectId)
|
||||
errors.Add($"{section.id}: TalkSceneSO 的 YarnProject 不匹配 {section.expectedYarnProjectId}");
|
||||
else
|
||||
{
|
||||
var nodeNames = new HashSet<string>(sceneSo.yarnProject.NodeNames, StringComparer.Ordinal);
|
||||
foreach (var entry in section.entries.Where(entry => !nodeNames.Contains(entry.anchorNode)))
|
||||
errors.Add($"{section.id}: Yarn 节点不存在 {entry.anchorNode}");
|
||||
}
|
||||
}
|
||||
|
||||
status = errors.Count == 0
|
||||
? $"OK:{sections.Count} 个章节、{sections.Sum(s => s.Entries.Count)} 个阶段全部通过校验。"
|
||||
: $"校验失败({errors.Count}):\n{string.Join("\n", errors)}";
|
||||
if (errors.Count > 0) Debug.LogError($"[DevSavePromote] {status}");
|
||||
else Debug.Log($"[DevSavePromote] {status}");
|
||||
}
|
||||
|
||||
private static bool SceneAddressExists(string address)
|
||||
{
|
||||
var settings = AddressableAssetSettingsDefaultObject.Settings;
|
||||
return settings != null && settings.groups
|
||||
.Where(group => group != null)
|
||||
.SelectMany(group => group.entries)
|
||||
.Any(entry => string.Equals(entry.address, address, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
private static TalkSceneSO FindTalkSceneSo(string assetName)
|
||||
{
|
||||
foreach (var guid in AssetDatabase.FindAssets($"t:TalkSceneSO {assetName}"))
|
||||
{
|
||||
var asset = AssetDatabase.LoadAssetAtPath<TalkSceneSO>(AssetDatabase.GUIDToAssetPath(guid));
|
||||
if (asset != null && asset.name == assetName) return asset;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int FindDemoChapterOrder(string sceneSoName)
|
||||
{
|
||||
const string firstChapterPath = "Assets/ScriptableObjects/SceneSO/Demo/Day0_Prologue.asset";
|
||||
var chapter = AssetDatabase.LoadAssetAtPath<TalkSceneSO>(firstChapterPath);
|
||||
var visited = new HashSet<TalkSceneSO>();
|
||||
var order = 1;
|
||||
while (chapter != null && visited.Add(chapter))
|
||||
{
|
||||
if (string.Equals(chapter.name, sceneSoName, StringComparison.Ordinal)) return order;
|
||||
chapter = chapter.GetNextScene();
|
||||
order++;
|
||||
}
|
||||
|
||||
return int.MaxValue;
|
||||
}
|
||||
|
||||
private static DevSaveCatalogDto LoadCatalogForWrite()
|
||||
{
|
||||
var path = Path.Combine(ConstRef.TestSaveFilePath, "catalog.json");
|
||||
if (!File.Exists(path)) return new DevSaveCatalogDto();
|
||||
try
|
||||
{
|
||||
return JsonConvert.DeserializeObject<DevSaveCatalogDto>(File.ReadAllText(path, Encoding.UTF8))
|
||||
?? new DevSaveCatalogDto();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new DevSaveCatalogDto();
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteCatalog(DevSaveCatalogDto catalog)
|
||||
{
|
||||
Directory.CreateDirectory(ConstRef.TestSaveFilePath);
|
||||
File.WriteAllText(
|
||||
Path.Combine(ConstRef.TestSaveFilePath, "catalog.json"),
|
||||
JsonConvert.SerializeObject(catalog, Formatting.Indented),
|
||||
new UTF8Encoding(false));
|
||||
}
|
||||
|
||||
private static string SanitizeIdentifier(string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value)) return "unnamed";
|
||||
foreach (var character in Path.GetInvalidFileNameChars()) value = value.Replace(character, '_');
|
||||
value = value.Replace(' ', '_');
|
||||
return value.Length <= 48 ? value : value.Substring(0, 48);
|
||||
}
|
||||
|
||||
private sealed class ArchiveGroup
|
||||
{
|
||||
public readonly List<Candidate> Items;
|
||||
public string SceneName => Items[0].SceneName;
|
||||
public string SceneSoName => Items[0].SceneSoName;
|
||||
public string YarnProjectId => Items[0].YarnProjectId;
|
||||
public ArchiveGroup(List<Candidate> items) => Items = items;
|
||||
}
|
||||
|
||||
private sealed class Candidate
|
||||
{
|
||||
public readonly string SnapshotPath;
|
||||
public readonly string MetaPath;
|
||||
public readonly string SceneName;
|
||||
public readonly string SceneSoName;
|
||||
public readonly string YarnProjectId;
|
||||
public readonly string NodeName;
|
||||
public readonly string SavedAt;
|
||||
public string Label;
|
||||
|
||||
public Candidate(string snapshotPath, string metaPath, string sceneName, string sceneSoName,
|
||||
string yarnProjectId, string nodeName, string savedAt)
|
||||
{
|
||||
SnapshotPath = snapshotPath;
|
||||
MetaPath = metaPath;
|
||||
SceneName = sceneName;
|
||||
SceneSoName = sceneSoName;
|
||||
YarnProjectId = yarnProjectId;
|
||||
NodeName = nodeName;
|
||||
SavedAt = savedAt ?? string.Empty;
|
||||
Label = nodeName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public sealed class DevSaveCatalogTests
|
||||
{
|
||||
private string root;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
root = Path.Combine(Path.GetTempPath(), $"aibis-dev-save-{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(root);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
if (Directory.Exists(root)) Directory.Delete(root, true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CatalogUsesExplicitOrderAndKeepsInvalidEntriesVisible()
|
||||
{
|
||||
WriteCatalog(new DevSaveCatalogEntryDto { order = 20, label = "late", path = "S/late", anchorNode = "Late" },
|
||||
new DevSaveCatalogEntryDto { order = 10, label = "early", path = "S/early", anchorNode = "Early" });
|
||||
|
||||
var section = DevSaveCatalog.Load(root).Single();
|
||||
|
||||
Assert.That(section.Entries.Select(entry => entry.Label), Is.EqualTo(new[] { "early", "late" }));
|
||||
Assert.That(section.Entries.All(entry => !entry.IsValid), Is.True);
|
||||
Assert.That(section.Entries.All(entry => entry.Error.Contains("缺失")), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CatalogRejectsPathTraversal()
|
||||
{
|
||||
WriteCatalog(new DevSaveCatalogEntryDto { order = 1, label = "unsafe", path = "../outside", anchorNode = "Start" });
|
||||
|
||||
var entry = DevSaveCatalog.Load(root).Single().Entries.Single();
|
||||
|
||||
Assert.That(entry.IsValid, Is.False);
|
||||
Assert.That(entry.Error, Does.Contain("越过"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CatalogReportsCorruptSchemaAndAnchorMismatch()
|
||||
{
|
||||
WriteSnapshot("S/corrupt", "{");
|
||||
WriteSnapshot("S/schema", JsonConvert.SerializeObject(BuildSnapshot("Node", schema: 99)));
|
||||
WriteSnapshot("S/node", JsonConvert.SerializeObject(BuildSnapshot("Actual")));
|
||||
WriteCatalog(
|
||||
new DevSaveCatalogEntryDto { order = 1, label = "corrupt", path = "S/corrupt", anchorNode = "Node" },
|
||||
new DevSaveCatalogEntryDto { order = 2, label = "schema", path = "S/schema", anchorNode = "Node" },
|
||||
new DevSaveCatalogEntryDto { order = 3, label = "node", path = "S/node", anchorNode = "Expected" });
|
||||
|
||||
var entries = DevSaveCatalog.Load(root).Single().Entries;
|
||||
|
||||
Assert.That(entries[0].Error, Does.Contain("JSON"));
|
||||
Assert.That(entries[1].Error, Does.Contain("版本"));
|
||||
Assert.That(entries[2].Error, Does.Contain("节点不匹配"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CommittedCatalogContainsAllDemoChaptersWithValidUniqueEntries()
|
||||
{
|
||||
var sections = DevSaveCatalog.Load(ConstRef.TestSaveFilePath);
|
||||
Assert.That(DevSaveCatalog.LastError, Is.Null);
|
||||
Assert.That(sections.Select(section => section.Id), Is.EqualTo(new[]
|
||||
{
|
||||
"Day0Prologue", "Day1Begin", "Peipei1", "Day1Mid", "Day1Night", "Day1Sleep",
|
||||
"Day2Begin", "Huoshan1", "Day2Mid", "Peipei2", "Day2Night", "Day2Sleep", "GeneralEnd"
|
||||
}));
|
||||
foreach (var section in sections)
|
||||
{
|
||||
Assert.That(section.Entries.All(entry => entry.IsValid), Is.True,
|
||||
string.Join("\n", section.Entries.Where(entry => !entry.IsValid).Select(entry => $"{entry.Label}: {entry.Error}")));
|
||||
Assert.That(section.Entries.Select(entry => entry.Order).Distinct().Count(), Is.EqualTo(section.Entries.Count));
|
||||
Assert.That(section.Entries.Select(entry => entry.AnchorNode).Distinct().Count(), Is.EqualTo(section.Entries.Count));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StrictRestoreContextTracksPhaseWarningsAndErrors()
|
||||
{
|
||||
var context = new SnapshotRestoreContext(new SaveSnapshot(), strictMode: true);
|
||||
context.SetPhase("Provider restore");
|
||||
context.Warn("optional state missing");
|
||||
LogAssert.Expect(LogType.Error, "[SnapshotRestore] required state missing");
|
||||
context.Error("required state missing");
|
||||
|
||||
Assert.That(context.StrictMode, Is.True);
|
||||
Assert.That(context.CurrentPhase, Is.EqualTo("Provider restore"));
|
||||
Assert.That(context.Warnings, Is.EqualTo(new[] { "optional state missing" }));
|
||||
Assert.That(context.Errors, Is.EqualTo(new[] { "required state missing" }));
|
||||
Assert.That(context.HasErrors, Is.True);
|
||||
}
|
||||
|
||||
private void WriteCatalog(params DevSaveCatalogEntryDto[] entries)
|
||||
{
|
||||
var catalog = new DevSaveCatalogDto
|
||||
{
|
||||
sections = new List<DevSaveCatalogSectionDto>
|
||||
{
|
||||
new()
|
||||
{
|
||||
id = "S",
|
||||
title = "Section",
|
||||
expectedSceneName = "Scene/Test",
|
||||
expectedSceneSoName = "TestSO",
|
||||
expectedYarnProjectId = "TestYarn",
|
||||
entries = entries.ToList()
|
||||
}
|
||||
}
|
||||
};
|
||||
File.WriteAllText(Path.Combine(root, "catalog.json"), JsonConvert.SerializeObject(catalog));
|
||||
}
|
||||
|
||||
private void WriteSnapshot(string relativeDirectory, string json)
|
||||
{
|
||||
var directory = Path.Combine(root, relativeDirectory.Replace('/', Path.DirectorySeparatorChar));
|
||||
Directory.CreateDirectory(directory);
|
||||
File.WriteAllText(Path.Combine(directory, "snapshot.json"), json);
|
||||
}
|
||||
|
||||
private static SaveSnapshot BuildSnapshot(string node, int schema = SaveSnapshotSchema.CurrentVersion)
|
||||
{
|
||||
return new SaveSnapshot
|
||||
{
|
||||
schemaVersion = schema,
|
||||
scene = new SceneSnapshotDto { sceneName = "Scene/Test" },
|
||||
anchor = new AnchorSnapshot
|
||||
{
|
||||
sceneSoName = "TestSO",
|
||||
yarnProjectId = "TestYarn",
|
||||
nodeName = node
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b564a87c642e53646baa39708c8f72ac
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,669 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using AibisDream;
|
||||
using AibisDream.SaveSystem;
|
||||
using AibisDream.Utility;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.SaveSystem.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 存读档临时测试工具:触发存档、从槽位/测试归档读档、浏览 testsavs 历史。
|
||||
/// </summary>
|
||||
public class SaveSystemTestWindow : EditorWindow
|
||||
{
|
||||
private const string MenuPath = "AIBIS/存档测试工具";
|
||||
private const string WindowTitle = "SaveSystem Test";
|
||||
|
||||
private Vector2 _scrollPosition;
|
||||
private string _lastLog = string.Empty;
|
||||
private int _restoreSlotIndex;
|
||||
private int _manualSlotIndex = 1;
|
||||
private bool _testArchiveEnabled;
|
||||
private string _selectedArchiveEntryId;
|
||||
private Texture2D _selectedThumbnail;
|
||||
|
||||
private List<TestSaveArchiveEntry> _archiveEntries = new();
|
||||
private List<TestSaveArchiveEntry> _archiveEntriesSnapshot = new();
|
||||
private double _lastArchiveRefreshTime;
|
||||
private bool _repaintQueued;
|
||||
private List<string> _slotOverviewLabels = new();
|
||||
private List<string> _restoreLogSnapshot = new();
|
||||
private string _displaySelectedArchiveEntryId;
|
||||
private Texture2D _displayThumbnail;
|
||||
|
||||
private void RequestRepaint()
|
||||
{
|
||||
if (_repaintQueued)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_repaintQueued = true;
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
_repaintQueued = false;
|
||||
if (this != null)
|
||||
{
|
||||
Repaint();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[MenuItem(MenuPath)]
|
||||
public static void Open()
|
||||
{
|
||||
var window = GetWindow<SaveSystemTestWindow>(WindowTitle);
|
||||
window.minSize = new Vector2(480, 560);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_testArchiveEnabled = EditorPrefs.GetBool(TestSaveArchive.EditorPrefsEnabledKey, true);
|
||||
RefreshArchiveEntries(requestRepaint: false);
|
||||
EditorApplication.update += OnEditorUpdate;
|
||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
EditorApplication.update -= OnEditorUpdate;
|
||||
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
||||
ReleaseThumbnail();
|
||||
}
|
||||
|
||||
private void OnEditorUpdate()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (EditorApplication.timeSinceStartup - _lastArchiveRefreshTime < 1.0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshArchiveEntries(requestRepaint: true);
|
||||
}
|
||||
|
||||
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||
{
|
||||
if (state == PlayModeStateChange.EnteredPlayMode || state == PlayModeStateChange.ExitingPlayMode)
|
||||
{
|
||||
RefreshArchiveEntries();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (Event.current.type == EventType.Layout)
|
||||
{
|
||||
SnapshotDynamicGuiData();
|
||||
}
|
||||
|
||||
_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
|
||||
|
||||
DrawHeader();
|
||||
GUILayout.Space(8);
|
||||
DrawTestArchiveSettings();
|
||||
GUILayout.Space(8);
|
||||
DrawSaveActions();
|
||||
GUILayout.Space(8);
|
||||
DrawSlotRestoreSection();
|
||||
GUILayout.Space(8);
|
||||
DrawTestArchiveSection();
|
||||
GUILayout.Space(8);
|
||||
DrawRestoreLogSection();
|
||||
GUILayout.Space(8);
|
||||
DrawUtilitySection();
|
||||
GUILayout.Space(8);
|
||||
DrawLogSection();
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在 Layout/Repaint 之前快照可变列表,避免同一 GUI 帧内控件数量不一致。
|
||||
/// </summary>
|
||||
private void SnapshotDynamicGuiData()
|
||||
{
|
||||
_displaySelectedArchiveEntryId = _selectedArchiveEntryId;
|
||||
_displayThumbnail = _selectedThumbnail;
|
||||
|
||||
_archiveEntriesSnapshot.Clear();
|
||||
for (var i = 0; i < _archiveEntries.Count; i++)
|
||||
{
|
||||
_archiveEntriesSnapshot.Add(_archiveEntries[i]);
|
||||
}
|
||||
|
||||
_slotOverviewLabels.Clear();
|
||||
foreach (var vm in SlotManager.GetSlotViewModels())
|
||||
{
|
||||
if (vm.IsEmpty)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var meta = SlotManager.LoadMeta(vm.SlotIndex);
|
||||
_slotOverviewLabels.Add(
|
||||
$"slot_{vm.SlotIndex}" +
|
||||
(vm.IsAutoSlot ? " [自动]" : "") +
|
||||
$" | {vm.SavedAt} | {meta?.nodeName ?? "—"} | {vm.SceneName}");
|
||||
}
|
||||
|
||||
_restoreLogSnapshot.Clear();
|
||||
var restoreLog = SaveRestoreOrchestrator.LastRestoreLog;
|
||||
for (var i = 0; i < restoreLog.Count; i++)
|
||||
{
|
||||
_restoreLogSnapshot.Add(restoreLog[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawHeader()
|
||||
{
|
||||
EditorGUILayout.LabelField("存读档测试工具", EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox(
|
||||
"用于 Play Mode 下验证自动存档、槽位读档与 testsavs 测试归档。\n" +
|
||||
"正式存档目录: demo_saves/ | 测试归档: testsavs/(每次自动存档独立子文件夹)",
|
||||
MessageType.Info);
|
||||
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
EditorGUILayout.HelpBox("存档/读档操作需要在 Play Mode 下执行。", MessageType.Warning);
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField(
|
||||
$"状态: IsRestoring={SaveRestoreOrchestrator.IsRestoring}, " +
|
||||
$"SuppressAutoSave={SaveRestoreOrchestrator.IsAutoSaveSuppressed}");
|
||||
}
|
||||
|
||||
private void DrawTestArchiveSettings()
|
||||
{
|
||||
EditorGUILayout.LabelField("测试存档模式", EditorStyles.boldLabel);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
_testArchiveEnabled = EditorGUILayout.Toggle("启用测试存档模式", _testArchiveEnabled);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
EditorPrefs.SetBool(TestSaveArchive.EditorPrefsEnabledKey, _testArchiveEnabled);
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField($"testsavs 路径: {ConstRef.TestAutoSaveArchivePath}", EditorStyles.miniLabel);
|
||||
EditorGUILayout.HelpBox(
|
||||
"开启后:每次 AutoSave 仅在 testsavs 下新建一份独立存档,不写入、不覆盖 demo_saves/slot_0。\n" +
|
||||
"存多少次就保留多少份;关闭后恢复正式行为(仅覆盖 slot_0)。",
|
||||
MessageType.None);
|
||||
}
|
||||
|
||||
private void DrawSaveActions()
|
||||
{
|
||||
EditorGUILayout.LabelField("存档", EditorStyles.boldLabel);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("触发自动存档 (完整流程)"))
|
||||
{
|
||||
TriggerAutoSave();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("仅 Capture (不写盘)"))
|
||||
{
|
||||
CaptureInMemory();
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button("手动档: 复制 slot_0 → 上方指定槽位"))
|
||||
{
|
||||
CopyAutoToManual();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSlotRestoreSection()
|
||||
{
|
||||
EditorGUILayout.LabelField("从正式槽位读档", EditorStyles.boldLabel);
|
||||
EditorGUILayout.LabelField($"demo_saves 路径: {ConstRef.SaveFilePath}", EditorStyles.miniLabel);
|
||||
|
||||
var latest = SlotManager.GetLatestSlotIndex();
|
||||
EditorGUILayout.LabelField($"最近槽位: {(latest.HasValue ? $"slot_{latest.Value}" : "无")}");
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("读档: Latest"))
|
||||
{
|
||||
RestoreLatestSlot();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("读档: slot_0"))
|
||||
{
|
||||
RestoreSlot(SlotIndex.Auto);
|
||||
}
|
||||
}
|
||||
|
||||
_restoreSlotIndex = EditorGUILayout.IntSlider("槽位", _restoreSlotIndex, 0, SlotIndex.ManualEnd);
|
||||
if (GUILayout.Button($"读档: slot_{_restoreSlotIndex}"))
|
||||
{
|
||||
RestoreSlot(_restoreSlotIndex);
|
||||
}
|
||||
|
||||
GUILayout.Space(4);
|
||||
_manualSlotIndex = EditorGUILayout.IntSlider(
|
||||
"复制到手动槽位",
|
||||
_manualSlotIndex,
|
||||
SlotIndex.ManualStart,
|
||||
SlotIndex.ManualEnd);
|
||||
|
||||
DrawSlotBriefOverview();
|
||||
}
|
||||
|
||||
private void DrawSlotBriefOverview()
|
||||
{
|
||||
foreach (var label in _slotOverviewLabels)
|
||||
{
|
||||
EditorGUILayout.LabelField(label, EditorStyles.miniLabel);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawTestArchiveSection()
|
||||
{
|
||||
EditorGUILayout.LabelField("testsavs 测试归档", EditorStyles.boldLabel);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("刷新列表"))
|
||||
{
|
||||
RefreshArchiveEntries();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("清空 testsavs"))
|
||||
{
|
||||
ClearTestArchives();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("打开 testsavs 文件夹"))
|
||||
{
|
||||
OpenDirectory(ConstRef.TestAutoSaveArchivePath);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.LabelField($"共 {_archiveEntriesSnapshot.Count} 条", EditorStyles.miniLabel);
|
||||
|
||||
if (_archiveEntriesSnapshot.Count == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
"暂无测试归档。开启「testsavs 独立归档」后触发自动存档,或从正式 slot_0 手动归档。",
|
||||
MessageType.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox))
|
||||
{
|
||||
foreach (var entry in _archiveEntriesSnapshot)
|
||||
{
|
||||
DrawArchiveEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button("将当前 slot_0 手动归档到 testsavs"))
|
||||
{
|
||||
ArchiveCurrentAutoSlot();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawArchiveEntry(TestSaveArchiveEntry entry)
|
||||
{
|
||||
var isSelected = _displaySelectedArchiveEntryId == entry.EntryId;
|
||||
var boxStyle = isSelected ? EditorStyles.helpBox : EditorStyles.textArea;
|
||||
|
||||
using (new EditorGUILayout.VerticalScope(boxStyle))
|
||||
{
|
||||
EditorGUILayout.LabelField(entry.EntryId, EditorStyles.boldLabel);
|
||||
EditorGUILayout.LabelField(
|
||||
$"时间: {entry.Meta?.savedAt ?? "—"} | 节点: {entry.Meta?.nodeName ?? "—"}",
|
||||
EditorStyles.miniLabel);
|
||||
EditorGUILayout.LabelField(
|
||||
$"场景: {entry.Meta?.sceneName ?? "—"} | SO: {entry.Meta?.sceneSoName ?? "—"}",
|
||||
EditorStyles.miniLabel);
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
var maxWidth = EditorGUIUtility.currentViewWidth - 48f;
|
||||
var height = 120f;
|
||||
if (_displayThumbnail != null)
|
||||
{
|
||||
height = Mathf.Min(120f, _displayThumbnail.height * maxWidth / _displayThumbnail.width);
|
||||
GUILayout.Label(_displayThumbnail, GUILayout.Width(maxWidth), GUILayout.Height(height));
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField(
|
||||
"(无缩略图)",
|
||||
EditorStyles.miniLabel,
|
||||
GUILayout.Width(maxWidth),
|
||||
GUILayout.Height(height));
|
||||
}
|
||||
}
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("选中"))
|
||||
{
|
||||
SelectArchiveEntry(entry);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("读档"))
|
||||
{
|
||||
RestoreFromArchive(entry);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("删除"))
|
||||
{
|
||||
DeleteArchiveEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.Space(4);
|
||||
}
|
||||
|
||||
private void DrawRestoreLogSection()
|
||||
{
|
||||
EditorGUILayout.LabelField("读档 Pipeline 日志", EditorStyles.boldLabel);
|
||||
|
||||
if (_restoreLogSnapshot.Count == 0)
|
||||
{
|
||||
EditorGUILayout.LabelField("(暂无)", EditorStyles.miniLabel);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var line in _restoreLogSnapshot)
|
||||
{
|
||||
EditorGUILayout.LabelField(line, EditorStyles.wordWrappedMiniLabel);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawUtilitySection()
|
||||
{
|
||||
EditorGUILayout.LabelField("工具", EditorStyles.boldLabel);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("打开 demo_saves 文件夹"))
|
||||
{
|
||||
OpenDirectory(ConstRef.SaveFilePath);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("打开存档验证工具"))
|
||||
{
|
||||
SaveSystemValidationWindow.Open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawLogSection()
|
||||
{
|
||||
EditorGUILayout.LabelField("操作结果", EditorStyles.boldLabel);
|
||||
EditorGUILayout.SelectableLabel(_lastLog, EditorStyles.textArea, GUILayout.MinHeight(80));
|
||||
}
|
||||
|
||||
private void RefreshArchiveEntries(bool requestRepaint = true)
|
||||
{
|
||||
var newEntries = TestSaveArchive.ListEntries();
|
||||
var entriesChanged = !ArchiveEntriesEqual(newEntries, _archiveEntries);
|
||||
_archiveEntries = newEntries;
|
||||
_lastArchiveRefreshTime = EditorApplication.timeSinceStartup;
|
||||
|
||||
if (!string.IsNullOrEmpty(_selectedArchiveEntryId) &&
|
||||
!_archiveEntries.Exists(e => e.EntryId == _selectedArchiveEntryId))
|
||||
{
|
||||
_selectedArchiveEntryId = null;
|
||||
ReleaseThumbnail();
|
||||
entriesChanged = true;
|
||||
}
|
||||
|
||||
if (requestRepaint && entriesChanged)
|
||||
{
|
||||
RequestRepaint();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ArchiveEntriesEqual(List<TestSaveArchiveEntry> a, List<TestSaveArchiveEntry> b)
|
||||
{
|
||||
if (a.Count != b.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < a.Count; i++)
|
||||
{
|
||||
if (a[i].EntryId != b[i].EntryId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SelectArchiveEntry(TestSaveArchiveEntry entry)
|
||||
{
|
||||
_selectedArchiveEntryId = entry.EntryId;
|
||||
ReleaseThumbnail();
|
||||
|
||||
if (!string.IsNullOrEmpty(entry.ThumbnailPath) && File.Exists(entry.ThumbnailPath))
|
||||
{
|
||||
var bytes = File.ReadAllBytes(entry.ThumbnailPath);
|
||||
_selectedThumbnail = new Texture2D(2, 2);
|
||||
_selectedThumbnail.LoadImage(bytes);
|
||||
}
|
||||
|
||||
RequestRepaint();
|
||||
}
|
||||
|
||||
private void ReleaseThumbnail()
|
||||
{
|
||||
if (_selectedThumbnail != null)
|
||||
{
|
||||
DestroyImmediate(_selectedThumbnail);
|
||||
_selectedThumbnail = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerAutoSave()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Log("需要在 Play Mode 下执行。");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!SavePointEvaluator.CanAutoSave(out var reason))
|
||||
{
|
||||
Log($"CanAutoSave 拒绝: {reason}");
|
||||
return;
|
||||
}
|
||||
|
||||
var routine = SaveRestoreOrchestrator.AutoSaveRoutine();
|
||||
while (routine.MoveNext())
|
||||
{
|
||||
}
|
||||
|
||||
RefreshArchiveEntries();
|
||||
Log(TestSaveArchive.IsEnabled
|
||||
? "测试存档模式:已写入 testsavs(未覆盖 slot_0)。"
|
||||
: "正式模式:已写入 slot_0。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"自动存档失败: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private void CaptureInMemory()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (YarnVariableStorage.Instance == null)
|
||||
{
|
||||
Log("YarnVariableStorage 未初始化。");
|
||||
return;
|
||||
}
|
||||
|
||||
var snapshot = SnapshotService.Capture();
|
||||
Log($"Capture 成功: 场景={snapshot.scene?.sceneName}, 节点={snapshot.anchor?.nodeName}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"Capture 失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyAutoToManual()
|
||||
{
|
||||
if (!SlotDirectory.Exists(SlotIndex.Auto))
|
||||
{
|
||||
Log("slot_0 不存在。");
|
||||
return;
|
||||
}
|
||||
|
||||
SlotManager.CopyAutoToManual(_manualSlotIndex);
|
||||
Log($"已复制到 slot_{_manualSlotIndex}。");
|
||||
}
|
||||
|
||||
private void RestoreLatestSlot()
|
||||
{
|
||||
var latest = SlotManager.GetLatestSlotIndex();
|
||||
if (!latest.HasValue)
|
||||
{
|
||||
Log("没有 latest_slot。");
|
||||
return;
|
||||
}
|
||||
|
||||
RestoreSlot(latest.Value);
|
||||
}
|
||||
|
||||
private void RestoreSlot(int slotIndex)
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Log("读档需要在 Play Mode 下执行。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameManager.Instance == null)
|
||||
{
|
||||
Log("GameManager 未初始化。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SlotDirectory.Exists(slotIndex))
|
||||
{
|
||||
Log($"slot_{slotIndex} 不存在。");
|
||||
return;
|
||||
}
|
||||
|
||||
GameManager.Instance.TryRestoreSlot(slotIndex);
|
||||
Log($"已启动读档 slot_{slotIndex}。");
|
||||
}
|
||||
|
||||
private void RestoreFromArchive(TestSaveArchiveEntry entry)
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Log("读档需要在 Play Mode 下执行。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameManager.Instance == null)
|
||||
{
|
||||
Log("GameManager 未初始化。");
|
||||
return;
|
||||
}
|
||||
|
||||
GameManager.Instance.TryRestoreFile(
|
||||
entry.SnapshotPath,
|
||||
RestoreOptions.DevJump);
|
||||
Log($"已启动读档: {entry.EntryId}");
|
||||
}
|
||||
|
||||
private void ArchiveCurrentAutoSlot()
|
||||
{
|
||||
var snapshot = SlotManager.LoadSnapshot(SlotIndex.Auto);
|
||||
if (snapshot == null)
|
||||
{
|
||||
Log("slot_0 无快照。");
|
||||
return;
|
||||
}
|
||||
|
||||
var thumbnail = SlotManager.LoadThumbnail(SlotIndex.Auto);
|
||||
var entryId = TestSaveArchive.Archive(snapshot, thumbnail);
|
||||
RefreshArchiveEntries();
|
||||
Log($"已手动归档: {entryId}");
|
||||
}
|
||||
|
||||
private void DeleteArchiveEntry(TestSaveArchiveEntry entry)
|
||||
{
|
||||
var entryId = entry.EntryId;
|
||||
EditorApplication.delayCall += () => ConfirmDeleteArchiveEntry(entryId);
|
||||
}
|
||||
|
||||
private void ConfirmDeleteArchiveEntry(string entryId)
|
||||
{
|
||||
if (!EditorUtility.DisplayDialog("删除测试归档", $"删除 {entryId}?", "删除", "取消"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TestSaveArchive.DeleteEntry(entryId);
|
||||
if (_selectedArchiveEntryId == entryId)
|
||||
{
|
||||
_selectedArchiveEntryId = null;
|
||||
ReleaseThumbnail();
|
||||
}
|
||||
|
||||
RefreshArchiveEntries();
|
||||
Log($"已删除: {entryId}");
|
||||
}
|
||||
|
||||
private void ClearTestArchives()
|
||||
{
|
||||
EditorApplication.delayCall += ConfirmClearTestArchives;
|
||||
}
|
||||
|
||||
private void ConfirmClearTestArchives()
|
||||
{
|
||||
if (!EditorUtility.DisplayDialog("清空 testsavs", "删除所有测试归档?不可撤销。", "删除", "取消"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TestSaveArchive.ClearAll();
|
||||
_selectedArchiveEntryId = null;
|
||||
ReleaseThumbnail();
|
||||
RefreshArchiveEntries();
|
||||
Log("已清空 testsavs。");
|
||||
}
|
||||
|
||||
private static void OpenDirectory(string path)
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
EditorUtility.RevealInFinder(path);
|
||||
}
|
||||
|
||||
private void Log(string message)
|
||||
{
|
||||
_lastLog = $"[{DateTime.Now:HH:mm:ss}] {message}";
|
||||
Debug.Log($"[SaveSystemTest] {message}");
|
||||
RequestRepaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27c49345ec3a4e849af3f9da7045f7a3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,704 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AibisDream;
|
||||
using AibisDream.SaveSystem;
|
||||
using AibisDream.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.SaveSystem.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 存档系统 P1/P2/P3 存盘行为验证工具。
|
||||
/// 不验证读档(P4),不验证复杂 tags 边界(P3 后续)。
|
||||
/// </summary>
|
||||
public class SaveSystemValidationWindow : EditorWindow
|
||||
{
|
||||
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;
|
||||
private int _deleteSlotIndex = 1;
|
||||
private string _testNodeName = "SomeNode";
|
||||
private string _testTags = "";
|
||||
private int _restoreSlotIndex;
|
||||
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
|
||||
|
||||
DrawHeader();
|
||||
DrawSlotOverview();
|
||||
GUILayout.Space(12);
|
||||
DrawSaveHistorySection();
|
||||
GUILayout.Space(12);
|
||||
DrawDirectCaptureSection();
|
||||
GUILayout.Space(12);
|
||||
DrawAutoSaveSimulationSection();
|
||||
GUILayout.Space(12);
|
||||
DrawManualSlotSection();
|
||||
GUILayout.Space(12);
|
||||
DrawRestoreSection();
|
||||
GUILayout.Space(12);
|
||||
DrawSavePointEvaluationSection();
|
||||
GUILayout.Space(12);
|
||||
DrawUtilitySection();
|
||||
GUILayout.Space(12);
|
||||
DrawLogSection();
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
#region Drawing
|
||||
|
||||
private void DrawHeader()
|
||||
{
|
||||
EditorGUILayout.LabelField("存档系统存盘验证", EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox(
|
||||
"本工具仅验证 P1/P2/P3 的存盘行为:快照捕获、槽位落盘、元数据、可存点判定框架。\n" +
|
||||
"不验证读档(P4)和复杂 tags 边界(P3 后续)。\n" +
|
||||
"涉及运行时单例(DialogController / GameManager)的操作需要在 Play Mode 下执行。",
|
||||
MessageType.Info);
|
||||
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
EditorGUILayout.HelpBox("当前不在 Play Mode。Capture / TryAutoSave 等依赖运行时单例的操作可能失败。", MessageType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSlotOverview()
|
||||
{
|
||||
EditorGUILayout.LabelField("槽位概览", EditorStyles.boldLabel);
|
||||
|
||||
var latest = SlotManager.GetLatestSlotIndex();
|
||||
EditorGUILayout.LabelField($"最近槽位: {(latest.HasValue ? latest.Value.ToString() : "无")}");
|
||||
EditorGUILayout.LabelField($"存档根目录: {ConstRef.SaveFilePath}");
|
||||
EditorGUILayout.LabelField(
|
||||
$"读档状态: IsRestoring={SaveRestoreOrchestrator.IsRestoring}, " +
|
||||
$"SuppressAutoSave={SaveRestoreOrchestrator.IsAutoSaveSuppressed}");
|
||||
|
||||
var viewModels = SlotManager.GetSlotViewModels();
|
||||
foreach (var vm in viewModels)
|
||||
{
|
||||
DrawSlotViewModel(vm, latest);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSlotViewModel(SlotViewModel vm, int? latest)
|
||||
{
|
||||
var isLatest = latest.HasValue && latest.Value == vm.SlotIndex;
|
||||
var nodeName = SlotManager.LoadMeta(vm.SlotIndex)?.nodeName;
|
||||
var label = vm.IsEmpty
|
||||
? $"[{vm.SlotIndex}] (空)"
|
||||
: $"[{vm.SlotIndex}] {(vm.IsAutoSlot ? "[自动档]" : "")} {(isLatest ? "[最新]" : "")}\n" +
|
||||
$" 场景: {vm.SceneName}\n" +
|
||||
$" SO: {vm.SceneSoName}\n" +
|
||||
$" 节点: {nodeName}\n" +
|
||||
$" 时间: {vm.SavedAt}\n" +
|
||||
$" 缩略图: {(string.IsNullOrEmpty(vm.ThumbnailPath) ? "无" : Path.GetFileName(vm.ThumbnailPath))}";
|
||||
|
||||
EditorGUILayout.HelpBox(label, vm.IsEmpty ? MessageType.None : MessageType.Info);
|
||||
}
|
||||
|
||||
private void DrawDirectCaptureSection()
|
||||
{
|
||||
EditorGUILayout.LabelField("直接捕获快照", EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox(
|
||||
"调用 SnapshotService.Capture() 组装快照,并在内存中检查结构。\n" +
|
||||
"此操作不写盘,不经过 SavePointEvaluator。",
|
||||
MessageType.None);
|
||||
|
||||
if (GUILayout.Button("Capture Snapshot (内存)"))
|
||||
{
|
||||
CaptureSnapshotInMemory();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawAutoSaveSimulationSection()
|
||||
{
|
||||
EditorGUILayout.LabelField("模拟自动存档", EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox(
|
||||
"调用 SaveRestoreOrchestrator.TryAutoSave(),走完整的判定+捕获+落盘流程。\n" +
|
||||
"需要在 Play Mode 下且有 DialogController 运行时实例。",
|
||||
MessageType.None);
|
||||
|
||||
if (GUILayout.Button("TryAutoSave (完整流程)"))
|
||||
{
|
||||
TryAutoSaveFullFlow();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
_manualSlotIndex = EditorGUILayout.IntSlider("复制到槽位", _manualSlotIndex, 1, SlotIndex.ManualEnd);
|
||||
if (GUILayout.Button("Copy Auto → Manual"))
|
||||
{
|
||||
CopyAutoToManual(_manualSlotIndex);
|
||||
}
|
||||
|
||||
GUILayout.Space(8);
|
||||
|
||||
_deleteSlotIndex = EditorGUILayout.IntSlider("删除槽位", _deleteSlotIndex, 0, SlotIndex.ManualEnd);
|
||||
if (GUILayout.Button("Delete Slot"))
|
||||
{
|
||||
DeleteSlot(_deleteSlotIndex);
|
||||
}
|
||||
|
||||
GUILayout.Space(8);
|
||||
|
||||
if (GUILayout.Button("Clear All Saves"))
|
||||
{
|
||||
ClearAllSaves();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSavePointEvaluationSection()
|
||||
{
|
||||
EditorGUILayout.LabelField("可存点判定框架检查", EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox(
|
||||
"手动设置节点名和 tags,模拟 OnNodeStart 自动档判定(含 DetourResume)。\n" +
|
||||
"InProgress 来自运行时 DialogController;全局门控按实际 Play Mode 状态取值。",
|
||||
MessageType.None);
|
||||
|
||||
_testNodeName = EditorGUILayout.TextField("节点名", _testNodeName);
|
||||
_testTags = EditorGUILayout.TextField("Tags (逗号分隔)", _testTags);
|
||||
|
||||
if (GUILayout.Button("Evaluate CanAutoSave"))
|
||||
{
|
||||
EvaluateSavePoint();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawRestoreSection()
|
||||
{
|
||||
EditorGUILayout.LabelField("读档验证 (P4)", EditorStyles.boldLabel);
|
||||
EditorGUILayout.HelpBox(
|
||||
"触发 GameManager.TryRestoreSlot,验证预检、Phase + Barrier 编排、自动存档抑制与 Provider 还原日志。\n" +
|
||||
"需要在 Play Mode 下执行;不代表正式玩家 UI。",
|
||||
MessageType.None);
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Restore Latest"))
|
||||
{
|
||||
RestoreLatestSlot();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Restore slot_0"))
|
||||
{
|
||||
RestoreSlot(SlotIndex.Auto);
|
||||
}
|
||||
}
|
||||
|
||||
_restoreSlotIndex = EditorGUILayout.IntSlider("Restore 槽位", _restoreSlotIndex, 0, SlotIndex.ManualEnd);
|
||||
if (GUILayout.Button($"Restore slot_{_restoreSlotIndex}"))
|
||||
{
|
||||
RestoreSlot(_restoreSlotIndex);
|
||||
}
|
||||
|
||||
var restoreLog = SaveRestoreOrchestrator.LastRestoreLog;
|
||||
if (restoreLog.Count > 0)
|
||||
{
|
||||
EditorGUILayout.LabelField("Restore Pipeline Log", EditorStyles.boldLabel);
|
||||
foreach (var line in restoreLog)
|
||||
{
|
||||
EditorGUILayout.LabelField(line, EditorStyles.wordWrappedMiniLabel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawUtilitySection()
|
||||
{
|
||||
EditorGUILayout.LabelField("工具", EditorStyles.boldLabel);
|
||||
|
||||
if (GUILayout.Button("打开存档目录"))
|
||||
{
|
||||
OpenSaveDirectory();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("刷新"))
|
||||
{
|
||||
Repaint();
|
||||
Log("已刷新。");
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawLogSection()
|
||||
{
|
||||
GUILayout.Space(12);
|
||||
EditorGUILayout.LabelField("最后结果", EditorStyles.boldLabel);
|
||||
EditorGUILayout.SelectableLabel(_lastLog, EditorStyles.textArea, GUILayout.MinHeight(120));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Actions
|
||||
|
||||
private void CaptureSnapshotInMemory()
|
||||
{
|
||||
try
|
||||
{
|
||||
var storage = YarnVariableStorage.Instance;
|
||||
if (storage == null)
|
||||
{
|
||||
Log("YarnVariableStorage 未初始化,尝试直接 new SaveSnapshot 仅做结构演示。");
|
||||
var demo = new SaveSnapshot
|
||||
{
|
||||
gameVersion = Application.version,
|
||||
savedAt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
||||
scene = new SceneSnapshotDto { sceneName = "DemoScene" },
|
||||
anchor = new AnchorSnapshot { nodeName = "DemoNode" },
|
||||
yarnVariables = new YarnVariablesSnapshot()
|
||||
};
|
||||
PrintSnapshotSummary(demo, "演示快照(无运行时)");
|
||||
return;
|
||||
}
|
||||
|
||||
var snapshot = SnapshotService.Capture();
|
||||
PrintSnapshotSummary(snapshot, "内存快照");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"Capture 失败: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private void TryAutoSaveFullFlow()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Log("TryAutoSave 需要在 Play Mode 下执行。");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var beforeLatest = SlotManager.GetLatestSlotIndex();
|
||||
var beforeSnapshot = SlotManager.LoadSnapshot(0);
|
||||
|
||||
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();
|
||||
|
||||
var summary = string.Empty;
|
||||
if (afterSnapshot == null)
|
||||
{
|
||||
summary = "无快照写入(可能被 SavePointEvaluator 拒绝)。";
|
||||
}
|
||||
else
|
||||
{
|
||||
summary = $"落盘成功。\n" +
|
||||
$"场景: {afterSnapshot.scene?.sceneName}\n" +
|
||||
$"节点: {afterSnapshot.anchor?.nodeName}\n" +
|
||||
$"SO: {afterSnapshot.anchor?.sceneSoName}\n" +
|
||||
$"YarnProject: {afterSnapshot.anchor?.yarnProjectId}\n" +
|
||||
$"Sections: {string.Join(", ", afterSnapshot.sections?.Keys ?? Enumerable.Empty<string>())}\n" +
|
||||
$"latest_slot: {(afterLatest.HasValue ? afterLatest.Value.ToString() : "无")}";
|
||||
}
|
||||
|
||||
Log(summary);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"TryAutoSave 失败: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyAutoToManual(int slotIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!SlotDirectory.Exists(SlotIndex.Auto))
|
||||
{
|
||||
Log("自动档不存在,无法复制手动档。");
|
||||
return;
|
||||
}
|
||||
|
||||
SlotManager.CopyAutoToManual(slotIndex);
|
||||
Log($"已复制自动档到 slot_{slotIndex}。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"复制失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteSlot(int slotIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
SlotManager.DeleteSlot(slotIndex);
|
||||
Log($"已删除/清空 slot_{slotIndex}。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"删除失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearAllSaves()
|
||||
{
|
||||
if (!EditorUtility.DisplayDialog("确认", "删除所有存档槽位?此操作不可撤销。", "删除", "取消"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
for (var i = SlotIndex.Auto; i <= SlotIndex.ManualEnd; i++)
|
||||
{
|
||||
SlotManager.DeleteSlot(i);
|
||||
}
|
||||
|
||||
var latestPath = SlotDirectory.GetLatestSlotIndexPath();
|
||||
if (File.Exists(latestPath))
|
||||
{
|
||||
File.Delete(latestPath);
|
||||
}
|
||||
|
||||
Log("已清空所有槽位和 latest_slot 记录。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"清空失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void EvaluateSavePoint()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Log("SavePointEvaluator 需要运行时状态(IsRestoring / GameManager pause)。请在 Play Mode 下执行。");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var projectId = DialogController.Instance?.DialogueRunner?.YarnProject?.name;
|
||||
var tags = ParseTestTags(_testTags);
|
||||
var inProgress = SavePointEvaluator.InProgressNodeNames;
|
||||
|
||||
if (SaveRestoreOrchestrator.IsAutoSaveSuppressed)
|
||||
{
|
||||
Log("全局门控: AutoSaveSuppressed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (SaveRestoreOrchestrator.IsRestoring)
|
||||
{
|
||||
Log("全局门控: Restoring(读档重进走 OnRestoreEnterNode,不写盘)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameManager.Instance != null && GameManager.Session.IsPaused)
|
||||
{
|
||||
Log("全局门控: GamePaused");
|
||||
return;
|
||||
}
|
||||
|
||||
var detourResume = !string.IsNullOrEmpty(_testNodeName)
|
||||
&& inProgress.Contains(_testNodeName);
|
||||
var tagOk = SavePointEvaluator.EvaluateNodeTagsForAutoSave(
|
||||
_testNodeName, tags, out var tagReason);
|
||||
var wouldSave = !detourResume && tagOk;
|
||||
|
||||
Log(
|
||||
$"Project = {projectId ?? "(null)"}\n" +
|
||||
$"InProgress = [{string.Join(", ", inProgress)}]\n" +
|
||||
$"模拟节点 = {_testNodeName}, tags = [{string.Join(", ", tags)}]\n" +
|
||||
$"DetourResume = {detourResume}\n" +
|
||||
$"Tag 判定 = {tagOk}, TagReason = {tagReason}\n" +
|
||||
$"OnNodeStart 会自动存 = {wouldSave}\n" +
|
||||
$"(DialogController 当前上下文 CanAutoSave = {SavePointEvaluator.CanAutoSave(out var ctxReason)}, Reason = {ctxReason})");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"判定失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private static string[] ParseTestTags(string raw)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(raw))
|
||||
{
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
return raw.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(tag => tag.Trim())
|
||||
.Where(tag => tag.Length > 0)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private void RestoreLatestSlot()
|
||||
{
|
||||
var latest = SlotManager.GetLatestSlotIndex();
|
||||
if (!latest.HasValue)
|
||||
{
|
||||
Log("没有 latest_slot,无法读档。");
|
||||
return;
|
||||
}
|
||||
|
||||
RestoreSlot(latest.Value);
|
||||
}
|
||||
|
||||
private void RestoreSlot(int slotIndex)
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Log("Restore 需要在 Play Mode 下执行。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (GameManager.Instance == null)
|
||||
{
|
||||
Log("GameManager 未初始化,无法启动读档协程。");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SlotDirectory.Exists(slotIndex))
|
||||
{
|
||||
Log($"slot_{slotIndex} 不存在,无法读档。");
|
||||
return;
|
||||
}
|
||||
|
||||
GameManager.Instance.TryRestoreSlot(slotIndex);
|
||||
Log($"已启动 Restore slot_{slotIndex}。请观察 Restore Pipeline Log 与场景状态。");
|
||||
}
|
||||
|
||||
private void OpenSaveDirectory()
|
||||
{
|
||||
var path = ConstRef.SaveFilePath;
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
EditorUtility.RevealInFinder(path);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
private void PrintSnapshotSummary(SaveSnapshot snapshot, string label)
|
||||
{
|
||||
var json = SnapshotPersistence.Serialize(snapshot);
|
||||
var lines = new List<string>
|
||||
{
|
||||
$"=== {label} ===",
|
||||
$"gameVersion: {snapshot.gameVersion}",
|
||||
$"savedAt: {snapshot.savedAt}",
|
||||
$"schemaVersion: {snapshot.schemaVersion}",
|
||||
$"scene: {snapshot.scene?.sceneName}",
|
||||
$"anchor.sceneSoName: {snapshot.anchor?.sceneSoName}",
|
||||
$"anchor.yarnProjectId: {snapshot.anchor?.yarnProjectId}",
|
||||
$"anchor.nodeName: {snapshot.anchor?.nodeName}",
|
||||
$"yarnVariables.floats: {snapshot.yarnVariables?.floats?.Count ?? 0} entries",
|
||||
$"yarnVariables.strings: {snapshot.yarnVariables?.strings?.Count ?? 0} entries",
|
||||
$"yarnVariables.bools: {snapshot.yarnVariables?.bools?.Count ?? 0} entries",
|
||||
$"sections: {(snapshot.sections != null ? string.Join(", ", snapshot.sections.Keys) : "null")}",
|
||||
};
|
||||
|
||||
if (snapshot.sections != null)
|
||||
{
|
||||
AppendFixSectionHint(lines, snapshot, SnapshotProviderIds.PunchTape);
|
||||
AppendFixSectionHint(lines, snapshot, SnapshotProviderIds.Fix);
|
||||
AppendFixSectionHint(lines, snapshot, SnapshotProviderIds.FixPanel);
|
||||
AppendFixSectionHint(lines, snapshot, SnapshotProviderIds.BodyModule);
|
||||
AppendFixSectionHint(lines, snapshot, SnapshotProviderIds.Eye);
|
||||
}
|
||||
|
||||
lines.Add("JSON preview (first 1500 chars):");
|
||||
lines.Add(json.Length > 1500 ? json.Substring(0, 1500) + "..." : json);
|
||||
|
||||
Log(string.Join("\n", lines));
|
||||
}
|
||||
|
||||
private static void AppendFixSectionHint(List<string> lines, SaveSnapshot snapshot, string sectionId)
|
||||
{
|
||||
if (snapshot.sections.ContainsKey(sectionId))
|
||||
{
|
||||
lines.Add($" [fix-related] {sectionId}: captured");
|
||||
}
|
||||
}
|
||||
|
||||
private void Log(string message)
|
||||
{
|
||||
_lastLog = $"[{DateTime.Now:HH:mm:ss}] {message}";
|
||||
Debug.Log($"[SaveSystemValidator] {message}");
|
||||
Repaint();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9719ab6f265683c4484a170f6c4dc843
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -19,19 +19,8 @@ namespace AibisDream.Utility
|
||||
|
||||
public const string WishlistURL = "https://store.steampowered.com/app/3473430/_All_Our_Broken_Parts?utm_source=playtest";
|
||||
|
||||
/// <summary>
|
||||
/// 可提交的开发跳转存档根目录(DeveloperModePanel)。
|
||||
/// 编辑器中位于项目根目录,Development Build 中位于可执行文件旁;不会被 Unity 自动打包。
|
||||
/// </summary>
|
||||
public static readonly string TestSaveFilePath =
|
||||
Path.GetFullPath(Path.Combine(Application.dataPath, "..", "DevSaveFiles"));
|
||||
|
||||
public static readonly string SaveFilePath = Path.Combine(Application.persistentDataPath, "AllOurBrokenParts", "demo_saves");
|
||||
|
||||
/// <summary>测试阶段自动存档历史目录;每次自动存档独立子文件夹,不覆盖正式槽位。</summary>
|
||||
public static readonly string TestAutoSaveArchivePath =
|
||||
Path.Combine(Application.persistentDataPath, "AllOurBrokenParts", "testsavs");
|
||||
|
||||
/// <summary>P2 槽位相关常量。</summary>
|
||||
public const int SaveSlotCount = 8;
|
||||
/// <summary>存档槽位缩略图;关闭可避免主相机 Render + ReadPixels 的性能开销。</summary>
|
||||
@@ -44,12 +33,6 @@ namespace AibisDream.Utility
|
||||
public const string SaveThumbnailFileName = "thumbnail";
|
||||
public const string LatestSlotFileName = "latest_slot";
|
||||
|
||||
/// <summary>P1 快照层自测落盘路径(P2 槽位层接管后迁移)。</summary>
|
||||
public static readonly string SnapshotTestPath =
|
||||
Path.Combine(Application.persistentDataPath, "AllOurBrokenParts", "snapshot_test");
|
||||
|
||||
public const string SnapshotTestFileName = "latest_snapshot";
|
||||
|
||||
public static readonly string ChapterProgressPath = Path.Combine(Application.persistentDataPath, "AllOurBrokenParts", "Config", "chapter.json");
|
||||
|
||||
public static readonly string CharacterConfigPath = Path.Combine(Application.streamingAssetsPath, "Config", "character.csv");
|
||||
|
||||
@@ -113,25 +113,6 @@ namespace AibisDream
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryRestoreFile(
|
||||
string path,
|
||||
RestoreOptions options,
|
||||
Action<RestoreResult> completed = null)
|
||||
{
|
||||
if (!CanBeginRestore() || !TryAcquireCommand(SessionCommandKind.Restore))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
StartCoroutine(RestoreRoutine(
|
||||
() => SaveRestoreOrchestrator.PrepareRestoreFromFile(
|
||||
path,
|
||||
_talkSceneIndex,
|
||||
options ?? RestoreOptions.Default),
|
||||
completed));
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryPause()
|
||||
{
|
||||
if (!_session.CanPause)
|
||||
|
||||
@@ -15,10 +15,6 @@ namespace AibisDream.SaveSystem
|
||||
StrictValidation = true
|
||||
};
|
||||
|
||||
public static RestoreOptions DevJump => new()
|
||||
{
|
||||
StrictValidation = true
|
||||
};
|
||||
}
|
||||
|
||||
public sealed class RestoreResult
|
||||
|
||||
@@ -27,12 +27,6 @@ SaveRestoreOrchestrator.CreateManualSlot(slotIndex);
|
||||
// 槽位读档:会话命令统一从 GameManager 进入
|
||||
GameManager.Instance.TryRestoreSlot(slotIndex, result => { /* 处理结果 */ });
|
||||
|
||||
// 严格文件读档 / 开发跳转
|
||||
GameManager.Instance.TryRestoreFile(
|
||||
path,
|
||||
RestoreOptions.DevJump,
|
||||
result => { /* 处理结果 */ });
|
||||
|
||||
// 仅捕获内存快照;恢复仍须通过 GameManager,以保证会话互斥和失败清理
|
||||
var snap = SnapshotService.Capture();
|
||||
|
||||
@@ -69,8 +63,6 @@ Yarn 脚本:
|
||||
|
||||
正式槽位路径:`persistentDataPath/AllOurBrokenParts/demo_saves/slot_x/{snapshot.json, meta.json, thumbnail.png}`
|
||||
|
||||
P1 测试落盘路径:`persistentDataPath/AllOurBrokenParts/snapshot_test/latest_snapshot.json`(首次访问槽位系统时会尝试迁移到 `slot_0`)
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
|
||||
@@ -91,27 +91,18 @@ namespace AibisDream.SaveSystem
|
||||
|
||||
infoPanel?.HideSaveLoading();
|
||||
|
||||
if (TestSaveArchive.IsEnabled)
|
||||
{
|
||||
TestSaveArchive.Archive(snapshot, thumbnail);
|
||||
Debug.Log("[SaveRestoreOrchestrator] 测试存档模式:已写入 testsavs(不覆盖 slot_0)。");
|
||||
_isAutoSaving = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = SlotManager.SaveToAutoSlotAsync(snapshot, thumbnail).ContinueWith(
|
||||
writeTask =>
|
||||
_ = SlotManager.SaveToAutoSlotAsync(snapshot, thumbnail).ContinueWith(
|
||||
writeTask =>
|
||||
{
|
||||
if (writeTask.IsFaulted)
|
||||
{
|
||||
if (writeTask.IsFaulted)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"[SaveRestoreOrchestrator] 自动存档写盘失败: {writeTask.Exception?.GetBaseException()}");
|
||||
}
|
||||
Debug.LogError(
|
||||
$"[SaveRestoreOrchestrator] 自动存档写盘失败: {writeTask.Exception?.GetBaseException()}");
|
||||
}
|
||||
|
||||
_isAutoSaving = false;
|
||||
},
|
||||
TaskContinuationOptions.ExecuteSynchronously);
|
||||
}
|
||||
_isAutoSaving = false;
|
||||
},
|
||||
TaskContinuationOptions.ExecuteSynchronously);
|
||||
|
||||
if (omitAnchor || (snapshot?.anchor != null && string.IsNullOrEmpty(snapshot.anchor.nodeName)))
|
||||
{
|
||||
@@ -167,28 +158,6 @@ namespace AibisDream.SaveSystem
|
||||
return PrepareSnapshot(snapshot, sourceLabel, talkSceneIndex, options);
|
||||
}
|
||||
|
||||
internal static RestorePreparation PrepareRestoreFromFile(
|
||||
string savePath,
|
||||
TalkSceneGraphIndex talkSceneIndex,
|
||||
RestoreOptions options)
|
||||
{
|
||||
options ??= RestoreOptions.Default;
|
||||
try
|
||||
{
|
||||
SaveSnapshot snapshot;
|
||||
using (new CodeTimer("LoadSnapshot"))
|
||||
{
|
||||
snapshot = SnapshotPersistence.Load(savePath);
|
||||
}
|
||||
|
||||
return PrepareSnapshot(snapshot, savePath, talkSceneIndex, options);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return FailedPreparation(savePath, "LoadSnapshot", ex.Message, options);
|
||||
}
|
||||
}
|
||||
|
||||
internal static IEnumerator ExecutePreparedRestore(
|
||||
RestorePreparation preparation,
|
||||
Func<bool> isCancellationRequested)
|
||||
|
||||
@@ -10,17 +10,15 @@ using UnityEngine;
|
||||
namespace AibisDream.SaveSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 存档槽位业务核心:管理自动档、手动档、读档、继续游戏与 P1 迁移。
|
||||
/// 存档槽位业务核心:管理自动档、手动档、读档与继续游戏。
|
||||
/// </summary>
|
||||
public static class SlotManager
|
||||
{
|
||||
private static bool _migrated;
|
||||
private static readonly object SlotWriteLock = new object();
|
||||
|
||||
/// <summary>将快照与缩略图写入指定槽位。</summary>
|
||||
public static void SaveToSlot(int slotIndex, SaveSnapshot snapshot, byte[] thumbnailPng)
|
||||
{
|
||||
EnsureMigrated();
|
||||
WriteSlot(slotIndex, snapshot, thumbnailPng);
|
||||
}
|
||||
|
||||
@@ -37,8 +35,6 @@ namespace AibisDream.SaveSystem
|
||||
/// </summary>
|
||||
public static async Task SaveToAutoSlotAsync(SaveSnapshot snapshot, byte[] thumbnailPng)
|
||||
{
|
||||
EnsureMigrated();
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var json = SnapshotPersistence.Serialize(snapshot);
|
||||
@@ -53,8 +49,6 @@ namespace AibisDream.SaveSystem
|
||||
/// <summary>将当前自动档复制到指定手动档。</summary>
|
||||
public static void CopyAutoToManual(int manualSlotIndex)
|
||||
{
|
||||
EnsureMigrated();
|
||||
|
||||
if (manualSlotIndex < SlotIndex.ManualStart || manualSlotIndex > SlotIndex.ManualEnd)
|
||||
{
|
||||
Debug.LogError($"[SlotManager] 手动槽位编号非法: {manualSlotIndex}");
|
||||
@@ -99,8 +93,6 @@ namespace AibisDream.SaveSystem
|
||||
/// <summary>删除指定槽位。</summary>
|
||||
public static void DeleteSlot(int slotIndex)
|
||||
{
|
||||
EnsureMigrated();
|
||||
|
||||
if (slotIndex == SlotIndex.Auto)
|
||||
{
|
||||
// 自动档只清空内容,不删除目录
|
||||
@@ -128,8 +120,6 @@ namespace AibisDream.SaveSystem
|
||||
/// <summary>读取槽位的完整快照。</summary>
|
||||
public static SaveSnapshot LoadSnapshot(int slotIndex)
|
||||
{
|
||||
EnsureMigrated();
|
||||
|
||||
var path = SlotDirectory.GetSnapshotPath(slotIndex);
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
@@ -151,7 +141,6 @@ 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));
|
||||
}
|
||||
@@ -200,8 +189,6 @@ namespace AibisDream.SaveSystem
|
||||
/// <summary>获取最近写入的槽位编号;不存在返回 null。</summary>
|
||||
public static int? GetLatestSlotIndex()
|
||||
{
|
||||
EnsureMigrated();
|
||||
|
||||
var path = SlotDirectory.GetLatestSlotIndexPath();
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
@@ -239,8 +226,6 @@ namespace AibisDream.SaveSystem
|
||||
/// <summary>获取供 UI 展示的全部槽位视图模型。</summary>
|
||||
public static SlotViewModel[] GetSlotViewModels()
|
||||
{
|
||||
EnsureMigrated();
|
||||
|
||||
var result = new List<SlotViewModel>();
|
||||
for (var i = SlotIndex.Auto; i <= SlotIndex.ManualEnd; i++)
|
||||
{
|
||||
@@ -357,55 +342,6 @@ namespace AibisDream.SaveSystem
|
||||
thumbnailPath: thumbnailPath);
|
||||
}
|
||||
|
||||
private static void EnsureMigrated()
|
||||
{
|
||||
if (_migrated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_migrated = true;
|
||||
TryMigrateP1TestSnapshot();
|
||||
}
|
||||
|
||||
private static void TryMigrateP1TestSnapshot()
|
||||
{
|
||||
var testPath = Path.Combine(ConstRef.SnapshotTestPath, $"{ConstRef.SnapshotTestFileName}.json");
|
||||
if (!File.Exists(testPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (SlotDirectory.Exists(SlotIndex.Auto))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var snapshot = SnapshotPersistence.Load(testPath);
|
||||
if (snapshot == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SaveToAutoSlot(snapshot, null);
|
||||
|
||||
var migratedPath = testPath + ".migrated";
|
||||
if (File.Exists(migratedPath))
|
||||
{
|
||||
File.Delete(migratedPath);
|
||||
}
|
||||
File.Move(testPath, migratedPath);
|
||||
|
||||
Debug.Log($"[SlotManager] 已将 P1 测试存档从 {testPath} 迁移到 slot_0。");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[SlotManager] P1 测试存档迁移失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class LatestSlotRecord
|
||||
{
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using System.IO;
|
||||
using AibisDream.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -8,8 +6,8 @@ namespace AibisDream.SaveSystem
|
||||
/// <summary>
|
||||
/// 快照与磁盘的边界:序列化和读写 JSON 文件。
|
||||
/// <para>
|
||||
/// P2 起,业务存档统一通过 <see cref="SlotManager"/> 写入槽位目录;
|
||||
/// 本类保留按路径读写的低级接口,供迁移和外部调试使用。
|
||||
/// 业务存档统一通过 <see cref="SlotManager"/> 写入槽位目录;
|
||||
/// 本类只负责快照序列化、反序列化与槽位入口。
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public static class SnapshotPersistence
|
||||
@@ -21,12 +19,6 @@ namespace AibisDream.SaveSystem
|
||||
NullValueHandling = NullValueHandling.Ignore
|
||||
};
|
||||
|
||||
/// <summary>P1 自测落盘:<c>SnapshotTestPath/latest_snapshot.json</c>(P2 迁移源)。</summary>
|
||||
public static string GetTestFilePath()
|
||||
{
|
||||
return Path.Combine(ConstRef.SnapshotTestPath, ConstRef.SnapshotTestFileName);
|
||||
}
|
||||
|
||||
/// <summary>将快照序列化并写入指定槽位。</summary>
|
||||
public static void SaveToSlot(int slotIndex, SaveSnapshot snapshot)
|
||||
{
|
||||
@@ -58,26 +50,5 @@ namespace AibisDream.SaveSystem
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
/// <summary>将快照序列化并写入 path(自动补 .json 后缀)。</summary>
|
||||
public static void Save(SaveSnapshot snapshot, string 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);
|
||||
}
|
||||
|
||||
/// <summary>从 path 读取并反序列化为 <see cref="SaveSnapshot"/>。</summary>
|
||||
public static SaveSnapshot Load(string pathWithoutExtension)
|
||||
{
|
||||
var json = File.ReadAllText(JsonUtil.FormatAsJsonPath(pathWithoutExtension));
|
||||
return Deserialize(json);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,218 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AibisDream.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.SaveSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 测试存档模式:每次自动存档写入 <see cref="ConstRef.TestAutoSaveArchivePath"/> 下的独立子目录。
|
||||
/// 开启后不写入 slot_0,存多少次就保留多少份,与正式 demo_saves/ 完全隔离。
|
||||
/// </summary>
|
||||
public static class TestSaveArchive
|
||||
{
|
||||
public const string EditorPrefsEnabledKey = "AibisDream.SaveSystem.TestArchiveEnabled";
|
||||
|
||||
/// <summary>测试存档模式是否开启(Editor 下由 EditorPrefs 控制,构建产物恒为 false)。</summary>
|
||||
public static bool IsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return UnityEditor.EditorPrefs.GetBool(EditorPrefsEnabledKey, true);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly object ArchiveWriteLock = new object();
|
||||
|
||||
/// <summary>将快照写入 testsavs 新条目,返回文件夹名。每次调用均新建,不覆盖已有条目。</summary>
|
||||
public static string Archive(SaveSnapshot snapshot, byte[] thumbnailPng)
|
||||
{
|
||||
if (snapshot == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var entryId = BuildUniqueEntryId(snapshot);
|
||||
var entryDir = Path.Combine(ConstRef.TestAutoSaveArchivePath, entryId);
|
||||
Directory.CreateDirectory(entryDir);
|
||||
|
||||
var json = SnapshotPersistence.Serialize(snapshot);
|
||||
var meta = BuildMeta(entryId, snapshot);
|
||||
|
||||
lock (ArchiveWriteLock)
|
||||
{
|
||||
SlotAtomicWriter.WriteText(json, Path.Combine(entryDir, $"{ConstRef.SaveSnapshotFileName}.json"));
|
||||
SlotAtomicWriter.WriteJson(meta, Path.Combine(entryDir, $"{ConstRef.SaveMetaFileName}.json"));
|
||||
|
||||
if (thumbnailPng != null)
|
||||
{
|
||||
SlotAtomicWriter.WriteBytes(
|
||||
thumbnailPng,
|
||||
Path.Combine(entryDir, $"{ConstRef.SaveThumbnailFileName}.png"));
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"[TestSaveArchive] 已归档测试存档: {entryId}");
|
||||
return entryId;
|
||||
}
|
||||
|
||||
public static List<TestSaveArchiveEntry> ListEntries()
|
||||
{
|
||||
var result = new List<TestSaveArchiveEntry>();
|
||||
if (!Directory.Exists(ConstRef.TestAutoSaveArchivePath))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (var dir in Directory.GetDirectories(ConstRef.TestAutoSaveArchivePath))
|
||||
{
|
||||
var entryId = Path.GetFileName(dir);
|
||||
var snapshotPath = Path.Combine(dir, $"{ConstRef.SaveSnapshotFileName}.json");
|
||||
if (!File.Exists(snapshotPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var metaPath = Path.Combine(dir, $"{ConstRef.SaveMetaFileName}.json");
|
||||
var thumbPath = Path.Combine(dir, $"{ConstRef.SaveThumbnailFileName}.png");
|
||||
|
||||
SlotMeta meta = null;
|
||||
if (File.Exists(metaPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
meta = JsonConvert.DeserializeObject<SlotMeta>(File.ReadAllText(metaPath));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning($"[TestSaveArchive] 读取 meta 失败 ({entryId}): {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(new TestSaveArchiveEntry(
|
||||
entryId,
|
||||
dir,
|
||||
snapshotPath,
|
||||
File.Exists(thumbPath) ? thumbPath : null,
|
||||
meta));
|
||||
}
|
||||
|
||||
return result
|
||||
.OrderByDescending(e => e.Meta?.savedAt ?? string.Empty)
|
||||
.ThenByDescending(e => e.EntryId, StringComparer.Ordinal)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public static void DeleteEntry(string entryId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(entryId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var dir = Path.Combine(ConstRef.TestAutoSaveArchivePath, entryId);
|
||||
if (Directory.Exists(dir))
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearAll()
|
||||
{
|
||||
if (!Directory.Exists(ConstRef.TestAutoSaveArchivePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var dir in Directory.GetDirectories(ConstRef.TestAutoSaveArchivePath))
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
private static string BuildUniqueEntryId(SaveSnapshot snapshot)
|
||||
{
|
||||
var baseId = BuildEntryId(snapshot);
|
||||
var entryId = baseId;
|
||||
var suffix = 2;
|
||||
|
||||
while (Directory.Exists(Path.Combine(ConstRef.TestAutoSaveArchivePath, entryId)))
|
||||
{
|
||||
entryId = $"{baseId}_{suffix}";
|
||||
suffix++;
|
||||
}
|
||||
|
||||
return entryId;
|
||||
}
|
||||
|
||||
private static string BuildEntryId(SaveSnapshot snapshot)
|
||||
{
|
||||
var timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss_fff");
|
||||
var nodeName = snapshot.anchor?.nodeName;
|
||||
var safeNode = string.IsNullOrEmpty(nodeName) ? "no_node" : SanitizeEntryName(nodeName);
|
||||
return $"{timestamp}_{safeNode}";
|
||||
}
|
||||
|
||||
private static SlotMeta BuildMeta(string entryId, SaveSnapshot snapshot)
|
||||
{
|
||||
var summary = SaveSnapshotSummary.From(snapshot);
|
||||
return new SlotMeta
|
||||
{
|
||||
slotIndex = -1,
|
||||
savedAt = snapshot.savedAt,
|
||||
sceneName = summary.SceneName,
|
||||
sceneSoName = summary.SceneSoName,
|
||||
yarnProjectId = summary.YarnProjectId,
|
||||
nodeName = snapshot.anchor?.nodeName,
|
||||
schemaVersion = snapshot.schemaVersion,
|
||||
gameVersion = snapshot.gameVersion,
|
||||
thumbnailFile = $"{ConstRef.SaveThumbnailFileName}.png"
|
||||
};
|
||||
}
|
||||
|
||||
private static string SanitizeEntryName(string name)
|
||||
{
|
||||
foreach (var c in Path.GetInvalidFileNameChars())
|
||||
{
|
||||
name = name.Replace(c, '_');
|
||||
}
|
||||
|
||||
if (name.Length > 48)
|
||||
{
|
||||
name = name.Substring(0, 48);
|
||||
}
|
||||
|
||||
return string.IsNullOrWhiteSpace(name) ? "no_node" : name;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct TestSaveArchiveEntry
|
||||
{
|
||||
public readonly string EntryId;
|
||||
public readonly string DirectoryPath;
|
||||
public readonly string SnapshotPath;
|
||||
public readonly string ThumbnailPath;
|
||||
public readonly SlotMeta Meta;
|
||||
|
||||
public TestSaveArchiveEntry(
|
||||
string entryId,
|
||||
string directoryPath,
|
||||
string snapshotPath,
|
||||
string thumbnailPath,
|
||||
SlotMeta meta)
|
||||
{
|
||||
EntryId = entryId;
|
||||
DirectoryPath = directoryPath;
|
||||
SnapshotPath = snapshotPath;
|
||||
ThumbnailPath = thumbnailPath;
|
||||
Meta = meta;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 408acae5dfcc0a94094d87e33ba53cd4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -61,21 +61,16 @@ namespace AibisDream.UI
|
||||
[SerializeField] private DeveloperModeListRow variableRowTemplate;
|
||||
|
||||
[Header("Saves")]
|
||||
[SerializeField] private TMP_InputField saveSearchInput;
|
||||
[SerializeField] private Button reloadSavesButton;
|
||||
[SerializeField] private TMP_Text saveStatusText;
|
||||
[SerializeField] private RectTransform slotContent;
|
||||
[SerializeField] private DeveloperModeListRow slotRowTemplate;
|
||||
[SerializeField] private RectTransform devSaveContent;
|
||||
[SerializeField] private DeveloperModeListRow devSaveRowTemplate;
|
||||
|
||||
[Header("Paths")]
|
||||
[SerializeField] private Button openSaveFolderButton;
|
||||
[SerializeField] private Button copySaveFolderButton;
|
||||
[SerializeField] private Button openLogFolderButton;
|
||||
[SerializeField] private Button copyLogFolderButton;
|
||||
[SerializeField] private Button openDevSaveFolderButton;
|
||||
[SerializeField] private Button copyDevSaveFolderButton;
|
||||
[SerializeField] private Button openCurrentLogButton;
|
||||
[SerializeField] private Button copyCurrentLogButton;
|
||||
|
||||
@@ -94,8 +89,6 @@ namespace AibisDream.UI
|
||||
private readonly List<DeveloperModeListRow> _logRows = new();
|
||||
private readonly List<DeveloperModeListRow> _variableRows = new();
|
||||
private readonly List<DeveloperModeListRow> _slotRows = new();
|
||||
private readonly List<DeveloperModeListRow> _devSaveRows = new();
|
||||
|
||||
private VerText _verText;
|
||||
private RuntimeLogRecord? _selectedLog;
|
||||
private int _currentTab;
|
||||
@@ -256,10 +249,6 @@ namespace AibisDream.UI
|
||||
variableScopeButton?.onClick.AddListener(CycleVariableScope);
|
||||
variableTypeButton?.onClick.AddListener(CycleVariableType);
|
||||
|
||||
saveSearchInput?.onValueChanged.AddListener(_ =>
|
||||
{
|
||||
_savesDirty = true;
|
||||
});
|
||||
reloadSavesButton?.onClick.AddListener(() =>
|
||||
{
|
||||
_savesDirty = true;
|
||||
@@ -561,7 +550,6 @@ namespace AibisDream.UI
|
||||
{
|
||||
_savesDirty = false;
|
||||
RefreshSlotRows();
|
||||
RefreshDevSaveRows();
|
||||
}
|
||||
|
||||
private void RefreshSlotRows()
|
||||
@@ -592,47 +580,6 @@ namespace AibisDream.UI
|
||||
HideRows(_slotRows, viewModels.Length);
|
||||
}
|
||||
|
||||
private void RefreshDevSaveRows()
|
||||
{
|
||||
if (devSaveContent == null || devSaveRowTemplate == null) return;
|
||||
var sections = DevSaveCatalog.Load(ConstRef.TestSaveFilePath);
|
||||
var search = saveSearchInput?.text;
|
||||
var rowIndex = 0;
|
||||
|
||||
foreach (var section in sections)
|
||||
{
|
||||
var entries = section.Entries.Where(entry => string.IsNullOrWhiteSpace(search)
|
||||
|| Contains(section.Title, search)
|
||||
|| Contains(entry.Label, search)
|
||||
|| Contains(entry.AnchorNode, search)).ToArray();
|
||||
if (entries.Length == 0) continue;
|
||||
|
||||
GetRow(_devSaveRows, devSaveRowTemplate, devSaveContent, rowIndex++)
|
||||
.Bind($"── {section.Title} ({entries.Count(entry => entry.IsValid)}/{entries.Length}) ──", null, false,
|
||||
new Color(0.35f, 0.9f, 1f));
|
||||
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
var captured = entry;
|
||||
var text = entry.IsValid
|
||||
? $"{entry.Order:000} {entry.Label} | node={entry.AnchorNode} | scene={entry.Snapshot?.scene?.sceneName}"
|
||||
: $"{entry.Order:000} {entry.Label} | 不可用:{entry.Error}";
|
||||
GetRow(_devSaveRows, devSaveRowTemplate, devSaveContent, rowIndex++)
|
||||
.Bind(text, () => RestoreDevSave(captured), entry.IsValid && CanStartRestore(),
|
||||
entry.IsValid ? Color.white : new Color(1f, 0.5f, 0.45f), isError: !entry.IsValid);
|
||||
}
|
||||
}
|
||||
|
||||
if (sections.Count == 0)
|
||||
{
|
||||
GetRow(_devSaveRows, devSaveRowTemplate, devSaveContent, rowIndex++)
|
||||
.Bind(DevSaveCatalog.LastError ?? "开发检查点清单为空。", null, false,
|
||||
new Color(1f, 0.5f, 0.45f), isError: true);
|
||||
}
|
||||
|
||||
HideRows(_devSaveRows, rowIndex);
|
||||
}
|
||||
|
||||
private bool CanStartRestore()
|
||||
{
|
||||
if (_isRestorePending || SaveRestoreOrchestrator.IsRestoring || GameManager.Instance == null) return false;
|
||||
@@ -658,24 +605,6 @@ namespace AibisDream.UI
|
||||
_savesDirty = true;
|
||||
}
|
||||
|
||||
private void RestoreDevSave(DevSaveEntry entry)
|
||||
{
|
||||
if (entry == null || !entry.IsValid || !CanStartRestore())
|
||||
{
|
||||
SetSaveStatus("开发检查点当前不可加载。", true);
|
||||
return;
|
||||
}
|
||||
|
||||
_isRestorePending = true;
|
||||
SetSaveStatus($"正在跳转:{entry.Label}...", false);
|
||||
if (!GameManager.Instance.TryRestoreFile(entry.SnapshotPathWithoutExtension, RestoreOptions.DevJump, OnRestoreCompleted))
|
||||
{
|
||||
_isRestorePending = false;
|
||||
SetSaveStatus("跳转请求被 GameManager 拒绝。", true);
|
||||
}
|
||||
_savesDirty = true;
|
||||
}
|
||||
|
||||
private void OnRestoreCompleted(RestoreResult result)
|
||||
{
|
||||
_isRestorePending = false;
|
||||
@@ -699,8 +628,6 @@ namespace AibisDream.UI
|
||||
copySaveFolderButton?.onClick.AddListener(() => CopyPath(ConstRef.SaveFilePath));
|
||||
openLogFolderButton?.onClick.AddListener(() => RevealPath(ConstRef.LogFilePath, true));
|
||||
copyLogFolderButton?.onClick.AddListener(() => CopyPath(ConstRef.LogFilePath));
|
||||
openDevSaveFolderButton?.onClick.AddListener(() => RevealPath(ConstRef.TestSaveFilePath, false));
|
||||
copyDevSaveFolderButton?.onClick.AddListener(() => CopyPath(ConstRef.TestSaveFilePath));
|
||||
openCurrentLogButton?.onClick.AddListener(() => RevealPath(LogKit.CurrentLogFilePath, false));
|
||||
copyCurrentLogButton?.onClick.AddListener(() => CopyPath(LogKit.CurrentLogFilePath));
|
||||
|
||||
@@ -708,7 +635,6 @@ namespace AibisDream.UI
|
||||
{
|
||||
if (openSaveFolderButton != null) openSaveFolderButton.interactable = false;
|
||||
if (openLogFolderButton != null) openLogFolderButton.interactable = false;
|
||||
if (openDevSaveFolderButton != null) openDevSaveFolderButton.interactable = false;
|
||||
if (openCurrentLogButton != null) openCurrentLogButton.interactable = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using AibisDream.SaveSystem;
|
||||
using AibisDream.Utility;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
/// <summary>读取并严格校验项目内可提交的开发检查点清单。</summary>
|
||||
public static class DevSaveCatalog
|
||||
{
|
||||
public const int CurrentVersion = 1;
|
||||
private const string CatalogFileName = "catalog.json";
|
||||
public static string LastError { get; private set; }
|
||||
|
||||
public static List<DevSaveSection> Load(string root)
|
||||
{
|
||||
LastError = null;
|
||||
var result = new List<DevSaveSection>();
|
||||
var catalogPath = Path.Combine(root ?? string.Empty, CatalogFileName);
|
||||
if (string.IsNullOrWhiteSpace(root) || !File.Exists(catalogPath))
|
||||
{
|
||||
LastError = $"找不到测试存档清单:{catalogPath}";
|
||||
return result;
|
||||
}
|
||||
|
||||
DevSaveCatalogDto catalog;
|
||||
try
|
||||
{
|
||||
catalog = JsonConvert.DeserializeObject<DevSaveCatalogDto>(File.ReadAllText(catalogPath));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LastError = $"清单 JSON 损坏:{ex.Message}";
|
||||
return result;
|
||||
}
|
||||
|
||||
if (catalog == null || catalog.catalogVersion != CurrentVersion)
|
||||
{
|
||||
LastError = $"不支持的清单版本:{catalog?.catalogVersion.ToString() ?? "none"}";
|
||||
return result;
|
||||
}
|
||||
|
||||
foreach (var sectionDto in (catalog.sections ?? new List<DevSaveCatalogSectionDto>())
|
||||
.OrderBy(section => section.order))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(sectionDto.id)) continue;
|
||||
var entries = (sectionDto.entries ?? new List<DevSaveCatalogEntryDto>())
|
||||
.OrderBy(entry => entry.order)
|
||||
.Select(entry => BuildEntry(root, sectionDto, entry))
|
||||
.ToList();
|
||||
result.Add(new DevSaveSection(
|
||||
sectionDto.id,
|
||||
string.IsNullOrWhiteSpace(sectionDto.title) ? sectionDto.id : sectionDto.title,
|
||||
entries));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static DevSaveEntry BuildEntry(string root, DevSaveCatalogSectionDto section, DevSaveCatalogEntryDto dto)
|
||||
{
|
||||
var error = ValidateRelativePath(root, dto.path, out var entryDirectory);
|
||||
var snapshotPath = error == null
|
||||
? Path.Combine(entryDirectory, ConstRef.SaveSnapshotFileName)
|
||||
: string.Empty;
|
||||
var entry = new DevSaveEntry(
|
||||
dto.order,
|
||||
string.IsNullOrWhiteSpace(dto.label) ? dto.anchorNode : dto.label,
|
||||
dto.anchorNode,
|
||||
snapshotPath,
|
||||
section.expectedSceneName,
|
||||
section.expectedSceneSoName,
|
||||
section.expectedYarnProjectId,
|
||||
error);
|
||||
entry.Validate();
|
||||
return entry;
|
||||
}
|
||||
|
||||
private static string ValidateRelativePath(string root, string relativePath, out string fullPath)
|
||||
{
|
||||
fullPath = null;
|
||||
if (string.IsNullOrWhiteSpace(relativePath)) return "清单路径为空";
|
||||
if (Path.IsPathRooted(relativePath)) return "清单路径必须是相对路径";
|
||||
|
||||
try
|
||||
{
|
||||
var rootFull = Path.GetFullPath(root).TrimEnd(Path.DirectorySeparatorChar)
|
||||
+ Path.DirectorySeparatorChar;
|
||||
fullPath = Path.GetFullPath(Path.Combine(root, relativePath.Replace('/', Path.DirectorySeparatorChar)));
|
||||
if (!fullPath.StartsWith(rootFull, StringComparison.OrdinalIgnoreCase))
|
||||
return "清单路径越过 DevSaveFiles 根目录";
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return $"清单路径无效:{ex.Message}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DevSaveSection
|
||||
{
|
||||
public string Id { get; }
|
||||
public string Title { get; }
|
||||
public List<DevSaveEntry> Entries { get; }
|
||||
|
||||
public DevSaveSection(string id, string title, List<DevSaveEntry> entries)
|
||||
{
|
||||
Id = id;
|
||||
Title = title;
|
||||
Entries = entries ?? new List<DevSaveEntry>();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DevSaveEntry
|
||||
{
|
||||
public int Order { get; }
|
||||
public string Label { get; }
|
||||
public string AnchorNode { get; }
|
||||
public string SnapshotPathWithoutExtension { get; }
|
||||
public bool IsValid => string.IsNullOrEmpty(Error);
|
||||
public string Error { get; private set; }
|
||||
public SaveSnapshot Snapshot { get; private set; }
|
||||
|
||||
private readonly string _expectedSceneName;
|
||||
private readonly string _expectedSceneSoName;
|
||||
private readonly string _expectedYarnProjectId;
|
||||
|
||||
public DevSaveEntry(
|
||||
int order,
|
||||
string label,
|
||||
string anchorNode,
|
||||
string snapshotPathWithoutExtension,
|
||||
string expectedSceneName,
|
||||
string expectedSceneSoName,
|
||||
string expectedYarnProjectId,
|
||||
string initialError = null)
|
||||
{
|
||||
Order = order;
|
||||
Label = label ?? string.Empty;
|
||||
AnchorNode = anchorNode ?? string.Empty;
|
||||
SnapshotPathWithoutExtension = snapshotPathWithoutExtension;
|
||||
_expectedSceneName = expectedSceneName;
|
||||
_expectedSceneSoName = expectedSceneSoName;
|
||||
_expectedYarnProjectId = expectedYarnProjectId;
|
||||
Error = initialError;
|
||||
}
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Error)) return;
|
||||
if (string.IsNullOrEmpty(SnapshotPathWithoutExtension)
|
||||
|| !File.Exists(SnapshotPathWithoutExtension + ".json"))
|
||||
{
|
||||
Error = "存档文件缺失";
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Snapshot = SnapshotPersistence.Load(SnapshotPathWithoutExtension);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Error = $"JSON 无法读取:{ex.Message}";
|
||||
return;
|
||||
}
|
||||
|
||||
if (Snapshot == null || Snapshot.schemaVersion != SaveSnapshotSchema.CurrentVersion)
|
||||
Error = $"存档版本不兼容:{Snapshot?.schemaVersion.ToString() ?? "none"}";
|
||||
else if (Snapshot.scene == null || string.IsNullOrWhiteSpace(Snapshot.scene.sceneName))
|
||||
Error = "存档缺少场景";
|
||||
else if (Snapshot.anchor == null || string.IsNullOrWhiteSpace(Snapshot.anchor.nodeName))
|
||||
Error = "存档缺少 Yarn 锚点";
|
||||
else if (!Matches(_expectedSceneName, Snapshot.scene.sceneName))
|
||||
Error = $"场景不匹配:{Snapshot.scene.sceneName}";
|
||||
else if (!Matches(_expectedSceneSoName, Snapshot.anchor.sceneSoName))
|
||||
Error = $"TalkSceneSO 不匹配:{Snapshot.anchor.sceneSoName}";
|
||||
else if (!Matches(_expectedYarnProjectId, Snapshot.anchor.yarnProjectId))
|
||||
Error = $"YarnProject 不匹配:{Snapshot.anchor.yarnProjectId}";
|
||||
else if (!string.IsNullOrWhiteSpace(AnchorNode)
|
||||
&& !string.Equals(AnchorNode, Snapshot.anchor.nodeName, StringComparison.Ordinal))
|
||||
Error = $"节点不匹配:{Snapshot.anchor.nodeName}";
|
||||
}
|
||||
|
||||
private static bool Matches(string expected, string actual) =>
|
||||
string.IsNullOrWhiteSpace(expected) || string.Equals(expected, actual, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class DevSaveCatalogDto
|
||||
{
|
||||
public int catalogVersion = DevSaveCatalog.CurrentVersion;
|
||||
public List<DevSaveCatalogSectionDto> sections = new();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class DevSaveCatalogSectionDto
|
||||
{
|
||||
public int order;
|
||||
public string id;
|
||||
public string title;
|
||||
public string expectedSceneName;
|
||||
public string expectedSceneSoName;
|
||||
public string expectedYarnProjectId;
|
||||
public List<DevSaveCatalogEntryDto> entries = new();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class DevSaveCatalogEntryDto
|
||||
{
|
||||
public int order;
|
||||
public string label;
|
||||
public string path;
|
||||
public string anchorNode;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 260f8ad145646e94d9a1e4c9a935321b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-02 11:56:00",
|
||||
"sceneName": "Scene/OpenFixScene",
|
||||
"sceneSoName": "Day0_Prologue",
|
||||
"yarnProjectId": "FP_Prologue",
|
||||
"nodeName": "Start",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.7-20260701-213941",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.7-20260701-213941",
|
||||
"savedAt": "2026-07-02 11:56:00",
|
||||
"scene": {
|
||||
"sceneName": "Scene/OpenFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day0_Prologue",
|
||||
"yarnProjectId": "FP_Prologue",
|
||||
"nodeName": "Start"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {},
|
||||
"strings": {},
|
||||
"bools": {}
|
||||
},
|
||||
"sections": {
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Clinic"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"fix": {
|
||||
"state": "Dream",
|
||||
"args": ""
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": false,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": true,
|
||||
"isTaskPanelVisible": false,
|
||||
"tasks": []
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Body",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": false,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-15 20:00:13",
|
||||
"sceneName": "Scene/SubWay",
|
||||
"sceneSoName": "Day1_begin",
|
||||
"yarnProjectId": "FP_Day1_begin",
|
||||
"nodeName": "地铁ver5",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-15 20:00:13","scene":{"sceneName":"Scene/SubWay"},"anchor":{"sceneSoName":"Day1_begin","yarnProjectId":"FP_Day1_begin","nodeName":"地铁ver5"},"yarnVariables":{"floats":{},"strings":{},"bools":{}},"sections":{"env":{"curTime":"Day","curWeather":"Sunny","isInitialized":true},"actor":{"actors":[{"actorName":"地铁医生","slotName":"左边","actorType":"Anima","stateName":"idle","stateNormalizedTime":1.742072,"alpha":1.0,"isTalking":false},{"actorName":"地铁火山","slotName":"右边","actorType":"Anima","stateName":"idle","stateNormalizedTime":1.742072,"alpha":1.0,"isTalking":false}]},"audio":{"musicPaths":{},"sfxPaths":{"event:/Amb/amb":"event:/Amb/amb"},"ambState":"Subway"},"timeline":{"entries":[{"directorName":"地铁","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"subway":{"state":"Subway","args":""},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":false}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-15 20:02:25",
|
||||
"sceneName": "Scene/ClinicOut",
|
||||
"sceneSoName": "Day1_mid",
|
||||
"yarnProjectId": "FP_Day1_mid",
|
||||
"nodeName": "佩佩",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-15 20:02:25","scene":{"sceneName":"Scene/ClinicOut"},"anchor":{"sceneSoName":"Day1_mid","yarnProjectId":"FP_Day1_mid","nodeName":"佩佩"},"yarnVariables":{"floats":{},"strings":{},"bools":{}},"sections":{"env":{"curTime":"Day","curWeather":"Sunny","isInitialized":true},"actor":{"actors":[{"actorName":"诊室外佩佩","slotName":"诊室外栏杆","actorType":"Anima","stateName":"HOODBACK","stateNormalizedTime":0.1621352,"alpha":1.0,"isTalking":false}]},"audio":{"musicPaths":{},"sfxPaths":{"event:/Amb/amb":"event:/Amb/amb"},"ambState":"Outside"},"timeline":{"entries":[{"directorName":"诊室外头痛","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"诊室外","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"英里初登场","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"医生出地铁","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":true}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-15 20:02:36",
|
||||
"sceneName": "Scene/酒吧场景",
|
||||
"sceneSoName": "Day1_night",
|
||||
"yarnProjectId": "FP_Day1_night",
|
||||
"nodeName": "酒吧6",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-15 20:02:36","scene":{"sceneName":"Scene/酒吧场景"},"anchor":{"sceneSoName":"Day1_night","yarnProjectId":"FP_Day1_night","nodeName":"酒吧6"},"yarnVariables":{"floats":{},"strings":{},"bools":{}},"sections":{"env":{"curTime":"Evening","curWeather":"Snowy","isInitialized":true},"actor":{"actors":[{"actorName":"酒吧医生","slotName":"吧台左侧","actorType":"Anima","stateName":"Idle","stateNormalizedTime":10.8863344,"alpha":1.0,"isTalking":false},{"actorName":"酒吧调酒妹","slotName":"吧台内","actorType":"Anima","stateName":"1","stateNormalizedTime":2.857307,"alpha":0.0,"isTalking":false},{"actorName":"酒保","slotName":"酒保左侧","actorType":"Anima","stateName":"é\u0085å§å\u0085","stateNormalizedTime":6.01455,"alpha":0.0,"isTalking":false}]},"audio":{"musicPaths":{"event:/Music/music_bar":"event:/Music/music_bar"},"sfxPaths":{"event:/Amb/amb":"event:/Amb/amb"},"ambState":"Bar"},"timeline":{"entries":[{"directorName":"调酒蒙太奇","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"酒吧","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":false}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-15 20:02:53",
|
||||
"sceneName": "Scene/梦境",
|
||||
"sceneSoName": "Day1_sleep",
|
||||
"yarnProjectId": "FP_Day1_sleep",
|
||||
"nodeName": "开场",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-15 20:02:53","scene":{"sceneName":"Scene/梦境"},"anchor":{"sceneSoName":"Day1_sleep","yarnProjectId":"FP_Day1_sleep","nodeName":"开场"},"yarnVariables":{"floats":{},"strings":{},"bools":{}},"sections":{"audio":{"musicPaths":{"event:/Amb/amb_beachsample":"event:/Amb/amb_beachsample","event:/Music/music_bar":"event:/Music/music_bar"},"sfxPaths":{"event:/Amb/amb":"event:/Amb/amb"},"ambState":"Dream"},"timeline":{"entries":[{"directorName":"姐姐","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"惊醒","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"星空到海浪","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"醒来","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":true}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-15 20:02:55",
|
||||
"sceneName": "Scene/梦境",
|
||||
"sceneSoName": "Day1_sleep",
|
||||
"yarnProjectId": "FP_Day1_sleep",
|
||||
"nodeName": "教室苏醒",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-15 20:02:55","scene":{"sceneName":"Scene/梦境"},"anchor":{"sceneSoName":"Day1_sleep","yarnProjectId":"FP_Day1_sleep","nodeName":"教室苏醒"},"yarnVariables":{"floats":{},"strings":{},"bools":{}},"sections":{"audio":{"musicPaths":{},"sfxPaths":{"event:/Amb/amb":"event:/Amb/amb"},"ambState":"Dream"},"timeline":{"entries":[{"directorName":"姐姐","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"惊醒","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"星空到海浪","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"醒来","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":false}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-15 20:02:56",
|
||||
"sceneName": "Scene/梦境",
|
||||
"sceneSoName": "Day1_sleep",
|
||||
"yarnProjectId": "FP_Day1_sleep",
|
||||
"nodeName": "教室",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-15 20:02:56","scene":{"sceneName":"Scene/梦境"},"anchor":{"sceneSoName":"Day1_sleep","yarnProjectId":"FP_Day1_sleep","nodeName":"教室"},"yarnVariables":{"floats":{},"strings":{},"bools":{}},"sections":{"audio":{"musicPaths":{"event:/Music/mus_dream1":"event:/Music/mus_dream1"},"sfxPaths":{"event:/Amb/amb":"event:/Amb/amb"},"ambState":"Dream"},"timeline":{"entries":[{"directorName":"姐姐","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"惊醒","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"星空到海浪","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"醒来","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":false}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-15 20:03:12",
|
||||
"sceneName": "Scene/梦境",
|
||||
"sceneSoName": "Day1_sleep",
|
||||
"yarnProjectId": "FP_Day1_sleep",
|
||||
"nodeName": "走廊",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-15 20:03:12","scene":{"sceneName":"Scene/梦境"},"anchor":{"sceneSoName":"Day1_sleep","yarnProjectId":"FP_Day1_sleep","nodeName":"走廊"},"yarnVariables":{"floats":{"$gameStage":2.0,"$scj":1.0,"$ppStage":2.0},"strings":{},"bools":{"$Yarn.Internal.Once.507f30d8":true,"$Yarn.Internal.Once.4bd3a162":true,"$Yarn.Internal.Once.90392df9":true}},"sections":{"audio":{"musicPaths":{"event:/Music/mus_dream1":"event:/Music/mus_dream1"},"sfxPaths":{"event:/Amb/amb":"event:/Amb/amb"},"ambState":"Dream"},"timeline":{"entries":[{"directorName":"姐姐","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"惊醒","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"星空到海浪","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"醒来","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":false}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-15 20:03:15",
|
||||
"sceneName": "Scene/梦境",
|
||||
"sceneSoName": "Day1_sleep",
|
||||
"yarnProjectId": "FP_Day1_sleep",
|
||||
"nodeName": "楼梯间",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-15 20:03:15","scene":{"sceneName":"Scene/梦境"},"anchor":{"sceneSoName":"Day1_sleep","yarnProjectId":"FP_Day1_sleep","nodeName":"楼梯间"},"yarnVariables":{"floats":{"$gameStage":2.0,"$scj":1.0,"$ppStage":2.0},"strings":{},"bools":{"$Yarn.Internal.Once.507f30d8":true,"$Yarn.Internal.Once.4bd3a162":true,"$Yarn.Internal.Once.90392df9":true}},"sections":{"audio":{"musicPaths":{"event:/Music/mus_dream1":"event:/Music/mus_dream1"},"sfxPaths":{"event:/Amb/amb":"event:/Amb/amb"},"ambState":"Dream"},"timeline":{"entries":[{"directorName":"姐姐","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"惊醒","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"星空到海浪","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"醒来","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":false}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-15 20:03:18",
|
||||
"sceneName": "Scene/梦境",
|
||||
"sceneSoName": "Day1_sleep",
|
||||
"yarnProjectId": "FP_Day1_sleep",
|
||||
"nodeName": "天台",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-15 20:03:18","scene":{"sceneName":"Scene/梦境"},"anchor":{"sceneSoName":"Day1_sleep","yarnProjectId":"FP_Day1_sleep","nodeName":"天台"},"yarnVariables":{"floats":{"$gameStage":2.0,"$scj":1.0,"$ppStage":2.0},"strings":{},"bools":{"$Yarn.Internal.Once.507f30d8":true,"$Yarn.Internal.Once.4bd3a162":true,"$Yarn.Internal.Once.90392df9":true}},"sections":{"audio":{"musicPaths":{"event:/Music/mus_dream1":"event:/Music/mus_dream1"},"sfxPaths":{"event:/Amb/amb":"event:/Amb/amb"},"ambState":"Dream"},"timeline":{"entries":[{"directorName":"姐姐","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"惊醒","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"星空到海浪","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"醒来","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":false}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-15 20:03:24",
|
||||
"sceneName": "Scene/梦境",
|
||||
"sceneSoName": "Day1_sleep",
|
||||
"yarnProjectId": "FP_Day1_sleep",
|
||||
"nodeName": "天文台",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-15 20:03:24","scene":{"sceneName":"Scene/梦境"},"anchor":{"sceneSoName":"Day1_sleep","yarnProjectId":"FP_Day1_sleep","nodeName":"天文台"},"yarnVariables":{"floats":{"$gameStage":3.0,"$scj":1.0,"$ppStage":2.0},"strings":{},"bools":{"$Yarn.Internal.Once.d66d59be":true,"$Yarn.Internal.Once.507f30d8":true,"$Yarn.Internal.Once.4bd3a162":true,"$Yarn.Internal.Once.90392df9":true}},"sections":{"audio":{"musicPaths":{"event:/Music/mus_dream1":"event:/Music/mus_dream1"},"sfxPaths":{"event:/Amb/amb":"event:/Amb/amb"},"ambState":"Dream"},"timeline":{"entries":[{"directorName":"姐姐","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"惊醒","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"星空到海浪","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"醒来","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":false}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-15 20:03:26",
|
||||
"sceneName": "Scene/梦境",
|
||||
"sceneSoName": "Day1_sleep",
|
||||
"yarnProjectId": "FP_Day1_sleep",
|
||||
"nodeName": "海边",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-15 20:03:26","scene":{"sceneName":"Scene/梦境"},"anchor":{"sceneSoName":"Day1_sleep","yarnProjectId":"FP_Day1_sleep","nodeName":"海边"},"yarnVariables":{"floats":{"$gameStage":3.0,"$scj":1.0,"$ppStage":2.0},"strings":{},"bools":{"$Yarn.Internal.Once.d66d59be":true,"$Yarn.Internal.Once.507f30d8":true,"$Yarn.Internal.Once.4bd3a162":true,"$Yarn.Internal.Once.90392df9":true}},"sections":{"audio":{"musicPaths":{},"sfxPaths":{"event:/Amb/amb":"event:/Amb/amb"},"ambState":"Dream"},"timeline":{"entries":[{"directorName":"姐姐","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"惊醒","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"星空到海浪","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"醒来","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":false}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-13 13:53:21",
|
||||
"sceneName": "Scene/ClinicOut",
|
||||
"sceneSoName": "Day2_mid",
|
||||
"yarnProjectId": "FP_Day2_mid",
|
||||
"nodeName": "Start",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-13 13:53:21","scene":{"sceneName":"Scene/ClinicOut"},"anchor":{"sceneSoName":"Day2_mid","yarnProjectId":"FP_Day2_mid","nodeName":"Start"},"yarnVariables":{"floats":{},"strings":{},"bools":{}},"sections":{"env":{"curTime":"Day","curWeather":"Sunny","isInitialized":true},"actor":{"actors":[{"actorName":"诊室外火山","slotName":"诊室外栏杆","actorType":"Anima","stateName":"背影IDLE","stateNormalizedTime":0.2660912,"alpha":1.0,"isTalking":false}]},"audio":{"musicPaths":{},"sfxPaths":{},"ambState":"Outside"},"timeline":{"entries":[{"directorName":"诊室外","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"医生出地铁","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false},{"directorName":"诊室外头痛","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":true}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-30 14:31:23",
|
||||
"sceneName": "Scene/ClinicOut",
|
||||
"sceneSoName": "Day2_night",
|
||||
"yarnProjectId": "FP_Day2_night",
|
||||
"nodeName": "Start",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-30 14:31:23",
|
||||
"scene": {
|
||||
"sceneName": "Scene/ClinicOut"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day2_night",
|
||||
"yarnProjectId": "FP_Day2_night",
|
||||
"nodeName": "Start"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {},
|
||||
"strings": {},
|
||||
"bools": {
|
||||
"$global_isPeipeiBE": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": []
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {
|
||||
"music": "event:/Music/mus_peipei"
|
||||
},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Outside"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "诊室外",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "医生出地铁",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "诊室外头痛",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-30 14:31:23",
|
||||
"sceneName": "Scene/ClinicOut",
|
||||
"sceneSoName": "Day2_night",
|
||||
"yarnProjectId": "FP_Day2_night",
|
||||
"nodeName": "BE",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-30 14:31:23",
|
||||
"scene": {
|
||||
"sceneName": "Scene/ClinicOut"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day2_night",
|
||||
"yarnProjectId": "FP_Day2_night",
|
||||
"nodeName": "BE"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {},
|
||||
"strings": {},
|
||||
"bools": {
|
||||
"$global_isPeipeiBE": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": []
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {
|
||||
"music": "event:/Music/mus_peipei"
|
||||
},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Outside"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "诊室外",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "医生出地铁",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "诊室外头痛",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-07-15 20:03:30",
|
||||
"sceneName": "Scene/SubWay",
|
||||
"sceneSoName": "GeneralEnd",
|
||||
"yarnProjectId": "Test_GeneralEnd",
|
||||
"nodeName": "Start",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.2.1-20260705-010933",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"schemaVersion":1,"gameVersion":"0.5.2.1-20260705-010933","savedAt":"2026-07-15 20:03:30","scene":{"sceneName":"Scene/SubWay"},"anchor":{"sceneSoName":"GeneralEnd","yarnProjectId":"Test_GeneralEnd","nodeName":"Start"},"yarnVariables":{"floats":{},"strings":{},"bools":{}},"sections":{"env":{"curTime":"Night","curWeather":"Snowy","isInitialized":true},"actor":{"actors":[{"actorName":"地铁医生","slotName":"左边","actorType":"Anima","stateName":"idle","stateNormalizedTime":0.050316032,"alpha":1.0,"isTalking":false}]},"audio":{"musicPaths":{"event:/Music/music_ending_temp":"event:/Music/music_ending_temp"},"sfxPaths":{"event:/Amb/amb":"event:/Amb/amb"},"ambState":"Subway"},"timeline":{"entries":[{"directorName":"地铁","isActive":true,"phase":"Stopped","hasEverAppliedPlayback":false}]},"subway":{"state":"Subway","args":""},"screen":{"saturationWeight":0.0,"isFadeScreenCovered":true}}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:17:32",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "开场对话",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:17:32",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "开场对话"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {},
|
||||
"strings": {},
|
||||
"bools": {}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Clinic"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "Default",
|
||||
"args": ""
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": true,
|
||||
"isTaskPanelVisible": false,
|
||||
"tasks": []
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Body",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": false,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:17:37",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进门后",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:17:37",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进门后"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {},
|
||||
"strings": {},
|
||||
"bools": {}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Clinic"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "Default",
|
||||
"args": ""
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": true,
|
||||
"isTaskPanelVisible": false,
|
||||
"tasks": []
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Body",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": false,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:17:45",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "第一次身体检查_检查UF",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:17:45",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "第一次身体检查_检查UF"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {},
|
||||
"strings": {
|
||||
"$gameStage": "UF检查"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
},
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Sideeye",
|
||||
"stateNormalizedTime": 10.7053051,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"pluggedModuleName": "UF",
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:01dade5",
|
||||
"text": "● 定位佩佩的UF模块"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:17:47",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "UF深入检查",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:17:47",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "UF深入检查"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$PlugCount": 1.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "UF检查"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$UfChecked": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
},
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Sideeye",
|
||||
"stateNormalizedTime": 19.032732,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"pluggedModuleName": "UF",
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:04c146f",
|
||||
"text": "● 检查UF模块"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:17:51",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "第一次身体检查_检查视觉",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:17:51",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "第一次身体检查_检查视觉"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$PlugCount": 1.0,
|
||||
"$Yarn.Internal.Visiting.UF深入检查": 1.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "视觉检查"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$UfChecked": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
},
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Sideeye",
|
||||
"stateNormalizedTime": 33.75063,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"pluggedModuleName": "Eye",
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:01fada9",
|
||||
"text": "● 在视觉模块寻找线索"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [
|
||||
"Eye"
|
||||
],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:18:06",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进入记忆检查",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:18:06",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进入记忆检查"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$PlugCount": 2.0,
|
||||
"$Yarn.Internal.Visiting.UF深入检查": 1.0,
|
||||
"$Yarn.Internal.Visiting.IntoEyeView": 4.0,
|
||||
"$Yarn.Internal.Visiting.FirstDialogue": 1.0,
|
||||
"$eyeTargetTriggerCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.佩佩告诉你可以想象颜色": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_plant": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_poster": 1.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "记忆检查",
|
||||
"$currentEyeTarget": "poster"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$UfChecked": true,
|
||||
"$eyeChecked": true,
|
||||
"$eyenocolorKnown": true,
|
||||
"$peipeiReadyToShow": true,
|
||||
"$eyecolorKnown": true,
|
||||
"$isFinishedEyeCheck": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
},
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Sideeye",
|
||||
"stateNormalizedTime": 92.29114,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": [
|
||||
{
|
||||
"Category": "EyeView",
|
||||
"ClueName": "l10n.天空",
|
||||
"MemoryIndex": "liuying1-3",
|
||||
"used": false
|
||||
},
|
||||
{
|
||||
"Category": "EyeView",
|
||||
"ClueName": "l10n.植物",
|
||||
"MemoryIndex": "liuying1-2",
|
||||
"used": false
|
||||
},
|
||||
{
|
||||
"Category": "EyeView",
|
||||
"ClueName": "l10n.海报",
|
||||
"MemoryIndex": "liuying1-1",
|
||||
"used": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:01fada9",
|
||||
"text": "● 在视觉模块寻找线索"
|
||||
},
|
||||
{
|
||||
"lineId": "line:043e26d",
|
||||
"text": "● 检查“色彩数据”记忆"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [
|
||||
"Memory"
|
||||
],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CanImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:18:07",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "检查记忆",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:18:07",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "检查记忆"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$PlugCount": 2.0,
|
||||
"$Yarn.Internal.Visiting.UF深入检查": 1.0,
|
||||
"$Yarn.Internal.Visiting.IntoEyeView": 4.0,
|
||||
"$Yarn.Internal.Visiting.FirstDialogue": 1.0,
|
||||
"$eyeTargetTriggerCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.佩佩告诉你可以想象颜色": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_plant": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_poster": 1.0,
|
||||
"$Yarn.Internal.Visiting.MemoryPlugIn": 1.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "记忆检查",
|
||||
"$currentEyeTarget": "poster"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$UfChecked": true,
|
||||
"$eyeChecked": true,
|
||||
"$eyenocolorKnown": true,
|
||||
"$peipeiReadyToShow": true,
|
||||
"$eyecolorKnown": true,
|
||||
"$isFinishedEyeCheck": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
},
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Sideeye",
|
||||
"stateNormalizedTime": 96.79041,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": [
|
||||
{
|
||||
"Category": "EyeView",
|
||||
"ClueName": "l10n.天空",
|
||||
"MemoryIndex": "liuying1-3",
|
||||
"used": false
|
||||
},
|
||||
{
|
||||
"Category": "EyeView",
|
||||
"ClueName": "l10n.植物",
|
||||
"MemoryIndex": "liuying1-2",
|
||||
"used": false
|
||||
},
|
||||
{
|
||||
"Category": "EyeView",
|
||||
"ClueName": "l10n.海报",
|
||||
"MemoryIndex": "liuying1-1",
|
||||
"used": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"pluggedModuleName": "Memory",
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:01fada9",
|
||||
"text": "● 在视觉模块寻找线索"
|
||||
},
|
||||
{
|
||||
"lineId": "line:043e26d",
|
||||
"text": "● 检查“色彩数据”记忆"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [
|
||||
"Memory"
|
||||
],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CanImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:19:47",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进入分析",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:19:47",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进入分析"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$PlugCount": 2.0,
|
||||
"$Yarn.Internal.Visiting.UF深入检查": 1.0,
|
||||
"$Yarn.Internal.Visiting.IntoEyeView": 4.0,
|
||||
"$Yarn.Internal.Visiting.FirstDialogue": 1.0,
|
||||
"$eyeTargetTriggerCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.佩佩告诉你可以想象颜色": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_plant": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_poster": 1.0,
|
||||
"$Yarn.Internal.Visiting.MemoryPlugIn": 1.0,
|
||||
"$memoryCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.天空": 1.0,
|
||||
"$Yarn.Internal.Visiting.植物": 1.0,
|
||||
"$Yarn.Internal.Visiting.海报": 1.0,
|
||||
"$ufDiscussCount": 3.0,
|
||||
"$eyeDiscussCount": 2.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "分析",
|
||||
"$currentEyeTarget": "poster"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$UfChecked": true,
|
||||
"$eyeChecked": true,
|
||||
"$eyenocolorKnown": true,
|
||||
"$peipeiReadyToShow": true,
|
||||
"$eyecolorKnown": true,
|
||||
"$isFinishedEyeCheck": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
},
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Sideeye",
|
||||
"stateNormalizedTime": 481.14978,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": ""
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:01fada9",
|
||||
"text": "● 在视觉模块寻找线索"
|
||||
},
|
||||
{
|
||||
"lineId": "line:02a3a37",
|
||||
"text": "● 分析病理与治疗方案"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CanImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:19:53",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进入术前谈话",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:19:53",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进入术前谈话"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$PlugCount": 2.0,
|
||||
"$Yarn.Internal.Visiting.UF深入检查": 1.0,
|
||||
"$Yarn.Internal.Visiting.IntoEyeView": 4.0,
|
||||
"$Yarn.Internal.Visiting.FirstDialogue": 1.0,
|
||||
"$eyeTargetTriggerCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.佩佩告诉你可以想象颜色": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_plant": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_poster": 1.0,
|
||||
"$Yarn.Internal.Visiting.MemoryPlugIn": 1.0,
|
||||
"$memoryCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.天空": 1.0,
|
||||
"$Yarn.Internal.Visiting.植物": 1.0,
|
||||
"$Yarn.Internal.Visiting.海报": 1.0,
|
||||
"$ufDiscussCount": 3.0,
|
||||
"$eyeDiscussCount": 2.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "术前谈话",
|
||||
"$currentEyeTarget": "poster"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$UfChecked": true,
|
||||
"$eyeChecked": true,
|
||||
"$eyenocolorKnown": true,
|
||||
"$peipeiReadyToShow": true,
|
||||
"$eyecolorKnown": true,
|
||||
"$isFinishedEyeCheck": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
},
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "1I",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {
|
||||
"event:/Music/music_peipei_1": "event:/Music/music_peipei_1"
|
||||
},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Clinic"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "Clinic",
|
||||
"args": ""
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:01fada9",
|
||||
"text": "● 在视觉模块寻找线索"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CanImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:19:57",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进入手术",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:19:57",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进入手术"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$PlugCount": 2.0,
|
||||
"$Yarn.Internal.Visiting.UF深入检查": 1.0,
|
||||
"$Yarn.Internal.Visiting.IntoEyeView": 4.0,
|
||||
"$Yarn.Internal.Visiting.FirstDialogue": 1.0,
|
||||
"$eyeTargetTriggerCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.佩佩告诉你可以想象颜色": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_plant": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_poster": 1.0,
|
||||
"$Yarn.Internal.Visiting.MemoryPlugIn": 1.0,
|
||||
"$memoryCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.天空": 1.0,
|
||||
"$Yarn.Internal.Visiting.植物": 1.0,
|
||||
"$Yarn.Internal.Visiting.海报": 1.0,
|
||||
"$ufDiscussCount": 3.0,
|
||||
"$eyeDiscussCount": 2.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "手术",
|
||||
"$currentEyeTarget": "poster"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$UfChecked": true,
|
||||
"$eyeChecked": true,
|
||||
"$eyenocolorKnown": true,
|
||||
"$peipeiReadyToShow": true,
|
||||
"$eyecolorKnown": true,
|
||||
"$isFinishedEyeCheck": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
},
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2",
|
||||
"stateNormalizedTime": 2.13779116,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {
|
||||
"event:/Music/music_peipei_1": "event:/Music/music_peipei_1"
|
||||
},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:0deda99",
|
||||
"text": "● 执行视觉-记忆桥截断术"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CanImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:20:00",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "CutLine",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:20:00",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "CutLine"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$PlugCount": 2.0,
|
||||
"$Yarn.Internal.Visiting.UF深入检查": 1.0,
|
||||
"$Yarn.Internal.Visiting.IntoEyeView": 4.0,
|
||||
"$Yarn.Internal.Visiting.FirstDialogue": 1.0,
|
||||
"$eyeTargetTriggerCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.佩佩告诉你可以想象颜色": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_plant": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_poster": 1.0,
|
||||
"$Yarn.Internal.Visiting.MemoryPlugIn": 1.0,
|
||||
"$memoryCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.天空": 1.0,
|
||||
"$Yarn.Internal.Visiting.植物": 1.0,
|
||||
"$Yarn.Internal.Visiting.海报": 1.0,
|
||||
"$ufDiscussCount": 3.0,
|
||||
"$eyeDiscussCount": 2.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "手术",
|
||||
"$currentEyeTarget": "poster"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$UfChecked": true,
|
||||
"$eyeChecked": true,
|
||||
"$eyenocolorKnown": true,
|
||||
"$peipeiReadyToShow": true,
|
||||
"$eyecolorKnown": true,
|
||||
"$isFinishedEyeCheck": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
},
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2",
|
||||
"stateNormalizedTime": 11.7810183,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:0deda99",
|
||||
"text": "● 执行视觉-记忆桥截断术"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CanImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:20:00",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进入复查",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:20:00",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进入复查"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$PlugCount": 2.0,
|
||||
"$Yarn.Internal.Visiting.UF深入检查": 1.0,
|
||||
"$Yarn.Internal.Visiting.IntoEyeView": 4.0,
|
||||
"$Yarn.Internal.Visiting.FirstDialogue": 1.0,
|
||||
"$eyeTargetTriggerCount": 0.0,
|
||||
"$Yarn.Internal.Visiting.佩佩告诉你可以想象颜色": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_plant": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_poster": 1.0,
|
||||
"$Yarn.Internal.Visiting.MemoryPlugIn": 1.0,
|
||||
"$memoryCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.天空": 1.0,
|
||||
"$Yarn.Internal.Visiting.植物": 1.0,
|
||||
"$Yarn.Internal.Visiting.海报": 1.0,
|
||||
"$ufDiscussCount": 3.0,
|
||||
"$eyeDiscussCount": 2.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "复查",
|
||||
"$currentEyeTarget": "poster"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$UfChecked": true,
|
||||
"$eyeChecked": true,
|
||||
"$eyenocolorKnown": true,
|
||||
"$peipeiReadyToShow": true,
|
||||
"$eyecolorKnown": true,
|
||||
"$isFinishedEyeCheck": false
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
},
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2",
|
||||
"stateNormalizedTime": 12.9643087,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": []
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:20:02",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "复查_检查视觉",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:20:02",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "复查_检查视觉"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$PlugCount": 2.0,
|
||||
"$Yarn.Internal.Visiting.UF深入检查": 1.0,
|
||||
"$Yarn.Internal.Visiting.IntoEyeView": 4.0,
|
||||
"$Yarn.Internal.Visiting.FirstDialogue": 1.0,
|
||||
"$eyeTargetTriggerCount": 0.0,
|
||||
"$Yarn.Internal.Visiting.佩佩告诉你可以想象颜色": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_plant": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_poster": 1.0,
|
||||
"$Yarn.Internal.Visiting.MemoryPlugIn": 1.0,
|
||||
"$memoryCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.天空": 1.0,
|
||||
"$Yarn.Internal.Visiting.植物": 1.0,
|
||||
"$Yarn.Internal.Visiting.海报": 1.0,
|
||||
"$ufDiscussCount": 3.0,
|
||||
"$eyeDiscussCount": 2.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "复查",
|
||||
"$currentEyeTarget": "poster"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$UfChecked": true,
|
||||
"$eyeChecked": false,
|
||||
"$eyenocolorKnown": true,
|
||||
"$peipeiReadyToShow": true,
|
||||
"$eyecolorKnown": true,
|
||||
"$isFinishedEyeCheck": false
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
},
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2",
|
||||
"stateNormalizedTime": 19.3081741,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"pluggedModuleName": "Eye",
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:037c944",
|
||||
"text": "● 检查视觉模块"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [
|
||||
"Eye"
|
||||
],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-29 19:20:10",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进入结束对话",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-29 19:20:10",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day1_FIRST_PP1",
|
||||
"yarnProjectId": "FP_Peipei1",
|
||||
"nodeName": "进入结束对话"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$PlugCount": 2.0,
|
||||
"$Yarn.Internal.Visiting.UF深入检查": 1.0,
|
||||
"$Yarn.Internal.Visiting.IntoEyeView": 7.0,
|
||||
"$Yarn.Internal.Visiting.FirstDialogue": 1.0,
|
||||
"$eyeTargetTriggerCount": 2.0,
|
||||
"$Yarn.Internal.Visiting.佩佩告诉你可以想象颜色": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_plant": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_poster": 1.0,
|
||||
"$Yarn.Internal.Visiting.MemoryPlugIn": 1.0,
|
||||
"$memoryCount": 3.0,
|
||||
"$Yarn.Internal.Visiting.天空": 1.0,
|
||||
"$Yarn.Internal.Visiting.植物": 1.0,
|
||||
"$Yarn.Internal.Visiting.海报": 1.0,
|
||||
"$ufDiscussCount": 3.0,
|
||||
"$eyeDiscussCount": 2.0,
|
||||
"$Yarn.Internal.Visiting.Eye_posterAfterSurgery": 1.0,
|
||||
"$Yarn.Internal.Visiting.Eye_plantAfterSurgery": 1.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "结束对话",
|
||||
"$currentEyeTarget": "plant"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$UfChecked": true,
|
||||
"$eyeChecked": true,
|
||||
"$eyenocolorKnown": true,
|
||||
"$peipeiReadyToShow": true,
|
||||
"$eyecolorKnown": true,
|
||||
"$isFinishedEyeCheck": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "窗外佩佩",
|
||||
"slotName": "窗外",
|
||||
"actorType": "Sprite",
|
||||
"stateName": "Idle",
|
||||
"stateNormalizedTime": 0.0,
|
||||
"alpha": 0.0,
|
||||
"isTalking": false
|
||||
},
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2H",
|
||||
"stateNormalizedTime": 1.22089159,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {
|
||||
"event:/Amb/amb_beachsample": "event:/Amb/amb_beachsample"
|
||||
},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Clinic"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "Clinic",
|
||||
"args": ""
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": []
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": [
|
||||
"Eye"
|
||||
]
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-30 14:29:06",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "Start",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-30 14:29:06",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "Start"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {},
|
||||
"strings": {},
|
||||
"bools": {}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": []
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Clinic"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "Default",
|
||||
"args": ""
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": true,
|
||||
"isTaskPanelVisible": false,
|
||||
"tasks": []
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Body",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": false,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-30 14:29:06",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "进入佩佩开场对话",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-30 14:29:06",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "进入佩佩开场对话"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {},
|
||||
"strings": {},
|
||||
"bools": {}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": []
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Clinic"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "Default",
|
||||
"args": ""
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": true,
|
||||
"isTaskPanelVisible": false,
|
||||
"tasks": []
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Body",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": false,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-30 14:29:15",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "进入第一次发热",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-30 14:29:15",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "进入第一次发热"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {},
|
||||
"strings": {
|
||||
"$gameStage": "第一次发热"
|
||||
},
|
||||
"bools": {}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Pouting",
|
||||
"stateNormalizedTime": 25.1401443,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Clinic"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtEnd",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "Default",
|
||||
"args": ""
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": true,
|
||||
"isTaskPanelVisible": false,
|
||||
"tasks": []
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Body",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": false,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-30 14:29:18",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "系统发热",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-30 14:29:18",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "系统发热"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {},
|
||||
"strings": {
|
||||
"$gameStage": "第一次发热"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Pouting",
|
||||
"stateNormalizedTime": 36.1157532,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"pluggedModuleName": "UF",
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:06d0c20",
|
||||
"text": "● 检查UF模块"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [
|
||||
"UF"
|
||||
],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-30 14:29:21",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "进入身体检查",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-30 14:29:21",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "进入身体检查"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$feverMessageSeen": 0.0,
|
||||
"$feverCount": 1.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "身体检查"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$finishFirstCoolDown": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Pouting",
|
||||
"stateNormalizedTime": 49.9799,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:06d0c20",
|
||||
"text": "● 检查UF模块"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [
|
||||
"UF"
|
||||
],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-30 14:29:23",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "检查UF_不可检查",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-30 14:29:23",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "检查UF_不可检查"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$feverMessageSeen": 0.0,
|
||||
"$feverCount": 1.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "身体检查"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$finishFirstCoolDown": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Pouting",
|
||||
"stateNormalizedTime": 58.4737473,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"pluggedModuleName": "UF",
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:06d0c20",
|
||||
"text": "● 检查UF模块"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [
|
||||
"UF"
|
||||
],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-30 14:29:28",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "进入UF拆壳",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-30 14:29:28",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "进入UF拆壳"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$feverMessageSeen": 0.0,
|
||||
"$feverCount": 1.0,
|
||||
"$PlugCount": 1.0,
|
||||
"$Yarn.Internal.Visiting.UF深入失败": 1.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "UF拆壳"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$finishFirstCoolDown": true,
|
||||
"$UfChecked": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Pouting",
|
||||
"stateNormalizedTime": 74.33931,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"pluggedModuleName": "UF",
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:073a567",
|
||||
"text": "● 找到影响UF的“未知来源”"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": false,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-30 14:29:31",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "进入UF检查",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-30 14:29:31",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "进入UF检查"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$feverMessageSeen": 0.0,
|
||||
"$feverCount": 1.0,
|
||||
"$PlugCount": 1.0,
|
||||
"$Yarn.Internal.Visiting.UF深入失败": 1.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "UF检查"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$finishFirstCoolDown": true,
|
||||
"$UfChecked": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Pouting",
|
||||
"stateNormalizedTime": 88.156395,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "Body"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "BodyModule",
|
||||
"args": "Head"
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:073a567",
|
||||
"text": "● 找到影响UF的“未知来源”"
|
||||
},
|
||||
{
|
||||
"lineId": "line:0a431e3",
|
||||
"text": "● 深入检查UF模块"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": true,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-30 14:29:38",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "IntoEyeView",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"savedAt": "2026-06-30 14:29:38",
|
||||
"scene": {
|
||||
"sceneName": "Scene/PeipeiFixScene"
|
||||
},
|
||||
"anchor": {
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "IntoEyeView"
|
||||
},
|
||||
"yarnVariables": {
|
||||
"floats": {
|
||||
"$feverMessageSeen": 0.0,
|
||||
"$feverCount": 1.0,
|
||||
"$PlugCount": 1.0,
|
||||
"$Yarn.Internal.Visiting.UF深入失败": 1.0
|
||||
},
|
||||
"strings": {
|
||||
"$gameStage": "UF检查",
|
||||
"$currentEyeTarget": "plant"
|
||||
},
|
||||
"bools": {
|
||||
"$global.IsPlugHighLight": true,
|
||||
"$finishFirstCoolDown": true,
|
||||
"$UfChecked": true
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"env": {
|
||||
"curTime": "Day",
|
||||
"curWeather": "Sunny",
|
||||
"isInitialized": true
|
||||
},
|
||||
"actor": {
|
||||
"actors": [
|
||||
{
|
||||
"actorName": "佩佩",
|
||||
"slotName": "clinic",
|
||||
"actorType": "Anima",
|
||||
"stateName": "2Pouting",
|
||||
"stateNormalizedTime": 115.150826,
|
||||
"alpha": 1.0,
|
||||
"isTalking": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"musicPaths": {},
|
||||
"sfxPaths": {},
|
||||
"ambState": "UF"
|
||||
},
|
||||
"timeline": {
|
||||
"entries": [
|
||||
{
|
||||
"directorName": "引擎仓面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
},
|
||||
{
|
||||
"directorName": "进入维修间",
|
||||
"isActive": true,
|
||||
"phase": "AtStart",
|
||||
"hasEverAppliedPlayback": true
|
||||
},
|
||||
{
|
||||
"directorName": "插线面板",
|
||||
"isActive": true,
|
||||
"phase": "Stopped",
|
||||
"hasEverAppliedPlayback": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"punchTape": {
|
||||
"favorites": []
|
||||
},
|
||||
"fix": {
|
||||
"state": "UF",
|
||||
"args": ""
|
||||
},
|
||||
"fixPanel": {
|
||||
"isSystemOn": true,
|
||||
"currentRepairSystemType": "BodyModuleSystem",
|
||||
"isCableRetracted": false,
|
||||
"isTaskPanelVisible": true,
|
||||
"tasks": [
|
||||
{
|
||||
"lineId": "line:073a567",
|
||||
"text": "● 找到影响UF的“未知来源”"
|
||||
},
|
||||
{
|
||||
"lineId": "line:0a431e3",
|
||||
"text": "● 深入检查UF模块"
|
||||
}
|
||||
]
|
||||
},
|
||||
"bodyModule": {
|
||||
"moduleState": "Head",
|
||||
"isUFCoverRemoved": true,
|
||||
"isUFRemoved": false,
|
||||
"isColorRemoved": false,
|
||||
"isChipRemoved": true,
|
||||
"highlightedModules": [],
|
||||
"alarmedModules": []
|
||||
},
|
||||
"eye": {
|
||||
"eyeColorState": "CannotImagineColor"
|
||||
},
|
||||
"screen": {
|
||||
"saturationWeight": 0.0,
|
||||
"isFadeScreenCovered": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"slotIndex": -1,
|
||||
"savedAt": "2026-06-30 14:29:56",
|
||||
"sceneName": "Scene/PeipeiFixScene",
|
||||
"sceneSoName": "Day2_NEXT_PP2",
|
||||
"yarnProjectId": "FP_Peipei2",
|
||||
"nodeName": "进入分析",
|
||||
"schemaVersion": 1,
|
||||
"gameVersion": "0.5.1.1-20260430-002845",
|
||||
"thumbnailFile": "thumbnail.png"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user