MultiConstructor¶
Vanilla MultiConstructor : Stackable, IConstructionKit, IConstructionStarter, IReferencable, IEvaluable at Assets.Scripts.Objects.MultiConstructor. The held-item kit form for placing one of N prefab variants (rail-kit with 8 pieces, etc.). Sibling to Constructor (single-prefab kit).
Class layout¶
public class MultiConstructor : Stackable, IConstructionKit, IConstructionStarter, IReferencable, IEvaluable
{
[Header("Multi-Constructable")]
public List<Structure> Constructables = new List<Structure>();
[NonSerialized]
public int LastSelectedIndex;
public override void OnPrefabLoad() // strips null entries from Constructables, clamps LastSelectedIndex
public virtual void Construct(Grid3, Quaternion, int optionIndex, Item offhandItem, bool authoringMode, ulong, [int quantity])
public override string GetStationpediaCategory() => Localization.GetInterface(StationpediaCategoryStrings.KitCategory);
public bool CanBuild(int index) // checks Quantity >= Constructables[index].BuildStates[0].Tool.EntryQuantity
public List<Thing> GetConstructedPrefabs()
}
Constructables is a serialized list of every prefab the kit can place (e.g. all 8 rail variants for the rail-kit). LastSelectedIndex persists which variant the player last picked, so swapping back to the kit reopens on the same option.
Construct¶
Two overloads. The arity-7 form looks up the EntryQuantity for the chosen variant and forwards to the arity-8 form.
public virtual void Construct(Grid3 localPosition, Quaternion targetRotation, int optionIndex, Item offhandItem, bool authoringMode, ulong steamId)
{
int entryQuantity = Constructables[optionIndex].BuildStates[0].Tool.EntryQuantity;
Construct(localPosition, targetRotation, optionIndex, offhandItem, authoringMode, steamId, entryQuantity);
}
public virtual void Construct(Grid3 localPosition, Quaternion targetRotation, int optionIndex, Item offhandItem, bool authoringMode, ulong steamId, int quantity)
{
if (authoringMode || OnUseItem(quantity, null))
{
CreateStructureInstance createStructureInstance = new CreateStructureInstance(Constructables[optionIndex], localPosition, targetRotation, steamId);
if (PaintableMaterial != null && CustomColor.Normal != null)
{
createStructureInstance.CustomColor = CustomColor.Index;
}
if (GameManager.RunSimulation)
{
Constructor.SpawnConstruct(createStructureInstance);
}
}
}
Identical Quaternion handling to Constructor.Construct: the incoming targetRotation is stored in CreateStructureInstance.LocalRotation and forwarded to Constructor.SpawnConstruct. Note the asymmetry: MultiConstructor.Construct only calls SpawnConstruct when GameManager.RunSimulation == true, omitting the client-side new ConstructionCreationMessage(...).SendToServer() branch. Multi-kit placement on a remote client therefore relies on the calling code (e.g. InventoryManager.PlacementMode) to dispatch the network message via OnServer.UseMultiConstructor(...) rather than going through this method.
Differences from Constructor¶
| Aspect | Constructor | MultiConstructor |
|---|---|---|
| Built prefab | One: BuildStructure |
One of N: Constructables[optionIndex] |
| Per-prefab quantity | QuantityUsed (single int field) |
Constructables[i].BuildStates[0].Tool.EntryQuantity (per-variant) |
OnUsePrimary override |
Yes; calls Construct(targetLocation.ToGridPosition(), targetRotation, ...) |
None; placement dispatched at the inventory layer |
| Client network branch in own code | Yes: new ConstructionCreationMessage(...).SendToServer() |
No; relies on caller |
Constructables mutation hook |
n/a | OnPrefabLoad strips nulls, clamps LastSelectedIndex |
For mod patterns that need to insert a new variant into an existing rail-kit / wall-frame-kit, see Patterns/PrefabCloning.md "AddToConstructor" (the recipe that calls mirrorDef.constructor.Constructables.Insert(insertIndex + 1, mirroredDevice as Structure)).
They are siblings, not parent and child¶
MultiConstructor does not derive from Constructor. Both derive from Stackable and meet only at the IConstructionKit interface:
public class Constructor : Stackable, IConstructionKit // 301144
public class MultiConstructor : Stackable, IConstructionKit, IConstructionStarter, IReferencable, IEvaluable // 312705
Line numbers are the 0.2.6428.27798 decompile. The consequence is for any code that walks ElectronicReader.GetAllConstructors(thing) (which returns List<IConstructionKit>) and tries to prefer the single-prefab kit:
kit is Constructoris a correct and exact discriminator: it is true for aConstructorand false for aMultiConstructor, with no inheritance overlap to worry about either way.- But for a target whose only kit is a
MultiConstructor, the preference branch never fires and the code falls through to whatever its fallback is, typicallykits[0]. Cables and pipes are exactly that case, so a "prefer aConstructor" branch is dead code on the two most commonly painted prefab families in the game and cannot be exercised by testing against them. Pick a kit-built Structure with a single-prefab kit (a ladder, a wall frame) to cover that branch.
./Thing.md, "Lookup for a placed Structure (kit was involved)", carries the reverse-lookup recipe this matters to, and now records what a cable resolves to.
Verification history¶
- 2026-04-25: page created from a six-agent decompile pass on the placement pipeline. Source content lifted verbatim from
/tmp/decompile_check/Assets/Scripts/Objects/MultiConstructor.cs. No conflicts. - 2026-09-24 (game version 0.2.6428.27798): added "They are siblings, not parent and child" under "Differences from Constructor". Both class declarations re-read against the current decompile (
Constructor301144,MultiConstructor312705): both derive fromStackableand share onlyIConstructionKit, soMultiConstructoris not a subclass ofConstructor. Additive; the page's opening line already called them siblings, and nothing on the page claimed otherwise, so no fresh validator. Recorded because the consequence is not obvious from either page: code that prefers aConstructorwhen walkingElectronicReader.GetAllConstructorshas a branch that can never fire for a cable or a pipe, whose only kit is aMultiConstructor. Found while covering the Spray Paint Plus eyedropper's as-built pick, which is written that way and was being tested against cables.
Open questions¶
None.