单一数据源 + 懒加载缓存

This commit is contained in:
YHH
2025-09-30 23:37:47 +08:00
parent 952247def0
commit 632864b361
4 changed files with 116 additions and 95 deletions

View File

@@ -15,6 +15,7 @@ export type ComponentType<T extends Component = Component> = new (...args: any[]
export class ComponentRegistry {
protected static readonly _logger = createLogger('ComponentStorage');
private static componentTypes = new Map<Function, number>();
private static bitIndexToType = new Map<number, Function>();
private static componentNameToType = new Map<string, Function>();
private static componentNameToId = new Map<string, number>();
private static maskCache = new Map<string, BitMask64Data>();
@@ -40,9 +41,10 @@ export class ComponentRegistry {
const bitIndex = this.nextBitIndex++;
this.componentTypes.set(componentType, bitIndex);
this.bitIndexToType.set(bitIndex, componentType);
this.componentNameToType.set(typeName, componentType);
this.componentNameToId.set(typeName, bitIndex);
return bitIndex;
}
@@ -83,6 +85,15 @@ export class ComponentRegistry {
return this.componentTypes.has(componentType);
}
/**
* 通过位索引获取组件类型
* @param bitIndex 位索引
* @returns 组件类型构造函数或null
*/
public static getTypeByBitIndex(bitIndex: number): ComponentType | null {
return (this.bitIndexToType.get(bitIndex) as ComponentType) || null;
}
/**
* 通过名称获取组件类型
* @param componentName 组件名称
@@ -196,6 +207,7 @@ export class ComponentRegistry {
*/
public static reset(): void {
this.componentTypes.clear();
this.bitIndexToType.clear();
this.componentNameToType.clear();
this.componentNameToId.clear();
this.maskCache.clear();

View File

@@ -95,11 +95,6 @@ export class Entity {
*/
public readonly id: number;
/**
* 组件集合
*/
public readonly components: Component[] = [];
/**
* 所属场景引用
*/
@@ -124,36 +119,37 @@ export class Entity {
* 激活状态
*/
private _active: boolean = true;
/**
* 实体标签
*/
private _tag: number = 0;
/**
* 启用状态
*/
private _enabled: boolean = true;
/**
* 更新顺序
*/
private _updateOrder: number = 0;
/**
* 组件位掩码
* 组件位掩码(用于快速 hasComponent 检查)
*/
private _componentMask: BitMask64Data = BitMask64Utils.clone(BitMask64Utils.ZERO);
/**
* 按组件类型ID直址的稀疏数组
* 懒加载的组件数组缓存
*/
private _componentsByTypeId: (Component | undefined)[] = [];
private _componentCache: Component[] | null = null;
/**
* typeId到components数组中密集索引的映射表
* 本地组件存储(用于没有 Scene 的 Entity
* 当 Entity 添加到 Scene 时,组件会迁移到 Scene 的 componentStorageManager
*/
private _componentDenseIndexByTypeId: number[] = [];
private _localComponents: Map<ComponentType, Component> = new Map();
/**
* 构造函数
@@ -174,6 +170,55 @@ export class Entity {
return this._isDestroyed;
}
/**
* 获取组件数组(懒加载)
* @returns 只读的组件数组
*/
public get components(): readonly Component[] {
if (this._componentCache === null) {
this._rebuildComponentCache();
}
return this._componentCache!;
}
/**
* 从存储重建组件缓存
*/
private _rebuildComponentCache(): void {
const components: Component[] = [];
const mask = this._componentMask;
// 遍历位掩码中设置的位
for (let bitIndex = 0; bitIndex < 64; bitIndex++) {
const bitMask = BitMask64Utils.create(bitIndex);
if (BitMask64Utils.hasAny(mask, bitMask)) {
const componentType = ComponentRegistry.getTypeByBitIndex(bitIndex);
if (componentType) {
let component: Component | null = null;
// 优先从 Scene 存储获取
if (this.scene?.componentStorageManager) {
component = this.scene.componentStorageManager.getComponent(
this.id,
componentType
);
}
// Fallback 到本地存储
if (!component) {
component = this._localComponents.get(componentType) || null;
}
if (component) {
components.push(component);
}
}
}
}
this._componentCache = components;
}
/**
* 获取父实体
* @returns 父实体如果没有父实体则返回null
@@ -316,7 +361,7 @@ export class Entity {
/**
* 内部添加组件方法(不进行重复检查,用于初始化)
*
*
* @param component - 要添加的组件实例
* @returns 添加的组件实例
*/
@@ -327,17 +372,16 @@ export class Entity {
ComponentRegistry.register(componentType);
}
const typeId = ComponentRegistry.getBitIndex(componentType);
this._componentsByTypeId[typeId] = component;
const denseIndex = this.components.length;
this._componentDenseIndexByTypeId[typeId] = denseIndex;
this.components.push(component);
// 存储到本地 Map
this._localComponents.set(componentType, component);
// 更新位掩码
const componentMask = ComponentRegistry.getBitMask(componentType);
BitMask64Utils.orInPlace(this._componentMask, componentMask);
// 使缓存失效
this._componentCache = null;
return component;
}
@@ -384,50 +428,26 @@ export class Entity {
/**
* 获取指定类型的组件
*
*
* @param type - 组件类型
* @returns 组件实例或null
*/
public getComponent<T extends Component>(type: ComponentType<T>): T | null {
if (!ComponentRegistry.isRegistered(type)) {
// 快速检查:位掩码
if (!this.hasComponent(type)) {
return null;
}
const mask = ComponentRegistry.getBitMask(type);
if (BitMask64Utils.hasNone(this._componentMask, mask)) {
return null;
}
const typeId = ComponentRegistry.getBitIndex(type);
const component = this._componentsByTypeId[typeId];
if (component && component.constructor === type) {
return component as T;
}
if (this.scene && this.scene.componentStorageManager) {
const storageComponent = this.scene.componentStorageManager.getComponent(this.id, type);
if (storageComponent) {
this._componentsByTypeId[typeId] = storageComponent;
if (!this.components.includes(storageComponent)) {
const denseIndex = this.components.length;
this._componentDenseIndexByTypeId[typeId] = denseIndex;
this.components.push(storageComponent);
}
return storageComponent;
// 优先从 Scene 存储获取
if (this.scene?.componentStorageManager) {
const component = this.scene.componentStorageManager.getComponent(this.id, type);
if (component) {
return component;
}
}
for (let i = 0; i < this.components.length; i++) {
const component = this.components[i];
if (component instanceof type) {
this._componentsByTypeId[typeId] = component;
this._componentDenseIndexByTypeId[typeId] = i;
return component as T;
}
}
return null;
// Fallback 到本地存储
return (this._localComponents.get(type) as T) || null;
}
@@ -468,40 +488,28 @@ export class Entity {
/**
* 移除指定的组件
*
*
* @param component - 要移除的组件实例
*/
public removeComponent(component: Component): void {
const componentType = component.constructor as ComponentType;
if (!ComponentRegistry.isRegistered(componentType)) {
return;
}
const typeId = ComponentRegistry.getBitIndex(componentType);
this._componentsByTypeId[typeId] = undefined;
BitMask64Utils.clearBit(this._componentMask, typeId);
const denseIndex = this._componentDenseIndexByTypeId[typeId];
if (denseIndex !== undefined && denseIndex < this.components.length) {
const lastIndex = this.components.length - 1;
if (denseIndex !== lastIndex) {
const lastComponent = this.components[lastIndex];
this.components[denseIndex] = lastComponent;
const lastComponentType = lastComponent.constructor as ComponentType;
const lastTypeId = ComponentRegistry.getBitIndex(lastComponentType);
this._componentDenseIndexByTypeId[lastTypeId] = denseIndex;
}
this.components.pop();
}
this._componentDenseIndexByTypeId[typeId] = -1;
const bitIndex = ComponentRegistry.getBitIndex(componentType);
// 从本地存储移除
this._localComponents.delete(componentType);
// 更新位掩码
BitMask64Utils.clearBit(this._componentMask, bitIndex);
// 使缓存失效
this._componentCache = null;
// 从 Scene 存储移除
if (this.scene && this.scene.componentStorageManager) {
this.scene.componentStorageManager.removeComponent(this.id, componentType);
}
@@ -509,7 +517,7 @@ export class Entity {
if (component.onRemovedFromEntity) {
component.onRemovedFromEntity();
}
if (Entity.eventBus) {
Entity.eventBus.emitComponentRemoved({
timestamp: Date.now(),
@@ -546,14 +554,19 @@ export class Entity {
*/
public removeAllComponents(): void {
const componentsToRemove = [...this.components];
this._componentsByTypeId.length = 0;
this._componentDenseIndexByTypeId.length = 0;
// 清除本地存储
this._localComponents.clear();
// 清除位掩码
BitMask64Utils.clear(this._componentMask);
// 使缓存失效
this._componentCache = null;
for (const component of componentsToRemove) {
const componentType = component.constructor as ComponentType;
if (this.scene && this.scene.componentStorageManager) {
this.scene.componentStorageManager.removeComponent(this.id, componentType);
}
@@ -561,8 +574,6 @@ export class Entity {
component.onRemovedFromEntity();
}
this.components.length = 0;
// 通知所有相关的QuerySystem组件已全部移除
Entity.notifyQuerySystems(this);
}
@@ -895,8 +906,7 @@ export class Entity {
childCount: number;
childIds: number[];
depth: number;
indexMappingSize: number;
denseIndexMappingSize: number;
cacheBuilt: boolean;
} {
return {
name: this.name,
@@ -912,8 +922,7 @@ export class Entity {
childCount: this._children.length,
childIds: this._children.map(c => c.id),
depth: this.getDepth(),
indexMappingSize: this._componentsByTypeId.filter(c => c !== undefined).length,
denseIndexMappingSize: this._componentDenseIndexByTypeId.filter(idx => idx !== -1 && idx !== undefined).length
cacheBuilt: this._componentCache !== null
};
}
}

View File

@@ -717,7 +717,7 @@ export class EntityDataCollector {
/**
* 提取组件详细信息
*/
public extractComponentDetails(components: Component[]): Array<{
public extractComponentDetails(components: readonly Component[]): Array<{
typeName: string;
properties: Record<string, any>;
}> {

View File

@@ -266,7 +266,7 @@ describe('Entity - 组件缓存优化测试', () => {
expect(debugInfo.componentCount).toBe(2);
expect(debugInfo.componentTypes).toContain('TestPositionComponent');
expect(debugInfo.componentTypes).toContain('TestHealthComponent');
expect(debugInfo.indexMappingSize).toBe(2);
expect(debugInfo.cacheBuilt).toBe(true);
});
});
});