Files
esengine/packages/core/src/ECS/Utils/ComponentSparseSet.ts

419 lines
13 KiB
TypeScript
Raw Normal View History

import { Entity } from '../Entity';
import { ComponentType, ComponentRegistry } from '../Core/ComponentStorage';
import { BitMask64Utils, BitMask64Data } from './BigIntCompatibility';
import { SparseSet } from './SparseSet';
import { Pool } from '../../Utils/Pool/Pool';
import { IPoolable } from '../../Utils/Pool/IPoolable';
/**
*
*
* IPoolable接口
*/
class PoolableEntitySet extends Set<Entity> implements IPoolable {
constructor(...args: unknown[]) {
super();
}
reset(): void {
this.clear();
}
}
/**
*
*
*
*
*
* -
* -
* -
*/
export class ComponentSparseSet {
/**
*
*
* O(1)
*/
private _entities: SparseSet<Entity>;
/**
*
*
*
*
*/
private _componentMasks: BitMask64Data[] = [];
/**
*
*
*
*/
private _componentToEntities = new Map<ComponentType, PoolableEntitySet>();
/**
*
*
* 使core库的Pool系统来管理PoolableEntitySet对象的复用
*/
private static _entitySetPool = Pool.getPool(PoolableEntitySet, 50, 512);
constructor() {
this._entities = new SparseSet<Entity>();
}
/**
*
*
*
*
* @param entity
*/
public addEntity(entity: Entity): void {
// 如果实体已存在,先移除旧数据
if (this._entities.has(entity)) {
this.removeEntity(entity);
}
let componentMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
const entityComponents = new Set<ComponentType>();
// 分析实体组件并构建位掩码
for (const component of entity.components) {
const componentType = component.constructor as ComponentType;
entityComponents.add(componentType);
// 确保组件类型已注册
if (!ComponentRegistry.isRegistered(componentType)) {
ComponentRegistry.register(componentType);
}
// 获取组件位掩码并合并
const bitMask = ComponentRegistry.getBitMask(componentType);
BitMask64Utils.orInPlace(componentMask, bitMask);
}
// 添加实体到稀疏集合
this._entities.add(entity);
const entityIndex = this._entities.getIndex(entity)!;
// 确保位掩码数组有足够空间
while (this._componentMasks.length <= entityIndex) {
this._componentMasks.push(BitMask64Utils.clone(BitMask64Utils.ZERO));
}
this._componentMasks[entityIndex] = componentMask;
// 更新组件类型到实体的映射
this.updateComponentMappings(entity, entityComponents, true);
}
/**
*
*
*
*
* @param entity
*/
public removeEntity(entity: Entity): void {
const entityIndex = this._entities.getIndex(entity);
if (entityIndex === undefined) {
return; // 实体不存在
}
// 获取实体的组件类型集合
const entityComponents = this.getEntityComponentTypes(entity);
// 更新组件类型到实体的映射
this.updateComponentMappings(entity, entityComponents, false);
// 从稀疏集合中移除实体
this._entities.remove(entity);
// 维护位掩码数组的紧凑性
const lastIndex = this._componentMasks.length - 1;
if (entityIndex !== lastIndex) {
// 将最后一个位掩码移动到当前位置
this._componentMasks[entityIndex] = this._componentMasks[lastIndex];
}
this._componentMasks.pop();
}
/**
*
*
* @param componentType
* @returns
*/
public queryByComponent(componentType: ComponentType): Set<Entity> {
const entities = this._componentToEntities.get(componentType);
return entities ? new Set(entities) : new Set<Entity>();
}
/**
* AND操作
*
*
*
* @param componentTypes
* @returns
*/
public queryMultipleAnd(componentTypes: ComponentType[]): Set<Entity> {
if (componentTypes.length === 0) {
return new Set<Entity>();
}
if (componentTypes.length === 1) {
return this.queryByComponent(componentTypes[0]);
}
// 构建目标位掩码
let targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
for (const componentType of componentTypes) {
if (!ComponentRegistry.isRegistered(componentType)) {
return new Set<Entity>(); // 未注册的组件类型,结果为空
}
const bitMask = ComponentRegistry.getBitMask(componentType);
BitMask64Utils.orInPlace(targetMask, bitMask);
}
const result = ComponentSparseSet._entitySetPool.obtain();
// 遍历所有实体,检查位掩码匹配
this._entities.forEach((entity, index) => {
const entityMask = this._componentMasks[index];
if (BitMask64Utils.hasAll(entityMask, targetMask)) {
result.add(entity);
}
});
return result;
}
/**
* OR操作
*
*
*
* @param componentTypes
* @returns
*/
public queryMultipleOr(componentTypes: ComponentType[]): Set<Entity> {
if (componentTypes.length === 0) {
return new Set<Entity>();
}
if (componentTypes.length === 1) {
return this.queryByComponent(componentTypes[0]);
}
// 构建目标位掩码
let targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
for (const componentType of componentTypes) {
if (ComponentRegistry.isRegistered(componentType)) {
const bitMask = ComponentRegistry.getBitMask(componentType);
BitMask64Utils.orInPlace(targetMask, bitMask);
}
}
if (BitMask64Utils.equals(targetMask, BitMask64Utils.ZERO)) {
return new Set<Entity>(); // 没有有效的组件类型
}
const result = ComponentSparseSet._entitySetPool.obtain();
// 遍历所有实体,检查位掩码匹配
this._entities.forEach((entity, index) => {
const entityMask = this._componentMasks[index];
if (BitMask64Utils.hasAny(entityMask, targetMask)) {
result.add(entity);
}
});
return result;
}
/**
*
*
* @param entity
* @param componentType
* @returns
*/
public hasComponent(entity: Entity, componentType: ComponentType): boolean {
const entityIndex = this._entities.getIndex(entity);
if (entityIndex === undefined) {
return false;
}
if (!ComponentRegistry.isRegistered(componentType)) {
return false;
}
const entityMask = this._componentMasks[entityIndex];
const componentMask = ComponentRegistry.getBitMask(componentType);
return BitMask64Utils.hasAny(entityMask, componentMask);
}
/**
*
*
* @param entity
* @returns undefined
*/
public getEntityMask(entity: Entity): BitMask64Data | undefined {
const entityIndex = this._entities.getIndex(entity);
if (entityIndex === undefined) {
return undefined;
}
return this._componentMasks[entityIndex];
}
/**
*
*
* @returns
*/
public getAllEntities(): Entity[] {
return this._entities.toArray();
}
/**
*
*/
public get size(): number {
return this._entities.size;
}
/**
*
*/
public get isEmpty(): boolean {
return this._entities.isEmpty;
}
/**
*
*
* @param callback
*/
public forEach(callback: (entity: Entity, mask: BitMask64Data, index: number) => void): void {
this._entities.forEach((entity, index) => {
callback(entity, this._componentMasks[index], index);
});
}
/**
*
*/
public clear(): void {
this._entities.clear();
this._componentMasks.length = 0;
// 清理时将所有持有的实体集合返回到池中
for (const entitySet of this._componentToEntities.values()) {
ComponentSparseSet._entitySetPool.release(entitySet);
}
this._componentToEntities.clear();
}
/**
* 使
*/
public getMemoryStats(): {
entitiesMemory: number;
masksMemory: number;
mappingsMemory: number;
totalMemory: number;
} {
const entitiesStats = this._entities.getMemoryStats();
const masksMemory = this._componentMasks.length * 16; // 估计每个BigInt 16字节
let mappingsMemory = this._componentToEntities.size * 16; // Map条目开销
for (const entitySet of this._componentToEntities.values()) {
mappingsMemory += entitySet.size * 8; // 每个实体引用8字节
}
return {
entitiesMemory: entitiesStats.totalMemory,
masksMemory,
mappingsMemory,
totalMemory: entitiesStats.totalMemory + masksMemory + mappingsMemory
};
}
/**
*
*/
public validate(): boolean {
// 检查稀疏集合的有效性
if (!this._entities.validate()) {
return false;
}
// 检查位掩码数组长度一致性
if (this._componentMasks.length !== this._entities.size) {
return false;
}
// 检查组件映射的一致性
const allMappedEntities = new Set<Entity>();
for (const entitySet of this._componentToEntities.values()) {
for (const entity of entitySet) {
allMappedEntities.add(entity);
}
}
// 验证映射中的实体都在稀疏集合中
for (const entity of allMappedEntities) {
if (!this._entities.has(entity)) {
return false;
}
}
return true;
}
/**
*
*/
private getEntityComponentTypes(entity: Entity): Set<ComponentType> {
const componentTypes = new Set<ComponentType>();
for (const component of entity.components) {
componentTypes.add(component.constructor as ComponentType);
}
return componentTypes;
}
/**
*
*/
private updateComponentMappings(
entity: Entity,
componentTypes: Set<ComponentType>,
add: boolean
): void {
for (const componentType of componentTypes) {
let entities = this._componentToEntities.get(componentType);
if (add) {
if (!entities) {
entities = ComponentSparseSet._entitySetPool.obtain();
this._componentToEntities.set(componentType, entities);
}
entities.add(entity);
} else {
if (entities) {
entities.delete(entity);
if (entities.size === 0) {
this._componentToEntities.delete(componentType);
ComponentSparseSet._entitySetPool.release(entities);
}
}
}
}
}
}