@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
109 lines • 4.28 kB
TypeScript
/**
* Sentinel sender id for actions that originated on the local peer (not
* received over the wire). Used as the default `sender_id` for
* {@link SimActionExecutor#execute} so existing single-peer code keeps
* working. Valid peer ids must therefore be in `[0, 254]`.
*
* @type {number}
*/
export const SENDER_LOCAL: number;
/**
* The single legitimate gateway for replicated state mutations.
*
* On `execute(action, sender_id)`:
* 1. Iterate `action.affected_components((entity_id, component_class) => ...)`.
* For each, look up the live component on `world`, look up its replication
* adapter via the binary registry, and write
* `(entity_id, component_type_id, payload_len, payload)` into the current
* frame's `ActionLog` buffer.
* 2. Call `action.apply(world)`.
* 3. Append `(action_type_id, sender_id, action_payload_len, action_payload)`
* to the same frame's buffer. `sender_id` is the peer that originated
* the action — used by rollback orchestrators for stable-sort tie-
* breaking when reconstructing per-tick action order. Defaults to
* {@link SENDER_LOCAL} for actions generated by this peer.
*
* Code outside the executor that wants to mutate replicated state is doing it
* wrong: such mutations will not be replicated, will not be reversible, and
* will desync clients on rollback. Use a `SimAction`.
*
* @author Alex Goldring
* @copyright Company Named Limited (c) 2025
*/
export class SimActionExecutor {
/**
* @param {{
* world: EntityComponentDataset,
* action_log: ActionLog,
* action_registry: SimActionRegistry,
* component_registry: ReplicatedComponentRegistry,
* slot_table: ReplicationSlotTable,
* changed_entities?: ChangedEntitySet,
* }} options
*/
constructor({ world, action_log, action_registry, component_registry, slot_table, changed_entities }: {
world: EntityComponentDataset;
action_log: ActionLog;
action_registry: SimActionRegistry;
component_registry: ReplicatedComponentRegistry;
slot_table: ReplicationSlotTable;
changed_entities?: ChangedEntitySet;
});
/**
* @type {EntityComponentDataset}
*/
world: EntityComponentDataset;
/**
* @type {ActionLog}
*/
action_log: ActionLog;
/**
* @type {SimActionRegistry}
*/
action_registry: SimActionRegistry;
/**
* @type {ReplicatedComponentRegistry}
*/
component_registry: ReplicatedComponentRegistry;
/**
* Available to actions (via the executor reference passed to apply / affected_components)
* for translating network_id ↔ local entity_id.
* @type {ReplicationSlotTable}
*/
slot_table: ReplicationSlotTable;
/**
* Optional per-tick "which entities mutated this tick?" sink. When set,
* each `execute(action)` translates the action's affected entities to
* `network_id`s and adds them to this set. The orchestrator typically
* compacts the set into a {@link MutationLedger} at end-of-tick and
* clears it for the next.
*
* Null when the executor is configured for receive-only flows that
* don't need to record mutation history.
*
* @type {ChangedEntitySet|null}
*/
changed_entities: ChangedEntitySet | null;
/**
* Optional hook fired at the top of {@link execute}, before
* prior-bytes capture. Higher-level orchestrators install this
* to normalize the world before the executor reads live state
* (e.g. {@link NetworkSession} undoes render-time interpolation
* on remote-owned components). Should be idempotent and cheap
* when no work is needed.
*
* @type {(() => void) | null}
*/
before_execute: (() => void) | null;
/**
* Execute an action: capture prior state of affected components, apply, log.
*
* @param {SimAction} action
* @param {number} [sender_id] peer that originated this action.
* Defaults to {@link SENDER_LOCAL} for locally-originated actions.
* Must be in `[0, 254]` for remote-originated actions.
*/
execute(action: SimAction, sender_id?: number): void;
#private;
}
//# sourceMappingURL=SimActionExecutor.d.ts.map