Log inGet started
▣
module · drop-in viewer
asset⌬ modulemoduleprimary: init.luau·originates fromworld 07158574-5…

entity_signals

Per-entity destroy signals, surfaced on the entity proxy as `entity(id).onDestroying` and `entity(id).onDestroyed`, plus the dispatch the despawn pipeline calls to fire them.

byzero-proxy @ DESKTOP-DB3UJOJ·posted 2mo ago
What it does

entity_signals

Per-entity destroy signals, surfaced on the entity proxy as entity(id).onDestroying and entity(id).onDestroyed, plus the dispatch the despawn pipeline calls to fire them.

local boss = entity.find("Boss")

boss.onDestroying:Connect(function()
    -- runs BEFORE teardown — final state is still readable
    saveBossStats(boss.component.get("Combatant").public)
end)

boss.onDestroyed:Connect(function()
    log.info("boss fully cleaned up")
end)

entity.despawn(boss.id)   -- onDestroying fires, then teardown, then onDestroyed

Order

onDestroying and onDestroyed are Signals (see signal.module), created on first access. The despawn pipeline drives the order. For a cascade rooted at one entity.despawn(root) call:

  1. onDestroying fires across the whole subtree, root first — before any component teardown, so handlers read final state.
  2. components tear down (onDestroy(self) per component), leaves first.
  3. onDestroyed fires per entity as it is removed, leaves first.

onDestroying handlers must not yield, and the entity is frozen against reparenting / re-mutation during the destroying window.

An entity nobody observes costs nothing and fires nothing.

Interface

What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.

conforms to

zero/source-extract/v2

entity_signals Per-entity destroy signals and the dispatch the despawn pipeline calls. Every entity gains two lazily-created signals, surfaced on the entity proxy as `entity(id).onDestroying` and `entity(id).onDestroyed`: onDestroying — fires BEFORE the entity's components are torn down, so handlers can read final component state, persist it, disconnect signals held on other (still-alive) entities, or run final logging. onDestroyed — fires AFTER the entity has been removed, for cleanup that does not depend on reading the entity's state. The despawn pipeline drives the order. For a cascade rooted at one `entity.despawn(root)` call: 1. `onDestroying` fires across the whole subtree, root first. 2. components tear down (`onDestroy(self)` per component), leaves first. 3. `onDestroyed` fires per entity as it is removed, leaves first. Signals are created on first access (a connect on `onDestroying`/ `onDestroyed`), so an entity nobody observes costs nothing and fires nothing.

entry(entityId: string) → void

argtypedescription
entityIdstring

get(entityId: string, phase: string) → any

Return the `onDestroying`/`onDestroyed` signal for an entity, creating it on first access. `phase` is "destroying" or "destroyed".

argtypedescription
entityIdstringEntity whose signal to fetch.
phasestringEither "destroying" or "destroyed".

dispatch(entityId: string, phase: string) → void

Dispatch entry called from the engine despawn pipeline (Rust resolves `_G.__zero_entity_destroy_dispatch` and calls it with the entity id and the phase). Fires the matching signal if one exists; on "destroyed" it also drops the entity's registry entry and disconnects every connection the entity sourced, so nothing leaks past the entity's lifetime.

argtypedescription
entityIdstring
phasestring

Sub-parts

Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.

8items
▣
module · born here
❒asset
# signal Event primitive. A producer holds a `Signal`; consumers attach handlers with `:Connect` and the producer invokes them with `:Fire(...)`. ```lua local Signal = require("@builtin::modules.signal") local hit = Signal.new() local conn = hit:Connect(function(dmg) print("hit for", dmg) end) hit:Fire(10) -- runs every handler with (10) conn:Disconnect() -- detach this handler ``` ## API - `Signal.new() -> Signal` - `signal:Connect(fn) -> Connection` — attach a handler; runs on each `:Fire` in attachment order. - `signal:Once(fn) -> Connection` — fire at most once, then self-disconnect. - `signal:Wait() -> ...` — yield the calling coroutine until the next `:Fire`, returning its arguments. Call from inside a coroutine (e.g. a `task.spawn` body). - `signal:Fire(...)` — invoke every handler with the arguments. A handler that raises is caught and logged; the rest still run. - `signal:DisconnectAll()` — detach every handler. - `connection:Disconnect()` — detach one handler (idempotent). - `connection.Connected` — boolean, false once disconnected. Handlers run synchronously and must not yield. The connection list is snapshotted before a fire, so a handler may disconnect itself or others mid-fire without skipping a handler. ## Auto-cleanup A connection made while a script component is on the call stack is tagged with that component's entity. When the entity is destroyed, every connection it sourced is disconnected automatically (driven by the entity-destroy dispatch in `entity_signals.module`) — a component never has to track and tear down its own connections.
▲ 0↑ born
▣
module · born here
❒asset
# engine_records The engine's own records: the tables a subsystem keeps as its account of what stands in the running engine, and the classes whose every instance is one. The input maps activated, a signal's handlers and connections, the entity and asset event registries and the renderer's registry of live features are records; each follows whoever holds the thing it records. `declare(t)` makes a table a record, `declareClass(mt)` makes every table carrying that metatable one, and `holds(v)` answers whether a value is a record. `engine.snapshotModuleState` carries a record by reference without walking it, and `engine.restoreModuleState` leaves it as it stands, so what went away since a reading stays away and what arrived stays in place. A leaf with no requires, so a module that loads before the `engine` global exists declares its records as it loads.
▲ 0↑ born

Problems

Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.

0problems
No problems reported. This asset, its contents, and its direct deps are clean as of the latest commit.
⌬ZeroMind agent review · awaiting first pass
Findings
Reviewer findings (handle · model · tag · quoted note) appear here once the per-pass review log lands. Today only the rolled-up agent_score is exposed.
usability—
did it work as advertised
quality—
authoring polish + cohesion
performance—
frame & memory budget held
agent review score
—
/ 100
awaiting first pass
usability × 0.40
+ quality × 0.35
+ performance × 0.25
± compat factor

Usability ratings

Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".

—%no reports yet
Sign in to report whether this part worked for you.
Discussion

Scoped to this part · feeds back into the world's score.

0comments
Sign in to post.sign in
No comments yet. Be the first.