diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-29 04:36:27 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-29 04:36:27 +0800 |
| commit | 3a76bb5691a44d0b47cfb0abe332f1fe79c98a30 (patch) | |
| tree | aede2761514622f65e42ddfa3d9d2c6a256a67bb /docs | |
| parent | f22fe938b8e15fd88b87b47a38952b7ce47105ad (diff) | |
| download | living-village-3a76bb5691a44d0b47cfb0abe332f1fe79c98a30.tar.gz | |
p60: 江南可玩样板端到端盘点与缺口证据(只盘点,零代码改动)
入口:仓内不存在 LV_DEBUGGAME;用真实游戏内钩子驱动同一 Game 循环取证
(LV_P46_SHOT 启动/菜单、LV_P44_SHOT 白天 NPC 对话、LV_P39_SHOT 夜晚石灯笼、
LV_P53_REC 提示-交互-关闭短帧链),复制为 docs/evidence/p60-*.png 共 7 帧。
盘点结论(docs/evidence/p60-inventory.md):
- 已完成:桥/河/岸/石板路/植物、村民四向动画、昼夜光照、提示-交互-关闭链、玩家与可区分村民。
- 部分完成:① 民居可进入——功能与测试齐备(Interaction.fs:400-424、Game.fs:2688-2690、
PrototypeTests/P36PromptTests/SampleTests),但无内景游戏截图;② 中文界面——字形图集
(CjkGlyphAtlas.characterTable,307 字)缺 16 个 UI 用字:冬包卷品夏料春玩秋第背车轴页香鱼,
缺字被置空(Game.fs:73-92),影响右上日历「春夏秋冬·第N天」、对话页脚「第…页」、
背包/交易/物品名/回车提示等。
帧分析(p60-analysis.txt):黑块 0、白块 0/7 failures、字面豆腐块 0;
对话 rect (190,558,900,138),提示 rect (598,288,52,26) 且 paint 44.55 / restore 0.00(P53 PASS)。
缺口分层:阻塞确认门 = 缺字 16(G1)、民居内景无截图(G2)、逐帧 vision 自审未执行(G3,
本 writer 模型无图像输入且环境无 OCR/vision CLI/凭据);不阻塞 = 长视野成本留档(G4)、
复用钩子非单一入口(G5)。均只给最小整改建议,未修。
回归(p60-verification.txt):Desktop 304/304 + Kernel 119/119;
--performance-baseline ×3 digest 953775FAEB2F… 不变,determinism PASS。未 push。
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/evidence/p60-analysis.txt | 32 | ||||
| -rw-r--r-- | docs/evidence/p60-day-dialogue-a.png | bin | 0 -> 115774 bytes | |||
| -rw-r--r-- | docs/evidence/p60-day-dialogue-b.png | bin | 0 -> 117102 bytes | |||
| -rw-r--r-- | docs/evidence/p60-inventory.md | 82 | ||||
| -rw-r--r-- | docs/evidence/p60-menu.png | bin | 0 -> 56707 bytes | |||
| -rw-r--r-- | docs/evidence/p60-night-lantern.png | bin | 0 -> 92891 bytes | |||
| -rw-r--r-- | docs/evidence/p60-p53-chain.txt | 17 | ||||
| -rw-r--r-- | docs/evidence/p60-prompt-gone.png | bin | 0 -> 93815 bytes | |||
| -rw-r--r-- | docs/evidence/p60-prompt.png | bin | 0 -> 92198 bytes | |||
| -rw-r--r-- | docs/evidence/p60-startup.png | bin | 0 -> 54110 bytes | |||
| -rw-r--r-- | docs/evidence/p60-verification.txt | 24 |
11 files changed, 155 insertions, 0 deletions
diff --git a/docs/evidence/p60-analysis.txt b/docs/evidence/p60-analysis.txt new file mode 100644 index 0000000..926e2f0 --- /dev/null +++ b/docs/evidence/p60-analysis.txt @@ -0,0 +1,32 @@ +P60 江南可玩样板 — 端到端帧分析(真实 Desktop 实跑,xvfb 1280x720) +入口:无 LV_DEBUGGAME;使用真实游戏内证据钩子 LV_P46_SHOT(启动/菜单)、LV_P44_SHOT(白天对话)、 + LV_P39_SHOT(夜晚石灯笼)、LV_P53_REC(提示-交互-关闭短帧链)。 + +frame size mean std max_dark_block(24x24 fully opaque <=8) +p60-startup 1280x720 49.5 24.9 0 +p60-menu 1280x720 43.5 20.8 0 +p60-day-dialogue-a 1280x720 80.1 29.0 0 +p60-day-dialogue-b 1280x720 80.1 29.1 0 +p60-night-lantern 1280x720 82.6 20.0 0 +p60-prompt 1280x720 83.4 24.5 0 +p60-prompt-gone 1280x720 83.5 24.6 0 + +white-block scan (scripts/check-no-white-blocks.py, MIN_SIDE=64): checked=7 failures=0 -> 无白块 +black-block scan (24x24 fully-opaque <=8): max=0 -> 无黑块 + +tofu/atlas: runtime_atlas_glyphs=307 ui_cjk_missing=16 [冬包卷品夏料春玩秋第背车轴页香鱼] + 渲染语义:Game.fs:73-92 对缺字置空、绝不画伪字 -> 字面「豆腐块(□)」= 0,但缺字处为空白(信息缺失)。 + 受影响真实 UI: + - 右上日历 HUD 第一行 "春/夏/秋/冬 · 第N天"(HudLayout.fs:181)缺 春夏秋冬第 + - 对话框页脚 "第 %d/%d 页 ... 翻页 ..."(Game.fs:2859)缺 第 页 + - 交易/背包/物品:背包 缺,交易失败提示 缺;热键提示 "V 卖出 背包物品×1"(Interaction.fs:694)缺 背包品 + - 物品名 鱼/卷轴/香料(Interaction.fs:272-274)缺 鱼 卷 轴 香 料 + - 任务提示 "回车:接受任务"(Interaction.fs:714)缺 车 回(回在库) 车缺 + - "玩家"(Interaction.fs:630)缺 玩 + 逐帧可见位点:p60-day-dialogue-* 页脚、p60-night-lantern / p60-prompt / *-gone 右上日历均为空白位。 + +prompt rect (P53 chain): (598,288,52,26) paint delta=44.55 restore delta=0.00 -> PASS +dialogue panel rect (P44): (190,558,900,138) page=1/3 then 2/3, lines=4/page avatar=true + +vision 自审:本 writer 模型不支持图像输入、环境无 OCR/vision CLI 与凭据,逐帧图像可读性自审未能执行(见阻塞点)。 +verdict: 黑块 0;白块 0;字面豆腐块 0;但 UI 缺字 16 个(信息缺失缺口)。 diff --git a/docs/evidence/p60-day-dialogue-a.png b/docs/evidence/p60-day-dialogue-a.png Binary files differnew file mode 100644 index 0000000..de9a6f8 --- /dev/null +++ b/docs/evidence/p60-day-dialogue-a.png diff --git a/docs/evidence/p60-day-dialogue-b.png b/docs/evidence/p60-day-dialogue-b.png Binary files differnew file mode 100644 index 0000000..ec972a0 --- /dev/null +++ b/docs/evidence/p60-day-dialogue-b.png diff --git a/docs/evidence/p60-inventory.md b/docs/evidence/p60-inventory.md new file mode 100644 index 0000000..f2f009c --- /dev/null +++ b/docs/evidence/p60-inventory.md @@ -0,0 +1,82 @@ +# P60 江南可玩样板整体验证与缺口盘点(证据单) + +- 日期:2026-09-29 +- 目标:对「用户批准的江南水乡可玩样板」做一次端到端状态盘点,为今晨用户确认门准备证据。 +- 本单只盘点,**未修改任何代码**(Kernel/Sim/HUD/对话框/外部素材均未动)。 +- 帧与数字证据:`docs/evidence/p60-*.png`、`p60-analysis.txt`、`p60-p53-chain.txt`、`p60-verification.txt`。 + +## 入口说明(重要) + +仓库中**不存在 `LV_DEBUGGAME`**(全仓 grep 无匹配)。可玩样板的真实入口即 Desktop 应用本身; +本单用**真实游戏内证据钩子**驱动同一 Game 循环取证,未新增/mock 任何渲染路径: + +| 用途 | 钩子 | 产出 | +|---|---|---| +| 启动 / 菜单 | `LV_P46_SHOT=1` | `p46-splash-ripple.png`、`p46-menu-lantern-a/b.png` | +| 白天村内 NPC + 对话 | `LV_P44_SHOT=1` | `p44-dialog-a/b/c.png`(真实 `Interact` 开对话) | +| 夜晚村内石灯笼光晕 | `LV_P39_SHOT=1` | `p39-day/night/lantern-night.png` | +| 情境提示-交互-关闭 短帧链 | `LV_P53_REC=1` | `p53-far/prompt/dialog/gone.png` | + +复制进证据目录的帧:`p60-startup` `p60-menu` `p60-day-dialogue-a/b` `p60-night-lantern` `p60-prompt` `p60-prompt-gone`(共 7 帧 ≥ 3)。 + +## 逐项盘点 + +| # | 样板项 | 状态 | 证据 | 缺口 | +|---|---|---|---|---| +| 1 | 民居可进入 | **部分完成** | 功能:`src/LivingVillage.Desktop/Interaction.fs:400-424`(`EnterHome` → `home entered`/`home exited`),内景渲染 `Game.fs:2688-2690`(`VillageArt.drawInterior`),中文串 `Interaction.fs:575-576`;测试:`PrototypeTests.fs`(`EnterHome`/door→prompt 解析)、`P36PromptTests.fs`、`SampleTests.fs`、`P53InteractionPromptTests.fs:166` | **无内景游戏截图**(`docs/evidence` 无任何 interior/home 帧)→ 用户无法据此做视觉确认 | +| 2 | 桥、河、岸、石板路、植物 | **已完成** | 生成器 `MapGen.fs`(water/stone/peat、`Paths`、`MainRoadCenter`、`Bridges`)、`SceneDetail.fs:93-96`(岸线芦苇);帧:`p39-day.png`(桥)、`p47-day.png`(河道)、`p40-boat.png`;测试:`MapGenTests.fs` 37、`P47SceneDetailTests.fs` 6、`P39ArtTests.fs` 9、`P40ArtTests.fs` 8 | — | +| 3 | 村民四向动画 | **已完成** | `VillageArt` 四向×6 帧;测试 `P45CharacterAnimTests.fs:45`(四向可分)、`:67`(源格互异)、`:92`(行走推进/停止回 idle) 共 7;帧:`p45-char-a/b/c.png` | — | +| 4 | 中文界面 | **部分完成** | UI 文案集中 `ChineseText.fs`(`requiredUiLabels` 等);帧:`p60-menu.png`、`p60-startup.png`;测试 `P16UiTests.fs` 13 | **字形图集缺 16 个 UI 用字**,缺字被置空 → 详见缺口 G1 | +| 5 | 昼夜光照 | **已完成** | `M6Presentation`(`resolveStartTick`/`timePeriodLabel`/tint);帧:`p60-night-lantern.png`、`p39-night.png`、`p47-night.png`;测试 `P46MenuAmbienceTests.fs` 8、`P43HudTests.fs` 8、`P47SceneDetailTests.fs` 6 | — | +| 6 | 情境提示-交互-关闭 短帧链 | **已完成** | `Interaction.fs`(`InteractionResolver`)+ `P53InteractionPromptTests.fs` 9;链证据 `p60-p53-chain.txt`:far→prompt(`E 交谈`, `TalkTo (NpcId 0)`)→dialog→gone,提示只在邻近时出现、开对话即消失、关闭离开恢复 | — | +| 7 | 玩家与可区分村民 | **已完成** | 玩家四向动画同 #3;村民可见性巡游 `Game.fs:170-184`(P25 路点);帧:`p60-day-dialogue-a/b.png` 屏内见村民与对话弹层 | — | + +## 端到端帧数字(`p60-analysis.txt`) + +- 黑块(24×24 全不透明 ≤8):**0**;白块(`check-no-white-blocks.py` MIN_SIDE=64):**0/7 failures**。 +- 字面「豆腐块(□)」:**0**(`Game.fs:73-92` 对缺字置空、绝不画伪字)。 +- 对话弹层 rect(P44):`(190,558,900,138)`,page 1/3 → 2/3,4 行/页,avatar=true。 +- 提示条 rect(P53):`(598,288,52,26)`,paint delta 44.55,restore delta 0.00 → PASS。 + +## 缺口清单 + +### A. 阻塞用户确认门 + +- **G1 字形图集缺字 16 个(中文界面不完整)** + - 事实:运行时字形集为 `CjkGlyphAtlas.fs:14` 的 `characterTable`(307 字)。扫描全部 Desktop 源内用户可见字符串,缺: + `冬 包 卷 品 夏 料 春 玩 秋 第 背 车 轴 页 香 鱼`。 + - 影响(真实 UI,缺字处为空白): + - 右上日历首行 `春/夏/秋/冬 · 第N天`(`HudLayout.fs:181`)→ 季节与「第」空白; + - 对话页脚 `第 %d/%d 页 … 翻页 …`(`Game.fs:2859`)→「第/页」空白; + - 交易/背包:`背包不足`、`背包里没有可卖物品`(`PlayerTrade.fs:190,238`)、热键 `V 卖出 背包物品×1`(`Interaction.fs:694`); + - 物品名 `鱼/卷轴/香料`(`Interaction.fs:272-274`)、`玩家`(`Interaction.fs:630`)、`回车:接受任务`(`Interaction.fs:714`)。 + - 最小整改:把上述 16 字补入 `characterTable`(保持有序)并重新生成 `Assets/cjk-glyph-atlas.png` 与 `cjk-glyphs.txt`,再补一条「UI 字符串字符 ⊆ 图集」的回归测试。**未在本单实施。** +- **G2 民居内景无游戏截图** + - 事实:`民居可进入` 功能与测试齐备,但 `docs/evidence` 无内景帧,用户无法做视觉确认。 + - 最小整改:新增一条取证钩子(如真实 `EnterHome` 后拍整帧)或复用 autoplay 进屋,产出 `p60`/下一单的内景 PNG。**未在本单实施。** +- **G3 逐帧 vision 可读性自审未执行(本 writer 能力限制)** + - 事实:本 writer 模型不支持图像输入;环境无 `tesseract`、无 `mmx`/vision CLI、无 vision API 凭据,无法对 PNG 做图像级可读性判断。 + - 已用可复算的自动检查替代(黑/白块、rect 差、图集覆盖、帧统计),但**不能等同人工/视觉复核**。 + - 最小整改:由具备视觉输入的验收者(Hermes vision 三层复核流程)或视觉能力 writer 对 `p60-*.png` 逐帧复核。**属流程阻塞。** + +### B. 不阻塞 + +- **G4 长期逐日成本(P59 已记)**:M3 phase2 在 100 天视野的逐日成本上升未在 20 天窗口复现;与样板视觉确认无关,留档。 +- **G5 证据帧复用既有钩子**:因无 `LV_DEBUGGAME`,本单复用 P39/P44/P46/P53 钩子;若需「单一入口连贯录屏」,可另立一单做连续录制(非确认门必需)。 + +## 复现 + +```bash +D=/tmp/lv-p60 +mkdir -p $D/{p46,p44,p39,p53} +hook(){ timeout 150 xvfb-run -a -s "-screen 0 1280x720x24" env "$1"=1 LV_RECORD_DIR=$D/$2 \ + dotnet src/LivingVillage.Desktop/bin/Release/net8.0/LivingVillage.Desktop.dll > $D/$2/log.txt 2>&1; } +hook LV_P46_SHOT p46 +hook LV_P44_SHOT p44 +hook LV_P39_SHOT p39 +hook LV_P53_REC p53 +python3 scripts/analyze-p53.py $D/p53 docs/evidence/p60-p53-chain.txt +python3 scripts/check-no-white-blocks.py docs/evidence/p60-*.png +``` + +(字符串字符覆盖与帧统计见本目录 `p60-analysis.txt` 的生成脚本概要;本单未新增脚本。) diff --git a/docs/evidence/p60-menu.png b/docs/evidence/p60-menu.png Binary files differnew file mode 100644 index 0000000..c7d5c8c --- /dev/null +++ b/docs/evidence/p60-menu.png diff --git a/docs/evidence/p60-night-lantern.png b/docs/evidence/p60-night-lantern.png Binary files differnew file mode 100644 index 0000000..6437b66 --- /dev/null +++ b/docs/evidence/p60-night-lantern.png diff --git a/docs/evidence/p60-p53-chain.txt b/docs/evidence/p60-p53-chain.txt new file mode 100644 index 0000000..7b3b458 --- /dev/null +++ b/docs/evidence/p60-p53-chain.txt @@ -0,0 +1,17 @@ +P53 proximity-prompt / input-isolation analysis (LV_P53_REC=1) + +p53-far: panel=world prompt=none target=none rect=none +p53-prompt: panel=world prompt=E 交谈 target=TalkTo (NpcId 0) rect=598,288,52,26 +p53-dialog: panel=dialogue prompt=none target=TalkTo (NpcId 0) rect=none +p53-gone: panel=world prompt=none target=none rect=none + +frame p53-far: 1280x720 std=31.4 +frame p53-prompt: 1280x720 std=31.5 +frame p53-dialog: 1280x720 std=34.0 +frame p53-gone: 1280x720 std=31.6 + +prompt rect=(598, 288, 52, 26) paint delta (prompt vs far) = 44.55 (>= 12.0) +prompt rect restore delta (gone vs far) = 0.00 (<= 6.0) +dialogue overlay delta (dialog vs prompt, full frame) = 5.54 (>= 4.0) + +verdict: PASS diff --git a/docs/evidence/p60-prompt-gone.png b/docs/evidence/p60-prompt-gone.png Binary files differnew file mode 100644 index 0000000..ccf26e6 --- /dev/null +++ b/docs/evidence/p60-prompt-gone.png diff --git a/docs/evidence/p60-prompt.png b/docs/evidence/p60-prompt.png Binary files differnew file mode 100644 index 0000000..b7290e7 --- /dev/null +++ b/docs/evidence/p60-prompt.png diff --git a/docs/evidence/p60-startup.png b/docs/evidence/p60-startup.png Binary files differnew file mode 100644 index 0000000..661d013 --- /dev/null +++ b/docs/evidence/p60-startup.png diff --git a/docs/evidence/p60-verification.txt b/docs/evidence/p60-verification.txt new file mode 100644 index 0000000..8cae863 --- /dev/null +++ b/docs/evidence/p60-verification.txt @@ -0,0 +1,24 @@ +P60 验证日志 2026-09-28T20:35:42Z commit=f22fe93 + +## dotnet test LivingVillage.sln -c Release --no-build +/home/somhairle/projects/living-village/src/LivingVillage.Kernel.Tests/bin/Release/net8.0/LivingVillage.Kernel.Tests.dll (.NETCoreApp,Version=v8.0)的测试运行 +/home/somhairle/projects/living-village/src/LivingVillage.Desktop.Tests/bin/Release/net8.0/LivingVillage.Desktop.Tests.dll (.NETCoreApp,Version=v8.0)的测试运行 +已通过! - 失败: 0,通过: 304,已跳过: 0,总计: 304,持续时间: 5 s - LivingVillage.Desktop.Tests.dll (net8.0) +已通过! - 失败: 0,通过: 119,已跳过: 0,总计: 119,持续时间: 10 s - LivingVillage.Kernel.Tests.dll (net8.0) + +## --performance-baseline x3 (pin 953775FAEB2F…) +performance_sample repetition=1 seed=42 npc_count=4 warmup_ticks=120 measure_ticks=6000 elapsed_stopwatch_ticks=13194435 stopwatch_frequency=1000000000 elapsed_seconds=0.013194435 ticks_per_second=454737.168 allocated_bytes=3032344 gen0=0 gen1=0 gen2=0 final_tick=6120 final_digest=953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C runtime=.NET 8.0.31 runtime_version=8.0.31 +performance_sample repetition=2 seed=42 npc_count=4 warmup_ticks=120 measure_ticks=6000 elapsed_stopwatch_ticks=7861227 stopwatch_frequency=1000000000 elapsed_seconds=0.007861227 ticks_per_second=763239.632 allocated_bytes=3032104 gen0=0 gen1=0 gen2=0 final_tick=6120 final_digest=953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C runtime=.NET 8.0.31 runtime_version=8.0.31 +performance_sample repetition=3 seed=42 npc_count=4 warmup_ticks=120 measure_ticks=6000 elapsed_stopwatch_ticks=5732608 stopwatch_frequency=1000000000 elapsed_seconds=0.005732608 ticks_per_second=1046644.041 allocated_bytes=3032104 gen0=0 gen1=0 gen2=0 final_tick=6120 final_digest=953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C runtime=.NET 8.0.31 runtime_version=8.0.31 +performance_determinism=PASS +--- +performance_sample repetition=1 seed=42 npc_count=4 warmup_ticks=120 measure_ticks=6000 elapsed_stopwatch_ticks=13150232 stopwatch_frequency=1000000000 elapsed_seconds=0.013150232 ticks_per_second=456265.715 allocated_bytes=3032344 gen0=0 gen1=0 gen2=0 final_tick=6120 final_digest=953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C runtime=.NET 8.0.31 runtime_version=8.0.31 +performance_sample repetition=2 seed=42 npc_count=4 warmup_ticks=120 measure_ticks=6000 elapsed_stopwatch_ticks=8211585 stopwatch_frequency=1000000000 elapsed_seconds=0.008211585 ticks_per_second=730675.016 allocated_bytes=3032104 gen0=0 gen1=0 gen2=0 final_tick=6120 final_digest=953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C runtime=.NET 8.0.31 runtime_version=8.0.31 +performance_sample repetition=3 seed=42 npc_count=4 warmup_ticks=120 measure_ticks=6000 elapsed_stopwatch_ticks=6088086 stopwatch_frequency=1000000000 elapsed_seconds=0.006088086 ticks_per_second=985531.413 allocated_bytes=3032104 gen0=0 gen1=0 gen2=0 final_tick=6120 final_digest=953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C runtime=.NET 8.0.31 runtime_version=8.0.31 +performance_determinism=PASS +--- +performance_sample repetition=1 seed=42 npc_count=4 warmup_ticks=120 measure_ticks=6000 elapsed_stopwatch_ticks=12936091 stopwatch_frequency=1000000000 elapsed_seconds=0.012936091 ticks_per_second=463818.630 allocated_bytes=3032344 gen0=0 gen1=0 gen2=0 final_tick=6120 final_digest=953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C runtime=.NET 8.0.31 runtime_version=8.0.31 +performance_sample repetition=2 seed=42 npc_count=4 warmup_ticks=120 measure_ticks=6000 elapsed_stopwatch_ticks=7744118 stopwatch_frequency=1000000000 elapsed_seconds=0.007744118 ticks_per_second=774781.583 allocated_bytes=3032104 gen0=0 gen1=0 gen2=0 final_tick=6120 final_digest=953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C runtime=.NET 8.0.31 runtime_version=8.0.31 +performance_sample repetition=3 seed=42 npc_count=4 warmup_ticks=120 measure_ticks=6000 elapsed_stopwatch_ticks=5896266 stopwatch_frequency=1000000000 elapsed_seconds=0.005896266 ticks_per_second=1017593.168 allocated_bytes=3032104 gen0=0 gen1=0 gen2=0 final_tick=6120 final_digest=953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C runtime=.NET 8.0.31 runtime_version=8.0.31 +performance_determinism=PASS +--- |
