Skip to content

Build module

A Build module is a station Module that builds ships and equipment. It’s the engine inside every Shipyard, Wharf, Equipment dock, and player Plot — the actual construction happens here. Build modules contain one or more Build processors which run individual build tasks.

Build module is the most complex module datatype — 50+ accessors covering capability filters, ongoing-build queries, construction-vessel state, and per-category equipment restrictions.

Inheritance: component → destructible → module → walkablemodule → buildmodule.

The datatype is dense; group by concern.

Build processors (the actual build engines)

Section titled “Build processors (the actual build engines)”
PropertyTypeDescription
.buildprocessorbuildprocessorA contained build processor
.buildprocessorslistAll contained build processors
.freebuildprocessorbuildprocessorA free processor (not currently building)
.freebuildprocessorslistAll free processors
.isbusyboolALL processors are building
.isbuildingboolANY processor is building
PropertyTypeDescription
.canbuildclass.{class}boolCan build objects of this class
.canequipclass.{class}boolCan equip objects of this class
.cansupplyclass.{class}boolCan supply ammo/drones for this class
.canbuildequipment.{ware}boolCan install this specific equipment ware
.canbuildequipment.{list}boolCan install all wares in list
.canbuildmacro.{macro}boolCan build this specific macro

Buildable wares (whitelist / blacklist style)

Section titled “Buildable wares (whitelist / blacklist style)”
PropertyTypeDescription
.buildequipment.wareswarelistAll equipment this module can build (default + included - excluded)
.buildequipment.absolutewarelistAbsolute override list
.buildequipment.includedwarelistAdds on top of default
.buildequipment.excludedwarelistRemoves from default
.buildships.wareswarelistAll ships this module can build
.buildships.absolute / .included / .excludedwarelistSame overrides for ships
.buildmacroslistList of macros buildable

The .buildequipment.X family is split by equipment type:

PropertyWhat it returns
.buildequipment.countermeasuresCountermeasure wares
.buildequipment.dronesDrone wares
.buildequipment.enginesEngine wares
.buildequipment.lasertowersLasertower wares
.buildequipment.minesMine wares
.buildequipment.missilesMissile wares
.buildequipment.navbeaconsNav beacon wares
.buildequipment.resourceprobesResource probe wares
.buildequipment.satellitesSatellite wares
.buildequipment.shieldsShield wares
.buildequipment.softwareSoftware wares
.buildequipment.thrustersThruster wares
.buildequipment.turretsTurret wares
.buildequipment.weaponsWeapon wares
PropertyTypeDescription
.requiresconstructionvesselboolBuild requires a construction vessel right now
.mayrequireconstructionvesselboolBuild may need a vessel (tentative — .requiresconstructionvessel is authoritative once known)
.iswaitingforconstructionvesselboolHas resources / storage but is blocked on vessel arrival
.iswaitingforresourcesboolBlocked on input wares
.iswaitingforstorageboolBlocked on output storage space
.constructionvesselshipCurrently-deployed vessel, if any
.constructionvesseldeployedboolVessel is on-station
PropertyTypeDescription
.constructingcomponentslistAll components currently being constructed
.constructingmodulecomponentModule currently under construction
.buildstoragebuildstorageLinked build storage (raw materials)
.buildanchorcomponentAnchor point for builds
PropertyTypeDescription
.buildresources.{build}wareamountlistTotal resources for a build (or remaining if in-progress)
.neededbuildresources.{build}wareamountlistResources still needed for a build
PropertyTypeDescription
.numdocks.{docksize}intPer-size dock count (inherited from module)
.dock.{docksize}dockingbayA suitable dock for this size (may be occupied)
.freedock.{docksize}dockingbayA free suitable dock

Each build module contains one or more buildprocessor components. The processor is the active build enginebuildmodule.buildprocessor.build is the current build task; buildmodule.buildprocessor.queuedbuild is the next.

Processor accessors mirror most of the buildmodule’s, plus time-tracking:

PropertyTypeDescription
.buildmodulebuildmoduleContaining module
.buildbuildCurrent build task
.queuedbuildbuildNext queued build
.elapsedtimetimeTime spent on current build
.elapsedsteptimetimeTime spent on current step
.steptimetimePer-step time
.totaltimetimeTotal estimated time
.canabortbuildboolCurrent build can be cancelled
.stepresourceswareamountlistResources per step
.laststepresourceswareamountlistResources for final step (may differ due to rounding)
.neededslotresourceswareamountlistResources needed for current build slot
.neededsequenceresourceswareamountlistResources for the whole sequence
.recycledwareamountlistResources reclaimed during recycling builds

Plus the same .canbuild* / .buildequipment.X family inherited from the module.

<add_build
object="$BuildModule"
macro="$ShipMacro"
faction="faction.player"/>

Append modules to a station via the canonical pipeline

Section titled “Append modules to a station via the canonical pipeline”
<create_construction_sequence
station="$Station"
macros="$NewPlannedModules"
connectors="$Connectors"
base="$BaseSequence"/>
<apply_construction_sequence
station="$Station"
sequence="$ConstructionSequence"/>

Pattern from vanilla finalisestations.xml:91-160, diplomacy.xml:311-347. This is THE pipeline for adding new modules to an existing station.

<add_build_to_expand_station
object="$Station.buildstorage"
buildobject="$Station"
constructionplan="$ConstructionPlan"
result="$BuildID"/>

Pattern from factionsubgoal_buildstation.xml:211, finalisestations.xml:359. Required for staged stations in X4 9.0+<create_construction_sequence> errors on stations with .hasstagedconstruction=true. Use the add_build_to_expand_station pathway instead.

