Game-agnostic world generation plugin for Godot 4.7: planets, terrain fields, biomes and regions, with the generator's choices expressed as data.
  • GDScript 91.3%
  • Python 5.1%
  • Shell 2.1%
  • GAP 1.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
cmkrist a5d3186d1b Absorb the tile graph and the weather simulation
WorldTopology, AtmosphereGrid and WeatherSystem move here from EnC: climate and weather now live with the world they describe. All three keep their class names, so the 37, 8 and 6 files that reference them needed no edits.

The world parameter becomes untyped and the required shape is what the caller must provide: cell_count, face_size, altitude, is_water, moisture, temperature, settings.world_seed and topo. A plugin cannot name a game's WorldData, and the duck-typed boundary is what makes the move possible without dragging the game type along. Fourteen locals in atmosphere_grid.gd and six in a legacy test oracle needed explicit types, because a name derived from an untyped world infers as Variant.

atmosphere_grid.gd gains a class_name. It had none and was preloaded by path from nine places, which is how a move breaks consumers silently at parse time rather than at compile time. EnC's remaining references now point at the plugin.

Verified by EnC's tools/weather_golden_tests.gd: tile-graph geometry, the weather field at tick 0 and after 900 ticks, and the generated climate layers are byte-identical to values recorded before the move. The one-way contract is pinned too: stepping the weather does not mutate the climate layers ~20 gameplay files read. EnC's weather, weather-batch, tree-wind, moon-orbit, night-lighting and worldgen suites still pass, and performance_equivalence_tests reports 145621 checks with no failures against its retained legacy oracle.
2026-09-16 06:26:01 -04:00
addons/world_maker Absorb the tile graph and the weather simulation 2026-09-16 06:26:01 -04:00
bench Add a standalone benchmark harness with a committed baseline 2026-09-15 19:15:59 -04:00
docs Initial commit: worldmaker plugin skeleton 2026-09-15 16:46:04 -04:00
scenes Initial commit: worldmaker plugin skeleton 2026-09-15 16:46:04 -04:00
tests Add GridUtil: field maths over a tile graph, with a duck-typed world 2026-09-15 20:03:38 -04:00
tools Add a standalone benchmark harness with a committed baseline 2026-09-15 19:15:59 -04:00
.gitignore Add a standalone benchmark harness with a committed baseline 2026-09-15 19:15:59 -04:00
LICENSE Initial commit: worldmaker plugin skeleton 2026-09-15 16:46:04 -04:00
project.godot Initial commit: worldmaker plugin skeleton 2026-09-15 16:46:04 -04:00
README.md Add a standalone benchmark harness with a committed baseline 2026-09-15 19:15:59 -04:00

WorldMaker

A game-agnostic world generation plugin for Godot 4.7: planets, terrain fields, hydrology, biomes and regions — with the generator's choices expressed as data so a second game can use a different world without forking the engine.

This is the standalone source repository. The installable addon is addons/world_maker/; install it into any Godot project as res://addons/world_maker/:

python3 tools/package_addon.py /path/to/consumer/project

Status: skeleton

This release is the data contracts and the pipeline engine, verified and tested. It is deliberately not yet a terrain generator: the seven generation stages (tectonics, elevation, erosion, climate, hydrology, biome, region) are still in EnC and are ported in the migration phase described in docs/MIGRATION_FROM_ENC.md.

What works today:

PlanetSettings Physical inputs, derived geometry and time, stable generation signature
BiomeRuleset + BiomeDefinition Data-driven band classification, no hardcoded biome list
WorldGeometry Quantile/sea-level solving and altitude→position maths in one place
WorldPipeline + WorldPipelineStage Ordered stages as resources, with an up-front data-contract check
WorldBuildContext Named layer exchange between stages; thread-safe, no node tree
SnapshotEnvelope Versioned, signature-gated save envelope so plugin state can be persisted at all
WorldMaker Node facade: generate_async/generate_sync/cancel, progress and result signals

What does not exist yet: any built-in generation stage. You can write your own against WorldPipelineStage today; see docs/API.md.

const WorldMakerScript = preload("res://addons/world_maker/runtime/world_maker.gd")

var maker := WorldMakerScript.new()
maker.settings = PlanetSettings.create_default()
maker.ruleset = my_ruleset
maker.pipeline = my_pipeline          # ordered WorldPipelineStage resources
maker.generation_finished.connect(_on_world)
add_child(maker)
maker.generate_async()

func _on_world(context) -> void:
    var elevation: PackedFloat32Array = context.float_layer(&"elevation")

Why the split

EnC's world generation is entangled with the game in three specific ways, and this plugin exists to break each one:

  1. Gameplay data in generation config. WorldSettings carries inherited gene ranges, starting population, faction emblems and moon bookings, and its gene_ranges field preloads EnC's GeneSystem — so the resource cannot even parse outside EnC. PlanetSettings keeps only physics and geometry.
  2. A hardcoded pipeline. Stage order and progress labels live in a const array and a _build() method that names each stage class. WorldPipeline makes the list data, so a second game can reorder, drop or add steps.
  3. A world↔render dependency cycle. moon_orbits reaches into TestTerrainBaker, which reaches back into WorldData, while the terrain sampler hardcodes the same 0.06 height scale in two files. WorldGeometry owns those conversions with no rendering dependency.

Running the demo and tests

godot --headless --path .          # the playground demo, then quits
./tools/run_tests.sh               # unit suite

The test suite has no framework dependency, matching the convention already used in EnC and ToonGenerator. Pure-logic suites are standalone SceneTree scripts; test_threaded_generation ships a matching .tscn and runs as a scene, because a worker thread reports back through call_deferred and that needs real main-loop frames to flush. run_tests.sh picks the right runner automatically.

Coverage: PlanetSettings derivation and validation, biome band classification, geometry and sea-level quantile solving, pipeline ordering/progress/cancellation, the save envelope's version gating, and all three generation paths (threaded, non-threaded, synchronous).

Benchmarks

Runs standalone with no game present and no fixtures on disk: every workload is built in code, so this works from a fresh clone.

./tools/run_bench.sh              # run and print the table
./tools/run_bench.sh --compare    # gate against bench/baseline.json
./tools/run_bench.sh --update     # rewrite the baseline (say why in the commit)

Results go to bench/results/world_maker.json, gitignored because it is machine-specific. bench/baseline.json is the tracked artifact. tools/compare_bench.py fails when a case is slower than +25%, comparing medians over 9 measured runs after 2 discarded warmup runs.

It measures the pipeline engine, not terrain generation: the seven generation stages are still in EnC. Headline observations from the first baseline:

  • The pipeline scales linearly — 480 ns/tile at 16k versus 513 ns/tile at 65k — so there is no superlinear behaviour to fix before the real stages arrive.
  • Progress reporting is effectively free (497 versus 480 ns/tile), which matters because the editor drives it on every run.

The protocol is documented in EnC at docs/PLUGIN_BENCHMARK_PROTOCOL.md. The same harness, runner and gate are used by every plugin in the suite, so the numbers are comparable across them.

Layout

addons/world_maker/   the installable plugin (core/ data contracts, runtime/ services)
docs/                 ARCHITECTURE, API, MIGRATION_FROM_ENC
scenes/               playground demo
tests/                headless unit suite
bench/                standalone benchmarks + committed baseline
tools/                package_addon.py (install into a consumer, with --check), run_tests.sh, run_bench.sh

Licence

MIT.