Chem O’DunReferences and Guides

god.xml

Almost every station in a new X4 universe is placed by one part of the game, the god engine. Shipyards, wharfs, trading stations, defence platforms, faction factories, and many landmarks and anomalies all come from entries in libraries/god.xml. Each entry says what to create, how many, and where. The god engine places the objects, the scripts then finish them, and a script can create more objects from the same entries later.

This article covers the format, what the game does with each part of an entry and when, and the script side. It describes version 9.00.

Adding a station or factory from an extension needs The file, How many: quotas, Where: locations, Adding entries from an extension and the checklist in Traps.

Contents

Terms

Plan entries and staged construction plans are new in 9.00; in 8.00 <products> holds only <product> entries.

↑ Contents

How generation works

On a new game, after the map is built, the god engine works through every entry once:

  1. Zone entries first, then sector, cluster and galaxy. Entries are grouped by the class of their location. Entries tied to a named zone are placed first and galaxy-wide entries last.
  2. Each entry creates up to its quota. The quota sets a total for the galaxy and optional limits per cluster, sector and zone.
  3. Each object goes to a space that passes the entry's location filters: owner, space tags, distance from the sector core, economy and security values, sunlight, regions.

The loading screen shows station generation while this runs. The scripts then finish what was placed. A product entry places only a production module, and vanilla's md/finalisestations.xml adds the habitation, dock, pier, defence and connection modules, then the loadout. A plan entry builds the construction plan it names, often only its first stages, and the owning faction builds the rest during play; see Staged stations. Last, md/inituniverse.xml sets up every god station like any other station, for example with its trade wares.

During play, generation runs again only when a save is loaded, and only for extensions that are enabled now but not yet recorded in the save; see Loading a save. Apart from that, an entry is used only when a script asks for it.

↑ Contents

The file

Layout

The root holds one dataset, and any number of gamestart datasets can follow it:

<god>
  <objects> ... </objects>                   <!-- object entries -->
  <ships> ... </ships>                       <!-- ship entries -->
  <stations>
    <defaults> ... </defaults>
    <station id="..."> ... </station>        <!-- station entries -->
  </stations>
  <products>
    <product id="..."> ... </product>        <!-- product entries -->
    <station id="..."> ... </station>        <!-- plan entries -->
  </products>

  <gamestart ref="x4ep1_gamestart_tutorial1"> <!-- the same four sections --> </gamestart>
  <gamestart galaxy="timelines_map_mining_1_galaxy_macro"> ... </gamestart>
</god>

The file has no schema of its own: god.xml points at libraries/libraries.xsd, which defines it completely.

Which dataset is used

Exactly one dataset is used per game:

  1. a <gamestart ref="..."> whose ref is the id of the current gamestart, the start chosen on New Game (its <gamestart id> in libraries/gamestarts.xml);
  2. otherwise a <gamestart galaxy="..."> whose galaxy is the macro of the current galaxy;
  3. otherwise the root.

A matching gamestart dataset replaces the root dataset; the two are not merged. An entry in the root dataset is therefore absent from the starts that have a dataset of their own. To appear there too, it has to be added to that dataset as well. The schema puts the rule as "default god entries if no gamestart-specific god dataset found".

The base game has three gamestart datasets. x4ep1_gamestart_tutorial1 holds a single shipyard. x4ep1_gamestart_workshop holds two stations. The Timelines mining galaxy dataset is empty, marked "Used to patch DLC stations", and the DLCs add their entries to it. The Timelines DLC adds 16 more, one per scenario such as scenario_tharkas_cascade, with <add sel="/god">.

A gamestart can also switch the god engine off, and then no dataset is used. libraries/gamestarts.xml does that with <god enabled="false"/> inside <universe> for the tutorial_* starts, x4ep1_gamestart_tutorial2, the test starts, thevoid and most Timelines scenarios. x4ep1_gamestart_tutorial1 keeps it on and uses its own dataset.

Kinds of entry

Every entry has the same shape: the outer element carries the id, owner and other attributes, <quotas> says how many, <location> and <position> say where, and an inner element says what to build.