Restrict / extend what a station can build

Section titled “Restrict / extend what a station can build”
<!-- Replace the entire list (absolute) -->
<set_equipment_wares_absolute
container="$Container"
wares="[ware.X, ware.Y]"/>
<!-- Add on top of defaults -->
<set_equipment_wares_included
container="$Container"
wares="[ware.X]"/>
<!-- Remove from defaults -->
<set_equipment_wares_excluded
container="$Container"
wares="[ware.X]"/>
<!-- Same family for ships -->
<set_ship_wares_absolute container="$Wharf"
wares="[ware.ship_arg_m_corvette_01_a]"/>

Read back via .buildequipment.absolute / .included / .excluded / .wares (effective list).

<do_if value="$BuildModule.isbusy">
<!-- all processors building -->
</do_if>
<do_if value="$BuildModule.isbuilding">
<!-- at least one processor active -->
</do_if>

.isbusy is AND, .isbuilding is OR — easy to confuse.

There is no event_buildmodule_X family. Builds are observed through:

EventWhenNotes
event_object_construction_sequence_createdA new sequence applied to a stationHeavy vanilla use in finalisestations.xml
event_object_destroyedBuild module destroyedFilter event.object.isclass.{class.buildmodule}

Per-build completion: there’s no event_build_finished. Watch the parent station’s product list for new ships appearing, or poll buildprocessor.build for null transitions.

  • In X4 9.0, create_construction_sequence errors on stations with .hasstagedconstruction=true. Guard with do_if value="not $Station.hasstagedconstruction" or use <add_build_to_expand_station> instead. From memory + finalisestations.xml vanilla pattern.
  • .isbusy (AND) vs .isbuilding (OR). Two processors with one building shows isbuilding=true, isbusy=false. Pick the right one.
  • .requiresconstructionvessel vs .mayrequireconstructionvessel. The first is authoritative once the build is checked; the second is a forward-looking tentative read. Use the authoritative one for “can this start now”.
  • .canbuildmacro.{$macro} requires a wareref, not a string id. Same as Shipyard gotcha — pass macro.X, not "X".
  • set_equipment_wares_* operates at the build module level, not the station. A station with multiple equipment build modules needs you to target each. Or use the container-level shortcuts (Station.canbuildequipment.{$ware}) for reads.
  • .buildequipment.wares effective list reflects ALL overrides. It’s (default + included) - excluded. To know what was explicitly set, read .absolute / .included / .excluded separately.
  • Build processors are NOT independent objects. They are sub-components of the build module — accessed via the module, not via find_object class=class.buildprocessor.
  • iswaitingforresources and iswaitingforstorage are distinct stall reasons. Mods that monitor builds should check both.

Example 1: Find busy build modules in player shipyards

Section titled “Example 1: Find busy build modules in player shipyards”
<find_station_by_true_owner name="$Stations"
space="player.galaxy"
faction="faction.player"
multiple="true"/>
<set_value name="$Building" exact="0"/>
<do_for_each name="$s" in="$Stations">
<do_for_each name="$mod" in="$s.modules">
<do_if value="$mod.isclass.buildmodule
and $mod.isbuilding">
<set_value name="$Building"
operation="add" exact="1"/>
</do_if>
</do_for_each>
</do_for_each>
<write_to_logbook
text="$Building + ' build modules active'"/>

Example 2: Detect build stalled on construction vessel

Section titled “Example 2: Detect build stalled on construction vessel”
<cue name="WatchStalledBuilds" instantiate="true">
<conditions>
<event_cue_signalled cue="this"/>
</conditions>
<actions>
<find_station_by_true_owner name="$Stations"
space="player.galaxy"
faction="faction.player"
multiple="true"/>
<do_for_each name="$s" in="$Stations">
<do_for_each name="$mod" in="$s.modules">
<do_if value="$mod.isclass.buildmodule
and $mod.iswaitingforconstructionvessel">
<write_to_logbook
text="$s.knownname
+ ' waiting for construction vessel'"/>
</do_if>
</do_for_each>
</do_for_each>
</actions>
</cue>

Example 3: Expand a player HQ with new modules (X4 9.0+ safe)

Section titled “Example 3: Expand a player HQ with new modules (X4 9.0+ safe)”
<create_construction_sequence
station="$HQ"
macros="$NewModules"
base="$HQ.plannedconstruction.sequence"
comment="async calculation"/>
<!-- ... event_object_construction_sequence_created fires ... -->
<do_if value="not $HQ.hasstagedconstruction">
<apply_construction_sequence
station="$HQ"
sequence="event.param"/>
</do_if>
<do_else>
<add_build_to_expand_station
object="$HQ.buildstorage"
buildobject="$HQ"
constructionplan="event.param"
result="$BuildID"/>
</do_else>

Pattern from diplomacy.xml:311-347 + memory note about staged-construction guard.

  • Station construction pipeline: Architectural overview Construction sequencecreate_construction_sequenceevent_object_construction_sequence_createdapply_construction_sequencesignal_objects 'init station'. The full bootstrap.
  • Build module placement decisions: Architectural overview Faction economy — NPC factions decide which build module variants to add based on shortage signals.
  • Player-driven station expansion: Architectural overview Plot expansion UX — how the player’s drag-modules-into-plot flow translates into MD-side build module additions.
  • Construction vessel lifecycle: Architectural overview Construction vessel — when needed, dispatch, deployment, return.