UNPKG

@javelin/net

Version:

Networking protocol and utilities for Javelin ECS.

126 lines 5.38 kB
import { createPatch, getSchemaId, resetPatch, UNSAFE_internals, } from "@javelin/ecs"; import { createEntityMap } from "./entity_map"; import EntityPriorityQueue from "./entity_priority_queue"; import * as Message from "./message"; import * as MessageOp from "./message_op"; export function createMessageProducer(options = {}) { const { maxByteLength = Infinity } = options; const queue = [Message.createMessage()]; const entityPriorities = new EntityPriorityQueue(); const entityUpdates = createEntityMap(); const entityPatches = createEntityMap(); let previousModel = null; function amplify(entity, priority) { var _a; entityPriorities.changePriority(entity, ((_a = entityPriorities.getPriority(entity)) !== null && _a !== void 0 ? _a : 0) + priority); } function enqueue(op, kind) { let message = queue[0]; // calculate the new message length. if we exceed the maxByteLength threshold, // create an enqueue a new message if (message === undefined || op.byteLength + message.byteLength > maxByteLength) { message = Message.createMessage(); queue.unshift(message); } Message.insert(message, kind, op); return message; } function attach(entity, components) { enqueue(MessageOp.snapshot(Message.getEnhancedModel(), entity, components), Message.MessagePartKind.Attach); } function update(entity, components, priority = 1) { let updates = entityUpdates[entity]; if (updates === undefined) { updates = entityUpdates[entity] = new Map(); } // overwrite existing component updates with latest component, in case it // changed (i.e. the original component was detached and a new instance // was attached) for (let i = 0; i < components.length; i++) { const component = components[i]; updates.set(getSchemaId(component), component); } amplify(entity, priority); } function patch(entity, component, priority = 1) { var _a; const id = getSchemaId(component); const patches = ((_a = entityPatches[entity]) !== null && _a !== void 0 ? _a : (entityPatches[entity] = new Map())); const patch = patches.get(id); if (patch === undefined) { patches.set(id, createPatch(component)); } else { createPatch(component, patch); } amplify(entity, priority); } function detach(entity, components) { enqueue(MessageOp.detach(entity, components.map(getSchemaId)), Message.MessagePartKind.Detach); } function destroy(entity) { enqueue(MessageOp.destroy(entity), Message.MessagePartKind.Destroy); // remove any planned patches or updates since the entity was destroyed delete entityPatches[entity]; delete entityUpdates[entity]; entityPriorities.remove(entity); } function take(includeModel = previousModel !== UNSAFE_internals.model) { const message = queue.pop() || Message.createMessage(); // insert a new model automatically if it has changed. otherwise, the // caller can pass `true` to force model inclusion if (includeModel) { Message.model(message); previousModel = UNSAFE_internals.model; } const model = Message.getEnhancedModel(); while (true) { // take the next-highest priority entity out of the priority queue const entity = entityPriorities.poll(); if (entity === null || entity === undefined) { break; } const updates = entityUpdates[entity]; const patches = entityPatches[entity]; // include component updates if (updates && updates.size > 0) { const components = Array.from(updates.values()); const op = MessageOp.snapshot(model, entity, components); // message would exceed max byte length if (op.byteLength + (message === null || message === void 0 ? void 0 : message.byteLength) >= maxByteLength) { break; } Message.insert(message, Message.MessagePartKind.Snapshot, op); updates.clear(); } // include component patches if (patches && patches.size > 0) { for (const patch of patches.values()) { if (patch.changes.size === 0) { continue; } const op = MessageOp.patch(model, entity, patch); // message would exceed max byte length if (op.byteLength + (message === null || message === void 0 ? void 0 : message.byteLength) >= maxByteLength) { break; } Message.insert(message, Message.MessagePartKind.Patch, op); // reset the patch since it was incorporated into a message resetPatch(patch); } } } return message; } return { amplify, attach, update, patch, detach, destroy, take, }; } //# sourceMappingURL=message_producer.js.map