Entry Section and element Creates Inner element: what to build
object entry <objects>, <object> an object such as a landmark, anomaly or derelict <object macro="...">
ship entry <ships>, <ship> a ship <ship>, with the same content as the create_ship script action
station entry <stations>, <station> a station: shipyard, wharf, trading station, defence platform, headquarters, pirate base <station>: a <select> or constructionplan, plus <loadout>
product entry <products>, <product> a factory for one ware, started from its production module <module> with a <select ware="..." race="...">
plan entry <products>, <station> a factory for one ware, built from a given construction plan, possibly in stages <station constructionplan="...">, with an optional <stage>

Product and plan entries are the production entries; script properties and find filters use that name, such as isgodproductionentry. <select> and <loadout> are shown in the first example below; script actions and find filters are covered in The script side.

Ships in the universe come from libraries/jobs.xml, not from god.xml. Vanilla's only ship entries are 10 in the Timelines scenario datasets, most of them the player's ship for shipgodentry.

A vanilla station entry, with comments added. Its inner element is also named <station>:

<station id="tradestation_argon_01" race="argon" owner="argon" type="tradingstation">
  <!-- how many -->
  <quotas>
    <quota galaxy="1" zone="1" />
  </quotas>
  <!-- where -->
  <location class="sector" macro="cluster_06_sector002_macro" />
  <position x="-48800" y="0" z="27800" pitch="0" roll="0" />
  <!-- what to build -->
  <station>
    <select faction="argon" tags="[tradestation]" />
    <loadout>
      <level exact="0.75" />
    </loadout>
  </station>
</station>

In a station entry, <select faction="argon" tags="[shipyard]"/> picks a station from libraries/stations.xml whose <category> matches the faction and tags, and constructionplan="..." names a plan instead. <loadout><level exact="0.75"/></loadout> sets how fully the station is equipped. <loadout useplanloadout="true"/> takes the loadout stored in the construction plan instead of generating one; a few vanilla station entries use it, most of them in the Split DLC.

A vanilla product entry:

<product id="arg_energycells" ware="energycells" owner="argon" type="factory">
  <quotas>
    <quota galaxy="10" sector="6" />
  </quotas>
  <location class="galaxy" macro="xu_ep2_universe_macro" faction="[argon, hatikvah]" relation="self" comparison="ge">
    <economy max="0.6" maxbound="false" />
    <sunlight min="0.5" />
  </location>
  <module>
    <select ware="energycells" race="argon"/>
  </module>
</product>

<select ware race> picks the production module, and the finalise scripts build the rest of the station around it; see How generation works. A plan entry is shown in Staged stations.

The inner <object> and <ship> also take state, the initial state of the object: construction, operational or wreck. Vanilla does not use it.

Attributes

Every entry accepts:

Each kind adds its own:

Attribute Station entries Production entries Object and ship entries
owner required required optional, ownerless by default
race required
ware required
type optional optional
set optional optional
encyclopedia optional
friendgroup optional

The elements every entry accepts are <quota> or <quotas>, <location>, an optional <position>, and an optional <category tags="...">, which scripts can read back as the entry's tags.

↑ Contents

How many: quotas

A quota has these five attributes, plus gamestart on a <quota> inside <quotas>, described below:

Each level is capped by the one above it. cluster is at most galaxy, sector is at most the smaller of the two, and zone likewise, so <quota galaxy="1" zone="3"/> still creates one object. A quota where every level comes out as zero disables the entry. <quota galaxy="2" sector="1"/> creates two objects, at most one per sector.

One quota or one per gamestart

An entry has a single <quota>, a <quotas> list, or both:

<quotas>
  <quota galaxy="1" zone="1" gamestart="x4ep1_gamestart_trade" />
  <quota galaxy="3" />
</quotas>

The quota that applies is chosen in this order:

  1. a direct <quota> child, if there is one;
  2. the <quota> in <quotas> whose gamestart is the current gamestart;
  3. the <quota> in <quotas> without a gamestart.

When none of them applies, the entry is disabled, and nothing is logged. An entry whose quotas all name gamestarts creates nothing in any other start. Vanilla uses this for player-owned entries such as x4ep1_gamestart_trade_playerfactory. An entry with neither <quota> nor <quotas>, or with an empty <quotas>, is disabled with an error in the log.

