EventDispatcher<L extends GameListener, E> class
final
A pre-resolved set of listeners for one event type.
This is the whole point of the event system, and the thing the old one got
wrong. Dispatch used to walk - from object to object at runtime, type
testing each candidate, so a class that could never accept an event was
still visited and still checked, every time. Here the walk happens once,
at boot: EventDescriptor.has creates the dispatcher and the collect
pass fills it, so by the time an event is dispatched the receivers are
already known and dispatch is an indexed loop over a plain list.
Scope is the declaring owner
A dispatcher belongs to whoever declared it in describeEvents, and it
collects from that owner's composition and no further. Declared on an
EntityStruct, it reaches that struct's listeners only - which is what
makes onEntityMounted on MyPlayer fire for MyPlayer entities and
nothing else. Declared on a GameState, the same event reaches everything
beneath it, because a GameState collects from its scenes and a scene
from its prefabs.
There is no event object
Delivery is a closure captured once, at declare time, rather than a method on an event class:
late final EventDispatcher<EntityLifecycleListener, Entity> entityMounted;
@override void describeEvents(EventDescriptor d) {
super.describeEvents(d); entityMounted =
d.has((listener, entity) => listener.onEntityMounted(entity)); }
// and firing it:
entityMounted.call(entity);
This replaced a GameEvent<L> class per event with a dispatchListener
override. That design still allocated: an event carrying a payload had to
be constructed per dispatch, so the spawn path built one object per entity
and the tick built one per frame. Passing the payload as an argument
removes the object entirely - zero allocation per dispatch, whatever the
payload (the hot-path rules). The closure is built once during
describeEvents, which rule 5 explicitly permits.
It also deleted eight classes: an event that carries a Duration is now
EventDispatcher<Tickable, Duration> and needs no type of its own.
E is the payload type. For an event that carries nothing, see
SignalDispatcher and EventDescriptor.hasSignal.
Properties
- hashCode → int
-
The hash code for this object.
no setterinherited
- listenerCount → int
-
How many listeners were collected. Diagnostics and tests - the point of
the design is that this number is settled before the first dispatch.
no setterinherited
- reverse → bool
-
Whether to deliver in reverse collection order.
final
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
call(
E payload) → void -
Delivers
payloadto every collected listener that is currently listening, in collection order. -
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited