summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Kernel.Tests
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 14:55:37 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 14:55:37 +0800
commitab19df0ebad8da972cd30f89f7cfd8ef38b8c0ae (patch)
treebaa466d7afd04517d31cb3a1ab0fee04da0bcc5e /src/LivingVillage.Kernel.Tests
parent655c22afe53b740e795f66c4da57714985ddccec (diff)
downloadliving-village-ab19df0ebad8da972cd30f89f7cfd8ef38b8c0ae.tar.gz
feat(kernel): 地图边界参数化与存档 v2
Sim 地图边界由常量 52 改为可配置(configureBounds,默认 64x48 = 与全部基线一致);Sim.step 裁剪、initialWorld 中心出生时点按当前边界读取;WorldSave 升级 V2 头携带 width/height 两字段,V1 旧存档照常读入并自动回退到 64x48;回归:512x384 边界裁剪/初界转正/双份存档往返/案例 v1 档兼容读。修复前一段中报错已修正的测试代码(Ensure saved-file timeouts)。
Diffstat (limited to 'src/LivingVillage.Kernel.Tests')
-rw-r--r--src/LivingVillage.Kernel.Tests/M6aTests.fs58
1 files changed, 58 insertions, 0 deletions
diff --git a/src/LivingVillage.Kernel.Tests/M6aTests.fs b/src/LivingVillage.Kernel.Tests/M6aTests.fs
index 91f0a10..7f8d5ea 100644
--- a/src/LivingVillage.Kernel.Tests/M6aTests.fs
+++ b/src/LivingVillage.Kernel.Tests/M6aTests.fs
@@ -161,6 +161,64 @@ type M6aTests () =
Assert.AreEqual<SimulationSpeed>(OneX, resumed.Speed)
[<TestMethod>]
+ member _.BoundsAreParameterizableAndClampMovementAtLargeMapEdge () =
+ Sim.configureBounds 512 384
+ try
+ let world = Sim.initialWorld (uint64 42)
+ let stepped = Sim.step { Input = { MoveX = 1.0f; MoveY = 1.0f } } world
+ // Legacy maps clamp within 64x48; at 512x384 the avatar is free to wander
+ // well past the old tile limits.
+ let maxX = float32 (Sim.mapWidthTiles * Sim.tilePixels - Sim.tilePixels)
+ let maxY = float32 (Sim.mapHeightTiles * Sim.tilePixels - Sim.tilePixels)
+ Assert.IsTrue(stepped.Avatar.Pos.X <= maxX)
+ Assert.IsTrue(stepped.Avatar.Pos.Y <= maxY)
+ Assert.AreEqual<int>(512, Sim.mapWidthTiles)
+ finally
+ Sim.configureBounds 64 48
+
+ [<TestMethod>]
+ member _.SaveV1LegacyStillReadable () =
+ let world = Sim.initialWorld (uint64 42)
+ WorldSave.saveToFile "p7-legacy-src.save" world
+ let modern = System.IO.File.ReadAllText "p7-legacy-src.save"
+ // v2 = version|w|h|body...; strip the two bounds integers and roll the header back to v1.
+ let firstPipe = modern.IndexOf('|')
+ let secondPipe = modern.IndexOf('|', firstPipe + 1)
+ let thirdPipe = modern.IndexOf('|', secondPipe + 1)
+ System.IO.File.WriteAllText("p7-legacy.save", ("LV_WORLD_SAVE_V1" + modern.Substring(thirdPipe)))
+ let text = System.IO.File.ReadAllText "p7-legacy.save"
+ Sim.configureBounds 512 384
+ try
+ Assert.IsTrue(text.StartsWith("LV_WORLD_SAVE_V1"), "legacy header must be v1")
+ match WorldSave.loadFromFile "p7-legacy.save" with
+ | Ok loaded ->
+ Assert.AreEqual<int>(64, Sim.mapWidthTiles)
+ Assert.AreEqual<int>(48, Sim.mapHeightTiles)
+ | Error message ->
+ Assert.Fail(sprintf "legacy v1 load failed: %s" message)
+ finally
+ Sim.configureBounds 64 48
+
+ [<TestMethod>]
+ member _.SaveV2RecordsBoundsAndStaysDeterministic () =
+ Sim.configureBounds 512 384
+ try
+ let world = Sim.initialWorld (uint64 7)
+ WorldSave.saveToFile "p7-v2.save" world
+ let text = System.IO.File.ReadAllText "p7-v2.save"
+ Assert.IsTrue(text.StartsWith("LV_WORLD_SAVE_V2"), "v2 save must carry bounds")
+ Sim.configureBounds 64 48
+ match WorldSave.loadFromFile "p7-v2.save" with
+ | Ok loaded ->
+ Assert.AreEqual<int>(512, Sim.mapWidthTiles)
+ Assert.AreEqual<int>(384, Sim.mapHeightTiles)
+ Assert.AreEqual<int64>(loaded.Tick, world.Tick)
+ | Error message ->
+ Assert.Fail(sprintf "v2 load failed: %s" message)
+ finally
+ Sim.configureBounds 64 48
+
+ [<TestMethod>]
member _.ConfiguredLegacyStepCountsRemainExactUntilManualSpeedSelection () =
let control, legacySteps = SimulationControl.initialForConfiguredSteps 7
Assert.AreEqual<int option>(Some 7, legacySteps)