Station defaults

<stations><defaults> holds the station defaults, including a quota. Vanilla's are 3 per zone and 30 per sector:

<defaults>
  <location newzonechance="0.25" coreboundaryzoneheight="40000">
    <corerange max="1.3"/>
    <region allowhazardous="false" allowgravidar="true"/>
  </location>
  <modules production="5" storage="10" />
  <quota zone="3" sector="30" />
</defaults>

<modules> limits how many modules of each kind a generated station gets: production, build, storage, habitation, defence, comm, dock, pier, other, venture, welfare, processing and radar. A kind left out defaults to 20, according to the schema. The <location> values are the defaults for entries that do not set their own.

The default quota applies where the god engine chooses the zone: each zone then gets at most 3 stations of a station entry, even when the entry's own quota allows more per zone. It does not limit an entry's total: a station entry without a sector value can place more than 30 stations in one sector, and one tied to a single zone more than 3 in that zone.

Scaling by gamestart

A gamestart in gamestarts.xml can scale quotas:

<universe>
  <god>
    <quotas>
      <quota faction="..." tag="..." factor="..." />
    </quotas>
  </god>
</universe>

A factor of 0 disables the matching entries. Custom gamestarts have a matching property, universegodquotafactors, which no vanilla gamestart uses.

↑ Contents

Where: locations

<location> names the space an entry may use, a zone, a sector, a cluster or the whole galaxy, and filters the places inside it. Common vanilla locations:

The attributes:

Child elements narrow the choice further. Each may appear more than once:

With maxbound="false" on <economy>, <security> or <sunlight>, a space whose value lies above max still qualifies, as if its value were max; with the default maxbound="true" it is ruled out.

matchextension

By default an entry only uses spaces from its own extension. Base-game entries use base-game spaces, and an extension's entries use the spaces that extension adds; the rule dates from version 3.0. An extension that places objects in vanilla space, or in a DLC's space, has to set matchextension="false" on the location. The DLCs set it on entries placed in space they do not add themselves, such as the Split DLC's shipyard for the first tutorial.

The same holds for an entry that an extension replaces as a whole: the new entry belongs to the extension, even when it is an exact copy of the vanilla one. A replacement aimed at vanilla space needs matchextension="false" on its <location>, or the log reports no sectors in galaxy found and the entry creates nothing. See Adding entries from an extension.

A fixed position

<position x y z pitch yaw roll> puts the object at an exact spot:

↑ Contents

Staged stations

A construction plan can be divided into stages. An entry with such a plan builds the station up to a chosen stage, and the owning faction adds the remaining stages during play. Vanilla builds its prefab factories this way, from plan entries with ids such as arg_advancedcomposites_prefab_04_01.

Stages in a construction plan

In libraries/constructionplans.xml, bookmark="1" on an <entry> closes a stage with that module. Stage 1 runs from the first entry to the first bookmark, stage 2 up to the next one, and the entries after the last bookmark form the final stage. Vanilla's arg_advancedcomposites_prefab_04 has 55 entries with bookmarks on entries 15, 23 and 37, which makes four stages:

<entry index="15" macro="pier_arg_harbor_03_macro" connection="connectionsnap003" bookmark="1">

A staged plan needs its own habitation, docks and defence, as vanilla's prefab plans have, because nothing is added to it: vanilla's finaliser, the library cue NewStation_GenerateFactory in md/finalisestations.xml that both of its callers there run, leaves a station with a staged plan as it is. No schema describes bookmark; vanilla's plans are the reference.

The <stage> element

Inside the entry's <station> element, <stage> sets the stage the station is built to, as an exact value or a min to max range:

<station id="arg_advancedcomposites_prefab_04_01" ware="advancedcomposites" owner="argon" type="factory" priority="55">
  <quotas>
    <quota galaxy="2"/>
  </quotas>
  <location class="galaxy" macro="xu_ep2_universe_macro" faction="[argon, hatikvah]" relation="self" comparison="ge">
    <economy min="0.50" max="0.75" maxbound="false" />
  </location>
  <station constructionplan="arg_advancedcomposites_prefab_04">
    <stage min="1" max="4"/>
    <loadout>
      <level exact="0.7"/>
    </loadout>
  </station>
