fix: 存档功能修理
This commit is contained in:
@@ -49,6 +49,8 @@ tags: content save_on_exit
|
||||
|
||||
- `interaction` / `save_on_exit` 进入时不存档;对应节点完成后若直接结束本轮 Dialogue,则自动保存 state-only 档。
|
||||
- 若执行路径继续 `jump` / `detour` 到其他 Yarn 节点,退出档会取消并记录告警。
|
||||
- run / flow / current-node 稳定性只约束 `DialogueExit`:任何后续 Yarn 节点(包括 `detour`、`no_save`)都会取消节点末尾存档。
|
||||
- 普通 `NodeEnter` 和兼容命令 `<<save>>` 不受后续节点流转影响;它们始终使用请求触发时冻结的 node / YarnProject / TalkScene 生成 anchor,并继续进入串行写盘队列。
|
||||
- 放在目标节点**末尾**:所有状态命令(`switch_fix_system_to`、`hide_dialog`、`play_timeline` 等)执行完毕之后,`<<jump>>` / `<<detour>>` 之前。
|
||||
- `anchor.nodeName` 始终保留来源节点;`anchor.startDialogueOnRestore=false`,读档时只加载 YarnProject,不启动节点。
|
||||
- 退出档在 `DialogEnd` 同步初始化后等待一帧捕获;这一帧由 scoped interaction lock 保持输入锁定,捕获进入写盘队列后再交出控制权。
|
||||
@@ -153,6 +155,7 @@ Postflight 校验
|
||||
- **核心层**(`scene`、`anchor`、`yarnVariables`)由 `SnapshotRestore` 框架直管,不通过 Provider 注册。
|
||||
- **表现层**(`sections` 内各子系统)通过 `ISnapshotProvider` 扩展;`RestoreOrder` 表示同 Phase 内的建议顺序或软依赖。
|
||||
- **逐项还原(D1)**指各子系统各自写回状态,**不是** Provider 之间逐步 `yield return`。
|
||||
- Postflight 只核对 Scene、TalkSceneSO、YarnProject 与必要 Provider readiness;不要求 RestartNode 仍停在 anchor,也不校验 StateOnly 结束后的 DialogueRunner 状态。
|
||||
|
||||
Provider 使用 `ISyncSnapshotProvider` 或 `IAsyncSnapshotProvider` 显式声明同步/异步恢复;异步 Provider 必须把等待过程返回给编排层,禁止内部 fire-and-forget。
|
||||
|
||||
|
||||
@@ -422,18 +422,6 @@ namespace AibisDream.SaveSystem
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dialog.DialogueRunId != request.DialogueRunId)
|
||||
{
|
||||
reason = $"dialogue run changed ({request.DialogueRunId} -> {dialog.DialogueRunId})";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dialog.DialogueFlowVersion != request.FlowRevision)
|
||||
{
|
||||
reason = $"flow revision changed ({request.FlowRevision} -> {dialog.DialogueFlowVersion})";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.Equals(runner.YarnProject?.name, request.YarnProjectId, StringComparison.Ordinal))
|
||||
{
|
||||
reason = $"YarnProject changed to {runner.YarnProject?.name ?? "(none)"}";
|
||||
@@ -454,33 +442,51 @@ namespace AibisDream.SaveSystem
|
||||
}
|
||||
|
||||
var (currentNodeName, _) = dialog.GetCurrentNodeContext();
|
||||
if (request.Trigger == SaveTrigger.DialogueExit)
|
||||
{
|
||||
if (runner.IsDialogueRunning)
|
||||
{
|
||||
reason = "DialogueRunner is still running";
|
||||
return false;
|
||||
}
|
||||
return ValidateDialogueTiming(
|
||||
request,
|
||||
dialog.DialogueRunId,
|
||||
dialog.DialogueFlowVersion,
|
||||
currentNodeName,
|
||||
runner.IsDialogueRunning,
|
||||
out reason);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(currentNodeName))
|
||||
{
|
||||
reason = $"a current Yarn node is still present: {currentNodeName}";
|
||||
return false;
|
||||
}
|
||||
internal static bool ValidateDialogueTiming(
|
||||
SaveRequest request,
|
||||
long currentDialogueRunId,
|
||||
long currentFlowRevision,
|
||||
string currentNodeName,
|
||||
bool isDialogueRunning,
|
||||
out string reason)
|
||||
{
|
||||
if (request.Trigger != SaveTrigger.DialogueExit)
|
||||
{
|
||||
reason = null;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!runner.IsDialogueRunning)
|
||||
{
|
||||
reason = "DialogueRunner stopped before capture";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.Equals(currentNodeName, request.SourceNodeName, StringComparison.Ordinal))
|
||||
{
|
||||
reason = $"current node changed to {currentNodeName ?? "(none)"}";
|
||||
return false;
|
||||
}
|
||||
if (currentDialogueRunId != request.DialogueRunId)
|
||||
{
|
||||
reason = $"dialogue run changed ({request.DialogueRunId} -> {currentDialogueRunId})";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (currentFlowRevision != request.FlowRevision)
|
||||
{
|
||||
reason = $"flow revision changed ({request.FlowRevision} -> {currentFlowRevision})";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isDialogueRunning)
|
||||
{
|
||||
reason = "DialogueRunner is still running";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(currentNodeName))
|
||||
{
|
||||
reason = $"a current Yarn node is still present: {currentNodeName}";
|
||||
return false;
|
||||
}
|
||||
|
||||
reason = null;
|
||||
@@ -775,23 +781,6 @@ namespace AibisDream.SaveSystem
|
||||
var runner = DialogController.Instance?.DialogueRunner;
|
||||
if (!string.Equals(runner?.YarnProject?.name, snapshot.anchor.yarnProjectId, StringComparison.Ordinal))
|
||||
context.Error($"YarnProject mismatch: {runner?.YarnProject?.name ?? "none"}.");
|
||||
if (snapshot.anchor.startDialogueOnRestore)
|
||||
{
|
||||
var (currentNodeName, _) = DialogController.Instance != null
|
||||
? DialogController.Instance.GetCurrentNodeContext()
|
||||
: (null, null);
|
||||
if (runner == null || !runner.IsDialogueRunning)
|
||||
context.Error($"Yarn node did not start: {snapshot.anchor.nodeName}.");
|
||||
else if (!string.Equals(currentNodeName, snapshot.anchor.nodeName, StringComparison.Ordinal))
|
||||
context.Error(
|
||||
$"Yarn node mismatch: expected {snapshot.anchor.nodeName}, " +
|
||||
$"actual {currentNodeName ?? "none"}.");
|
||||
}
|
||||
else if (runner != null && runner.IsDialogueRunning)
|
||||
{
|
||||
context.Error(
|
||||
$"StateOnly restore unexpectedly started Yarn node {snapshot.anchor.nodeName}.");
|
||||
}
|
||||
|
||||
if (snapshot.sections != null
|
||||
&& snapshot.sections.ContainsKey(SnapshotProviderIds.Fix)
|
||||
|
||||
Reference in New Issue
Block a user