把掩码从BigInt-like多态都改成Mask64

This commit is contained in:
YHH
2025-09-03 00:39:00 +08:00
parent ef80b03a44
commit bda547dd2e
5 changed files with 53 additions and 242 deletions

View File

@@ -1,205 +1,15 @@
import { Component } from '../Component';
import { IBigIntLike, BigIntFactory } from '../Utils/BigIntCompatibility';
import { BitMask64Utils, BitMask64Data } from '../Utils/BigIntCompatibility';
import { SoAStorage, EnableSoA, HighPrecision, Float64, Int32, SerializeMap, SerializeSet, SerializeArray, DeepCopy } from './SoAStorage';
import { createLogger } from '../../Utils/Logger';
import { getComponentTypeName } from '../Decorators';
import { ComponentRegistry, ComponentType } from './ComponentStorage/ComponentRegistry';
// 重新导出装饰器
// 重新导出装饰器和核心类型
export { EnableSoA, HighPrecision, Float64, Int32, SerializeMap, SerializeSet, SerializeArray, DeepCopy };
export { ComponentRegistry, ComponentType };
/**
* 组件类型定义
* 支持任意构造函数签名,提供更好的类型安全性
*/
export type ComponentType<T extends Component = Component> = new (...args: any[]) => T;
/**
* 组件注册表
* 管理组件类型的位掩码分配
*/
export class ComponentRegistry {
protected static readonly _logger = createLogger('ComponentStorage');
private static componentTypes = new Map<Function, number>();
private static componentNameToType = new Map<string, Function>();
private static componentNameToId = new Map<string, number>();
private static maskCache = new Map<string, IBigIntLike>();
private static nextBitIndex = 0;
private static maxComponents = 64; // 支持最多64种组件类型
/**
* 注册组件类型并分配位掩码
* @param componentType 组件类型
* @returns 分配的位索引
*/
public static register<T extends Component>(componentType: ComponentType<T>): number {
if (this.componentTypes.has(componentType)) {
return this.componentTypes.get(componentType)!;
}
if (this.nextBitIndex >= this.maxComponents) {
throw new Error(`Maximum number of component types (${this.maxComponents}) exceeded`);
}
const bitIndex = this.nextBitIndex++;
this.componentTypes.set(componentType, bitIndex);
this.componentNameToType.set(getComponentTypeName(componentType), componentType);
this.componentNameToId.set(getComponentTypeName(componentType), bitIndex);
return bitIndex;
}
/**
* 获取组件类型的位掩码
* @param componentType 组件类型
* @returns 位掩码
*/
public static getBitMask<T extends Component>(componentType: ComponentType<T>): IBigIntLike {
const bitIndex = this.componentTypes.get(componentType);
if (bitIndex === undefined) {
throw new Error(`Component type ${getComponentTypeName(componentType)} is not registered`);
}
return BigIntFactory.one().shiftLeft(bitIndex);
}
/**
* 获取组件类型的位索引
* @param componentType 组件类型
* @returns 位索引
*/
public static getBitIndex<T extends Component>(componentType: ComponentType<T>): number {
const bitIndex = this.componentTypes.get(componentType);
if (bitIndex === undefined) {
throw new Error(`Component type ${getComponentTypeName(componentType)} is not registered`);
}
return bitIndex;
}
/**
* 检查组件类型是否已注册
* @param componentType 组件类型
* @returns 是否已注册
*/
public static isRegistered<T extends Component>(componentType: ComponentType<T>): boolean {
return this.componentTypes.has(componentType);
}
/**
* 通过名称获取组件类型
* @param componentName 组件名称
* @returns 组件类型构造函数
*/
public static getComponentType(componentName: string): Function | null {
return this.componentNameToType.get(componentName) || null;
}
/**
* 获取所有已注册的组件类型
* @returns 组件类型映射
*/
public static getAllRegisteredTypes(): Map<Function, number> {
return new Map(this.componentTypes);
}
/**
* 获取所有组件名称到类型的映射
* @returns 名称到类型的映射
*/
public static getAllComponentNames(): Map<string, Function> {
return new Map(this.componentNameToType);
}
/**
* 通过名称获取组件类型ID
* @param componentName 组件名称
* @returns 组件类型ID
*/
public static getComponentId(componentName: string): number | undefined {
return this.componentNameToId.get(componentName);
}
/**
* 注册组件类型(通过名称)
* @param componentName 组件名称
* @returns 分配的组件ID
*/
public static registerComponentByName(componentName: string): number {
if (this.componentNameToId.has(componentName)) {
return this.componentNameToId.get(componentName)!;
}
if (this.nextBitIndex >= this.maxComponents) {
throw new Error(`Maximum number of component types (${this.maxComponents}) exceeded`);
}
const bitIndex = this.nextBitIndex++;
this.componentNameToId.set(componentName, bitIndex);
return bitIndex;
}
/**
* 创建单个组件的掩码
* @param componentName 组件名称
* @returns 组件掩码
*/
public static createSingleComponentMask(componentName: string): IBigIntLike {
const cacheKey = `single:${componentName}`;
if (this.maskCache.has(cacheKey)) {
return this.maskCache.get(cacheKey)!;
}
const componentId = this.getComponentId(componentName);
if (componentId === undefined) {
throw new Error(`Component type ${componentName} is not registered`);
}
const mask = BigIntFactory.one().shiftLeft(componentId);
this.maskCache.set(cacheKey, mask);
return mask;
}
/**
* 创建多个组件的掩码
* @param componentNames 组件名称数组
* @returns 组合掩码
*/
public static createComponentMask(componentNames: string[]): IBigIntLike {
const sortedNames = [...componentNames].sort();
const cacheKey = `multi:${sortedNames.join(',')}`;
if (this.maskCache.has(cacheKey)) {
return this.maskCache.get(cacheKey)!;
}
let mask = BigIntFactory.zero();
for (const name of componentNames) {
const componentId = this.getComponentId(name);
if (componentId !== undefined) {
mask = mask.or(BigIntFactory.one().shiftLeft(componentId));
}
}
this.maskCache.set(cacheKey, mask);
return mask;
}
/**
* 清除掩码缓存
*/
public static clearMaskCache(): void {
this.maskCache.clear();
}
/**
* 重置注册表(用于测试)
*/
public static reset(): void {
this.componentTypes.clear();
this.componentNameToType.clear();
this.componentNameToId.clear();
this.maskCache.clear();
this.nextBitIndex = 0;
}
}
/**
* 高性能组件存储器
@@ -532,13 +342,13 @@ export class ComponentStorageManager {
* @param entityId 实体ID
* @returns 组件位掩码
*/
public getComponentMask(entityId: number): IBigIntLike {
let mask = BigIntFactory.zero();
public getComponentMask(entityId: number): BitMask64Data {
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
for (const [componentType, storage] of this.storages.entries()) {
if (storage.hasComponent(entityId)) {
const componentMask = ComponentRegistry.getBitMask(componentType as ComponentType);
mask = mask.or(componentMask);
BitMask64Utils.orInPlace(mask, componentMask);
}
}

View File

@@ -1,5 +1,5 @@
import { Component } from '../../Component';
import { IBigIntLike, BigIntFactory } from '../../Utils/BigIntCompatibility';
import { BitMask64Utils, BitMask64Data } from '../../Utils/BigIntCompatibility';
import { createLogger } from '../../../Utils/Logger';
import { getComponentTypeName } from '../../Decorators';
@@ -17,7 +17,7 @@ export class ComponentRegistry {
private static componentTypes = new Map<Function, number>();
private static componentNameToType = new Map<string, Function>();
private static componentNameToId = new Map<string, number>();
private static maskCache = new Map<string, IBigIntLike>();
private static maskCache = new Map<string, BitMask64Data>();
private static nextBitIndex = 0;
private static maxComponents = 64; // 支持最多64种组件类型
@@ -51,13 +51,13 @@ export class ComponentRegistry {
* @param componentType 组件类型
* @returns 位掩码
*/
public static getBitMask<T extends Component>(componentType: ComponentType<T>): IBigIntLike {
public static getBitMask<T extends Component>(componentType: ComponentType<T>): BitMask64Data {
const bitIndex = this.componentTypes.get(componentType);
if (bitIndex === undefined) {
const typeName = getComponentTypeName(componentType);
throw new Error(`Component type ${typeName} is not registered`);
}
return BigIntFactory.one().shiftLeft(bitIndex);
return BitMask64Utils.create(bitIndex);
}
/**
@@ -141,7 +141,7 @@ export class ComponentRegistry {
* @param componentName 组件名称
* @returns 组件掩码
*/
public static createSingleComponentMask(componentName: string): IBigIntLike {
public static createSingleComponentMask(componentName: string): BitMask64Data {
const cacheKey = `single:${componentName}`;
if (this.maskCache.has(cacheKey)) {
@@ -153,7 +153,7 @@ export class ComponentRegistry {
throw new Error(`Component type ${componentName} is not registered`);
}
const mask = BigIntFactory.one().shiftLeft(componentId);
const mask = BitMask64Utils.create(componentId);
this.maskCache.set(cacheKey, mask);
return mask;
}
@@ -163,7 +163,7 @@ export class ComponentRegistry {
* @param componentNames 组件名称数组
* @returns 组合掩码
*/
public static createComponentMask(componentNames: string[]): IBigIntLike {
public static createComponentMask(componentNames: string[]): BitMask64Data {
const sortedNames = [...componentNames].sort();
const cacheKey = `multi:${sortedNames.join(',')}`;
@@ -171,11 +171,12 @@ export class ComponentRegistry {
return this.maskCache.get(cacheKey)!;
}
let mask = BigIntFactory.zero();
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
for (const name of componentNames) {
const componentId = this.getComponentId(name);
if (componentId !== undefined) {
mask = mask.or(BigIntFactory.one().shiftLeft(componentId));
const componentMask = BitMask64Utils.create(componentId);
BitMask64Utils.orInPlace(mask, componentMask);
}
}

View File

@@ -1,7 +1,7 @@
import { Entity } from '../Entity';
import { Component } from '../Component';
import { ComponentRegistry, ComponentType } from './ComponentStorage';
import { IBigIntLike, BigIntFactory } from '../Utils/BigIntCompatibility';
import { BitMask64Utils, BitMask64Data } from '../Utils/BigIntCompatibility';
import { createLogger } from '../../Utils/Logger';
import { getComponentTypeName } from '../Decorators';
@@ -28,7 +28,7 @@ export enum QueryConditionType {
export interface QueryCondition {
type: QueryConditionType;
componentTypes: ComponentType[];
mask: IBigIntLike;
mask: BitMask64Data;
}
/**
@@ -483,7 +483,7 @@ export class QuerySystem {
const result: Entity[] = [];
for (const entity of smallestSet) {
if (entity.componentMask.and(mask).equals(mask)) {
if (BitMask64Utils.hasAll(entity.componentMask, mask)) {
result.push(entity);
}
}
@@ -587,7 +587,7 @@ export class QuerySystem {
const mask = this.createComponentMask(componentTypes);
const entities = this.entities.filter(entity =>
entity.componentMask.and(mask).isZero()
BitMask64Utils.hasNone(entity.componentMask, mask)
);
this.addToCache(cacheKey, entities);
@@ -872,14 +872,14 @@ export class QuerySystem {
* @param componentTypes 组件类型列表
* @returns 生成的位掩码
*/
private createComponentMask(componentTypes: ComponentType[]): IBigIntLike {
let mask = BigIntFactory.zero();
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
let hasValidComponents = false;
for (const type of componentTypes) {
try {
const bitMask = ComponentRegistry.getBitMask(type);
mask = mask.or(bitMask);
BitMask64Utils.orInPlace(mask, bitMask);
hasValidComponents = true;
} catch (error) {
this._logger.warn(`组件类型 ${getComponentTypeName(type)} 未注册,跳过`);
@@ -888,7 +888,7 @@ export class QuerySystem {
// 如果没有有效的组件类型,返回一个不可能匹配的掩码
if (!hasValidComponents) {
return BigIntFactory.create(-1); // 所有位都是1不可能与任何实体匹配
return { lo: 0xFFFFFFFF, hi: 0xFFFFFFFF }; // 所有位都是1不可能与任何实体匹配
}
return mask;
@@ -1134,12 +1134,12 @@ export class QueryBuilder {
/**
* 创建组件掩码
*/
private createComponentMask(componentTypes: ComponentType[]): IBigIntLike {
let mask = BigIntFactory.zero();
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
for (const type of componentTypes) {
try {
const bitMask = ComponentRegistry.getBitMask(type);
mask = mask.or(bitMask);
BitMask64Utils.orInPlace(mask, bitMask);
} catch (error) {
this._logger.warn(`组件类型 ${getComponentTypeName(type)} 未注册,跳过`);
}

View File

@@ -1,7 +1,7 @@
import { Component } from './Component';
import { ComponentRegistry, ComponentType } from './Core/ComponentStorage';
import { EventBus } from './Core/EventBus';
import { IBigIntLike, BigIntFactory } from './Utils/BigIntCompatibility';
import { BitMask64Utils, BitMask64Data } from './Utils/BigIntCompatibility';
import { createLogger } from '../Utils/Logger';
import { getComponentInstanceTypeName, getComponentTypeName } from './Decorators';
import type { IScene } from './IScene';
@@ -161,7 +161,7 @@ export class Entity {
*
* 用于快速查询实体拥有的组件类型。
*/
private _componentMask: IBigIntLike = BigIntFactory.zero();
private _componentMask: BitMask64Data = BitMask64Utils.clone(BitMask64Utils.ZERO);
/**
* 按组件类型ID直址的稀疏数组
@@ -310,7 +310,7 @@ export class Entity {
*
* @returns 实体的组件位掩码
*/
public get componentMask(): IBigIntLike {
public get componentMask(): BitMask64Data {
return this._componentMask;
}
@@ -354,7 +354,7 @@ export class Entity {
// 更新位掩码
const componentMask = ComponentRegistry.getBitMask(componentType);
this._componentMask = this._componentMask.or(componentMask);
BitMask64Utils.orInPlace(this._componentMask, componentMask);
return component;
}
@@ -422,7 +422,7 @@ export class Entity {
}
const mask = ComponentRegistry.getBitMask(type);
if (this._componentMask.and(mask).isZero()) {
if (BitMask64Utils.hasNone(this._componentMask, mask)) {
return null;
}
@@ -475,7 +475,7 @@ export class Entity {
}
const mask = ComponentRegistry.getBitMask(type);
return !this._componentMask.and(mask).isZero();
return BitMask64Utils.hasAny(this._componentMask, mask);
}
/**
@@ -510,8 +510,8 @@ export class Entity {
this._componentsByTypeId[typeId] = undefined;
// 更新位掩码
const componentMask = ComponentRegistry.getBitMask(componentType);
this._componentMask = this._componentMask.and(componentMask.not());
const bitIndex = ComponentRegistry.getBitIndex(componentType);
BitMask64Utils.clearBit(this._componentMask, bitIndex);
}
// 从迭代数组中移除
@@ -579,7 +579,7 @@ export class Entity {
// 清空稀疏数组和位掩码
this._componentsByTypeId.length = 0;
this._componentMask = BigIntFactory.zero();
BitMask64Utils.clear(this._componentMask);
// 移除组件
for (const component of componentsToRemove) {
@@ -981,7 +981,7 @@ export class Entity {
destroyed: this._isDestroyed,
componentCount: this.components.length,
componentTypes: this.components.map(c => getComponentInstanceTypeName(c)),
componentMask: this._componentMask.toString(2), // 二进制表示
componentMask: BitMask64Utils.toString(this._componentMask, 2), // 二进制表示
parentId: this._parent?.id || null,
childCount: this._children.length,
childIds: this._children.map(c => c.id),

View File

@@ -1,6 +1,6 @@
import { Entity } from '../Entity';
import { ComponentType, ComponentRegistry } from '../Core/ComponentStorage';
import { IBigIntLike, BigIntFactory } from './BigIntCompatibility';
import { BitMask64Utils, BitMask64Data } from './BigIntCompatibility';
import { SparseSet } from './SparseSet';
import { Pool } from '../../Utils/Pool/Pool';
import { IPoolable } from '../../Utils/Pool/IPoolable';
@@ -44,7 +44,7 @@ export class ComponentSparseSet {
* 与实体稀疏集合的密集数组对应,存储每个实体的组件位掩码。
* 数组索引与稀疏集合的密集数组索引一一对应。
*/
private _componentMasks: IBigIntLike[] = [];
private _componentMasks: BitMask64Data[] = [];
/**
* 组件类型到实体集合的映射
@@ -77,7 +77,7 @@ export class ComponentSparseSet {
this.removeEntity(entity);
}
let componentMask = BigIntFactory.zero();
let componentMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
const entityComponents = new Set<ComponentType>();
// 分析实体组件并构建位掩码
@@ -92,7 +92,7 @@ export class ComponentSparseSet {
// 获取组件位掩码并合并
const bitMask = ComponentRegistry.getBitMask(componentType);
componentMask = componentMask.or(bitMask);
BitMask64Utils.orInPlace(componentMask, bitMask);
}
// 添加实体到稀疏集合
@@ -101,7 +101,7 @@ export class ComponentSparseSet {
// 确保位掩码数组有足够空间
while (this._componentMasks.length <= entityIndex) {
this._componentMasks.push(BigIntFactory.zero());
this._componentMasks.push(BitMask64Utils.clone(BitMask64Utils.ZERO));
}
this._componentMasks[entityIndex] = componentMask;
@@ -169,13 +169,13 @@ export class ComponentSparseSet {
}
// 构建目标位掩码
let targetMask = BigIntFactory.zero();
let targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
for (const componentType of componentTypes) {
if (!ComponentRegistry.isRegistered(componentType)) {
return new Set<Entity>(); // 未注册的组件类型,结果为空
}
const bitMask = ComponentRegistry.getBitMask(componentType);
targetMask = targetMask.or(bitMask);
BitMask64Utils.orInPlace(targetMask, bitMask);
}
const result = ComponentSparseSet._entitySetPool.obtain();
@@ -183,7 +183,7 @@ export class ComponentSparseSet {
// 遍历所有实体,检查位掩码匹配
this._entities.forEach((entity, index) => {
const entityMask = this._componentMasks[index];
if ((entityMask.and(targetMask)).equals(targetMask)) {
if (BitMask64Utils.hasAll(entityMask, targetMask)) {
result.add(entity);
}
});
@@ -209,15 +209,15 @@ export class ComponentSparseSet {
}
// 构建目标位掩码
let targetMask = BigIntFactory.zero();
let targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
for (const componentType of componentTypes) {
if (ComponentRegistry.isRegistered(componentType)) {
const bitMask = ComponentRegistry.getBitMask(componentType);
targetMask = targetMask.or(bitMask);
BitMask64Utils.orInPlace(targetMask, bitMask);
}
}
if (targetMask.equals(BigIntFactory.zero())) {
if (BitMask64Utils.equals(targetMask, BitMask64Utils.ZERO)) {
return new Set<Entity>(); // 没有有效的组件类型
}
@@ -226,7 +226,7 @@ export class ComponentSparseSet {
// 遍历所有实体,检查位掩码匹配
this._entities.forEach((entity, index) => {
const entityMask = this._componentMasks[index];
if (!(entityMask.and(targetMask)).equals(BigIntFactory.zero())) {
if (BitMask64Utils.hasAny(entityMask, targetMask)) {
result.add(entity);
}
});
@@ -254,7 +254,7 @@ export class ComponentSparseSet {
const entityMask = this._componentMasks[entityIndex];
const componentMask = ComponentRegistry.getBitMask(componentType);
return !(entityMask.and(componentMask)).equals(BigIntFactory.zero());
return BitMask64Utils.hasAny(entityMask, componentMask);
}
/**
@@ -263,7 +263,7 @@ export class ComponentSparseSet {
* @param entity 实体
* @returns 组件位掩码如果实体不存在则返回undefined
*/
public getEntityMask(entity: Entity): IBigIntLike | undefined {
public getEntityMask(entity: Entity): BitMask64Data | undefined {
const entityIndex = this._entities.getIndex(entity);
if (entityIndex === undefined) {
return undefined;
@@ -299,7 +299,7 @@ export class ComponentSparseSet {
*
* @param callback 遍历回调函数
*/
public forEach(callback: (entity: Entity, mask: IBigIntLike, index: number) => void): void {
public forEach(callback: (entity: Entity, mask: BitMask64Data, index: number) => void): void {
this._entities.forEach((entity, index) => {
callback(entity, this._componentMasks[index], index);
});