refactor(core): 改进事件系统类型安全并消除 ESLint 警告 (#208)

This commit is contained in:
YHH
2025-11-01 16:12:18 +08:00
committed by GitHub
parent 57c7e7be3f
commit 3ad5dc9ca3
6 changed files with 310 additions and 159 deletions

View File

@@ -0,0 +1,166 @@
import { Entity } from '../Entity';
/**
* 实体缓存管理器
*
* 负责管理 EntitySystem 中的实体缓存,提供帧缓存和持久缓存两级缓存机制。
* 使用面向对象设计,将数据和行为封装在类中。
*
* @example
* ```typescript
* const cache = new EntityCache();
* cache.setPersistent(entities);
* const cached = cache.getPersistent();
* cache.invalidate();
* ```
*/
export class EntityCache {
/**
* 帧缓存
*
* 在update周期内使用每帧结束后清理
*/
private _frameCache: readonly Entity[] | null = null;
/**
* 持久缓存
*
* 跨帧使用,直到被显式失效
*/
private _persistentCache: readonly Entity[] | null = null;
/**
* 被跟踪的实体集合
*
* 用于跟踪哪些实体正在被此系统处理
*/
private _trackedEntities: Set<Entity> = new Set();
/**
* 获取帧缓存
*/
public getFrame(): readonly Entity[] | null {
return this._frameCache;
}
/**
* 设置帧缓存
*
* @param entities 要缓存的实体列表
*/
public setFrame(entities: readonly Entity[]): void {
this._frameCache = entities;
}
/**
* 获取持久缓存
*/
public getPersistent(): readonly Entity[] | null {
return this._persistentCache;
}
/**
* 设置持久缓存
*
* @param entities 要缓存的实体列表
*/
public setPersistent(entities: readonly Entity[]): void {
this._persistentCache = entities;
}
/**
* 获取被跟踪的实体集合
*/
public getTracked(): ReadonlySet<Entity> {
return this._trackedEntities;
}
/**
* 添加被跟踪的实体
*
* @param entity 要跟踪的实体
*/
public addTracked(entity: Entity): void {
this._trackedEntities.add(entity);
}
/**
* 移除被跟踪的实体
*
* @param entity 要移除的实体
*/
public removeTracked(entity: Entity): void {
this._trackedEntities.delete(entity);
}
/**
* 检查实体是否被跟踪
*
* @param entity 要检查的实体
*/
public isTracked(entity: Entity): boolean {
return this._trackedEntities.has(entity);
}
/**
* 使持久缓存失效
*
* 当实体变化时调用,强制下次查询时重新计算
*/
public invalidate(): void {
this._persistentCache = null;
}
/**
* 清除帧缓存
*
* 在每帧结束时调用
*/
public clearFrame(): void {
this._frameCache = null;
}
/**
* 清除所有缓存
*
* 在系统重置或销毁时调用
*/
public clearAll(): void {
this._frameCache = null;
this._persistentCache = null;
this._trackedEntities.clear();
}
/**
* 检查是否有有效的持久缓存
*/
public hasPersistent(): boolean {
return this._persistentCache !== null;
}
/**
* 检查是否有有效的帧缓存
*/
public hasFrame(): boolean {
return this._frameCache !== null;
}
/**
* 获取缓存统计信息
*/
public getStats(): {
hasFrame: boolean;
hasPersistent: boolean;
trackedCount: number;
frameEntityCount: number;
persistentEntityCount: number;
} {
return {
hasFrame: this._frameCache !== null,
hasPersistent: this._persistentCache !== null,
trackedCount: this._trackedEntities.size,
frameEntityCount: this._frameCache?.length ?? 0,
persistentEntityCount: this._persistentCache?.length ?? 0
};
}
}

View File

@@ -9,14 +9,15 @@ import { createLogger } from '../../Utils/Logger';
import type { EventListenerConfig, TypeSafeEventSystem, EventHandler } from '../Core/EventSystem';
import type { ComponentConstructor, ComponentInstance } from '../../Types/TypeHelpers';
import type { IService } from '../../Core/ServiceContainer';
import { EntityCache } from './EntityCache';
/**
* 事件监听器记录
* 只存储引用信息,用于系统销毁时自动清理
*/
interface EventListenerRecord {
eventSystem: TypeSafeEventSystem;
eventType: string;
handler: EventHandler;
listenerRef: string;
}
@@ -63,9 +64,7 @@ interface EventListenerRecord {
* }
* ```
*/
export abstract class EntitySystem<_TComponents extends readonly ComponentConstructor[] = []>
implements ISystemBase, IService
{
export abstract class EntitySystem implements ISystemBase, IService {
private _updateOrder: number;
private _enabled: boolean;
private _performanceMonitor: PerformanceMonitor | null;
@@ -85,30 +84,24 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
/**
* 统一的实体缓存管理器
*/
private _entityCache: {
frame: readonly Entity[] | null;
persistent: readonly Entity[] | null;
tracked: Set<Entity>;
invalidate(): void;
clearFrame(): void;
clearAll(): void;
};
private _entityCache: EntityCache;
/**
* 获取系统处理的实体列表
*/
public get entities(): readonly Entity[] {
// 如果在update周期内优先使用帧缓存
if (this._entityCache.frame !== null) {
return this._entityCache.frame;
const frameCache = this._entityCache.getFrame();
if (frameCache !== null) {
return frameCache;
}
// 否则使用持久缓存
if (this._entityCache.persistent === null) {
this._entityCache.persistent = this.queryEntities();
if (!this._entityCache.hasPersistent()) {
this._entityCache.setPersistent(this.queryEntities());
}
return this._entityCache.persistent;
return this._entityCache.getPersistent()!;
}
/**
@@ -159,22 +152,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
// 初始化logger
this.logger = createLogger(this.getLoggerName());
this._entityCache = {
frame: null,
persistent: null,
tracked: new Set<Entity>(),
invalidate() {
this.persistent = null;
},
clearFrame() {
this.frame = null;
},
clearAll() {
this.frame = null;
this.persistent = null;
this.tracked.clear();
}
};
this._entityCache = new EntityCache();
}
/**
@@ -521,7 +499,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
const entityMap = this.getEntityIdMap(allEntities);
const size = idSet.size;
const result = new Array(size);
const result = new Array<Entity>(size);
let index = 0;
for (const id of idSet) {
@@ -564,10 +542,11 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
this.onBegin();
// 查询实体并存储到帧缓存中
// 响应式查询会自动维护最新的实体列表updateEntityTracking会在检测到变化时invalidate
this._entityCache.frame = this.queryEntities();
entityCount = this._entityCache.frame.length;
const queriedEntities = this.queryEntities();
this._entityCache.setFrame(queriedEntities);
entityCount = queriedEntities.length;
this.process(this._entityCache.frame);
this.process(queriedEntities);
} finally {
monitor.endMonitoring(this._systemName, startTime, entityCount);
}
@@ -587,7 +566,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
try {
// 使用缓存的实体列表,避免重复查询
const entities = this._entityCache.frame || [];
const entities = this._entityCache.getFrame() || [];
entityCount = entities.length;
this.lateProcess(entities);
this.onEnd();
@@ -697,17 +676,17 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
// 检查新增的实体
for (const entity of currentEntities) {
if (!this._entityCache.tracked.has(entity)) {
this._entityCache.tracked.add(entity);
if (!this._entityCache.isTracked(entity)) {
this._entityCache.addTracked(entity);
this.onAdded(entity);
hasChanged = true;
}
}
// 检查移除的实体
for (const entity of this._entityCache.tracked) {
for (const entity of this._entityCache.getTracked()) {
if (!currentSet.has(entity)) {
this._entityCache.tracked.delete(entity);
this._entityCache.removeTracked(entity);
this.onRemoved(entity);
hasChanged = true;
}
@@ -778,15 +757,16 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
* @param eventType 事件类型
* @param handler 事件处理函数
* @param config 监听器配置
* @returns 监听器引用ID可用于手动移除监听器
*/
protected addEventListener<T = any>(
protected addEventListener<T>(
eventType: string,
handler: EventHandler<T>,
config?: EventListenerConfig
): void {
): string | null {
if (!this.scene?.eventSystem) {
this.logger.warn(`${this.systemName}: 无法添加事件监听器scene.eventSystem 不可用`);
return;
return null;
}
const listenerRef = this.scene.eventSystem.on(eventType, handler, config);
@@ -796,21 +776,22 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
this._eventListeners.push({
eventSystem: this.scene.eventSystem,
eventType,
handler,
listenerRef
});
}
return listenerRef;
}
/**
* 移除特定的事件监听器
*
* @param eventType 事件类型
* @param handler 事件处理函数
* @param listenerRef 监听器引用ID由 addEventListener 返回)
*/
protected removeEventListener<T = any>(eventType: string, handler: EventHandler<T>): void {
protected removeEventListener(eventType: string, listenerRef: string): void {
const listenerIndex = this._eventListeners.findIndex(
(listener) => listener.eventType === eventType && listener.handler === handler
(listener) => listener.eventType === eventType && listener.listenerRef === listenerRef
);
if (listenerIndex >= 0) {
@@ -895,7 +876,7 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
* ```
*/
protected requireComponent<T extends ComponentConstructor>(entity: Entity, componentType: T): ComponentInstance<T> {
const component = entity.getComponent(componentType as any);
const component = entity.getComponent(componentType);
if (!component) {
throw new Error(`Component ${componentType.name} not found on entity ${entity.name} in ${this.systemName}`);
}
@@ -929,7 +910,9 @@ export abstract class EntitySystem<_TComponents extends readonly ComponentConstr
entity: Entity,
...components: T
): { [K in keyof T]: ComponentInstance<T[K]> } {
return components.map((type) => this.requireComponent(entity, type)) as any;
return components.map((type) => this.requireComponent(entity, type)) as {
[K in keyof T]: ComponentInstance<T[K]>;
};
}
/**