Child Entities
Child entities give you a clean, logical way to bind related entities together so you can traverse and manage them as a tree. Add a child to a parent and you instantly get:
On the child:
.parent(and.root) to reach back up the tree.On the parent:
.childrenplus helpers likegetChild,getChildBy,getChildrenBy, andremoveChild.
Child entities are declared on the server and are automatically converted as instances and available on the client via state. This keeps server authority while still giving the client read-friendly access to the structure.
Why use child entities?
Simple traversal:
car:getChild("engine")orcar:getChild("wheels/frontLeft").Strong locality: Each feature (e.g., door/engine/wheel) lives as its own entity with its own lifecycle, methods and attributes, yet stays discoverable from its parent.
Reliable: Accurately retrieve an entity child, create links, and ensuring access aligns with expectations.
Predictable sync: Child links are written to the parent’s state (
state.children[name] = child.id) so clients always see the same structure.Safer code: The API prevents adding children that aren’t created yet, catching mistakes early.
Key concepts at a glance
Parent/Child/Root
child.parentis set automatically byaddChild.child.rootis the topmost ancestor (useful for cross-feature coordination).parent.childrenis a name > entity map.
Server > Client
Server uses
addChildwhich updatesself.state.children.Clients read the structure from state when requested and resolve the client instances
Quick start
Create entities (server)
local car = new Car(vector3(0,0,0))
local engine = new Engine(vector3(0,0,0))
local piston = new Piston(vec3(0,0,0))
local sparkPlugs = new SparkPlugsvector3(0,0,0))
local exhaust = new Exhaust(vector3(0,0,0))
Attach children
car:addChild("engine", engine)
engine:addChild("piston", piston)
engine:addChild("sparkPlugs", sparkPlugs)
engine:addChild("exhaust", exhaust)Under the hood this sets:
engine.parent = carandengine.root = carcar.children["engine"] = enginecar.state.children["engine"] = engine.id(so clients auto-see it)And the same for all engine components
Use it (client or server)
local engine = car:getChild("engine")
local piston = car:getChild("engine/piston")
-- OR
local piston = engine:getChild("piston")
-- Search helpers (examples)
local anyDoor = car:getChildBy("__type", "Door")
local damagedWheels = car:getChildrenBy("health", function(h) return h and h < 0.5 end)</> API reference
addChild(name: string, child: BaseEntity) SERVER
SERVERAdd an entity as child of this entity under the specified name.
children can be accessed using the methods or directly with self.children
removeChild(childOrName: BaseEntity | string) SERVER
SERVERDetach a child entity by instance or by name.
getChild(path: string) CLIENT SERVER
CLIENT SERVERFetch a child entity by name or by slash-separated path:
car:getChild("engine")
car:getChild("engine/piston")When you use a slash-separated path, it's just syntax sugar for chained calls:
car:getChild("engine/piston")
-- is equivalent to:
car:getChild("engine"):getChild("piston")
getChildBy(key: string, value) CLIENT SERVER
CLIENT SERVERFinds the first child by a custom field, value can also be a function working as a filter.
whose child[key] == value or satisfies value as a function value(child[key]).
getChildrenBy(key: string, value) CLIENT SERVER
CLIENT SERVERReturns a name > child dictionary table of all matches, similar to Child Entities but doesnt stop at first match
Tips
Attach during OnAwake Use it to attach children so the full tree is reliably ready when
OnSpawnfires.Root awareness If a child needs to coordinate with siblings in other branches, use
self.rootto get the top entity and query from there.
Last updated