Modularize map generation and add four generators - #240
Conversation
9e9f0f1 to
b74f6df
Compare
#238 (already merged) added CustomGamePreferences.h, which serializes CustomGameSetup::generator by taking Sint32 MapGenerationDescriptor::* member pointers directly. #240 replaced generator's type with GenerationRequest, whose method-specific options live in a generic std::map<std::string,int> instead of fixed struct fields — an architecture change, not a rename — so the file no longer compiled. - CustomGamePreferences::encode()/decode() now convert through toLegacyDescriptor()/fromLegacyDescriptor() (the compatibility adapter #240 already built for exactly this kind of interop), so the on-disk wire format and its corruption-recovery bounds are unchanged. decode()'s method-validity check now asks the live GeneratorRegistry instead of a hardcoded 1-8 range, so it stays correct as generators are added or retired. - Widened several fields() bounds (terrain weights 0-64 -> 0-100, riverDiameter's max 64 -> 65, oldIslandSize 1-64 -> 1-70) to match the modular registry's current ranges. These are approximate, same as before: the reused legacy fields (e.g. riverDiameter also stands in for lake size/channel width/bridge width) don't have one true bound, so this is a safe envelope, not a tight per-method one. Without this, decode() could reject a preferences file that a normal save legitimately produced (oldIslandSize's own default already exceeded the old 1-64 bound for any method other than Isles/Old Islands). - Found and fixed a related crash bug in the compatibility adapter itself while tracing this: Lattice and Maze register wheat/wood/ stone/algae controls with no entry in legacyField()'s mapping table, so converting either method through toLegacyDescriptor/ fromLegacyDescriptor threw an uncaught std::invalid_argument. Added the four missing mappings (they match pre-existing legacy struct fields exactly) and changed every other option with no legacy slot (loopiness, home-radius, cell-size, ...) from throwing to falling back to its control's default value, so a newer generator's full option set can never crash this adapter again. - test/CustomGameSetupHarness.cpp: preferencesModel()/preferencesScreen() built a GenerationRequest via the same member-pointer approach; updated both to build a temporary MapGenerationDescriptor and convert. Switched preferencesModel()'s method from Old Islands to Crater Lakes (one of the four modern height-map generators that still exposes a repeat-landscape control; Old Islands never did in the new registry, so it always round-tripped back to 0). The per-field assertions in preferencesScreen() now compare against the same achievable conversion rather than raw field maximums, since only the options a method actually registers survive a GenerationRequest round trip. Verified: full scons -j8 release=1 server=0 client build is clean. CustomGameSetupHarness passes in default, preferences-write and preferences-read modes. MapGeneratorDefaultsTest and MapGeneratorStudy --catalog also pass, unaffected by the adapter fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KFxsZmLM4qsovemHqDrHGP
e0508e0 to
2a0895c
Compare
|
Rebased onto the (also just-rebased) #238 branch — it forked from the same Most conflicts were pure append/append (translation files) or a stale-vs-final doc mismatch, resolved by taking this branch's own final version of The real find, after conflicts resolved: the branch didn't compile. While tracing that, I also found and fixed an unrelated crash in the compatibility adapter itself: Lattice and Maze register Verification on this head:
Requesting review from @Giszmo and @kylelutze (same as #238, since this stacks directly on it). No merge performed. |
Merging directly. CI green on all three platforms, no merge conflicts, no reviewer objections. Stacked map-generator work (#240) follows.
#238 (already merged) added CustomGamePreferences.h, which serializes CustomGameSetup::generator by taking Sint32 MapGenerationDescriptor::* member pointers directly. #240 replaced generator's type with GenerationRequest, whose method-specific options live in a generic std::map<std::string,int> instead of fixed struct fields — an architecture change, not a rename — so the file no longer compiled. - CustomGamePreferences::encode()/decode() now convert through toLegacyDescriptor()/fromLegacyDescriptor() (the compatibility adapter #240 already built for exactly this kind of interop), so the on-disk wire format and its corruption-recovery bounds are unchanged. decode()'s method-validity check now asks the live GeneratorRegistry instead of a hardcoded 1-8 range, so it stays correct as generators are added or retired. - Widened several fields() bounds (terrain weights 0-64 -> 0-100, riverDiameter's max 64 -> 65, oldIslandSize 1-64 -> 1-70) to match the modular registry's current ranges. These are approximate, same as before: the reused legacy fields (e.g. riverDiameter also stands in for lake size/channel width/bridge width) don't have one true bound, so this is a safe envelope, not a tight per-method one. Without this, decode() could reject a preferences file that a normal save legitimately produced (oldIslandSize's own default already exceeded the old 1-64 bound for any method other than Isles/Old Islands). - Found and fixed a related crash bug in the compatibility adapter itself while tracing this: Lattice and Maze register wheat/wood/ stone/algae controls with no entry in legacyField()'s mapping table, so converting either method through toLegacyDescriptor/ fromLegacyDescriptor threw an uncaught std::invalid_argument. Added the four missing mappings (they match pre-existing legacy struct fields exactly) and changed every other option with no legacy slot (loopiness, home-radius, cell-size, ...) from throwing to falling back to its control's default value, so a newer generator's full option set can never crash this adapter again. - test/CustomGameSetupHarness.cpp: preferencesModel()/preferencesScreen() built a GenerationRequest via the same member-pointer approach; updated both to build a temporary MapGenerationDescriptor and convert. Switched preferencesModel()'s method from Old Islands to Crater Lakes (one of the four modern height-map generators that still exposes a repeat-landscape control; Old Islands never did in the new registry, so it always round-tripped back to 0). The per-field assertions in preferencesScreen() now compare against the same achievable conversion rather than raw field maximums, since only the options a method actually registers survive a GenerationRequest round trip. Verified: full scons -j8 release=1 server=0 client build is clean. CustomGameSetupHarness passes in default, preferences-write and preferences-read modes. MapGeneratorDefaultsTest and MapGeneratorStudy --catalog also pass, unaffected by the adapter fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KFxsZmLM4qsovemHqDrHGP
Rebased onto master now that #238 has merged. That surfaced a real compile break: the harness still called Map::oldMakeIslandsMap/Game::oldMakeIslandsMap, which the registry-driven generator rewrite removed. Route it through MapGenerator::generateMap(Game&, const MapGenerationDescriptor&, seed) instead, which owns map sizing and the game association internally. Seed explicitly since generation determinism no longer follows the global sync-rand state. Also start from setMethodDefaults() rather than hand-picked constants: #238's defaults tuning tightened several control ranges (island-size moved to 50-70, the shared "workers" control caps at 8), so the harness's old literals (oldIslandSize=35, nbWorkers=48) now fail request validation. Defaulting first and overriding only what this decorative colony actually needs to differ keeps it from rotting the same way again as ranges keep moving. Verified: full client and menu-colony-harness build clean; `check`, `navigation`, and `generate` subcommands all pass (generate grows the colony from 8 to 56 units over the same 12,000-tick warmup, confirming the reduced starting worker count doesn't defeat the decorative intent). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Le23P4h9QuDjwExuK6HU96
2a0895c to
db88fb0
Compare
|
Retargeted onto master and rebased now that #238 has merged. Master's tree was byte-identical to #238's old branch tip (clean squash merge), so That surfaced a real compile break in CI, though:
Verified on this head (
CI is running now. Requesting review from @Giszmo and @kylelutze (unchanged from the original description). No merge performed. |
Map generation was spread across central dispatch code, overloaded descriptor fields, global random state, and duplicated helpers, which made new generators hard to add safely. This follow-up to #238 introduces a registry-driven modular framework: each generator owns its named options, controls, and ordered recipe; the lobby, editor, compatibility adapter, lifecycle service, and study tools consume the same definitions.
It also incorporates the finalized Contested Commons, Lattice, Maze, and Fjord Continent generators. Integration fixes include real shoreline generation for Lattice and Maze, larger playable home areas, coarse 20/24/32-tile Maze cells, stone seams inside Maze water walls, clumped resources, and guaranteed wheat/wood deposits on both banks of every fjord. All 18 new strings have reviewed translations in every locale.
Validation:
Rectangular map follow-up
Rectangular previews now crop thumbnail padding, preserve aspect ratio and align colony markers with terrain. Legacy seam-crossing start coordinates are normalized (including a Shattered Coast start recorded at y=-6); generated-world validation now checks start bounds. Native pixel checks cover 4:1 and 8:1 maps in both orientations at compact and larger window sizes.
A 960-case generation audit still reports 51 seed-specific placement failures (38/720 rectangular attempts and 13/240 square attempts). This preview/start-coordinate fix does not claim to resolve those layout-quality limitations.
Failures by generator (rectangular / square): River 3/1, Separate Islands 8/1, Shattered Coast 11/3, Contested Commons 1/6, Fjord Continent 15/2. The other seven generators had none in this sample. Failures involve small/crowded settlement or resource placement; five Commons 512×512 cases reached the dispersion evaluation limit.
Generated reports, study data and screenshot files are excluded from the branch tip and final source changes. Existing image embeds reference earlier review commits; future artifacts stay outside tracked source.