fix: 存档功能修理

This commit is contained in:
2026-07-27 16:00:30 +08:00
parent 3e6fab9762
commit 31e6ae87be
7 changed files with 278 additions and 181 deletions
@@ -287,6 +287,109 @@ namespace AibisDream.DeveloperMode.Editor.Tests
Assert.That(exit.AnchorSpec.StartDialogueOnRestore, Is.False);
}
[TestCase(false, "DetourNode", true)]
[TestCase(false, "NoSaveNode", false)]
[TestCase(true, "AnotherNode", true)]
public void ValidateDialogueTiming_NonExitRequestIgnoresLaterDialogueState(
bool explicitCommand,
string currentNodeName,
bool isDialogueRunning)
{
var request = explicitCommand
? SaveRequest.Explicit("SourceNode", "ProjectA", "ChapterA", 3, 7)
: SaveRequest.NodeEnter("SourceNode", "ProjectA", "ChapterA", 3, 7);
var valid = SaveRestoreOrchestrator.ValidateDialogueTiming(
request,
currentDialogueRunId: 99,
currentFlowRevision: 101,
currentNodeName: currentNodeName,
isDialogueRunning: isDialogueRunning,
out var reason);
Assert.That(valid, Is.True, reason);
Assert.That(request.AnchorSpec.NodeName, Is.EqualTo("SourceNode"));
}
[Test]
public void ValidateDialogueTiming_ConsecutiveNodeEnterRequestsRemainEligible()
{
var first = SaveRequest.NodeEnter("FirstNode", "ProjectA", "ChapterA", 3, 7);
var second = SaveRequest.NodeEnter("SecondNode", "ProjectA", "ChapterA", 3, 8);
var firstValid = SaveRestoreOrchestrator.ValidateDialogueTiming(
first,
currentDialogueRunId: 3,
currentFlowRevision: 8,
currentNodeName: "SecondNode",
isDialogueRunning: true,
out var firstReason);
var secondValid = SaveRestoreOrchestrator.ValidateDialogueTiming(
second,
currentDialogueRunId: 3,
currentFlowRevision: 8,
currentNodeName: "SecondNode",
isDialogueRunning: true,
out var secondReason);
Assert.That(firstValid, Is.True, firstReason);
Assert.That(secondValid, Is.True, secondReason);
Assert.That(first.AnchorSpec.NodeName, Is.EqualTo("FirstNode"));
Assert.That(second.AnchorSpec.NodeName, Is.EqualTo("SecondNode"));
}
[Test]
public void ValidateDialogueTiming_DialogueExitAcceptsStableCompletedFlow()
{
var request = SaveRequest.DialogueExit(
"InteractionNode",
"ProjectA",
"ChapterA",
3,
9);
var valid = SaveRestoreOrchestrator.ValidateDialogueTiming(
request,
currentDialogueRunId: 3,
currentFlowRevision: 9,
currentNodeName: null,
isDialogueRunning: false,
out var reason);
Assert.That(valid, Is.True, reason);
}
[TestCase(4, 9, null, false, "dialogue run changed")]
[TestCase(3, 10, null, false, "flow revision changed")]
[TestCase(3, 9, "DetourNode", false, "current Yarn node")]
[TestCase(3, 9, "NoSaveNode", false, "current Yarn node")]
[TestCase(3, 9, "JumpTarget", true, "still running")]
public void ValidateDialogueTiming_DialogueExitRejectsChangedOrRunningFlow(
long currentDialogueRunId,
long currentFlowRevision,
string currentNodeName,
bool isDialogueRunning,
string expectedReason)
{
var request = SaveRequest.DialogueExit(
"InteractionNode",
"ProjectA",
"ChapterA",
3,
9);
var valid = SaveRestoreOrchestrator.ValidateDialogueTiming(
request,
currentDialogueRunId,
currentFlowRevision,
currentNodeName,
isDialogueRunning,
out var reason);
Assert.That(valid, Is.False);
Assert.That(reason, Does.Contain(expectedReason));
}
[Test]
public void InteractionLock_ComposesWithDialogueLock()
{
Binary file not shown.
+120 -120
View File
@@ -89,123 +89,123 @@ rstuvwxyz{|}~̀́̂̃̄̅̆
挨挪挫振挺挽捂捅捆捉捋捌捍捎捏捐捕捜捞损
捡换捣捧据捶捷捺捻掀掂授掉掌掏掐排掘掠探
接控推掩措掰掷掺揉揍描提插換握揣揩揪揭援
揺揽搀搁搂搅損搏搓搔搜搞搬搭携摄摆摇摊
摘摧摩摸摹撇撑撒撕撞撤撩撬播撮撰撵撸撼
擅操擎擒擦攀攒攥支收改攻放政故效敌敏救
教敛敞敢散敦敬数敲整敵敷文斋斌斑斗料斜
斤斥斧斩断斯新方施旁旅旋族旗无既日旦旧
早旬旭旱时旷旺昂昆昌明昏易昔星映春昧昨
是昼显時晃晋晌晒晓晕晚晦晨晩普景晰晴晶
晾暂暇暑暖暗暮暴曙曝曰曲更書曹曼曾替最
有朋服朔朗望朝期朦木未末本术朱朴朵机朽
杂权杆杉李杏材村杖杜束杠条来杨杭杯杰東
板极构枉析枕林枚果枝枠枢枣枪枫枯架柄柏
柑柒染柔柜柠查柬柱柳柴査柿栅标栈栋栏树
栖栗校株样核根格栽桂桃框案桌桐桑桔档桥
桨桩桶梁梅梆梗梢梦梧梨梭梯械梳检棉棋棍
棕棘棚棠森棱棵棺椅植椎椒検椭椰椿楚業楷
楽概榄榆榔榕榜榨榴構槐様槛槽標樟模権横
橄橘橙機橡橱檀檐檬欠次欢欣欧欲欺款歇歉
止正此步武歧歩歪歹死歼殃殉殊残殖殴段殷
殿毁毅母毎每毒比毕毙毛毡毫毯氏民氓气気
氢氧氨氮氯水永汁求汇汉汐汗汚汛汝汞江池
汤汪汰汹決汽沁沃沈沉沐沙沛沟没沢沥沦沧沪
沫沮河沸油治沼沽沾沿況泄泉泊泌法泛泞泡波
泣泥注泪泰泳泵泻泼泽洁洋洒洗洛洞津洩洪洲
活洼洽派流浅浆浇浊测济浏浑浓浙浦浩浪浮浴
海浸涂消涉涌涕涛涝涡涣涤润涧涨涩涮涯液涵
淀淆淋淌淑淘淡淤淫淮深淳混淹添清済渉渊渐
渔渗渝渠渡渣渤温港渲渴游渺湃湖湘湾湿溃溅
溉源準溜溢溪溯溶溺滇滋滑滔滚滞满滤滥滨滩
滴漂漆漏漓演漠漫漱漾潇潘潜潤潭潮澄澈澎澜
澡澳激濒瀑灌火灭灯灰灵灶灸灼灾灿炉炊炎炒
炕炫炬炭炮炸点炼烁烂烈烘烙烛烟烤烦烧烫热
烹焉焊焕焚無焦焰然焼煌煎煙煞煤照煩煮煽熄
熊熏熔熙熟熬熱燃燕燥爆爪爬爱爵父爷爸爹爽
片版牌牙牛牡牢牧物牲牵特牺犀犁犬犯状犹狂
狈狐狗狞狠狡独狭狮狰狱狸狼猎猖猛猜猩猪猫
猬献猴猾猿玄率玉王玖玛玩玫环现玲玷玻珊珍
珠班現球琅理琉琐琢琳琴琼瑙瑞瑟瑰璃璧環瓜
瓢瓣瓤瓦瓶瓷甘甚甜生産甥用甩甫田由甲申电
男甸町画畅界畏畔留畜略番異畴畸疆疏疑疗疙
疚疟疤疫疮疯疲疹疼疾病症痊痒痕痘痛痢痪痰
痴痹瘟瘤瘦瘩瘪瘫瘸瘾療癌癣癸発登白百皂的
皆皇皓皖皮皱皺皿盆盈益盏盐监盒盔盖盗盘盛
盟目盯盲直相盹盼盾省眉看真眠眨眩眯眶眷眺
眼着睁睐睛睡督睦睫睬睹瞄瞅瞌瞎瞒瞥瞧瞩瞪
瞬瞭瞳瞻矗矛矢矣知矩矫短矮石矾矿码砂砌砍
研砕砖砚砰破砸砾础硅硕硝硫硬确碌碍碎碑碗
碘碟碧碰碱碳確碾磁磅磊磕磨磷礁示礼社祀祈
祖祝神祟祠祥票祭祷祸禀禁禄禅福禹离禽禾秀
私秃秆秉秋种科秒秘租秤秦秧秩积称秸移秽稀
程稍税稚稠稳稻稼稽稿穆積穏穗穴究穷空穿突
窃窄窍窑窒窓窖窗窘窜窝窟窣窥窸窿立竖站竞
竟章竣童竭端竹竿笋笑笔笙笛符笨第笺笼筆等
筋筏筐筑筒答策筛筝筷筹签简箕算管箩箫箭箱
節範篇篓篡篮篱篷簇簡簧簸簿籍米类籽粉粋粒
粗粘粟粤粥粪粮粱粹精糊糕糖糙糟糠糯系紊純
素索紧紫累細終組経結絮絵絶継続綺緑緒線練
縛縮績繁繋繰纠红纤约级纪纫纬纯纱纲纳纵纷
纸纹纺纽线练组绅细织终绊绍绎经绑绒结绕绘
给绚络绝绞统绢绣继绩绪续绰绳维绵绷绸综绽
绿缀缅缆缉缎缓缔缕编缘缚缝缠缤缩缭缰缴缶
缸缺罐网罕罗罚罢罩罪置署羊美羔羚羞羡群羹
羽翁翅翔翘翠翩翰翻翼耀老考者而耍耐耕耗耘
耙耦耳耷耸耻耽耿聂聆聊聋职联聘聚聞聪肃肆
肇肉肋肌肖肘肚肛肝肠股肢肤肥肩肪肮肯育肴
肺肾肿胀胁胃胆背胎胖胚胜胞胡胧胰胳胶胸能
脂脆脉脊脏脐脑脓脖脚脯脱脳脸脾腊腋腐腔腕
腥腮腰腹腺腻腾腿膀膊膏膛膜膝膨臀臂臊臣自
臭至致臼舀舅舆興舌舍舎舒舔舞舟航般舰舱舵
舶船艇艘良艰色艳艺艾节芋芒芙芜芝芥芦芬芭
芯花芳芸芹芽苇苍苏苑苔苗苛苞苟若苦英苹茁
茂范茄茅茉茎茧茫茬茵茶茸荆草荐荒荔荡荣荤
荧荫药荷莉莫莱莲获莹莺莽菇菊菌菜菠菩菱菲
萄萌萍萎萝萤营萧萨落葉著葛葡董葫葬葱葵蒂
蒋蒙蒜蒲蒸蓄蓉蓝蓬蔑蔓蔗蔚蔡蔬蔵蔼蔽蕉蕊
蕴蕾薄薇薛薪薬薯藉藏藐藕藤藻蘑虎虏虐虑虚
虫虹虽虾蚀蚁蚂蚊蚌蚓蚕蚣蚤蚪蚯蛀蛇蛋蛙蛛
蛤蛮蛾蜀蜂蜈蜒蜓蜕蜗蜘蜜蜡蜻蝇蝉蝌蝎蝗蝙
蝠蝴蝶螃融螺蟀蟆蟋蟹蠕蠢血衅行衍術衔街衙
衝衡衣补表衫衬衰衷袁袄袋袍袖袜被袭袱裁裂
装裏裕裙補裤裳裸裹褂褄複褐褒褥褪襟西要覆
見規視覗覚覧観见观规觅视览觉角解触言計訓
記訝設許診証評試詰話該詳誉誊認誓語説読誰
調請論謝識警譬議计订认讥讨让训议讯记讲讳
讶许讹论讼讽设访诀证评识诈诉诊词译试诗诚
话诞诡询该详诫诬语误诱诲说诵请诸诺读诽课
谁调谅谆谈谊谋谍谎谐谓谚谜谢谣谤谦谨谬谭
谱谴谷豁豆豊豌豚象豪豫豹豺貌負費貼資質贅
贝贞负贡财责贤败账货质贩贪贫贬购贮贯贰贱
贴贵贷贸费贺贻贼贾贿赁赂赃资赋赌赎赏赐赔
赖赘赚赛赞赠赡赢赣赤赦赫走赴赵赶起趁超越
趋趟趣足趴趾跃跋跌跑跛距跟跡跤跨跪路跳践
跷跺踊踏踝踢踩踪踮踱蹂蹄蹈蹋蹦蹬蹭蹲躁躏
身躬躯躲躺車転軽載輪轄车轧轨轩转轮软轰轱
轴轻载轿较辅辆辈辉辐辑输辖辗辘辙辛辜辞辟
辣辨辩辫辰辱边辺辻込辽达辿迁迂迄迅过迈迎
运近返还这进远违连迟迢迪迫迭述迷迹追退送
适逃逆选逊透逐递途逗通逛逝逞速造逢連逮逸
逻逼逾遂遅遇運遍過遏道違遗遠遣遥遭遮遵選
避邀邑邓那邦邪邮邻郁郊郎郑部郭都鄂鄙酉酌
配酒酗酝酣酥酪酬酱酵酷酸酿醇醉醋醒采释里
重野量金針鉢鉴鋼錆録鏡针钉钓钙钝钞钟钠钢
钥钦钧钩钮钱钳钻钾铁铃铅铆铐铛铜铝铬铭铲
银铸铺链销锁锄锅锈锋锌锐错锚锡锣锤锥锦键
锯锰锹锻镀镇镍镐镑镜镰镶長长門閉開間関閲
闇门闪闭问闯闰闲间闷闸闹闺闻闽阀阁阅阈阎
阐阔队阱防阳阴阵阶阻阿附际陆陈陋陌降限陕
陡院除陥陨险陪陵陶陷陽隅隆隋階随隐隔隘隙
障隠隧隶难雀雁雄雅集雇雌雏雕離難雨雪雲雳
零雷雹雾需霄震霉霍霎霓霜霞霧露霸霹青靖静
非靠靡面革靴靶鞋鞍鞠鞭韦韧韩韭音韵響頃項
頑頭頼題額顔願類页顶顷项顺须顽顾顿颁颂预
颅领颇颈颊频颓颖颗题颜额颠颤風风飕飘飛飞
食飲餐館饥饭饮饰饱饲饵饶饺饼饿馁馅馆馈馋
馍馏馒首香馨駄駆騒马驮驯驰驱驳驴驶驹驻驼
驾骂骄骆骇验骏骑骗骚骡骤骨髓高鬓鬼魁魂魄
魅魏魔魚鮮鱼鲁鲍鲜鲤鲨鲫鲸鳄鳍鳖鳞鳥鴉鸚
鸟鸡鸣鸥鸦鸭鸯鸳鸵鸽鸿鹃鹅鹉鹊鹏鹤鹦鹰鹿
麗麦麻黄黎黑黒黔默黙黯鼎鼓鼠鼻齐齿龄龙龟
갚계귨꾣뇤덅됬뚳램묈뷴뼭섉솳숅쉪싧썮썹쐣
펽풆퓳퓵!(),:;?
揺揽搀搁搂搅損搏搓搔搜搞搬搭携摄摆摇摊
摘摧摩摸摹撇撑撒撕撞撤撩撬播撮撰撵撸撼
擅操擎擒擦攀攒攥支收改攻放政故效敌敏救
教敛敞敢散敦敬数敲整敵敷文斋斌斑斗料斜
斤斥斧斩断斯新方施旁旅旋族旗无既日旦旧
早旬旭旱时旷旺昂昆昌明昏易昔星映春昧昨
是昼显時晃晋晌晒晓晕晚晦晨晩普景晰晴晶
晾暂暇暑暖暗暮暴曙曝曰曲更書曹曼曾替最
有朋服朔朗望朝期朦木未末本术朱朴朵机朽
杂权杆杉李杏材村杖杜束杠条来杨杭杯杰東
板极构枉析枕林枚果枝枠枢枣枪枫枯架柄柏
柑柒染柔柜柠查柬柱柳柴査柿栅标栈栋栏树
栖栗校株样核根格栽桂桃框案桌桐桑桔档桥
桨桩桶梁梅梆梗梢梦梧梨梭梯械梳检棉棋棍
棕棘棚棠森棱棵棺椅植椎椒検椭椰椿楚業楷
楽概榄榆榔榕榜榨榴構槐様槛槽標樟模権横
橄橘橙機橡橱檀檐檬欠次欢欣欧欲欺款歇歉
止正此步武歧歩歪歹死歼殃殉殊残殖殴段殷
殿毁毅母毎每毒比毕毙毛毡毫毯氏民氓气気
氢氧氨氮氯水永汁求汇汉汐汗汚汛汝汞江池
汤汪汰汹決汽沁沃沈沉沐沙沛沟没沢沥沦
沧沪沫沮河沸油治沼沽沾沿況泄泉泊泌法泛泞
泡波泣泥注泪泰泳泵泻泼泽洁洋洒洗洛洞津洩
洪洲活洼洽派流浅浆浇浊测济浏浑浓浙浦浩浪
浮浴海浸涂消涉涌涕涛涝涡涣涤润涧涨涩涮涯
液涵淀淆淋淌淑淘淡淤淫淮深淳混淹添清済渉
渊渐渔渗渝渠渡渣渤温港渲渴游渺湃湖湘湾湿
溃溅溉源準溜溢溪溯溶溺滇滋滑滔滚滞满滤滥
滨滩滴漂漆漏漓演漠漫漱漾潇潘潜潤潭潮澄澈
澎澜澡澳激濒瀑灌火灭灯灰灵灶灸灼灾灿炉炊
炎炒炕炫炬炭炮炸点炼烁烂烈烘烙烛烟烤烦烧
烫热烹焉焊焕焚無焦焰然焼煌煎煙煞煤照煩煮
煽熄熊熏熔熙熟熬熱燃燕燥爆爪爬爱爵父爷爸
爹爽片版牌牙牛牡牢牧物牲牵特牺犀犁犬犯状
犹狂狈狐狗狞狠狡独狭狮狰狱狸狼猎猖猛猜猩
猪猫猬献猴猾猿玄率玉王玖玛玩玫环现玲玷玻
珊珍珠班現球琅理琉琐琢琳琴琼瑙瑞瑟瑰璃璧
環瓜瓢瓣瓤瓦瓶瓷甘甚甜生産甥用甩甫田由甲
申电男甸町画畅界畏畔留畜略番異畴畸疆疏疑
疗疙疚疟疤疫疮疯疲疹疼疾病症痊痒痕痘痛痢
痪痰痴痹瘟瘤瘦瘩瘪瘫瘸瘾療癌癣癸発登白百
皂的皆皇皓皖皮皱皺皿盆盈益盏盐监盒盔盖盗
盘盛盟目盯盲直相盹盼盾省眉看真眠眨眩眯眶
眷眺眼着睁睐睛睡督睦睫睬睹瞄瞅瞌瞎瞒瞥瞧
瞩瞪瞬瞭瞳瞻矗矛矢矣知矩矫短矮石矾矿码砂
砌砍研砕砖砚砰破砸砾础硅硕硝硫硬确碌碍碎
碑碗碘碟碧碰碱碳確碾磁磅磊磕磨磷礁示礼社
祀祈祖祝神祟祠祥票祭祷祸禀禁禄禅福禹离禽
禾秀私秃秆秉秋种科秒秘租秤秦秧秩积称秸移
秽稀程稍税稚稠稳稻稼稽稿穆積穏穗穴究穷空
穿突窃窄窍窑窒窓窖窗窘窜窝窟窣窥窸窿立竖
站竞竟章竣童竭端竹竿笋笑笔笙笛符笨第笺笼
筆等筋筏筐筑筒答策筛筝筷筹签简箕算管箩箫
箭箱節範篇篓篡篮篱篷簇簡簧簸簿籍米类籽粉
粋粒粗粘粟粤粥粪粮粱粹精糊糕糖糙糟糠糯系
紊純素索紧紫累細終組経結絮絵絶継続綺緑緒
線練縛縮績繁繋繰纠红纤约级纪纫纬纯纱纲纳
纵纷纸纹纺纽线练组绅细织终绊绍绎经绑绒结
绕绘给绚络绝绞统绢绣继绩绪续绰绳维绵绷绸
综绽绿缀缅缆缉缎缓缔缕编缘缚缝缠缤缩缭缰
缴缶缸缺罐网罕罗罚罢罩罪置署羊美羔羚羞羡
群羹羽翁翅翔翘翠翩翰翻翼耀老考者而耍耐耕
耗耘耙耦耳耷耸耻耽耿聂聆聊聋职联聘聚聞聪
肃肆肇肉肋肌肖肘肚肛肝肠股肢肤肥肩肪肮肯
育肴肺肾肿胀胁胃胆背胎胖胚胜胞胡胧胰胳胶
胸能脂脆脉脊脏脐脑脓脖脚脯脱脳脸脾腊腋腐
腔腕腥腮腰腹腺腻腾腿膀膊膏膛膜膝膨臀臂臊
臣自臭至致臼舀舅舆興舌舍舎舒舔舞舟航般舰
舱舵舶船艇艘良艰色艳艺艾节芋芒芙芜芝芥芦
芬芭芯花芳芸芹芽苇苍苏苑苔苗苛苞苟若苦英
苹茁茂范茄茅茉茎茧茫茬茵茶茸荆草荐荒荔荡
荣荤荧荫药荷莉莫莱莲获莹莺莽菇菊菌菜菠菩
菱菲萄萌萍萎萝萤营萧萨落葉著葛葡董葫葬葱
葵蒂蒋蒙蒜蒲蒸蓄蓉蓝蓬蔑蔓蔗蔚蔡蔬蔵蔼蔽
蕉蕊蕴蕾薄薇薛薪薬薯藉藏藐藕藤藻蘑虎虏虐
虑虚虫虹虽虾蚀蚁蚂蚊蚌蚓蚕蚣蚤蚪蚯蛀蛇蛋
蛙蛛蛤蛮蛾蜀蜂蜈蜒蜓蜕蜗蜘蜜蜡蜻蝇蝉蝌蝎
蝗蝙蝠蝴蝶螃融螺蟀蟆蟋蟹蠕蠢血衅行衍術衔
街衙衝衡衣补表衫衬衰衷袁袄袋袍袖袜被袭袱
裁裂装裏裕裙補裤裳裸裹褂褄複褐褒褥褪襟西
要覆見規視覗覚覧観见观规觅视览觉角解触言
計訓記訝設許診証評試詰話該詳誉誊認誓語説
読誰調請論謝識警譬議计订认讥讨让训议讯记
讲讳讶许讹论讼讽设访诀证评识诈诉诊词译试
诗诚话诞诡询该详诫诬语误诱诲说诵请诸诺读
诽课谁调谅谆谈谊谋谍谎谐谓谚谜谢谣谤谦谨
谬谭谱谴谷豁豆豊豌豚象豪豫豹豺貌負費貼資
質贅贝贞负贡财责贤败账货质贩贪贫贬购贮贯
贰贱贴贵贷贸费贺贻贼贾贿赁赂赃资赋赌赎赏
赐赔赖赘赚赛赞赠赡赢赣赤赦赫走赴赵赶起趁
超越趋趟趣足趴趾跃跋跌跑跛距跟跡跤跨跪路
跳践跷跺踊踏踝踢踩踪踮踱蹂蹄蹈蹋蹦蹬蹭蹲
躁躏身躬躯躲躺車転軽載輪轄车轧轨轩转轮软
轰轱轴轻载轿较辅辆辈辉辐辑输辖辗辘辙辛辜
辞辟辣辨辩辫辰辱边辺辻込辽达辿迁迂迄迅过
迈迎运近返还这进远违连迟迢迪迫迭述迷迹追
退送适逃逆选逊透逐递途逗通逛逝逞速造逢連
逮逸逻逼逾遂遅遇運遍過遏道違遗遠遣遥遭遮
遵選避邀邑邓那邦邪邮邻郁郊郎郑部郭都鄂鄙
酉酌配酒酗酝酣酥酪酬酱酵酷酸酿醇醉醋醒采
释里重野量金針鉢鉴鋼錆録鏡针钉钓钙钝钞钟
钠钢钥钦钧钩钮钱钳钻钾铁铃铅铆铐铛铜铝铬
铭铲银铸铺链销锁锄锅锈锋锌锐错锚锡锣锤锥
锦键锯锰锹锻镀镇镍镐镑镜镰镶長长門閉開間
関閲闇门闪闭问闯闰闲间闷闸闹闺闻闽阀阁阅
阈阎阐阔队阱防阳阴阵阶阻阿附际陆陈陋陌降
限陕陡院除陥陨险陪陵陶陷陽隅隆隋階随隐隔
隘隙障隠隧隶难雀雁雄雅集雇雌雏雕離難雨雪
雲雳零雷雹雾需霄震霉霍霎霓霜霞霧露霸霹青
靖静非靠靡面革靴靶鞋鞍鞠鞭韦韧韩韭音韵響
頃項頑頭頼題額顔願類页顶顷项顺须顽顾顿颁
颂预颅领颇颈颊频颓颖颗题颜额颠颤風风飕飘
飛飞食飲餐館饥饭饮饰饱饲饵饶饺饼饿馁馅馆
馈馋馍馏馒首香馨駄駆騒马驮驯驰驱驳驴驶驹
驻驼驾骂骄骆骇验骏骑骗骚骡骤骨髓高鬓鬼魁
魂魄魅魏魔魚鮮鱼鲁鲍鲜鲤鲨鲫鲸鳄鳍鳖鳞鳥
鴉鸚鸟鸡鸣鸥鸦鸭鸯鸳鸵鸽鸿鹃鹅鹉鹊鹏鹤鹦
鹰鹿麗麦麻黄黎黑黒黔默黙黯鼎鼓鼠鼻齐齿龄
龙龟갚계귨꾣뇤덅됬뚳램묈뷴뼭섉솳숅쉪싧썮
썹쐣펽풆퓳퓵!(),:;?
+3
View File
@@ -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,9 +442,42 @@ namespace AibisDream.SaveSystem
}
var (currentNodeName, _) = dialog.GetCurrentNodeContext();
if (request.Trigger == SaveTrigger.DialogueExit)
return ValidateDialogueTiming(
request,
dialog.DialogueRunId,
dialog.DialogueFlowVersion,
currentNodeName,
runner.IsDialogueRunning,
out reason);
}
internal static bool ValidateDialogueTiming(
SaveRequest request,
long currentDialogueRunId,
long currentFlowRevision,
string currentNodeName,
bool isDialogueRunning,
out string reason)
{
if (runner.IsDialogueRunning)
if (request.Trigger != SaveTrigger.DialogueExit)
{
reason = null;
return true;
}
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;
@@ -467,21 +488,6 @@ namespace AibisDream.SaveSystem
reason = $"a current Yarn node is still present: {currentNodeName}";
return false;
}
}
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;
}
}
reason = null;
return true;
@@ -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)
@@ -65,11 +65,11 @@ tags: hub
<<detour 风筝1_把它带走>>
<<endif>>
->放线 #line:08a1756
->放线 #line:08a1756 #notrack
<<detour 放线>>
->收线<<if $t>1>> #line:0b475d7
->收线<<if $t>1>> #line:0b475d7 #notrack
<<detour 收线>>
->保持<<if $t<0>> #line:0930771
->保持<<if $t<0>> #line:0930771 #notrack
<<detour 保持>>
<<detour 风筝回合推进_Set>>
@@ -388,11 +388,11 @@ tags: hub
<<detour 风筝2_别忘了>>
<<endif>>
->放线 #line:08c3eee
->放线 #line:08c3eee #notrack
<<detour 风筝2_放线>>
->收线 #line:08e99b8
->收线 #line:08e99b8 #notrack
<<detour 风筝2_收线>>
->保持 #line:0e846d1
->保持 #line:0e846d1 #notrack
<<detour 风筝2_保持>>
<<detour 风筝2回合推进_Set>>
+2
View File
@@ -234,6 +234,8 @@ P7 横切
`interaction` / `save_on_exit` 登记退出 checkpoint,节点完成并直接结束本轮 Dialogue 后写 state-only 档。
- `anchor.nodeName` 对所有档位都保存触发节点;`anchor.startDialogueOnRestore` 独立决定读档时是否启动 Yarn。
- 退出 checkpoint 在触发时冻结 node / YarnProject / TalkScene / Dialogue run`DialogEnd` 初始化期间使用 scoped interaction lock,下一帧捕获完成后才开放玩法输入。
- Dialogue run / flow revision / current node / runner 停止状态的稳定性检查只用于 `DialogueExit`。退出节点后若开始任何新 Yarn 节点(含 detour、`no_save`、jump 目标或新 Dialogue),取消该节点末尾存档。
- `NodeEnter``ExplicitCommand` 不因下一帧发生节点流转而取消;它们使用触发时冻结的 node / YarnProject / TalkScene 生成 anchor。连续产生的有效请求全部进入串行队列,后产生的 checkpoint 最终覆盖自动档。
- **Fresh 进入 vs detour 续跑**`SavePointEvaluator``yarnProjectId` 维护 `InProgressNodes`;节点尚未 `onNodeComplete` 时再次 `onNodeStart`Yarn detour 返回父节点)→ `DetourResume`,跳过自动存。`OnNodeComplete` 移出集合;切换 YarnProject / `StopDialog` 重置;读档 anchor 重进仅 `OnRestoreEnterNode` 标记,不写盘。
- **tag 规则**`hub` / `linear` / `content` 默认进入时保存;`interaction` 默认 Dialogue 退出时保存;
`save_on_exit` 可覆盖其他一级类型;`no_save` 禁止保存,并与上述退出语义冲突。