diff --git a/src/ecs/core/index.js b/src/ecs/core/index.js new file mode 100644 index 00000000..31bec1c8 --- /dev/null +++ b/src/ecs/core/index.js @@ -0,0 +1 @@ +export * from './types.js' \ No newline at end of file diff --git a/src/ecs/core/types.js b/src/ecs/core/types.js new file mode 100644 index 00000000..8f177d17 --- /dev/null +++ b/src/ecs/core/types.js @@ -0,0 +1,7 @@ +/** @import { Constructor } from '../../reflect/index.js' */ + +/** + * @template {unknown[]} T + * @typedef {{[K in keyof T]:Constructor}} TupleConstructor + */ +export default {} \ No newline at end of file diff --git a/src/ecs/index.js b/src/ecs/index.js index 63ebbd77..7ed0d162 100644 --- a/src/ecs/index.js +++ b/src/ecs/index.js @@ -1,5 +1,6 @@ export * from './archetype/index.js' export * from './query/index.js' +export * from './core/index.js' export * from './registry.js' export * from './schedule/index.js' export * from './typestore.js' diff --git a/src/ecs/query/query.js b/src/ecs/query/query.js index 5c0fa1e4..ea4894fc 100644 --- a/src/ecs/query/query.js +++ b/src/ecs/query/query.js @@ -1,5 +1,6 @@ +/** @import { TupleConstructor } from '../core/index.js'*/ /** @import { TableId, TableRow } from '../typedef/index.js'*/ -/** @import { Constructor, TypeId } from '../../reflect/index.js'*/ +/** @import { TypeId } from '../../reflect/index.js'*/ import { Entity } from '../entities/index.js' import { World } from '../registry.js' @@ -307,9 +308,4 @@ function filter(archetype, filters) { * @param {[...T]} components1 * @param {[...T]} components2 * @returns {void} - */ - -/** - * @template {unknown[]} T - * @typedef {{[K in keyof T]:Constructor}} TupleConstructor */ \ No newline at end of file diff --git a/src/ecs/registry.js b/src/ecs/registry.js index 46563517..bcb2cb36 100644 --- a/src/ecs/registry.js +++ b/src/ecs/registry.js @@ -1,4 +1,5 @@ /** @import { Constructor, TypeId } from '../reflect/index.js'*/ +/** @import { TupleConstructor } from './core/index.js'*/ /** @import { ArchetypeId, TableId, TableRow } from './typedef/index.js'*/ import { Table, Tables } from './tables/index.js' @@ -197,6 +198,47 @@ export class World { this.callInsertComponentHook(entity, existingIds) } + /** + * @template {unknown[]} T + * @param {Entity} entity + * @param {TupleConstructor} components + */ + remove(entity, components) { + const location = this.entities.get(entity.index) + + if (!location) { + return + } + + const { archetypeId: oldArchetypeId, index, tableId: oldTableId } = location + const oldArchetype = this.archetypes.get(oldArchetypeId) + const oldTable = this.tables.get(oldTableId) + + if (!oldTable) return + + const removedIds = (components.map((c) => typeid(c))) + const existingIds = oldArchetype.types + const newIds = removeElements(existingIds, removedIds) + const [newTableId, newTable, newArchetypeId] = this.resolve(newIds) + + this.callRemoveComponentHook(entity, removedIds) + + const newIndex = oldTable.moveTo(newTable, index) + const swapped = /** @type {Entity | null}*/ (oldTable.get(typeid(Entity), index)) + + location.tableId = newTableId + location.archetypeId = newArchetypeId + location.index = newIndex + + if (swapped) { + const swappedlocation = /** @type {EntityLocation} */ (this.entities.get(swapped.index)) + + swappedlocation.index = index + } + + this.callInsertComponentHook(entity, newIds) + } + /** * @template {{}[]} T * @param {[...T][]} entities @@ -379,4 +421,14 @@ export class World { */ function deduplicate(newIds) { return [...new Set(newIds)] +} + +/** + * @private + * @param {readonly TypeId[]} arr + * @param {readonly TypeId[]} remove + * @returns {TypeId[]} + */ +function removeElements(arr, remove) { + return arr.filter((e) => !remove.includes(e)) } \ No newline at end of file