Skip to content

Galaxy seeding

How does X4’s universe come to exist at game start? Every shipyard, factory, defence station, NPC, and faction relationship has to be set up before the player presses Continue. This is the galaxy seeding pipeline — a three-stage flow from declarative XML to operational world objects.

┌──────────────────────────────────────────┐
│ libraries/god.xml │
│ (declarative initial-content XML) │
└────────────────┬─────────────────────────┘
┌──────────────────────────────────────────┐
│ Engine: parse god.xml, │
│ emit event_god_created_factory │
│ for each <object> entry │
└────────────────┬─────────────────────────┘
┌──────────────────────────────────────────┐
│ md/finalisestations.xml │
│ God_DefaultFinaliseFactory cue │
│ (the "finalize" pipeline) │
└────────────────┬─────────────────────────┘
┌──────────────────────────────────────────┐
│ Engine: connect components, │
│ apply construction sequences, │
│ populate cargo & NPCs │
└────────────────┬─────────────────────────┘
┌──────────────────────────────────────────┐
│ Operational stations in the world │
│ (ready for player + NPC interaction) │
└──────────────────────────────────────────┘

god.xml declares every initial station with <object> entries:

<object id="argon_shipyard_1"
macro="station_arg_shy_1_macro"
sector="cluster_01_sector_001"
faction="argon">
<position x="0" y="0" z="0"/>
</object>

The engine reads this file ONCE at game start. After that, god.xml is no longer consulted — changes only affect new games.

For each <object> in god.xml, the engine fires event_god_created_factory. The vanilla md/finalisestations.xml listens for this event:

<cue name="God_DefaultFinaliseFactory" instantiate="true" namespace="this">
<conditions>
<event_god_created_factory space="player.galaxy"/>
<check_value value="event.param.isgamestartgodentry"/>
</conditions>
<actions>
<set_value name="$Station" exact="event.param"/>
<!-- ... build planned modules + construction sequence ... -->
</actions>
</cue>

The isgamestartgodentry check distinguishes initial-seed entries from runtime-spawned ones (NPC stations built during gameplay).

The FinaliseStations script (~1100 lines) handles:

  1. Module composition — reads the station macro to determine planned modules
  2. Construction sequence creation — calls <create_construction_sequence> with the module list
  3. Construction application — calls <apply_construction_sequence> to materialize the modules
  4. Cargo population — adds initial wares to storage modules
  5. NPC populating — populates habitation modules and walkable interiors
  6. Loadout — applies equipment + drones via set_module_loadout_level
  7. Final signaling — fires signal_objects 'init station' to notify the station is ready

The pipeline uses stationgroups.xml and constructionplans.xml to know which modules to build and in what order.

After FinaliseStations completes, the station has:

  • All planned modules built and connected
  • Initial cargo populated
  • NPCs in habitation modules and walkable interiors
  • Default loadout (turrets, shields, defence drones)
  • Trade subscriptions registered
  • Faction logic aware of the station

The station is now visible to find_station_by_true_owner queries, can receive trade offers, can be boarded, can build ships, etc.

For stations built DURING gameplay (NPC factions expanding, player constructing), the same event_god_created_factory fires but with isgamestartgodentry=false. The same FinaliseStations pipeline runs, except step 4 (cargo population) may be skipped or reduced.

Player station construction goes through a slightly different path — the player picks modules via the Plot UI, which calls <create_construction_sequence> + <apply_construction_sequence>. The same engine events fire, but FinaliseStations distinguishes player-owned vs NPC-owned.

The Player HQ has its own dedicated seed-and-init path — setup.xml registers it. The HQ doesn’t exist until the player completes a quest arc, after which player.headquarters becomes non-null.

A new faction’s stations need:

  1. Faction declaration in libraries/factions.xml
  2. Station group in stationgroups.xml
  3. Construction plan in constructionplans.xml
  4. Initial seeding in god.xml
  5. (Optional) god_factions logic for runtime expansion

Without all five, the station may seed but not build correctly, or may not be expandable by NPC faction logic.

A common modder mistake: putting init logic in a cue that fires only at GameStart. This logic doesn’t re-fire on save load. Any runtime state set during seeding must be re-applied from a heartbeat cue on load. See Setup runs once memory for the Station-side gotcha.

god.xml uses XML attribute values heavily. Standard MD attribute-string traps apply:

  • Faction economy — how factions GROW after initial seed
  • Construction sequence — the runtime mechanism
  • NPC instantiation — how NPCs populate stations during seeding