@javelin/net
Version:
Networking protocol and utilities for Javelin ECS.
152 lines • 6.64 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createMessageProducer = void 0;
const ecs_1 = require("@javelin/ecs");
const entity_map_1 = require("./entity_map");
const entity_priority_queue_1 = __importDefault(require("./entity_priority_queue"));
const Message = __importStar(require("./message"));
const MessageOp = __importStar(require("./message_op"));
function createMessageProducer(options = {}) {
const { maxByteLength = Infinity } = options;
const queue = [Message.createMessage()];
const entityPriorities = new entity_priority_queue_1.default();
const entityUpdates = entity_map_1.createEntityMap();
const entityPatches = entity_map_1.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(ecs_1.getSchemaId(component), component);
}
amplify(entity, priority);
}
function patch(entity, component, priority = 1) {
var _a;
const id = ecs_1.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, ecs_1.createPatch(component));
}
else {
ecs_1.createPatch(component, patch);
}
amplify(entity, priority);
}
function detach(entity, components) {
enqueue(MessageOp.detach(entity, components.map(ecs_1.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 !== ecs_1.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 = ecs_1.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
ecs_1.resetPatch(patch);
}
}
}
return message;
}
return {
amplify,
attach,
update,
patch,
detach,
destroy,
take,
};
}
exports.createMessageProducer = createMessageProducer;
//# sourceMappingURL=message_producer.js.map