</station>

Each of the two stations from this entry starts with one to four of the plan's four stages, picked for each station separately. The schema describes <stage> as "the construction sequence stage index to initially expand this station to (defaults to 0)". In the script actions that take the same element, stage 0 stands for the whole sequence.

Every vanilla plan entry has a <stage>, mostly a range such as min="1" max="3". The schema allows it in station entries as well, which vanilla does not use.

A stage past the plan's last one gives an empty station. The station is created operational, with no modules and only a generic name such as BOR Factory, and nothing is logged. So exact and max have to stay within the plan's stage count. Of vanilla's 101 ranges, 69 end at the plan's last stage, 31 before it, and one after it: the Boron DLC's bor_hullparts_prefab_08_01 asks for min="4" max="8" on the seven-stage bor_hullparts_prefab_08, so a station from it can come out empty.

Fixed plans

A <plan> in constructionplans.xml can carry fixed="1". A staged station with a fixed plan grows only stage by stage, through the faction's regular expansion; without fixed="1", the faction can also extend it for a ware it needs. See the next section. Every plan that a vanilla plan entry names is fixed, and so are the plans of the Kha'ak scrap processors in vanilla's station entries.

No schema describes fixed on a plan. On a construction sequence, the property isfixed is true when the sequence "is flagged as fixed and cannot be adjusted", and the find actions take hasfixedconstruction, which matches a station whose current or planned sequence is flagged as fixed. A station built from a plan with fixed="1" has such a sequence.

Expansion during play

The owning faction builds the remaining stages during play, one stage at a time and hours apart. Vanilla's faction scripts do it in two ways:

So the stations of a staged entry keep growing after generation, and the faction can also place new ones from the same entry's plan. Since vanilla's prefab plans are all fixed, its staged stations grow through ExpandPrefabs only.

Checking stages from a script

Property Result
hasstagedconstruction the current or planned construction sequence has stages; also a filter of the find actions
hasfutureconstructionstage the sequence has stages that are not built yet
plannedconstruction.sequence the planned sequence, or the current one when no build is queued
.stage.count, .stage.current on a sequence: the number of stages, and the stage it is set to build to
.stage.{$n}.first, .stage.{$n}.last on a sequence: the indices of the first and last module of stage $n
.finalsequence on a sequence: a copy of the full staged sequence

On a staged station, constructionsequence covers only the stages already built, and the plan's stages are read from plannedconstruction.sequence: a station built to stage 4 of a seven-stage plan has a constructionsequence.stage.count of 4 and a plannedconstruction.sequence.stage.count of 7.

↑ Contents

When entries are used

New game

The entries of the chosen dataset are generated as described in How generation works. The save attribute of an extension's content.xml plays no part here: in a test, the same extension generated the same factories on two new games, once with save="false" and once with save="true". The attribute matters only on a load.

Loading a save

On every load the game compares the extensions enabled now with the extensions recorded in the save. Only the entries supplied by extensions that are new to the save are generated; when there are none, nothing is generated. A save records only the extensions with save="true" in their content.xml (see Anatomy of an extension), and only those count here. This has a few consequences:

Entries that start inactive

startactive="false" gives an entry an inactive starting state. Generation skips an inactive entry: nothing is created from it, on a new game or on a load. Creating an object from the entry with one of the create_god_* actions marks the entry active. Vanilla marks an entry inactive when only a script is meant to create its objects. The base game's tel_*_new and par_*_new production entries exist for saves made before 7.00 and sit next to active entries for the same wares: a cue in md/setup.xml creates them with create_god_factory when it patches such a save. The Timelines and Boron DLCs keep further inactive entries for their own scripts. There is no script action that switches an entry's active state.

Player starts on a god entry

A gamestart's player <location> can name a god entry with stationgodentry or shipgodentry, and the player then starts at the station, or on the ship, created from that entry. A Pirate DLC gamestart and several Timelines scenarios use it. When the entry is invalid or its object is not found, the game logs a message and tries a random station or ship.

↑ Contents

Adding entries from an extension

