feat: blueprint v2 reader dispatch + validation + params cross-check (terrain-water task 02)

Reader sniffs the first byte (0x49 raw-ISLA v2 vs 0x07 v1 string
prefix) and routes to the v2 tagged-section parser or the intact v1
path (v1 loads log a deprecation warning — fallback stays live).

v2 validation: magic/version gate (loud reject), MapSize sanity bound
[256, 32768] before allocation, every section length checked against
remaining file, section-consumed-exactly check, params-first and
no-duplicate-section rules, biome and town-tier ordinal range checks.
Unknown tags skip by length — the forward-compat property D-030 buys.

ServerChunkManager cross-checks embedded params against config
(seed + MapSize) and logs a prominent desync warning — canon H7's
silent failure becomes loud. ServerConfig.json pins the reference
world: WorldSeed 1409879727, 8K.

Round-trip oracle GREEN: reference v1 (537,054,156 B) -> v2
(335,727,522 B, -192 MB) -> parse -> semantic equality holds
(heights bitwise, biomes, 94 towns, 4/1/37/39 road paths
point-for-point). v1 parse 1.9s, v2 write 1.4s, v2 parse 1.6s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Stewart Howe 2026-08-06 07:27:42 -04:00
parent c305fd6565
commit 8532d88771
3 changed files with 239 additions and 2 deletions

View file

@ -39,6 +39,22 @@ namespace IslaApocalypse.Server
if (_blueprint != null)
{
// Params cross-check (v2 blueprints only): the file carries its resolved
// generation inputs, so a config edited after generation is detectable —
// canon H7's silent desync becomes loud. Warning, not an abort: the world
// still loads; the developer decides what to do about the mismatch.
if (_blueprint.Params != null)
{
var p = _blueprint.Params;
if (p.WorldSeed != BlueprintFormat.SENTINEL_WORLD_SEED && p.WorldSeed != ConfigManager.WorldSeed)
GD.PrintErr($"[Server] ⚠⚠ BLUEPRINT/CONFIG DESYNC: blueprint was generated with seed " +
$"{p.WorldSeed} but ServerConfig.json says {ConfigManager.WorldSeed}. " +
"The world you load is not the world this config describes.");
if (p.MapSize != ConfigManager.MapSize)
GD.PrintErr($"[Server] ⚠⚠ BLUEPRINT/CONFIG DESYNC: blueprint MapSize {p.MapSize} " +
$"vs config MapSize {ConfigManager.MapSize}.");
}
GD.Print("[Server] Blueprint loaded. Locating Capitol City...");
// 2. Find the Capitol in the parsed data