UNPKG

@javelin/ecs

Version:

151 lines 4.64 kB
import { createModel, createSchemaInstance, createStackPool, resetSchemaInstance, } from "@javelin/core"; import { UNSAFE_internals, UNSAFE_setModel } from "./internal"; export const $type = Symbol("javelin_component_type"); export const $pool = Symbol("javelin_component_pool"); const { schemaIndex, schemaPools, instanceTypeLookup } = UNSAFE_internals; let schemaIds = 0; function createComponentBase(schema, pool = true) { return Object.defineProperties({}, { [$type]: { value: schemaIndex.get(schema), writable: false, enumerable: false, }, [$pool]: { value: pool, writable: false, enumerable: false, }, }); } /** * Check if a component is an instance of a component type. * @param component * @param schema * @returns * @example * const A = {} * const B = {} * const a = component(A) * isComponentOf(a, A) // true * isComponentOf(a, B) // false */ export function isComponentOf(component, schema) { return getSchemaId(component) === schemaIndex.get(schema); } export function createComponentPool(schema, poolSize) { const componentPool = createStackPool(() => createSchemaInstance(schema, createComponentBase(schema)), component => resetSchemaInstance(component, schema), poolSize); return componentPool; } const modelConfig = new Map(); /** * Manually register a component type. Optionally specify a unique, integer id * and/or size for the component type's object pool. * @param schema * @param schemaId * @param [poolSize=1000] * @returns * @example <caption>register a schema as a component type (optional)</caption> * ```ts * const Vehicle = { torque: number } * registerSchema(Vehicle) * ``` * @example <caption>register a schema with a fixed id</caption> * ```ts * const Vehicle = { torque: number } * registerSchema(Vehicle, 22) * ``` * @example <caption>register a schema with a fixed id and pool size</caption> * ```ts * const Particle = { color: number } * registerSchema(Particle, 3, 10_000) * ``` */ export function registerSchema(schema, schemaId, poolSize = 1000) { let type = schemaIndex.get(schema); if (type !== undefined) { return type; } type = schemaId; if (type === undefined) { while (modelConfig.has(schemaIds)) { schemaIds++; } type = schemaIds; } else if (modelConfig.has(type)) { throw new Error("Failed to register component type: a component with same id is already registered"); } if (poolSize > 0) { schemaPools.set(type, createComponentPool(schema, poolSize)); } modelConfig.set(type, schema); schemaIndex.set(schema, type); UNSAFE_setModel(createModel(modelConfig)); return type; } function createComponentInner(schema) { const type = registerSchema(schema); const pool = UNSAFE_internals.schemaPools.get(type); return (pool ? pool.retain() : createSchemaInstance(schema, createComponentBase(schema, false))); } /** * Use a Schema to create a component. The second parameter is an optional * object that will be used to assign initial values to the new component * instance. * @param schema * @param props * @returns * @example * ```ts * const Quaternion = { x: number, y: number, z: number, w: number } * const quaternion = component(Quaternion, { w: 1 }) * ``` */ export function component(schema, props) { const instance = createComponentInner(schema); if (props !== undefined) { Object.assign(instance, props); } return instance; } export function toComponentFromType(object, type) { try { ; object[$type] = type; object[$pool] = false; } catch { } if (object[$type] !== type) { instanceTypeLookup.set(object, type); } return object; } /** * Instruct the ECS to treat an object as a component instance of a given * schema. * @param object * @param schema * @returns */ export function toComponent(object, schema) { const type = registerSchema(schema, undefined, 0); return toComponentFromType(object, type); } /** * Get the type id (number) of a component. Throws an error if the object is * not a valid component. * @param component * @returns */ export function getSchemaId(component) { var _a; const type = (_a = component[$type]) !== null && _a !== void 0 ? _a : instanceTypeLookup.get(component); if (type === undefined) { throw new Error("Failed to get component type id: object is not a component"); } return type; } //# sourceMappingURL=component.js.map