An extension patches god.xml with a diff file at the same path inside the extension, extensions/<extension folder>/libraries/god.xml, as all five DLCs do. The extension itself is covered in Anatomy of an extension, the patch syntax in XML diff patching.

A complete example: an extension named example_tradeposts that adds one Argon trading station anywhere in Argon space.

<?xml version="1.0" encoding="utf-8"?>
<diff>
  <add sel="/god/stations">
    <station id="example_tradepost_argon" race="argon" owner="argon" type="tradingstation">
      <quotas>
        <quota galaxy="1" />
      </quotas>
      <location class="galaxy" macro="xu_ep2_universe_macro" faction="argon" relation="self" comparison="ge" matchextension="false" />
      <station>
        <select faction="argon" tags="[tradestation]" />
        <loadout>
          <level exact="1.0" />
        </loadout>
      </station>
    </station>
  </add>
</diff>

Without matchextension="false" this entry would look for Argon space added by example_tradeposts itself, find none, and create nothing; the log would report no sectors in galaxy found. For the station to appear in running games as well, the extension's content.xml needs save="true"; see Loading a save.

Points to keep in mind:

Updating an extension

Version 1.10 of example_tradeposts adds a Paranid trading post, example_tradepost_paranid, to its diff. New games and saves without the extension get it from generation. Saves made with 1.00 do not, so the update adds an MD script in the extension's md/ folder (see Scripting/MD/Libraries/Map) that creates the station once, modelled on vanilla's own 9.00 patch cue Patch900Stations_SV in extensions/ego_dlc_split/md/setup_dlc_split.xml:

<?xml version="1.0" encoding="utf-8"?>
<mdscript name="ExampleTradePosts" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="md.xsd">
  <cues>
    <cue name="AddParanidTradePost" namespace="this">
      <conditions>
        <!-- once per game: on a new game, or on the first load with this script -->
        <event_cue_signalled cue="md.Setup.Start" />
        <!-- only in the main galaxy -->
        <check_value value="player.galaxy.macro == macro.xu_ep2_universe_macro" />
      </conditions>
      <delay exact="5s" />
      <actions>
        <find_station_by_true_owner name="$Existing" faction="faction.paranid" godstationentry="'example_tradepost_paranid'" space="player.galaxy" checkoperational="false" />
        <do_if value="not $Existing">
          <create_god_station groupname="$Created" id="'example_tradepost_paranid'" />
          <do_for_each name="$Station" in="$Created">
            <signal_objects object="player.galaxy" param="'init station'" param2="$Station" param3="false" />
          </do_for_each>
        </do_if>
      </actions>
    </cue>
  </cues>
</mdscript>

The find_station_by_true_owner check skips the creation when the station already exists, for example in a game where generation created it. create_god_station without state creates the station operational, so vanilla's InitGodCreatedStation initialises it one frame later: the station gets its trade wares, NPCs and AI, and the starting stock of a gamestart station. The example's own 'init station' signal, copied from vanilla's patch, repeats that init; a station does not need it, a factory does. See Creating from an entry.

Both examples in this article were tested in game on version 9.00.

↑ Contents

The script side

Creating from an entry

create_god_station, create_god_factory, create_god_ship and create_god_object create one object from the entry with the given id. They take name or groupname for the result and an optional state; without it, the schema says, the god entry's default is used. An unknown id logs Invalid god station entry ID: '...' (and the same for the other kinds), and the action returns nothing.

Vanilla finishes what these actions create as follows:

Events

event_god_created_station, event_god_created_factory, event_god_created_ship and event_god_created_object fire for every object the god engine creates. event.object is the space it was created in, and event.param is the new object. For a factory, event.param2 is the list of module macros and event.param3 the base construction sequence.

Properties

Property Result
isgodobject created by the god engine
isgodobjectentry, isgodshipentry, isgodstationentry, isgodproductionentry created from that kind of entry
isgamestartgodentry created by generation, on a new game or on a load
isrespawnablegodobject from an entry with respawnable="true"
godentry the entry id
godentryname the entry name
godentrytags, hasgodentrytag.{$tag} the tags of the entry's <category>
generationseed the seed defined by the object's source, such as the god engine, for use as seed in random evaluators; null if none

On a space, .god tells whether god entries may use it.

