UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

85 lines (77 loc) 2.69 kB
import { assert } from "../../../core/assert.js"; import { ResourceAccessKind } from "../../../core/model/ResourceAccessKind.js"; import { ResourceAccessSpecification } from "../../../core/model/ResourceAccessSpecification.js"; import { System } from "../../ecs/System.js"; import { NetworkIdentity } from "./components/NetworkIdentity.js"; /** * ECS system that owns the per-entity replication lifecycle. * * Responsibilities: * - When an entity gains a {@link NetworkIdentity}, allocate a `network_id` * in the peer's slot table (or honour an explicit pre-set one — used by * `Snapshotter` and incoming-packet flows). * - When an entity loses its `NetworkIdentity` (or is destroyed), free the * slot. * * **Not** responsible for the per-tick `begin_tick` / `end_tick` cadence — * the engine's `EntityManager` doesn't expose pre/post-simulate hooks, so the * application code wraps its `engine.simulate(dt)` call: * * ```js * peer.begin_tick(frame_number); * engine.simulate(dt); * peer.end_tick(); * ``` * * Add this system to the engine once per `NetworkPeer` instance: * * ```js * const peer = new NetworkPeer({ ... }); * const network_system = new NetworkSystem(peer); * engine.entityManager.addSystem(network_system); * ``` * * @author Alex Goldring * @copyright Company Named Limited (c) 2025 */ export class NetworkSystem extends System { dependencies = [NetworkIdentity]; components_used = [ ResourceAccessSpecification.from(NetworkIdentity, ResourceAccessKind.Write), ]; /** * @param {NetworkPeer} peer */ constructor(peer) { super(); assert.ok(peer && peer.slot_table, 'NetworkSystem: peer must be a NetworkPeer instance with a slot_table'); /** * @type {NetworkPeer} */ this.peer = peer; } /** * @param {NetworkIdentity} identity * @param {number} entity */ link(identity, entity) { if (identity.network_id < 0) { // Local spawn: allocate a fresh network_id. identity.network_id = this.peer.slot_table.allocate(entity); } else { // Pre-set (e.g. from a Snapshotter or a remote peer's spawn action). // Honour the explicit ID so both sides share the same slot. this.peer.slot_table.allocate_at(identity.network_id, entity); } } /** * @param {NetworkIdentity} identity * @param {number} entity */ unlink(identity, entity) { if (identity.network_id >= 0) { this.peer.slot_table.free(identity.network_id); identity.network_id = -1; } } }