UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

183 lines (154 loc) 4.5 kB
import { assert } from "../../core/assert.js"; /** * Uniquely identifies an entity by both its ID and generation. * Lets us uniquely distinguish between two entities, even those with the same ID that were created at different times * @example * // 1. Get your EntityComponentDataset to where you manager entities. * const ecd = ... ; // EntityComponentDataset * * // 2. Create an entity (we'll get an ID). * const entityId = ecd.createEntity(); * * // 3. Create an EntityReference and bind it to the entity. * const entityRef = EntityReference.bind(ecd, entityId); * * // 4. After you no longer need the entity - destroy the entity via reference. * entityRef.destroy(ecd); * * @see {@link EntityComponentDataset} * @author Alex Goldring * @copyright Company Named Limited (c) 2025 */ export class EntityReference { /** * Entity ID * When entity is live - this is the entity ID inside associated `EntityComponentDataset`, when the entity is not live - it's set to -1 * @type {number} */ id = -1 /** * Entity generation number. This uniquely identifies an entity in combination with the ID * Generation of an existing entity must match for it to be considered "the same". * @see {@link EntityComponentDataset.getEntityGeneration} * @type {number} */ generation = -1 /** * * @param {EntityReference} other */ copy(other) { assert.defined(other, 'other'); this.id = other.id; this.generation = other.generation; } /** * * @returns {EntityReference} */ clone() { const r = new EntityReference(); r.copy(this); return r; } /** * * @return {number} */ hash() { return (this.id * 31) ^ this.generation; } /** * * @param {EntityReference} other * @return {boolean} */ equals(other) { return this.id === other.id && this.generation === other.generation ; } /** * Checks whether referenced entity exists and the generation matches * @param {EntityComponentDataset} ecd * @returns {boolean} */ verify(ecd) { if (this.id < 0) { // special case return false; } return ecd.entityExists(this.id) && this.generation === ecd.getEntityGeneration(this.id) ; } /** * Destroys entity bound to this reference * If the reference is invalid for the given dataset - does nothing * @param {EntityComponentDataset} ecd * @returns {boolean} true if entity was destroyed, false otherwise */ destroy(ecd) { if (this.verify(ecd)) { ecd.removeEntity(this.id); return true; } else { return false; } } /** * Bind reference to a specific entity * @param {EntityComponentDataset} ecd * @param {number} entity */ bind(ecd, entity) { assert.defined(ecd, 'ecd'); assert.equal(ecd.isEntityComponentDataset, true, 'ecd.isEntityComponentDataset !== true'); const generation = ecd.getEntityGeneration(entity); this.from(entity, generation); } /** * * @param {number} id * @param {number} generation */ from(id, generation) { assert.isNonNegativeInteger(id, 'id'); assert.isNonNegativeInteger(generation, 'generation'); this.id = id; this.generation = generation; } /** * * @param {number} id * @param {number} generation * @return {EntityReference} */ static from(id, generation) { const r = new EntityReference(); r.from(id, generation); return r; } /** * * @param {EntityComponentDataset} ecd * @param {number} id * @returns {EntityReference} */ static bind(ecd, id) { const r = new EntityReference(); r.bind(ecd, id); return r; } } /** * @readonly * @type {boolean} */ EntityReference.prototype.isEntityReference = true; /** * Special utility singleton to describe an invalid reference. * @readonly * @type {EntityReference} */ EntityReference.NULL = Object.freeze(new EntityReference());