Finding objects by entry

find_station and find_station_by_true_owner take godstationentry and godproductionentry, find_ship takes godshipentry, and find_object takes godobjectentry and godentrytags. Vanilla's respawn logic in md/factionlogic_stations.xml uses godstationentry to check whether a respawnable station still exists before it calls create_god_station.

Construction plans

get_god_production_construction_plan (faction, product, space) and get_god_station_construction_plan (faction, type, space) look up construction plans from the production and station entries. Vanilla's economy scripts use the first to start a new staged factory where the faction has no staged station for the ware in the sector; see Expansion during play.

Allowing or blocking a space

set_space_god_allowed space="..." allow="false" stops god entries from using a space, and reset_space_god_allowed returns it to normal. A setting on a space overrides the one on its parent spaces.

Production quotas during play

The quotas also matter after generation. Vanilla's economy scripts call check_production_allowed before building new production; its comment says it applies the module compatibilities from modules.xml and the quotas from god.xml. A production module in modules.xml can set respectquota, described as "respect the god.xml quota definitions for this ware for the station's owner and location (defaults to true)"; in vanilla only the Pirate DLC sets it.

↑ Contents

Checking the result

The messages most likely to come up while writing entries:

Log message Meaning
GodDB::Import(): File '...' is an invalid god XML file A file that is not a diff has a root element other than <god>.
[GODDB] Error: God Entry : '...' is invalid because neither <quota> or <quotas> is defined. The entry has no quota.
[GODDB] Error: God Entry ID: '...' is invalid because <quotas> is empty. <quotas> has no <quota>.
[GODDB] Error: God Entry : '...' has a position defined but not a zone nor sector. <position> with a cluster or galaxy location.
[GODDB] Error: God Entry : '...' has a position defined but has multiple objects defined in its quota. A fixed position with a quota above one.
[GODDB] Error: God Entry ID: '...' has a fixed position but also location evaluators which may conflict. A position plus location filters.
[GODDB] Error: God Entry : '...' has a 'newzonechance' of ... while also having a specified zone. newzonechance on a zone entry; the value is ignored.
[GodObjectDB] Error: GodEntryID: '...' is invalid because the ID is not unique - an entry with that ID already exists. Duplicate id; the entry that comes later in the patched file is invalid. Station and object entries use this prefix, ship and production entries [GodShipDB] and [GodProductionDB].
... God Entry ID: '...' - Zone ... with fixed position ... is selected for placement but does not fully suit the location criteria The fixed position lies in a zone that does not pass all of the location filters.
... God Entry ID: '...' has a fixed map position flagged for safepos that places it in a hazardous region. ... A safepos position inside a hazardous region; the message suggests safepos="false" or allowhazardous.
[God Engine] God Entry ID: '...' no sectors in galaxy found, error in map? No sector matched the location's space at all. Most often an entry, or a whole-entry replacement, tied by the default matchextension to space its extension does not add.
[GodEngine] God Entry ID: '...' could not find sector '...'. The location's macro names no such sector; the same message exists for zones and clusters.
[GodProductionEntry] Error: GodEntryID: '...' is unable to find suitable locations for ... remaining productions. No space passed the location filters for the rest of the quota. Station entries log the same text with the [GodStationEntry] prefix.
... FactoryGenerator: No Station generated using group/ref/macro null and Ware ... No factory could be built for the ware named. One cause is a second production entry for the same owner and ware; see Adding entries from an extension.
[GodProductionEntry] God Entry ID: '...' station was not created for zone ... Follows the line above; the entry named creates nothing more.
... is unable to resolve a valid macro. The <select>, plan or module selection found nothing.
GodStationEntry() station id '...' in god.xml does not specify a valid owner, skipping! Bad owner; similar messages exist for race on stations, owner and ware on production entries, and owner on ships.
Unable to instance god station from entry ID: '...'. Creating an object from the entry failed; the same message exists for factories, ships and objects.
No matching god production entry for ware '...' (faction '...' in space '...'). A lookup by ware, faction and space found no production entry.
Invalid god station entry ID: '...' A create_god_station names no station entry; the same message exists for the other kinds, and the action returns nothing.

↑ Contents

Traps

↑ Contents