diff options
| -rw-r--r-- | docs/维护说明.md | 76 | ||||
| -rw-r--r-- | src/LivingVillage.Desktop/Game.fs | 2 |
2 files changed, 77 insertions, 1 deletions
diff --git a/docs/维护说明.md b/docs/维护说明.md new file mode 100644 index 0000000..de5698a --- /dev/null +++ b/docs/维护说明.md @@ -0,0 +1,76 @@ +# 维护说明 + +结论先行:主分支保持 0 警告 0 错误 + Desktop 69/69、Kernel 50/50 全绿;性能基线 +final_digest 固定 953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C。 +本文记录模块职责、不变量与逐字可复制的验收命令。 + +## 模块职责 + +- `src/LivingVillage.Kernel/`:纯确定性模拟(需求/关系/谣言/年鉴/交易),无渲染依赖。 + - `Sim.fs`:世界结构、`Sim.step` 主推进、对话/交易/谣言决策、地图边界 + `configureBounds`(默认 64×48,可到 512×384)。 + - `WorldSave.fs`:存档序列化。V2 头携带地图宽高,V1 旧档读入自动回退 64×48。 + - `Personality.fs / Interaction.fs(fsm) / M6*.fs`:NPC 行为状态机与里程碑数据。 +- `src/LivingVillage.Desktop/`:MonoGame 渲染与交互层。 + - `VillageArt.fs`:图集加载与世界/人物/室内绘制;CC0 覆盖层(LV_ASSET_PACK=cc0)。 + - `Interaction.fs`:M5 视图与情境解析(FloatingPrompt / panelLines / 情境提示)。 + - `M6Presentation.fs`:昼夜光照纯函数(lightingBlend)与渲染档(Blend/LanternGlow)。 + - `TitleScreen.fs / Game.fs`:标题布局与主循环;LV Autos(sample / flow / record / map tour)。 + - `ProceduralMap.fs`:512×384 确定性地形(splitmix 随机游走河道 + 三倍频值噪声 + 泊松布点)。 + - `SampleScript.fs`:自动演示脚本(靠近→提示→交互→关闭→离开全流程)。 +- `src/LivingVillage.Headless/`:headless 入口 + PerformanceProbe(digest、基跑)。 +- `scripts/make-jiangnan-art.py / make-cc0-art.py`:原创与 CC0 素材确定性生成。 +- `third_party/`:Kenney Tiny Farm、Puny Characters(均 CC0 1.0,来源与 sha256 在 PROVENANCE.md)。 + +## 模拟状态不变量(验收依据) + +1. **数组快照**:`Sim.world.Npcs` 数组与 `InteractionResolver.resolve` / `refreshPrompt` 的 + 调用之间必须保持恒定——选择/提示路径从不 mutation(PrototypeTests 快照回归)。 +2. **确定性 RNG**:世界推进只随 `World.Rng`(splitmix)与 `(seed)` 派生,禁止墙钟与 + `System.Random`。昼夜/波纹/入场/动画帧全是 `tick → 值` 纯函数。 +3. **存档 v1/v2**:`WorldSave` v2 头携带 `width height`,V1 读入回退默认。`worldDigest` + 对版本头与边界 token 不敏感(剥头后重构 V1 常量语义再 SHA256),摘要只绑定模拟状态。 +4. **地图 512×384 大世界**:`ProceduralMap.generate` 同 seed 两次生成逐字节一致; + 村核矩形(24..38 × 16..34)由生成器不变式保证可通行。 + +## 性能基线命令 + +```bash +dotnet src/LivingVillage.Headless/bin/Release/net8.0/LivingVillage.Headless.dll --performance-baseline +``` + +- 口径:seed=42,npc=4,warmup=120,measure=6000,repetitions=3(见首行 `performance_config`)。 +- 门槛:`final_digest=953775FAEB2FDDE97289491AA260BD8D390C571E48A7A13AD2CB6FB7124F7F6C` 三次一致 + `performance_determinism=PASS`。 +- digest 变化处理:先比对 `WorldSave.save world` 全文文本(版本头变化不构成失败即 digest 规范化后等价); + 再查 Sim.step 数值路径是否被改动(不允许)。历史归属见 `artifacts/perf-independent/*/README.md`。 + +## 已验证命令 + +```bash +# 完整重建(0 警告 0 错误) +dotnet clean LivingVillage.sln 2>&1 | tail -n1 +rm -rf src/*/bin src/*/obj +dotnet restore LivingVillage.sln +dotnet build LivingVillage.sln -c Release 2>&1 | tail -n3 + +# 全量测试 +dotnet test src/LivingVillage.Desktop.Tests -c Release --no-build +dotnet test src/LivingVillage.Kernel.Tests -c Release --no-build + +# 素材再生成(确定性,输出 byte-identical) +python3 scripts/make-jiangnan-art.py && python3 scripts/make-cc0-art.py + +# Xvfb 录屏取证(沿用既有 pN harness 外参即可;harness 不入库) +pkill -f "Xvfb :99"; Xvfb :99 -screen 0 1280x720x24 & sleep 2 +ffmpeg -y -f x11grab -video_size 1280x720 -framerate 10 -i :99 -pix_fmt yuv420p out.mp4 +LV_AUTOPLAY_SAMPLE=1 LV_AUTOPLAY_DAYLIGHT=1 LV_AUTOPLAY_RECORD=1 \ + dotnet src/LivingVillage.Desktop/bin/Release/net8.0/LivingVillage.Desktop.dll +``` + +## 取证快照位置(近期) + +- `/tmp/lv-p2-ui/`、`/tmp/lv-p3-fixes/`(标题/键位/P5 提示与修) +- `/tmp/lv-p6-art/`(昼夜光照/四帧行走/标题入场) +- `/tmp/lv-p7-map/`(512×384 大世界巡游帧 + 夜灯对照) +- `/tmp/lv-p8-cc0/`(CC0 同 seed 对照帧) +- `artifacts/perf-independent/<TS>/`(digest 3 联测回读) diff --git a/src/LivingVillage.Desktop/Game.fs b/src/LivingVillage.Desktop/Game.fs index 62ba8f0..9fab5f7 100644 --- a/src/LivingVillage.Desktop/Game.fs +++ b/src/LivingVillage.Desktop/Game.fs @@ -730,7 +730,7 @@ type LivingVillageGame() as this = let ringAlpha = int (18.0f * glow) for prop in renderPlan.Props do match prop.Kind with - | RiverLantern -> + | VillageArt.RenderPropKind.RiverLantern -> let position = VillageArt.worldTile renderPlan prop.Position let screenX = position.X * Sim.tilePixels - int camera.X + Sim.tilePixels / 2 let screenY = position.Y * Sim.tilePixels - int camera.Y - Sim.tilePixels / 2 |
