import type { EntityId } from 'db://assets/mx/module/ecs/EntityId'; import { ECS_INSTANCE_TYPE, type EcsComponent, type ComponentCtor } from 'db://assets/mx/module/ecs/Component'; import { View1, View2 } from 'db://assets/mx/module/ecs/View'; import { createMembershipSet, membershipAdd, membershipForEach, membershipHas, type MembershipSet } from '../../tools/MembershipSet'; const COMPONENT_CTOR_PREFIX = '__mx_ecs_ctor__'; const _duplicateCtorWarned = createMembershipSet(); export function componentTypeKey(ctor: ComponentCtor): string { return ctor.ecsTypeId ?? ctor.name ?? 'UnknownComponent'; } function canonicalComponentCtor(ctor: ComponentCtor): ComponentCtor { const typeKey = componentTypeKey(ctor); const g = globalThis as unknown as Record | undefined>; const key = `${COMPONENT_CTOR_PREFIX}${typeKey}`; const existing = g[key]; if (!existing) { g[key] = ctor; return ctor; } if (existing !== ctor && !membershipHas(_duplicateCtorWarned, typeKey)) { membershipAdd(_duplicateCtorWarned, typeKey); console.log('[World] duplicate component ctor merged', typeKey); } return existing as ComponentCtor; } /** 单类型组件存储桶 */ export class ComponentStorage { private readonly _map = new Map(); set(id: EntityId, comp: T): void { this._map.set(id, comp); } get(id: EntityId): T | undefined { return this._map.get(id); } has(id: EntityId): boolean { return this._map.has(id); } delete(id: EntityId): void { this._map.delete(id); } /** 遍历桶内所有组件(含已销毁实体的残留,调用方需自行 isAlive 过滤) */ forEach(fn: (id: EntityId, comp: T) => void): void { this._map.forEach((comp, id) => fn(id, comp)); } get size(): number { return this._map.size; } clear(): void { this._map.clear(); } } /** 实体世界:组件分桶存储 + 实体生命周期 + 查询 */ export class World { private _nextId: EntityId = 1; private readonly _alive = createMembershipSet(); private readonly _storagesByTypeId = new Map>(); /** 下一实体 ID(快照恢复用) */ get nextEntityId(): EntityId { return this._nextId; } /** 设置下一实体 ID(快照恢复前调用,须 ≥ 已有最大实体 ID + 1) */ setNextEntityId(next: EntityId): void { this._nextId = Math.max(1, next); } /** 创建新实体 */ spawn(): EntityId { const id = this._nextId++; membershipAdd(this._alive, id); return id; } /** 以指定 ID 复活实体(战斗快照冷恢复) */ spawnWithId(id: EntityId): EntityId { if (id <= 0) return this.spawn(); membershipAdd(this._alive, id); if (id >= this._nextId) this._nextId = id + 1; return id; } /** 销毁实体(组件数据保留以便本帧查询,下帧清理) */ destroy(id: EntityId): void { this._alive.delete(id); } /** 实体是否存活 */ isAlive(id: EntityId): boolean { return id !== 0 && this._alive.has(id); } /** 清理已销毁实体的残留组件(可定期调用) */ gc(): void { const alive = this._alive; this._storagesByTypeId.forEach((storage) => { storage.forEach((id) => { if (!alive.has(id)) storage.delete(id); }); }); } private _storageForTypeId(typeId: string): ComponentStorage { let s = this._storagesByTypeId.get(typeId); if (!s) { s = new ComponentStorage(); this._storagesByTypeId.set(typeId, s); } return s as ComponentStorage; } private _storage(ctor: ComponentCtor): ComponentStorage { const canonical = canonicalComponentCtor(ctor); return this._storageForTypeId(componentTypeKey(canonical)); } private _tagInstanceType(comp: EcsComponent, ctor: ComponentCtor): void { (comp as Record)[ECS_INSTANCE_TYPE] = componentTypeKey(ctor); } private _matchesInstanceType(comp: EcsComponent, expectedTypeId: string): boolean { const actual = (comp as Record)[ECS_INSTANCE_TYPE]; if (actual == null) return true; if (actual === expectedTypeId) return true; console.error(`[World] component type mismatch expected=${expectedTypeId} actual=${actual}`); return false; } /** 添加组件(覆盖已有) */ addComponent(id: EntityId, comp: T): T { const ctor = canonicalComponentCtor(comp.constructor as ComponentCtor); this._tagInstanceType(comp, comp.constructor as ComponentCtor); this._storage(ctor).set(id, comp); return comp; } /** 读取组件,不存在返回 undefined */ getComponent(id: EntityId, ctor: ComponentCtor): T | undefined { const typeId = componentTypeKey(canonicalComponentCtor(ctor)); const comp = this._storage(ctor).get(id); if (!comp) return undefined; if (!this._matchesInstanceType(comp, typeId)) return undefined; return comp as T; } /** 读取组件,不存在抛错 */ requireComponent(id: EntityId, ctor: ComponentCtor): T { const comp = this.getComponent(id, ctor); if (!comp) throw new Error(`[World] entity ${id} missing component ${componentTypeKey(ctor)}`); return comp; } /** 是否拥有某组件 */ hasComponent(id: EntityId, ctor: ComponentCtor): boolean { return this.getComponent(id, ctor) != null; } /** 移除组件 */ removeComponent(id: EntityId, ctor: ComponentCtor): void { this._storage(ctor).delete(id); } /** 单组件查询视图 */ view(ctor: ComponentCtor): View1 { return new View1(this._storage(ctor), (id) => this.isAlive(id)); } /** 双组件查询视图(按 ctorA 桶遍历 + 过滤 ctorB) */ view2( ctorA: ComponentCtor, ctorB: ComponentCtor, ): View2 { return new View2( this._storage(ctorA), ctorB, (id, ctor) => this.getComponent(id, ctor), (id) => this.isAlive(id), ); } /** 遍历所有存活实体 */ forEachAlive(fn: (id: EntityId) => void): void { membershipForEach(this._alive, fn); } /** 存活实体数量 */ get aliveCount(): number { return this._alive.size; } }