feat(core):统一 Core 库的命名规范和代码风格 (#207)

This commit is contained in:
YHH
2025-11-01 10:23:46 +08:00
committed by GitHub
parent 6778ccace4
commit 57c7e7be3f
7 changed files with 414 additions and 429 deletions

View File

@@ -36,7 +36,7 @@ export abstract class Component implements IComponent {
* *
* 用于为每个组件分配唯一的ID。 * 用于为每个组件分配唯一的ID。
*/ */
public static _idGenerator: number = 0; private static idGenerator: number = 0;
/** /**
* 组件唯一标识符 * 组件唯一标识符
@@ -58,7 +58,7 @@ export abstract class Component implements IComponent {
* 自动分配唯一ID给组件。 * 自动分配唯一ID给组件。
*/ */
constructor() { constructor() {
this.id = Component._idGenerator++; this.id = Component.idGenerator++;
} }
/** /**

View File

@@ -43,21 +43,21 @@ interface QueryCacheEntry {
* ``` * ```
*/ */
export class QuerySystem { export class QuerySystem {
private _logger = createLogger('QuerySystem'); private readonly _logger = createLogger('QuerySystem');
private entities: Entity[] = []; private _entities: Entity[] = [];
private entityIndex: EntityIndex; private _entityIndex: EntityIndex;
private _version = 0; private _version = 0;
private queryCache = new Map<string, QueryCacheEntry>(); private _queryCache = new Map<string, QueryCacheEntry>();
private cacheMaxSize = 1000; private _cacheMaxSize = 1000;
private cacheTimeout = 5000; private _cacheTimeout = 5000;
private componentMaskCache = new Map<string, BitMask64Data>(); private _componentMaskCache = new Map<string, BitMask64Data>();
private archetypeSystem: ArchetypeSystem; private _archetypeSystem: ArchetypeSystem;
private queryStats = { private _queryStats = {
totalQueries: 0, totalQueries: 0,
cacheHits: 0, cacheHits: 0,
indexHits: 0, indexHits: 0,
@@ -67,12 +67,12 @@ export class QuerySystem {
}; };
constructor() { constructor() {
this.entityIndex = { this._entityIndex = {
byTag: new Map(), byTag: new Map(),
byName: new Map() byName: new Map()
}; };
this.archetypeSystem = new ArchetypeSystem(); this._archetypeSystem = new ArchetypeSystem();
} }
/** /**
@@ -84,7 +84,7 @@ export class QuerySystem {
* @param entities 新的实体列表 * @param entities 新的实体列表
*/ */
public setEntities(entities: Entity[]): void { public setEntities(entities: Entity[]): void {
this.entities = entities; this._entities = entities;
this.clearQueryCache(); this.clearQueryCache();
this.clearReactiveQueries(); this.clearReactiveQueries();
this.rebuildIndexes(); this.rebuildIndexes();
@@ -100,11 +100,11 @@ export class QuerySystem {
* @param deferCacheClear 是否延迟缓存清理(用于批量操作) * @param deferCacheClear 是否延迟缓存清理(用于批量操作)
*/ */
public addEntity(entity: Entity, deferCacheClear: boolean = false): void { public addEntity(entity: Entity, deferCacheClear: boolean = false): void {
if (!this.entities.includes(entity)) { if (!this._entities.includes(entity)) {
this.entities.push(entity); this._entities.push(entity);
this.addEntityToIndexes(entity); this.addEntityToIndexes(entity);
this.archetypeSystem.addEntity(entity); this._archetypeSystem.addEntity(entity);
// 通知响应式查询 // 通知响应式查询
this.notifyReactiveQueriesEntityAdded(entity); this.notifyReactiveQueriesEntityAdded(entity);
@@ -131,16 +131,16 @@ export class QuerySystem {
if (entities.length === 0) return; if (entities.length === 0) return;
// 使用Set来快速检查重复 // 使用Set来快速检查重复
const existingIds = new Set(this.entities.map(e => e.id)); const existingIds = new Set(this._entities.map((e) => e.id));
let addedCount = 0; let addedCount = 0;
for (const entity of entities) { for (const entity of entities) {
if (!existingIds.has(entity.id)) { if (!existingIds.has(entity.id)) {
this.entities.push(entity); this._entities.push(entity);
this.addEntityToIndexes(entity); this.addEntityToIndexes(entity);
// 更新索引管理器 // 更新索引管理器
this.archetypeSystem.addEntity(entity); this._archetypeSystem.addEntity(entity);
existingIds.add(entity.id); existingIds.add(entity.id);
addedCount++; addedCount++;
@@ -166,7 +166,7 @@ export class QuerySystem {
// 避免调用栈溢出,分批添加 // 避免调用栈溢出,分批添加
for (const entity of entities) { for (const entity of entities) {
this.entities.push(entity); this._entities.push(entity);
} }
// 批量更新索引 // 批量更新索引
@@ -174,7 +174,7 @@ export class QuerySystem {
this.addEntityToIndexes(entity); this.addEntityToIndexes(entity);
// 更新索引管理器 // 更新索引管理器
this.archetypeSystem.addEntity(entity); this._archetypeSystem.addEntity(entity);
} }
// 清理缓存 // 清理缓存
@@ -189,17 +189,17 @@ export class QuerySystem {
* @param entity 要移除的实体 * @param entity 要移除的实体
*/ */
public removeEntity(entity: Entity): void { public removeEntity(entity: Entity): void {
const index = this.entities.indexOf(entity); const index = this._entities.indexOf(entity);
if (index !== -1) { if (index !== -1) {
const componentTypes: ComponentType[] = []; const componentTypes: ComponentType[] = [];
for (const component of entity.components) { for (const component of entity.components) {
componentTypes.push(component.constructor as ComponentType); componentTypes.push(component.constructor as ComponentType);
} }
this.entities.splice(index, 1); this._entities.splice(index, 1);
this.removeEntityFromIndexes(entity); this.removeEntityFromIndexes(entity);
this.archetypeSystem.removeEntity(entity); this._archetypeSystem.removeEntity(entity);
if (componentTypes.length > 0) { if (componentTypes.length > 0) {
this.notifyReactiveQueriesEntityRemoved(entity, componentTypes); this.notifyReactiveQueriesEntityRemoved(entity, componentTypes);
@@ -222,7 +222,7 @@ export class QuerySystem {
*/ */
public updateEntity(entity: Entity): void { public updateEntity(entity: Entity): void {
// 检查实体是否在查询系统中 // 检查实体是否在查询系统中
if (!this.entities.includes(entity)) { if (!this._entities.includes(entity)) {
// 如果实体不在系统中,直接添加 // 如果实体不在系统中,直接添加
this.addEntity(entity); this.addEntity(entity);
return; return;
@@ -232,7 +232,7 @@ export class QuerySystem {
this.removeEntityFromIndexes(entity); this.removeEntityFromIndexes(entity);
// 更新ArchetypeSystem中的实体状态 // 更新ArchetypeSystem中的实体状态
this.archetypeSystem.updateEntity(entity); this._archetypeSystem.updateEntity(entity);
// 重新添加实体到索引(基于新的组件状态) // 重新添加实体到索引(基于新的组件状态)
this.addEntityToIndexes(entity); this.addEntityToIndexes(entity);
@@ -253,28 +253,27 @@ export class QuerySystem {
// 标签索引 // 标签索引
const tag = entity.tag; const tag = entity.tag;
if (tag !== undefined) { if (tag !== undefined) {
const tagSet = this.entityIndex.byTag.get(tag) || this.createAndSetTagIndex(tag); const tagSet = this._entityIndex.byTag.get(tag) || this.createAndSetTagIndex(tag);
tagSet.add(entity); tagSet.add(entity);
} }
// 名称索引 // 名称索引
const name = entity.name; const name = entity.name;
if (name) { if (name) {
const nameSet = this.entityIndex.byName.get(name) || this.createAndSetNameIndex(name); const nameSet = this._entityIndex.byName.get(name) || this.createAndSetNameIndex(name);
nameSet.add(entity); nameSet.add(entity);
} }
} }
private createAndSetTagIndex(tag: number): Set<Entity> { private createAndSetTagIndex(tag: number): Set<Entity> {
const set = new Set<Entity>(); const set = new Set<Entity>();
this.entityIndex.byTag.set(tag, set); this._entityIndex.byTag.set(tag, set);
return set; return set;
} }
private createAndSetNameIndex(name: string): Set<Entity> { private createAndSetNameIndex(name: string): Set<Entity> {
const set = new Set<Entity>(); const set = new Set<Entity>();
this.entityIndex.byName.set(name, set); this._entityIndex.byName.set(name, set);
return set; return set;
} }
@@ -284,22 +283,22 @@ export class QuerySystem {
private removeEntityFromIndexes(entity: Entity): void { private removeEntityFromIndexes(entity: Entity): void {
// 从标签索引移除 // 从标签索引移除
if (entity.tag !== undefined) { if (entity.tag !== undefined) {
const tagSet = this.entityIndex.byTag.get(entity.tag); const tagSet = this._entityIndex.byTag.get(entity.tag);
if (tagSet) { if (tagSet) {
tagSet.delete(entity); tagSet.delete(entity);
if (tagSet.size === 0) { if (tagSet.size === 0) {
this.entityIndex.byTag.delete(entity.tag); this._entityIndex.byTag.delete(entity.tag);
} }
} }
} }
// 从名称索引移除 // 从名称索引移除
if (entity.name) { if (entity.name) {
const nameSet = this.entityIndex.byName.get(entity.name); const nameSet = this._entityIndex.byName.get(entity.name);
if (nameSet) { if (nameSet) {
nameSet.delete(entity); nameSet.delete(entity);
if (nameSet.size === 0) { if (nameSet.size === 0) {
this.entityIndex.byName.delete(entity.name); this._entityIndex.byName.delete(entity.name);
} }
} }
} }
@@ -312,15 +311,15 @@ export class QuerySystem {
* 通常在大量实体变更后调用以确保索引一致性。 * 通常在大量实体变更后调用以确保索引一致性。
*/ */
private rebuildIndexes(): void { private rebuildIndexes(): void {
this.entityIndex.byTag.clear(); this._entityIndex.byTag.clear();
this.entityIndex.byName.clear(); this._entityIndex.byName.clear();
// 清理ArchetypeSystem和ComponentIndexManager // 清理ArchetypeSystem和ComponentIndexManager
this.archetypeSystem.clear(); this._archetypeSystem.clear();
for (const entity of this.entities) { for (const entity of this._entities) {
this.addEntityToIndexes(entity); this.addEntityToIndexes(entity);
this.archetypeSystem.addEntity(entity); this._archetypeSystem.addEntity(entity);
} }
} }
@@ -342,7 +341,7 @@ export class QuerySystem {
*/ */
public queryAll(...componentTypes: ComponentType[]): QueryResult { public queryAll(...componentTypes: ComponentType[]): QueryResult {
const startTime = performance.now(); const startTime = performance.now();
this.queryStats.totalQueries++; this._queryStats.totalQueries++;
// 使用内部响应式查询作为智能缓存 // 使用内部响应式查询作为智能缓存
const reactiveQuery = this.getOrCreateReactiveQuery(QueryConditionType.ALL, componentTypes); const reactiveQuery = this.getOrCreateReactiveQuery(QueryConditionType.ALL, componentTypes);
@@ -351,7 +350,7 @@ export class QuerySystem {
const entities = reactiveQuery.getEntities(); const entities = reactiveQuery.getEntities();
// 统计为缓存命中(响应式查询本质上是永不过期的智能缓存) // 统计为缓存命中(响应式查询本质上是永不过期的智能缓存)
this.queryStats.cacheHits++; this._queryStats.cacheHits++;
return { return {
entities, entities,
@@ -379,7 +378,7 @@ export class QuerySystem {
*/ */
public queryAny(...componentTypes: ComponentType[]): QueryResult { public queryAny(...componentTypes: ComponentType[]): QueryResult {
const startTime = performance.now(); const startTime = performance.now();
this.queryStats.totalQueries++; this._queryStats.totalQueries++;
// 使用内部响应式查询作为智能缓存 // 使用内部响应式查询作为智能缓存
const reactiveQuery = this.getOrCreateReactiveQuery(QueryConditionType.ANY, componentTypes); const reactiveQuery = this.getOrCreateReactiveQuery(QueryConditionType.ANY, componentTypes);
@@ -388,7 +387,7 @@ export class QuerySystem {
const entities = reactiveQuery.getEntities(); const entities = reactiveQuery.getEntities();
// 统计为缓存命中(响应式查询本质上是永不过期的智能缓存) // 统计为缓存命中(响应式查询本质上是永不过期的智能缓存)
this.queryStats.cacheHits++; this._queryStats.cacheHits++;
return { return {
entities, entities,
@@ -416,7 +415,7 @@ export class QuerySystem {
*/ */
public queryNone(...componentTypes: ComponentType[]): QueryResult { public queryNone(...componentTypes: ComponentType[]): QueryResult {
const startTime = performance.now(); const startTime = performance.now();
this.queryStats.totalQueries++; this._queryStats.totalQueries++;
// 使用内部响应式查询作为智能缓存 // 使用内部响应式查询作为智能缓存
const reactiveQuery = this.getOrCreateReactiveQuery(QueryConditionType.NONE, componentTypes); const reactiveQuery = this.getOrCreateReactiveQuery(QueryConditionType.NONE, componentTypes);
@@ -425,7 +424,7 @@ export class QuerySystem {
const entities = reactiveQuery.getEntities(); const entities = reactiveQuery.getEntities();
// 统计为缓存命中(响应式查询本质上是永不过期的智能缓存) // 统计为缓存命中(响应式查询本质上是永不过期的智能缓存)
this.queryStats.cacheHits++; this._queryStats.cacheHits++;
return { return {
entities, entities,
@@ -452,14 +451,14 @@ export class QuerySystem {
*/ */
public queryByTag(tag: number): QueryResult { public queryByTag(tag: number): QueryResult {
const startTime = performance.now(); const startTime = performance.now();
this.queryStats.totalQueries++; this._queryStats.totalQueries++;
const cacheKey = `tag:${tag}`; const cacheKey = `tag:${tag}`;
// 检查缓存 // 检查缓存
const cached = this.getFromCache(cacheKey); const cached = this.getFromCache(cacheKey);
if (cached) { if (cached) {
this.queryStats.cacheHits++; this._queryStats.cacheHits++;
return { return {
entities: cached, entities: cached,
count: cached.length, count: cached.length,
@@ -469,8 +468,8 @@ export class QuerySystem {
} }
// 使用索引查询 // 使用索引查询
this.queryStats.indexHits++; this._queryStats.indexHits++;
const entities = Array.from(this.entityIndex.byTag.get(tag) || []); const entities = Array.from(this._entityIndex.byTag.get(tag) || []);
// 缓存结果 // 缓存结果
this.addToCache(cacheKey, entities); this.addToCache(cacheKey, entities);
@@ -500,14 +499,14 @@ export class QuerySystem {
*/ */
public queryByName(name: string): QueryResult { public queryByName(name: string): QueryResult {
const startTime = performance.now(); const startTime = performance.now();
this.queryStats.totalQueries++; this._queryStats.totalQueries++;
const cacheKey = `name:${name}`; const cacheKey = `name:${name}`;
// 检查缓存 // 检查缓存
const cached = this.getFromCache(cacheKey); const cached = this.getFromCache(cacheKey);
if (cached) { if (cached) {
this.queryStats.cacheHits++; this._queryStats.cacheHits++;
return { return {
entities: cached, entities: cached,
count: cached.length, count: cached.length,
@@ -517,8 +516,8 @@ export class QuerySystem {
} }
// 使用索引查询 // 使用索引查询
this.queryStats.indexHits++; this._queryStats.indexHits++;
const entities = Array.from(this.entityIndex.byName.get(name) || []); const entities = Array.from(this._entityIndex.byName.get(name) || []);
// 缓存结果 // 缓存结果
this.addToCache(cacheKey, entities); this.addToCache(cacheKey, entities);
@@ -548,14 +547,14 @@ export class QuerySystem {
*/ */
public queryByComponent<T extends Component>(componentType: ComponentType<T>): QueryResult { public queryByComponent<T extends Component>(componentType: ComponentType<T>): QueryResult {
const startTime = performance.now(); const startTime = performance.now();
this.queryStats.totalQueries++; this._queryStats.totalQueries++;
const cacheKey = this.generateCacheKey('component', [componentType]); const cacheKey = this.generateCacheKey('component', [componentType]);
// 检查缓存 // 检查缓存
const cached = this.getFromCache(cacheKey); const cached = this.getFromCache(cacheKey);
if (cached) { if (cached) {
this.queryStats.cacheHits++; this._queryStats.cacheHits++;
return { return {
entities: cached, entities: cached,
count: cached.length, count: cached.length,
@@ -564,8 +563,8 @@ export class QuerySystem {
}; };
} }
this.queryStats.indexHits++; this._queryStats.indexHits++;
const entities = this.archetypeSystem.getEntitiesByComponent(componentType); const entities = this._archetypeSystem.getEntitiesByComponent(componentType);
// 缓存结果 // 缓存结果
this.addToCache(cacheKey, entities); this.addToCache(cacheKey, entities);
@@ -582,12 +581,12 @@ export class QuerySystem {
* 从缓存获取查询结果 * 从缓存获取查询结果
*/ */
private getFromCache(cacheKey: string): readonly Entity[] | null { private getFromCache(cacheKey: string): readonly Entity[] | null {
const entry = this.queryCache.get(cacheKey); const entry = this._queryCache.get(cacheKey);
if (!entry) return null; if (!entry) return null;
// 检查缓存是否过期或版本过期 // 检查缓存是否过期或版本过期
if (Date.now() - entry.timestamp > this.cacheTimeout || entry.version !== this._version) { if (Date.now() - entry.timestamp > this._cacheTimeout || entry.version !== this._version) {
this.queryCache.delete(cacheKey); this._queryCache.delete(cacheKey);
return null; return null;
} }
@@ -600,11 +599,11 @@ export class QuerySystem {
*/ */
private addToCache(cacheKey: string, entities: Entity[]): void { private addToCache(cacheKey: string, entities: Entity[]): void {
// 如果缓存已满,清理最少使用的条目 // 如果缓存已满,清理最少使用的条目
if (this.queryCache.size >= this.cacheMaxSize) { if (this._queryCache.size >= this._cacheMaxSize) {
this.cleanupCache(); this.cleanupCache();
} }
this.queryCache.set(cacheKey, { this._queryCache.set(cacheKey, {
entities: entities, // 直接使用引用,通过版本号控制失效 entities: entities, // 直接使用引用,通过版本号控制失效
timestamp: Date.now(), timestamp: Date.now(),
hitCount: 0, hitCount: 0,
@@ -618,22 +617,24 @@ export class QuerySystem {
private cleanupCache(): void { private cleanupCache(): void {
// 移除过期的缓存条目 // 移除过期的缓存条目
const now = Date.now(); const now = Date.now();
for (const [key, entry] of this.queryCache.entries()) { for (const [key, entry] of this._queryCache.entries()) {
if (now - entry.timestamp > this.cacheTimeout) { if (now - entry.timestamp > this._cacheTimeout) {
this.queryCache.delete(key); this._queryCache.delete(key);
} }
} }
// 如果还是太满,移除最少使用的条目 // 如果还是太满,移除最少使用的条目
if (this.queryCache.size >= this.cacheMaxSize) { if (this._queryCache.size >= this._cacheMaxSize) {
let minHitCount = Infinity; let minHitCount = Infinity;
let oldestKey = ''; let oldestKey = '';
let oldestTimestamp = Infinity; let oldestTimestamp = Infinity;
// 单次遍历找到最少使用或最旧的条目 // 单次遍历找到最少使用或最旧的条目
for (const [key, entry] of this.queryCache.entries()) { for (const [key, entry] of this._queryCache.entries()) {
if (entry.hitCount < minHitCount || if (
(entry.hitCount === minHitCount && entry.timestamp < oldestTimestamp)) { entry.hitCount < minHitCount ||
(entry.hitCount === minHitCount && entry.timestamp < oldestTimestamp)
) {
minHitCount = entry.hitCount; minHitCount = entry.hitCount;
oldestKey = key; oldestKey = key;
oldestTimestamp = entry.timestamp; oldestTimestamp = entry.timestamp;
@@ -641,7 +642,7 @@ export class QuerySystem {
} }
if (oldestKey) { if (oldestKey) {
this.queryCache.delete(oldestKey); this._queryCache.delete(oldestKey);
} }
} }
} }
@@ -650,8 +651,8 @@ export class QuerySystem {
* 清除所有查询缓存 * 清除所有查询缓存
*/ */
private clearQueryCache(): void { private clearQueryCache(): void {
this.queryCache.clear(); this._queryCache.clear();
this.componentMaskCache.clear(); this._componentMaskCache.clear();
} }
/** /**
@@ -679,10 +680,13 @@ export class QuerySystem {
} }
// 多组件查询:使用排序后的类型名称创建键 // 多组件查询:使用排序后的类型名称创建键
const sortKey = componentTypes.map(t => { const sortKey = componentTypes
.map((t) => {
const name = getComponentTypeName(t); const name = getComponentTypeName(t);
return name; return name;
}).sort().join(','); })
.sort()
.join(',');
const fullKey = `${prefix}:${sortKey}`; const fullKey = `${prefix}:${sortKey}`;
@@ -724,10 +728,7 @@ export class QuerySystem {
* }); * });
* ``` * ```
*/ */
public createReactiveQuery( public createReactiveQuery(componentTypes: ComponentType[], config?: ReactiveQueryConfig): ReactiveQuery {
componentTypes: ComponentType[],
config?: ReactiveQueryConfig
): ReactiveQuery {
if (!componentTypes || componentTypes.length === 0) { if (!componentTypes || componentTypes.length === 0) {
throw new Error('组件类型列表不能为空'); throw new Error('组件类型列表不能为空');
} }
@@ -741,10 +742,7 @@ export class QuerySystem {
const query = new ReactiveQuery(condition, config); const query = new ReactiveQuery(condition, config);
const initialEntities = this.executeTraditionalQuery( const initialEntities = this.executeTraditionalQuery(QueryConditionType.ALL, componentTypes);
QueryConditionType.ALL,
componentTypes
);
query.initializeWith(initialEntities); query.initializeWith(initialEntities);
const cacheKey = this.generateCacheKey('all', componentTypes); const cacheKey = this.generateCacheKey('all', componentTypes);
@@ -810,18 +808,21 @@ export class QuerySystem {
*/ */
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data { private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
// 生成缓存键 // 生成缓存键
const cacheKey = componentTypes.map(t => { const cacheKey = componentTypes
.map((t) => {
return getComponentTypeName(t); return getComponentTypeName(t);
}).sort().join(','); })
.sort()
.join(',');
// 检查缓存 // 检查缓存
const cached = this.componentMaskCache.get(cacheKey); const cached = this._componentMaskCache.get(cacheKey);
if (cached) { if (cached) {
return cached; return cached;
} }
// 使用ComponentRegistry而不是ComponentTypeManager,确保bitIndex一致 // 使用ComponentRegistry而不是ComponentTypeManager,确保bitIndex一致
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO); const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
for (const type of componentTypes) { for (const type of componentTypes) {
// 确保组件已注册 // 确保组件已注册
if (!ComponentRegistry.isRegistered(type)) { if (!ComponentRegistry.isRegistered(type)) {
@@ -832,7 +833,7 @@ export class QuerySystem {
} }
// 缓存结果 // 缓存结果
this.componentMaskCache.set(cacheKey, mask); this._componentMaskCache.set(cacheKey, mask);
return mask; return mask;
} }
@@ -847,7 +848,7 @@ export class QuerySystem {
* 获取所有实体 * 获取所有实体
*/ */
public getAllEntities(): readonly Entity[] { public getAllEntities(): readonly Entity[] {
return this.entities; return this._entities;
} }
/** /**
@@ -883,28 +884,32 @@ export class QuerySystem {
}; };
} { } {
return { return {
entityCount: this.entities.length, entityCount: this._entities.length,
indexStats: { indexStats: {
componentIndexSize: this.archetypeSystem.getAllArchetypes().length, componentIndexSize: this._archetypeSystem.getAllArchetypes().length,
tagIndexSize: this.entityIndex.byTag.size, tagIndexSize: this._entityIndex.byTag.size,
nameIndexSize: this.entityIndex.byName.size nameIndexSize: this._entityIndex.byName.size
}, },
queryStats: { queryStats: {
...this.queryStats, ...this._queryStats,
cacheHitRate: this.queryStats.totalQueries > 0 ? cacheHitRate:
(this.queryStats.cacheHits / this.queryStats.totalQueries * 100).toFixed(2) + '%' : '0%' this._queryStats.totalQueries > 0
? ((this._queryStats.cacheHits / this._queryStats.totalQueries) * 100).toFixed(2) + '%'
: '0%'
}, },
optimizationStats: { optimizationStats: {
archetypeSystem: this.archetypeSystem.getAllArchetypes().map(a => ({ archetypeSystem: this._archetypeSystem.getAllArchetypes().map((a) => ({
id: a.id, id: a.id,
componentTypes: a.componentTypes.map(t => getComponentTypeName(t)), componentTypes: a.componentTypes.map((t) => getComponentTypeName(t)),
entityCount: a.entities.size entityCount: a.entities.size
})) }))
}, },
cacheStats: { cacheStats: {
size: this._reactiveQueries.size, size: this._reactiveQueries.size,
hitRate: this.queryStats.totalQueries > 0 ? hitRate:
(this.queryStats.cacheHits / this.queryStats.totalQueries * 100).toFixed(2) + '%' : '0%' this._queryStats.totalQueries > 0
? ((this._queryStats.cacheHits / this._queryStats.totalQueries) * 100).toFixed(2) + '%'
: '0%'
} }
}; };
} }
@@ -915,7 +920,7 @@ export class QuerySystem {
* @param entity 要查询的实体 * @param entity 要查询的实体
*/ */
public getEntityArchetype(entity: Entity): Archetype | undefined { public getEntityArchetype(entity: Entity): Archetype | undefined {
return this.archetypeSystem.getEntityArchetype(entity); return this._archetypeSystem.getEntityArchetype(entity);
} }
// ============================================================ // ============================================================
@@ -941,10 +946,7 @@ export class QuerySystem {
* @param componentTypes 组件类型列表 * @param componentTypes 组件类型列表
* @returns 响应式查询实例 * @returns 响应式查询实例
*/ */
private getOrCreateReactiveQuery( private getOrCreateReactiveQuery(queryType: QueryConditionType, componentTypes: ComponentType[]): ReactiveQuery {
queryType: QueryConditionType,
componentTypes: ComponentType[]
): ReactiveQuery {
// 生成缓存键(与传统缓存键格式一致) // 生成缓存键(与传统缓存键格式一致)
const cacheKey = this.generateCacheKey(queryType, componentTypes); const cacheKey = this.generateCacheKey(queryType, componentTypes);
@@ -996,13 +998,10 @@ export class QuerySystem {
* @param componentTypes 组件类型列表 * @param componentTypes 组件类型列表
* @returns 匹配的实体列表 * @returns 匹配的实体列表
*/ */
private executeTraditionalQuery( private executeTraditionalQuery(queryType: QueryConditionType, componentTypes: ComponentType[]): Entity[] {
queryType: QueryConditionType,
componentTypes: ComponentType[]
): Entity[] {
switch (queryType) { switch (queryType) {
case QueryConditionType.ALL: { case QueryConditionType.ALL: {
const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, 'AND'); const archetypeResult = this._archetypeSystem.queryArchetypes(componentTypes, 'AND');
const entities: Entity[] = []; const entities: Entity[] = [];
for (const archetype of archetypeResult.archetypes) { for (const archetype of archetypeResult.archetypes) {
for (const entity of archetype.entities) { for (const entity of archetype.entities) {
@@ -1012,7 +1011,7 @@ export class QuerySystem {
return entities; return entities;
} }
case QueryConditionType.ANY: { case QueryConditionType.ANY: {
const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, 'OR'); const archetypeResult = this._archetypeSystem.queryArchetypes(componentTypes, 'OR');
const entities: Entity[] = []; const entities: Entity[] = [];
for (const archetype of archetypeResult.archetypes) { for (const archetype of archetypeResult.archetypes) {
for (const entity of archetype.entities) { for (const entity of archetype.entities) {
@@ -1023,9 +1022,7 @@ export class QuerySystem {
} }
case QueryConditionType.NONE: { case QueryConditionType.NONE: {
const mask = this.createComponentMask(componentTypes); const mask = this.createComponentMask(componentTypes);
return this.entities.filter(entity => return this._entities.filter((entity) => BitMask64Utils.hasNone(entity.componentMask, mask));
BitMask64Utils.hasNone(entity.componentMask, mask)
);
} }
default: default:
return []; return [];
@@ -1241,7 +1238,7 @@ export class QueryBuilder {
* 创建组件掩码 * 创建组件掩码
*/ */
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data { private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO); const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
for (const type of componentTypes) { for (const type of componentTypes) {
try { try {
const bitMask = ComponentRegistry.getBitMask(type); const bitMask = ComponentRegistry.getBitMask(type);

View File

@@ -21,14 +21,11 @@ export class EntityComparer {
*/ */
public compare(self: Entity, other: Entity): number { public compare(self: Entity, other: Entity): number {
let compare = self.updateOrder - other.updateOrder; let compare = self.updateOrder - other.updateOrder;
if (compare == 0) if (compare == 0) compare = self.id - other.id;
compare = self.id - other.id;
return compare; return compare;
} }
} }
/** /**
* 游戏实体类 * 游戏实体类
* *
@@ -103,7 +100,7 @@ export class Entity {
/** /**
* 销毁状态标志 * 销毁状态标志
*/ */
public _isDestroyed: boolean = false; private _isDestroyed: boolean = false;
/** /**
* 父实体引用 * 父实体引用
@@ -164,6 +161,18 @@ export class Entity {
return this._isDestroyed; return this._isDestroyed;
} }
/**
* 设置销毁状态(内部使用)
*
* 此方法供Scene和批量操作使用以提高性能。
* 不应在普通业务逻辑中调用应使用destroy()方法。
*
* @internal
*/
public setDestroyedState(destroyed: boolean): void {
this._isDestroyed = destroyed;
}
/** /**
* 获取组件数组(懒加载) * 获取组件数组(懒加载)
* @returns 只读的组件数组 * @returns 只读的组件数组
@@ -193,10 +202,7 @@ export class Entity {
if (BitMask64Utils.getBit(mask, bitIndex)) { if (BitMask64Utils.getBit(mask, bitIndex)) {
const componentType = ComponentRegistry.getTypeByBitIndex(bitIndex); const componentType = ComponentRegistry.getTypeByBitIndex(bitIndex);
if (componentType) { if (componentType) {
const component = this.scene.componentStorageManager.getComponent( const component = this.scene.componentStorageManager.getComponent(this.id, componentType);
this.id,
componentType
);
if (component) { if (component) {
components.push(component); components.push(component);
@@ -346,10 +352,7 @@ export class Entity {
* const health = entity.createComponent(Health, 100); * const health = entity.createComponent(Health, 100);
* ``` * ```
*/ */
public createComponent<T extends Component>( public createComponent<T extends Component>(componentType: ComponentType<T>, ...args: any[]): T {
componentType: ComponentType<T>,
...args: any[]
): T {
const component = new componentType(...args); const component = new componentType(...args);
return this.addComponent(component); return this.addComponent(component);
} }
@@ -394,11 +397,13 @@ export class Entity {
const componentType = component.constructor as ComponentType<T>; const componentType = component.constructor as ComponentType<T>;
if (!this.scene) { if (!this.scene) {
throw new Error(`Entity must be added to Scene before adding components. Use scene.createEntity() instead of new Entity()`); throw new Error(
'Entity must be added to Scene before adding components. Use scene.createEntity() instead of new Entity()'
);
} }
if (!this.scene.componentStorageManager) { if (!this.scene.componentStorageManager) {
throw new Error(`Scene does not have componentStorageManager`); throw new Error('Scene does not have componentStorageManager');
} }
if (this.hasComponent(componentType)) { if (this.hasComponent(componentType)) {
@@ -427,7 +432,6 @@ export class Entity {
}); });
} }
// 通知所有相关的QuerySystem组件已变动 // 通知所有相关的QuerySystem组件已变动
Entity.notifyQuerySystems(this); Entity.notifyQuerySystems(this);
@@ -464,9 +468,6 @@ export class Entity {
return component as T | null; return component as T | null;
} }
/** /**
* 检查实体是否拥有指定类型的组件 * 检查实体是否拥有指定类型的组件
* *
@@ -506,10 +507,7 @@ export class Entity {
* position.x = 100; * position.x = 100;
* ``` * ```
*/ */
public getOrCreateComponent<T extends Component>( public getOrCreateComponent<T extends Component>(type: ComponentType<T>, ...args: any[]): T {
type: ComponentType<T>,
...args: any[]
): T {
let component = this.getComponent(type); let component = this.getComponent(type);
if (!component) { if (!component) {
component = this.createComponent(type, ...args); component = this.createComponent(type, ...args);
@@ -645,8 +643,6 @@ export class Entity {
return removedComponents; return removedComponents;
} }
/** /**
* 获取所有指定类型的组件 * 获取所有指定类型的组件
* *
@@ -700,7 +696,7 @@ export class Entity {
*/ */
public addChild(child: Entity): Entity { public addChild(child: Entity): Entity {
if (child === this) { if (child === this) {
throw new Error("Entity cannot be its own child"); throw new Error('Entity cannot be its own child');
} }
if (child._parent === this) { if (child._parent === this) {
@@ -891,7 +887,6 @@ export class Entity {
} }
} }
/** /**
* 销毁实体 * 销毁实体
* *
@@ -949,7 +944,7 @@ export class Entity {
collectChildren(this); collectChildren(this);
for (const entity of toDestroy) { for (const entity of toDestroy) {
entity._isDestroyed = true; entity.setDestroyedState(true);
} }
for (const entity of toDestroy) { for (const entity of toDestroy) {
@@ -1016,11 +1011,11 @@ export class Entity {
activeInHierarchy: this.activeInHierarchy, activeInHierarchy: this.activeInHierarchy,
destroyed: this._isDestroyed, destroyed: this._isDestroyed,
componentCount: this.components.length, componentCount: this.components.length,
componentTypes: this.components.map(c => getComponentInstanceTypeName(c)), componentTypes: this.components.map((c) => getComponentInstanceTypeName(c)),
componentMask: BitMask64Utils.toString(this._componentMask, 2), // 二进制表示 componentMask: BitMask64Utils.toString(this._componentMask, 2), // 二进制表示
parentId: this._parent?.id || null, parentId: this._parent?.id || null,
childCount: this._children.length, childCount: this._children.length,
childIds: this._children.map(c => c.id), childIds: this._children.map((c) => c.id),
depth: this.getDepth(), depth: this.getDepth(),
cacheBuilt: this._componentCache !== null cacheBuilt: this._componentCache !== null
}; };

View File

@@ -8,10 +8,18 @@ import { TypeSafeEventSystem } from './Core/EventSystem';
import { EventBus } from './Core/EventBus'; import { EventBus } from './Core/EventBus';
import { ReferenceTracker } from './Core/ReferenceTracker'; import { ReferenceTracker } from './Core/ReferenceTracker';
import { IScene, ISceneConfig } from './IScene'; import { IScene, ISceneConfig } from './IScene';
import { getComponentInstanceTypeName, getSystemInstanceTypeName, getSystemMetadata } from "./Decorators"; import { getComponentInstanceTypeName, getSystemInstanceTypeName, getSystemMetadata } from './Decorators';
import { TypedQueryBuilder } from './Core/Query/TypedQuery'; import { TypedQueryBuilder } from './Core/Query/TypedQuery';
import { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer'; import {
import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer'; SceneSerializer,
SceneSerializationOptions,
SceneDeserializationOptions
} from './Serialization/SceneSerializer';
import {
IncrementalSerializer,
IncrementalSnapshot,
IncrementalSerializationOptions
} from './Serialization/IncrementalSerializer';
import { ComponentPoolManager } from './Core/ComponentPool'; import { ComponentPoolManager } from './Core/ComponentPool';
import { PerformanceMonitor } from '../Utils/PerformanceMonitor'; import { PerformanceMonitor } from '../Utils/PerformanceMonitor';
import { ServiceContainer, type ServiceType } from '../Core/ServiceContainer'; import { ServiceContainer, type ServiceType } from '../Core/ServiceContainer';
@@ -30,7 +38,7 @@ export class Scene implements IScene {
* *
* 用于标识和调试的友好名称。 * 用于标识和调试的友好名称。
*/ */
public name: string = ""; public name: string = '';
/** /**
* 场景自定义数据 * 场景自定义数据
@@ -46,7 +54,6 @@ export class Scene implements IScene {
*/ */
public readonly entities: EntityList; public readonly entities: EntityList;
/** /**
* 实体ID池 * 实体ID池
* *
@@ -231,8 +238,7 @@ export class Scene implements IScene {
*/ */
private get performanceMonitor(): PerformanceMonitor { private get performanceMonitor(): PerformanceMonitor {
if (!this._performanceMonitor) { if (!this._performanceMonitor) {
this._performanceMonitor = this._services.tryResolve(PerformanceMonitor) this._performanceMonitor = this._services.tryResolve(PerformanceMonitor) ?? new PerformanceMonitor();
?? new PerformanceMonitor();
} }
return this._performanceMonitor; return this._performanceMonitor;
} }
@@ -242,24 +248,21 @@ export class Scene implements IScene {
* *
* 在场景创建时调用,子类可以重写此方法来设置初始实体和组件。 * 在场景创建时调用,子类可以重写此方法来设置初始实体和组件。
*/ */
public initialize(): void { public initialize(): void {}
}
/** /**
* 场景开始运行时的回调 * 场景开始运行时的回调
* *
* 在场景开始运行时调用,可以在此方法中执行场景启动逻辑。 * 在场景开始运行时调用,可以在此方法中执行场景启动逻辑。
*/ */
public onStart(): void { public onStart(): void {}
}
/** /**
* 场景卸载时的回调 * 场景卸载时的回调
* *
* 在场景被销毁时调用,可以在此方法中执行清理工作。 * 在场景被销毁时调用,可以在此方法中执行清理工作。
*/ */
public unload(): void { public unload(): void {}
}
/** /**
* 开始场景,启动实体处理器等 * 开始场景,启动实体处理器等
@@ -338,7 +341,7 @@ export class Scene implements IScene {
* @param name 实体名称 * @param name 实体名称
*/ */
public createEntity(name: string) { public createEntity(name: string) {
let entity = new Entity(name, this.identifierPool.checkOut()); const entity = new Entity(name, this.identifierPool.checkOut());
this.eventSystem.emitSync('entity:created', { entityName: name, entity, scene: this }); this.eventSystem.emitSync('entity:created', { entityName: name, entity, scene: this });
@@ -384,7 +387,7 @@ export class Scene implements IScene {
* @param namePrefix 实体名称前缀 * @param namePrefix 实体名称前缀
* @returns 创建的实体列表 * @returns 创建的实体列表
*/ */
public createEntities(count: number, namePrefix: string = "Entity"): Entity[] { public createEntities(count: number, namePrefix: string = 'Entity'): Entity[] {
const entities: Entity[] = []; const entities: Entity[] = [];
// 批量创建实体对象,不立即添加到系统 // 批量创建实体对象,不立即添加到系统
@@ -408,7 +411,6 @@ export class Scene implements IScene {
return entities; return entities;
} }
/** /**
* 批量销毁实体 * 批量销毁实体
*/ */
@@ -416,7 +418,7 @@ export class Scene implements IScene {
if (entities.length === 0) return; if (entities.length === 0) return;
for (const entity of entities) { for (const entity of entities) {
entity._isDestroyed = true; entity.setDestroyedState(true);
} }
for (const entity of entities) { for (const entity of entities) {
@@ -473,7 +475,9 @@ export class Scene implements IScene {
/** /**
* 根据名称查找实体(别名方法) * 根据名称查找实体(别名方法)
*
* @param name 实体名称 * @param name 实体名称
* @deprecated 请使用 findEntity() 代替此方法
*/ */
public getEntityByName(name: string): Entity | null { public getEntityByName(name: string): Entity | null {
return this.findEntity(name); return this.findEntity(name);
@@ -481,7 +485,9 @@ export class Scene implements IScene {
/** /**
* 根据标签查找实体(别名方法) * 根据标签查找实体(别名方法)
*
* @param tag 实体标签 * @param tag 实体标签
* @deprecated 请使用 findEntitiesByTag() 代替此方法
*/ */
public getEntitiesByTag(tag: number): Entity[] { public getEntitiesByTag(tag: number): Entity[] {
return this.findEntitiesByTag(tag); return this.findEntitiesByTag(tag);
@@ -577,9 +583,7 @@ export class Scene implements IScene {
* scene.addEntityProcessor(system); * scene.addEntityProcessor(system);
* ``` * ```
*/ */
public addEntityProcessor<T extends EntitySystem>( public addEntityProcessor<T extends EntitySystem>(systemTypeOrInstance: ServiceType<T> | T): T {
systemTypeOrInstance: ServiceType<T> | T
): T {
let system: T; let system: T;
let constructor: any; let constructor: any;
@@ -609,7 +613,7 @@ export class Scene implements IScene {
} else { } else {
this.logger.warn( this.logger.warn(
`Attempting to register a different instance of ${constructor.name}, ` + `Attempting to register a different instance of ${constructor.name}, ` +
`but type is already registered. Returning existing instance.` 'but type is already registered. Returning existing instance.'
); );
return existingSystem as T; return existingSystem as T;
} }
@@ -758,7 +762,6 @@ export class Scene implements IScene {
}; };
} }
/** /**
* 获取场景的调试信息 * 获取场景的调试信息
*/ */
@@ -786,13 +789,13 @@ export class Scene implements IScene {
entityCount: this.entities.count, entityCount: this.entities.count,
processorCount: systems.length, processorCount: systems.length,
isRunning: this._didSceneBegin, isRunning: this._didSceneBegin,
entities: this.entities.buffer.map(entity => ({ entities: this.entities.buffer.map((entity) => ({
name: entity.name, name: entity.name,
id: entity.id, id: entity.id,
componentCount: entity.components.length, componentCount: entity.components.length,
componentTypes: entity.components.map(c => getComponentInstanceTypeName(c)) componentTypes: entity.components.map((c) => getComponentInstanceTypeName(c))
})), })),
processors: systems.map(processor => ({ processors: systems.map((processor) => ({
name: getSystemInstanceTypeName(processor), name: getSystemInstanceTypeName(processor),
updateOrder: processor.updateOrder, updateOrder: processor.updateOrder,
entityCount: (processor as any)._entities?.length || 0 entityCount: (processor as any)._entities?.length || 0
@@ -910,11 +913,7 @@ export class Scene implements IScene {
throw new Error('必须先调用 createIncrementalSnapshot() 创建基础快照'); throw new Error('必须先调用 createIncrementalSnapshot() 创建基础快照');
} }
return IncrementalSerializer.computeIncremental( return IncrementalSerializer.computeIncremental(this, this._incrementalBaseSnapshot, options);
this,
this._incrementalBaseSnapshot,
options
);
} }
/** /**
@@ -941,14 +940,13 @@ export class Scene implements IScene {
incremental: IncrementalSnapshot | string | Uint8Array, incremental: IncrementalSnapshot | string | Uint8Array,
componentRegistry?: Map<string, any> componentRegistry?: Map<string, any>
): void { ): void {
const isSerializedData = typeof incremental === 'string' || const isSerializedData = typeof incremental === 'string' || incremental instanceof Uint8Array;
incremental instanceof Uint8Array;
const snapshot = isSerializedData const snapshot = isSerializedData
? IncrementalSerializer.deserializeIncremental(incremental as string | Uint8Array) ? IncrementalSerializer.deserializeIncremental(incremental as string | Uint8Array)
: incremental as IncrementalSnapshot; : (incremental as IncrementalSnapshot);
const registry = componentRegistry || ComponentRegistry.getAllComponentNames() as Map<string, any>; const registry = componentRegistry || (ComponentRegistry.getAllComponentNames() as Map<string, any>);
IncrementalSerializer.applyIncremental(this, snapshot, registry); IncrementalSerializer.applyIncremental(this, snapshot, registry);
} }

View File

@@ -20,7 +20,6 @@ interface EventListenerRecord {
listenerRef: string; listenerRef: string;
} }
/** /**
* 实体系统的基类 * 实体系统的基类
* *
@@ -64,9 +63,9 @@ interface EventListenerRecord {
* } * }
* ``` * ```
*/ */
export abstract class EntitySystem< export abstract class EntitySystem<_TComponents extends readonly ComponentConstructor[] = []>
_TComponents extends readonly ComponentConstructor[] = [] implements ISystemBase, IService
> implements ISystemBase, IService { {
private _updateOrder: number; private _updateOrder: number;
private _enabled: boolean; private _enabled: boolean;
private _performanceMonitor: PerformanceMonitor | null; private _performanceMonitor: PerformanceMonitor | null;
@@ -77,7 +76,6 @@ export abstract class EntitySystem<
private _scene: Scene | null; private _scene: Scene | null;
protected logger: ReturnType<typeof createLogger>; protected logger: ReturnType<typeof createLogger>;
/** /**
* 实体ID映射缓存 * 实体ID映射缓存
*/ */
@@ -161,7 +159,6 @@ export abstract class EntitySystem<
// 初始化logger // 初始化logger
this.logger = createLogger(this.getLoggerName()); this.logger = createLogger(this.getLoggerName());
this._entityCache = { this._entityCache = {
frame: null, frame: null,
persistent: null, persistent: null,
@@ -203,7 +200,9 @@ export abstract class EntitySystem<
*/ */
private getPerformanceMonitor(): PerformanceMonitor { private getPerformanceMonitor(): PerformanceMonitor {
if (!this._performanceMonitor) { if (!this._performanceMonitor) {
throw new Error(`${this._systemName}: PerformanceMonitor未注入请确保在Core.create()之后再添加System到Scene`); throw new Error(
`${this._systemName}: PerformanceMonitor未注入请确保在Core.create()之后再添加System到Scene`
);
} }
return this._performanceMonitor; return this._performanceMonitor;
} }
@@ -316,16 +315,28 @@ export abstract class EntitySystem<
/** /**
* 检查是否为单一条件查询 * 检查是否为单一条件查询
*
* 使用位运算优化多条件检测。将每种查询条件映射到不同的位:
* - all: 第0位 (1)
* - any: 第1位 (2)
* - none: 第2位 (4)
* - tag: 第3位 (8)
* - name: 第4位 (16)
* - component: 第5位 (32)
*/ */
private isSingleCondition(condition: QueryCondition): boolean { private isSingleCondition(condition: QueryCondition): boolean {
// 使用位OR运算合并所有条件标记
const flags = const flags =
((condition.all.length > 0) ? 1 : 0) | (condition.all.length > 0 ? 1 : 0) |
((condition.any.length > 0) ? 2 : 0) | (condition.any.length > 0 ? 2 : 0) |
((condition.none.length > 0) ? 4 : 0) | (condition.none.length > 0 ? 4 : 0) |
((condition.tag !== undefined) ? 8 : 0) | (condition.tag !== undefined ? 8 : 0) |
((condition.name !== undefined) ? 16 : 0) | (condition.name !== undefined ? 16 : 0) |
((condition.component !== undefined) ? 32 : 0); (condition.component !== undefined ? 32 : 0);
// 位运算技巧:如果只有一个位被设置,则 flags & (flags - 1) == 0
// 例如flags=4 (100), flags-1=3 (011), 4&3=0
// 但如果 flags=6 (110), flags-1=5 (101), 6&5=4≠0
return flags !== 0 && (flags & (flags - 1)) === 0; return flags !== 0 && (flags & (flags - 1)) === 0;
} }
@@ -472,8 +483,7 @@ export abstract class EntitySystem<
*/ */
private getEntityIdMap(allEntities: readonly Entity[]): Map<number, Entity> { private getEntityIdMap(allEntities: readonly Entity[]): Map<number, Entity> {
const currentVersion = this.scene?.querySystem?.version ?? 0; const currentVersion = this.scene?.querySystem?.version ?? 0;
if (this._entityIdMap !== null && if (this._entityIdMap !== null && this._entityIdMapVersion === currentVersion) {
this._entityIdMapVersion === currentVersion) {
return this._entityIdMap; return this._entityIdMap;
} }
@@ -798,12 +808,9 @@ export abstract class EntitySystem<
* @param eventType 事件类型 * @param eventType 事件类型
* @param handler 事件处理函数 * @param handler 事件处理函数
*/ */
protected removeEventListener<T = any>( protected removeEventListener<T = any>(eventType: string, handler: EventHandler<T>): void {
eventType: string,
handler: EventHandler<T>
): void {
const listenerIndex = this._eventListeners.findIndex( const listenerIndex = this._eventListeners.findIndex(
listener => listener.eventType === eventType && listener.handler === handler (listener) => listener.eventType === eventType && listener.handler === handler
); );
if (listenerIndex >= 0) { if (listenerIndex >= 0) {
@@ -887,15 +894,10 @@ export abstract class EntitySystem<
* } * }
* ``` * ```
*/ */
protected requireComponent<T extends ComponentConstructor>( protected requireComponent<T extends ComponentConstructor>(entity: Entity, componentType: T): ComponentInstance<T> {
entity: Entity,
componentType: T
): ComponentInstance<T> {
const component = entity.getComponent(componentType as any); const component = entity.getComponent(componentType as any);
if (!component) { if (!component) {
throw new Error( throw new Error(`Component ${componentType.name} not found on entity ${entity.name} in ${this.systemName}`);
`Component ${componentType.name} not found on entity ${entity.name} in ${this.systemName}`
);
} }
return component as ComponentInstance<T>; return component as ComponentInstance<T>;
} }
@@ -927,9 +929,7 @@ export abstract class EntitySystem<
entity: Entity, entity: Entity,
...components: T ...components: T
): { [K in keyof T]: ComponentInstance<T[K]> } { ): { [K in keyof T]: ComponentInstance<T[K]> } {
return components.map((type) => return components.map((type) => this.requireComponent(entity, type)) as any;
this.requireComponent(entity, type)
) as any;
} }
/** /**
@@ -950,10 +950,7 @@ export abstract class EntitySystem<
* } * }
* ``` * ```
*/ */
protected forEach( protected forEach(entities: readonly Entity[], processor: (entity: Entity, index: number) => void): void {
entities: readonly Entity[],
processor: (entity: Entity, index: number) => void
): void {
for (let i = 0; i < entities.length; i++) { for (let i = 0; i < entities.length; i++) {
processor(entities[i]!, i); processor(entities[i]!, i);
} }
@@ -1000,10 +997,7 @@ export abstract class EntitySystem<
* } * }
* ``` * ```
*/ */
protected mapEntities<R>( protected mapEntities<R>(entities: readonly Entity[], mapper: (entity: Entity, index: number) => R): R[] {
entities: readonly Entity[],
mapper: (entity: Entity, index: number) => R
): R[] {
return Array.from(entities).map(mapper); return Array.from(entities).map(mapper);
} }
@@ -1052,10 +1046,7 @@ export abstract class EntitySystem<
* } * }
* ``` * ```
*/ */
protected someEntity( protected someEntity(entities: readonly Entity[], predicate: (entity: Entity, index: number) => boolean): boolean {
entities: readonly Entity[],
predicate: (entity: Entity, index: number) => boolean
): boolean {
for (let i = 0; i < entities.length; i++) { for (let i = 0; i < entities.length; i++) {
if (predicate(entities[i]!, i)) { if (predicate(entities[i]!, i)) {
return true; return true;
@@ -1081,10 +1072,7 @@ export abstract class EntitySystem<
* } * }
* ``` * ```
*/ */
protected everyEntity( protected everyEntity(entities: readonly Entity[], predicate: (entity: Entity, index: number) => boolean): boolean {
entities: readonly Entity[],
predicate: (entity: Entity, index: number) => boolean
): boolean {
for (let i = 0; i < entities.length; i++) { for (let i = 0; i < entities.length; i++) {
if (!predicate(entities[i]!, i)) { if (!predicate(entities[i]!, i)) {
return false; return false;

View File

@@ -52,7 +52,6 @@ export class EntityDataCollector {
}; };
} }
/** /**
* 获取原始实体列表 * 获取原始实体列表
* @param scene 场景实例 * @param scene 场景实例
@@ -92,7 +91,6 @@ export class EntityDataCollector {
})); }));
} }
/** /**
* 获取实体详细信息 * 获取实体详细信息
* @param entityId 实体ID * @param entityId 实体ID
@@ -108,9 +106,9 @@ export class EntityDataCollector {
const entity = entityList.buffer.find((e: any) => e.id === entityId); const entity = entityList.buffer.find((e: any) => e.id === entityId);
if (!entity) return null; if (!entity) return null;
const baseDebugInfo = entity.getDebugInfo ? const baseDebugInfo = entity.getDebugInfo
entity.getDebugInfo() : ? entity.getDebugInfo()
this.buildFallbackEntityInfo(entity, scene); : this.buildFallbackEntityInfo(entity, scene);
const componentDetails = this.extractComponentDetails(entity.components); const componentDetails = this.extractComponentDetails(entity.components);
@@ -163,7 +161,6 @@ export class EntityDataCollector {
return { name: sceneName, type: sceneType }; return { name: sceneName, type: sceneType };
} }
/** /**
* 收集实体数据(包含内存信息) * 收集实体数据(包含内存信息)
* @param scene 场景实例 * @param scene 场景实例
@@ -208,7 +205,6 @@ export class EntityDataCollector {
}; };
} }
private collectArchetypeData(scene: any): { private collectArchetypeData(scene: any): {
distribution: Array<{ signature: string; count: number; memory: number }>; distribution: Array<{ signature: string; count: number; memory: number }>;
topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>; topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>;
@@ -224,7 +220,9 @@ export class EntityDataCollector {
}; };
} }
private getArchetypeDistributionFast(entityContainer: any): Array<{ signature: string; count: number; memory: number }> { private getArchetypeDistributionFast(
entityContainer: any
): Array<{ signature: string; count: number; memory: number }> {
const distribution = new Map<string, { count: number; componentTypes: string[] }>(); const distribution = new Map<string, { count: number; componentTypes: string[] }>();
if (entityContainer && entityContainer.entities) { if (entityContainer && entityContainer.entities) {
@@ -251,7 +249,9 @@ export class EntityDataCollector {
.slice(0, 20); .slice(0, 20);
} }
private getTopEntitiesByComponentsFast(entityContainer: any): Array<{ id: string; name: string; componentCount: number; memory: number }> { private getTopEntitiesByComponentsFast(
entityContainer: any
): Array<{ id: string; name: string; componentCount: number; memory: number }> {
if (!entityContainer || !entityContainer.entities) { if (!entityContainer || !entityContainer.entities) {
return []; return [];
} }
@@ -266,7 +266,6 @@ export class EntityDataCollector {
.sort((a: any, b: any) => b.componentCount - a.componentCount); .sort((a: any, b: any) => b.componentCount - a.componentCount);
} }
private collectArchetypeDataWithMemory(scene: any): { private collectArchetypeDataWithMemory(scene: any): {
distribution: Array<{ signature: string; count: number; memory: number }>; distribution: Array<{ signature: string; count: number; memory: number }>;
topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>; topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>;
@@ -282,7 +281,6 @@ export class EntityDataCollector {
}; };
} }
private extractArchetypeStatistics(archetypeSystem: any): { private extractArchetypeStatistics(archetypeSystem: any): {
distribution: Array<{ signature: string; count: number; memory: number }>; distribution: Array<{ signature: string; count: number; memory: number }>;
topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>; topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>;
@@ -319,7 +317,6 @@ export class EntityDataCollector {
return { distribution, topEntities }; return { distribution, topEntities };
} }
private extractArchetypeStatisticsWithMemory(archetypeSystem: any): { private extractArchetypeStatisticsWithMemory(archetypeSystem: any): {
distribution: Array<{ signature: string; count: number; memory: number }>; distribution: Array<{ signature: string; count: number; memory: number }>;
topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>; topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>;
@@ -368,9 +365,9 @@ export class EntityDataCollector {
return { distribution, topEntities }; return { distribution, topEntities };
} }
private getArchetypeDistributionWithMemory(
entityContainer: any
private getArchetypeDistributionWithMemory(entityContainer: any): Array<{ signature: string; count: number; memory: number }> { ): Array<{ signature: string; count: number; memory: number }> {
const distribution = new Map<string, { count: number; memory: number; componentTypes: string[] }>(); const distribution = new Map<string, { count: number; memory: number; componentTypes: string[] }>();
if (entityContainer && entityContainer.entities) { if (entityContainer && entityContainer.entities) {
@@ -403,8 +400,9 @@ export class EntityDataCollector {
.sort((a, b) => b.count - a.count); .sort((a, b) => b.count - a.count);
} }
private getTopEntitiesByComponentsWithMemory(
private getTopEntitiesByComponentsWithMemory(entityContainer: any): Array<{ id: string; name: string; componentCount: number; memory: number }> { entityContainer: any
): Array<{ id: string; name: string; componentCount: number; memory: number }> {
if (!entityContainer || !entityContainer.entities) { if (!entityContainer || !entityContainer.entities) {
return []; return [];
} }
@@ -419,7 +417,6 @@ export class EntityDataCollector {
.sort((a: any, b: any) => b.componentCount - a.componentCount); .sort((a: any, b: any) => b.componentCount - a.componentCount);
} }
private getEmptyEntityDebugData(): IEntityDebugData { private getEmptyEntityDebugData(): IEntityDebugData {
return { return {
totalEntities: 0, totalEntities: 0,
@@ -433,20 +430,20 @@ export class EntityDataCollector {
}; };
} }
private calculateFallbackEntityStats(entityList: any): any { private calculateFallbackEntityStats(entityList: any): any {
const allEntities = entityList.buffer || []; const allEntities = entityList.buffer || [];
const activeEntities = allEntities.filter((entity: any) => const activeEntities = allEntities.filter((entity: any) => entity.enabled && !entity.isDestroyed);
entity.enabled && !entity._isDestroyed
);
return { return {
totalEntities: allEntities.length, totalEntities: allEntities.length,
activeEntities: activeEntities.length, activeEntities: activeEntities.length,
pendingAdd: 0, pendingAdd: 0,
pendingRemove: 0, pendingRemove: 0,
averageComponentsPerEntity: activeEntities.length > 0 ? averageComponentsPerEntity:
allEntities.reduce((sum: number, e: any) => sum + (e.components?.length || 0), 0) / activeEntities.length : 0 activeEntities.length > 0
? allEntities.reduce((sum: number, e: any) => sum + (e.components?.length || 0), 0) /
activeEntities.length
: 0
}; };
} }
@@ -496,11 +493,14 @@ export class EntityDataCollector {
for (let i = 0; i < maxKeys; i++) { for (let i = 0; i < maxKeys; i++) {
const key = keys[i]; const key = keys[i];
if (!key || excludeKeys.includes(key) || if (
!key ||
excludeKeys.includes(key) ||
key === 'constructor' || key === 'constructor' ||
key === '__proto__' || key === '__proto__' ||
key.startsWith('_cc_') || key.startsWith('_cc_') ||
key.startsWith('__')) { key.startsWith('__')
) {
continue; continue;
} }
@@ -534,7 +534,6 @@ export class EntityDataCollector {
} }
} }
private buildEntityHierarchyTree(entityList: { buffer?: Entity[] }): Array<{ private buildEntityHierarchyTree(entityList: { buffer?: Entity[] }): Array<{
id: number; id: number;
name: string; name: string;
@@ -553,7 +552,6 @@ export class EntityDataCollector {
const rootEntities: any[] = []; const rootEntities: any[] = [];
entityList.buffer.forEach((entity: Entity) => { entityList.buffer.forEach((entity: Entity) => {
if (!entity.parent) { if (!entity.parent) {
const hierarchyNode = this.buildEntityHierarchyNode(entity); const hierarchyNode = this.buildEntityHierarchyNode(entity);
@@ -626,12 +624,13 @@ export class EntityDataCollector {
const batch = entities.slice(i, i + batchSize); const batch = entities.slice(i, i + batchSize);
batch.forEach((entity: Entity) => { batch.forEach((entity: Entity) => {
const baseDebugInfo = entity.getDebugInfo ? const baseDebugInfo = entity.getDebugInfo
entity.getDebugInfo() : ? entity.getDebugInfo()
this.buildFallbackEntityInfo(entity, scene); : this.buildFallbackEntityInfo(entity, scene);
const componentCacheStats = (entity as any).getComponentCacheStats ? const componentCacheStats = (entity as any).getComponentCacheStats
(entity as any).getComponentCacheStats() : null; ? (entity as any).getComponentCacheStats()
: null;
const componentDetails = this.extractComponentDetails(entity.components); const componentDetails = this.extractComponentDetails(entity.components);
@@ -639,13 +638,14 @@ export class EntityDataCollector {
...baseDebugInfo, ...baseDebugInfo,
parentName: entity.parent?.name || null, parentName: entity.parent?.name || null,
components: componentDetails, components: componentDetails,
componentTypes: baseDebugInfo.componentTypes || componentTypes: baseDebugInfo.componentTypes || componentDetails.map((comp) => comp.typeName),
componentDetails.map((comp) => comp.typeName), cachePerformance: componentCacheStats
cachePerformance: componentCacheStats ? { ? {
hitRate: componentCacheStats.cacheStats.hitRate, hitRate: componentCacheStats.cacheStats.hitRate,
size: componentCacheStats.cacheStats.size, size: componentCacheStats.cacheStats.size,
maxSize: componentCacheStats.cacheStats.maxSize maxSize: componentCacheStats.cacheStats.maxSize
} : null }
: null
}; };
}); });
} }
@@ -694,7 +694,7 @@ export class EntityDataCollector {
try { try {
const propertyKeys = Object.keys(component); const propertyKeys = Object.keys(component);
propertyKeys.forEach(propertyKey => { propertyKeys.forEach((propertyKey) => {
if (!propertyKey.startsWith('_') && propertyKey !== 'entity' && propertyKey !== 'constructor') { if (!propertyKey.startsWith('_') && propertyKey !== 'entity' && propertyKey !== 'constructor') {
const propertyValue = (component as any)[propertyKey]; const propertyValue = (component as any)[propertyKey];
if (propertyValue !== undefined && propertyValue !== null) { if (propertyValue !== undefined && propertyValue !== null) {
@@ -726,7 +726,11 @@ export class EntityDataCollector {
* @param componentIndex 组件索引 * @param componentIndex 组件索引
* @param scene 场景实例 * @param scene 场景实例
*/ */
public getComponentProperties(entityId: number, componentIndex: number, scene?: IScene | null): Record<string, any> { public getComponentProperties(
entityId: number,
componentIndex: number,
scene?: IScene | null
): Record<string, any> {
try { try {
if (!scene) return {}; if (!scene) return {};
@@ -740,7 +744,7 @@ export class EntityDataCollector {
const properties: Record<string, any> = {}; const properties: Record<string, any> = {};
const propertyKeys = Object.keys(component); const propertyKeys = Object.keys(component);
propertyKeys.forEach(propertyKey => { propertyKeys.forEach((propertyKey) => {
if (!propertyKey.startsWith('_') && propertyKey !== 'entity') { if (!propertyKey.startsWith('_') && propertyKey !== 'entity') {
const propertyValue = (component as any)[propertyKey]; const propertyValue = (component as any)[propertyKey];
if (propertyValue !== undefined && propertyValue !== null) { if (propertyValue !== undefined && propertyValue !== null) {
@@ -786,7 +790,7 @@ export class EntityDataCollector {
if (obj.length === 0) return []; if (obj.length === 0) return [];
if (obj.length > 10) { if (obj.length > 10) {
const sample = obj.slice(0, 3).map(item => this.formatPropertyValue(item, 1)); const sample = obj.slice(0, 3).map((item) => this.formatPropertyValue(item, 1));
return { return {
_isLazyArray: true, _isLazyArray: true,
_arrayLength: obj.length, _arrayLength: obj.length,
@@ -795,7 +799,7 @@ export class EntityDataCollector {
}; };
} }
return obj.map(item => this.formatPropertyValue(item, 1)); return obj.map((item) => this.formatPropertyValue(item, 1));
} }
const keys = Object.keys(obj); const keys = Object.keys(obj);
@@ -922,7 +926,12 @@ export class EntityDataCollector {
* @param propertyPath 属性路径 * @param propertyPath 属性路径
* @param scene 场景实例 * @param scene 场景实例
*/ */
public expandLazyObject(entityId: number, componentIndex: number, propertyPath: string, scene?: IScene | null): any { public expandLazyObject(
entityId: number,
componentIndex: number,
propertyPath: string,
scene?: IScene | null
): any {
try { try {
if (!scene) return null; if (!scene) return null;

View File

@@ -27,7 +27,6 @@ describe('Component - 组件基类测试', () => {
let scene: Scene; let scene: Scene;
beforeEach(() => { beforeEach(() => {
Component._idGenerator = 0;
component = new TestComponent(); component = new TestComponent();
scene = new Scene(); scene = new Scene();
entity = scene.createEntity('TestEntity'); entity = scene.createEntity('TestEntity');
@@ -51,12 +50,11 @@ describe('Component - 组件基类测试', () => {
}); });
test('组件ID应该递增分配', () => { test('组件ID应该递增分配', () => {
const startId = Component._idGenerator;
const component1 = new TestComponent(); const component1 = new TestComponent();
const component2 = new TestComponent(); const component2 = new TestComponent();
expect(component2.id).toBe(component1.id + 1); expect(component2.id).toBe(component1.id + 1);
expect(component1.id).toBeGreaterThanOrEqual(startId); expect(component1.id).toBeGreaterThanOrEqual(0);
}); });
}); });