Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

component_events

Per-instance runtime for declared component events. A component's events block (built with Event(...), see event.module) is a schema: a map of event name to descriptor. This module turns that schema into the live objects an instance actually fires and listens on.

Three faces, one Signal

Each declared event resolves to one signal.module Signal, reachable through three tables that share it:

  • buildSignals(schema) returns the private, fire-capable table (:Fire, the raw Signal method). Engine-internal — never handed to user code directly.
  • buildEmitter(signals, schema) returns the owner-side emitter, bound into the declaring component's own env as events. Each entry has :fire(payload) only — lowercase, symmetric with the facade — and validates the payload against the event's declared members before dispatch. The component's own code fires with events.onHit:fire({ dmg = 10 }).
  • buildFacade(signals) returns a subscribe-only view over the same table, exposed to outside callers through the ComponentProxy's .events key. Each entry has :connect(fn) / :once(fn) / :wait() — no :fire.

setup(schema) builds all three in one call and returns { signals, emitter, facade }; the engine calls it once per instance.

local schema  = { onHit = { payload = { dmg = Field.number(0, NoSync) }, sync = false } }
local runtime = component_events.setup(schema)

-- inside the component's own code (env global `events` is runtime.emitter):
events.onHit:fire({ dmg = 10 })

-- outside code, through the proxy (proxy.events is runtime.facade):
proxy.events.onHit:connect(function(p) print("hit for", p.dmg) end)

Fire authority by construction

buildFacade never returns the underlying Signal object, only a fresh table exposing connect / once / wait. There is no fire method to find on the facade at any key, so outside code cannot fire a component's events no matter what it holds a reference to. Firing authority lives only with the owner, through the emitter's env events global.

Both tables reject access to an undeclared event name: the private table's metatable raises on a bad key, and the facade raises on a bad key too, so a typo surfaces immediately instead of silently returning nil.

Cleanup

Connections made through the facade are ordinary signal.module connections, tracked and torn down the same way as any other signal connection: entity_signals.module disconnects everything sourced from an entity when that entity is destroyed. Component events carry no separate cleanup path.