Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

Assembly

Holds what fills every slot at and under its entity: a vehicle whose wheel, engine, seat and light slots parts fill, a mech with weapon hardpoints, a ship or a modular building assembled from parts, a character with equipment points. Put it on the root the slots belong to; the slots are the Slot components on that entity and its descendants, and the role sockets of any Humanoid among them (righthand, head, ...), which a part fills the way Humanoid:attach seats an item.

The configuration

config maps each slot's path to the guid of the part filling it, or to false for a slot left empty. A slot it does not name holds the slot's default. A part's own slots nest under the slot it fills (engine/turbo), so one table describes the whole assembled object. A path naming a slot of a part that is not built at the moment (the engine was swapped away) stays in the table and applies when that part is back.

config is a synced, saved field, which gives the slot family its behaviour:

  • Undo. Each fill, empty and configure is one undoable step; undo puts the previous part back.
  • Multiplayer. The entity's owner writes it and every peer builds the same parts from it. A peer that does not own the entity is refused with the owner's id.
  • Saving. The configuration is saved with the scene, and the parts are rebuilt from it when the scene loads. The parts themselves are runtime children and are never written into the scene.

Changing what one slot holds rebuilds that slot's part (and the parts in its slots) and nothing else: every other part, its entities and their state stay.

Methods

MethodReturnsNotes
:fill(path, part)entity or nilFill a slot; part is an AssetRef, identity, guid or path, nil returns the slot to its default. Raises when the part does not fit, naming why, or when no slot answers to the path, listing the slots.
:empty(path)Leave a slot empty, its default included.
:configure(config)Replace the whole configuration. Keys are slot paths; a value is a part, false, or { part = ..., <slot> = ... } for a part and its own slots. Nothing changes when any part does not fit; the refusal names each.
:resolve()treeEvery slot: { path, name, kind, tags, from, part, guid, source, fill, slot, slots }. source is config, default, empty or none; fill the entity the part was built on; slots the slots of that part.
:slot(path)report or nilOne slot as resolve reports it.
:fits(path, part)(boolean, string)Whether a part fits a slot, and why or why not.
:candidates(path){ { identity, guid, name } }The bundles this world holds that fit a slot.
:refresh()Rebuild every slot whose part differs from the configuration.

An Assembly on a part's root (so the part can be assembled on its own too) passes its calls, once the part is built into a slot, to the Assembly holding that part, with its paths under the slot the part fills. Any other Assembly below this one holds its own slots: an assembled car parented onto a truck, or an assembled item a character holds through Humanoid:attach, keeps its own configuration, and the Assembly above leaves its slots alone.

Usage

local asm = car.component.get("Assembly")

-- One configuration for the whole car
asm:configure({
    wheel_fl = "parts.SportWheel", wheel_fr = "parts.SportWheel",
    wheel_rl = "parts.SportWheel", wheel_rr = "parts.SportWheel",
    engine = { part = "parts.V8", turbo = "parts.Turbo" },
    seat = "parts.BucketSeat",
})

-- Swap one part: only the front-left wheel is rebuilt
asm:fill("wheel_fl", "parts.OffroadWheel")

-- Why does a part not fit?
print(asm:fits("wheel_fl", "parts.V8"))  -- false, "slot 'wheel_fl' takes parts of kind 'wheel'; 'parts.V8' fits { engine }"

-- What fills what
for _, s in ipairs(asm:resolve()) do
    print(s.path, s.part, s.source)
    for _, inner in ipairs(s.slots) do print("  ", inner.path, inner.part) end
end

-- What could go in the engine slot?
for _, p in ipairs(asm:candidates("engine")) do print(p.identity) end

The Slot README covers declaring slots and the Part README declaring what a part fits.