Compare commits
3 Commits
master
...
style/code
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c7c3c98af | ||
|
|
be7b3afb4a | ||
|
|
3e037f4ae0 |
@@ -31,9 +31,32 @@
|
||||
"@typescript-eslint/no-unsafe-call": "warn",
|
||||
"@typescript-eslint/no-unsafe-return": "warn",
|
||||
"@typescript-eslint/no-unsafe-argument": "warn",
|
||||
"@typescript-eslint/no-unsafe-function-type": "error",
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
|
||||
"@typescript-eslint/no-non-null-assertion": "off"
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/naming-convention": [
|
||||
"error",
|
||||
{
|
||||
"selector": "memberLike",
|
||||
"modifiers": ["private"],
|
||||
"format": ["camelCase"],
|
||||
"leadingUnderscore": "require"
|
||||
},
|
||||
{
|
||||
"selector": "memberLike",
|
||||
"modifiers": ["public"],
|
||||
"format": ["camelCase"],
|
||||
"leadingUnderscore": "forbid"
|
||||
},
|
||||
{
|
||||
"selector": "memberLike",
|
||||
"modifiers": ["protected"],
|
||||
"format": ["camelCase"],
|
||||
"leadingUnderscore": "require"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"node_modules/",
|
||||
|
||||
@@ -329,8 +329,8 @@ export class Core {
|
||||
*/
|
||||
public static setScene<T extends IScene>(scene: T): T {
|
||||
if (!this._instance) {
|
||||
Core._logger.warn("Core实例未创建,请先调用Core.create()");
|
||||
throw new Error("Core实例未创建");
|
||||
Core._logger.warn('Core实例未创建,请先调用Core.create()');
|
||||
throw new Error('Core实例未创建');
|
||||
}
|
||||
|
||||
return this._instance._sceneManager.setScene(scene);
|
||||
@@ -387,7 +387,7 @@ export class Core {
|
||||
*/
|
||||
public static loadScene<T extends IScene>(scene: T): void {
|
||||
if (!this._instance) {
|
||||
Core._logger.warn("Core实例未创建,请先调用Core.create()");
|
||||
Core._logger.warn('Core实例未创建,请先调用Core.create()');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -422,7 +422,7 @@ export class Core {
|
||||
*/
|
||||
public static update(deltaTime: number): void {
|
||||
if (!this._instance) {
|
||||
Core._logger.warn("Core实例未创建,请先调用Core.create()");
|
||||
Core._logger.warn('Core实例未创建,请先调用Core.create()');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -472,7 +472,7 @@ export class Core {
|
||||
*/
|
||||
public static enableDebug(config: IECSDebugConfig): void {
|
||||
if (!this._instance) {
|
||||
Core._logger.warn("Core实例未创建,请先调用Core.create()");
|
||||
Core._logger.warn('Core实例未创建,请先调用Core.create()');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,8 +76,8 @@ export interface UpdatableMetadata {
|
||||
* ```
|
||||
*/
|
||||
export function Injectable(): ClassDecorator {
|
||||
return function (target: Function): void {
|
||||
const existing = injectableMetadata.get(target as Constructor);
|
||||
return function (target: Constructor): void {
|
||||
const existing = injectableMetadata.get(target);
|
||||
|
||||
injectableMetadata.set(target as Constructor, {
|
||||
injectable: true,
|
||||
@@ -117,13 +117,13 @@ export function Injectable(): ClassDecorator {
|
||||
* ```
|
||||
*/
|
||||
export function Updatable(priority: number = 0): ClassDecorator {
|
||||
return function (target: Function): void {
|
||||
return function (target: Constructor): void {
|
||||
// 验证类原型上是否有update方法
|
||||
const prototype = (target as Constructor & { prototype: { update?: unknown } }).prototype;
|
||||
if (!prototype || typeof prototype.update !== 'function') {
|
||||
throw new Error(
|
||||
`@Updatable() decorator requires class ${target.name} to implement IUpdatable interface with update() method. ` +
|
||||
`Please add 'implements IUpdatable' and define update(deltaTime?: number): void method.`
|
||||
"Please add 'implements IUpdatable' and define update(deltaTime?: number): void method."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -228,6 +228,7 @@ export function getInjectMetadata(target: Constructor): Map<number, ServiceType<
|
||||
* const instance = createInstance(MySystem, container);
|
||||
* ```
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export function createInstance<T>(
|
||||
constructor: new (...args: any[]) => T,
|
||||
container: ServiceContainer
|
||||
@@ -249,7 +250,7 @@ export function createInstance<T>(
|
||||
if (typeof serviceType === 'string' || typeof serviceType === 'symbol') {
|
||||
// 字符串或Symbol类型的服务标识
|
||||
throw new Error(
|
||||
`String and Symbol service identifiers are not yet supported in constructor injection. ` +
|
||||
'String and Symbol service identifiers are not yet supported in constructor injection. ' +
|
||||
`Please use class types for ${constructor.name} parameter ${i}`
|
||||
);
|
||||
} else {
|
||||
@@ -338,7 +339,7 @@ export function registerInjectable<T extends IService>(
|
||||
if (!isInjectable(serviceType)) {
|
||||
throw new Error(
|
||||
`${serviceType.name} is not marked as @Injectable(). ` +
|
||||
`Please add @Injectable() decorator to the class.`
|
||||
'Please add @Injectable() decorator to the class.'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,9 @@ export interface IService {
|
||||
* 服务类型
|
||||
*
|
||||
* 支持任意构造函数签名,以便与依赖注入装饰器配合使用
|
||||
* 使用 any[] 以允许任意参数类型的构造函数
|
||||
* 使用 any[] 以允许任意参数类型的构造函数,这是类型系统的必要妥协
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type ServiceType<T extends IService> = new (...args: any[]) => T;
|
||||
|
||||
/**
|
||||
@@ -240,7 +241,7 @@ export class ServiceContainer {
|
||||
|
||||
// 检测循环依赖
|
||||
if (this._resolving.has(type as ServiceType<IService>)) {
|
||||
const chain = Array.from(this._resolving).map(t => t.name).join(' -> ');
|
||||
const chain = Array.from(this._resolving).map((t) => t.name).join(' -> ');
|
||||
throw new Error(`Circular dependency detected: ${chain} -> ${type.name}`);
|
||||
}
|
||||
|
||||
@@ -337,7 +338,7 @@ export class ServiceContainer {
|
||||
// 如果有单例实例,调用 dispose
|
||||
if (registration.instance) {
|
||||
// 从可更新列表中移除
|
||||
const index = this._updatableServices.findIndex(item => item.instance === registration.instance);
|
||||
const index = this._updatableServices.findIndex((item) => item.instance === registration.instance);
|
||||
if (index !== -1) {
|
||||
this._updatableServices.splice(index, 1);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,16 @@ export abstract class Component implements IComponent {
|
||||
*
|
||||
* 用于为每个组件分配唯一的ID。
|
||||
*/
|
||||
public static _idGenerator: number = 0;
|
||||
private static _nextId: number = 0;
|
||||
|
||||
/**
|
||||
* 获取下一个组件ID(只读)
|
||||
*
|
||||
* @returns 下一个将要分配的组件ID
|
||||
*/
|
||||
public static get nextComponentId(): number {
|
||||
return Component._nextId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件唯一标识符
|
||||
@@ -58,7 +67,7 @@ export abstract class Component implements IComponent {
|
||||
* 自动分配唯一ID给组件。
|
||||
*/
|
||||
constructor() {
|
||||
this.id = Component._idGenerator++;
|
||||
this.id = Component._nextId++;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Entity } from '../Entity';
|
||||
import { ComponentType, ComponentRegistry } from './ComponentStorage';
|
||||
import { BitMask64Data, BitMask64Utils } from "../Utils";
|
||||
import { BitMaskHashMap } from "../Utils/BitMaskHashMap";
|
||||
import { BitMask64Data, BitMask64Utils } from '../Utils';
|
||||
import { BitMaskHashMap } from '../Utils/BitMaskHashMap';
|
||||
|
||||
/**
|
||||
* 原型标识符
|
||||
@@ -247,7 +247,7 @@ export class ArchetypeSystem {
|
||||
*/
|
||||
private updateAllArchetypeArrays(): void {
|
||||
this._allArchetypes = [];
|
||||
for (let archetype of this._archetypes.values()) {
|
||||
for (const archetype of this._archetypes.values()) {
|
||||
this._allArchetypes.push(archetype);
|
||||
}
|
||||
}
|
||||
@@ -258,7 +258,7 @@ export class ArchetypeSystem {
|
||||
private getEntityComponentTypes(entity: Entity): ComponentType[] {
|
||||
let componentTypes = this._entityComponentTypesCache.get(entity);
|
||||
if (!componentTypes) {
|
||||
componentTypes = entity.components.map(component => component.constructor as ComponentType);
|
||||
componentTypes = entity.components.map((component) => component.constructor as ComponentType);
|
||||
this._entityComponentTypesCache.set(entity, componentTypes);
|
||||
}
|
||||
return componentTypes;
|
||||
@@ -269,7 +269,7 @@ export class ArchetypeSystem {
|
||||
* 使用ComponentRegistry确保与Entity.componentMask使用相同的bitIndex
|
||||
*/
|
||||
private generateArchetypeId(componentTypes: ComponentType[]): ArchetypeId {
|
||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
for (const type of componentTypes) {
|
||||
if (!ComponentRegistry.isRegistered(type)) {
|
||||
ComponentRegistry.register(type);
|
||||
|
||||
@@ -9,7 +9,6 @@ import { ComponentRegistry, ComponentType } from './ComponentStorage/ComponentRe
|
||||
export { ComponentRegistry, ComponentType };
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 高性能组件存储器
|
||||
*/
|
||||
@@ -152,7 +151,7 @@ export class ComponentStorage<T extends Component> {
|
||||
usedSlots: number;
|
||||
freeSlots: number;
|
||||
fragmentation: number;
|
||||
} {
|
||||
} {
|
||||
const totalSlots = this.dense.length;
|
||||
const usedSlots = this.dense.length;
|
||||
const freeSlots = 0; // 永远无空洞
|
||||
@@ -173,7 +172,7 @@ export class ComponentStorage<T extends Component> {
|
||||
*/
|
||||
export class ComponentStorageManager {
|
||||
private static readonly _logger = createLogger('ComponentStorage');
|
||||
private storages = new Map<Function, ComponentStorage<Component> | SoAStorage<Component>>();
|
||||
private storages = new Map<ComponentType, ComponentStorage<Component> | SoAStorage<Component>>();
|
||||
|
||||
/**
|
||||
* 检查组件类型是否启用SoA存储
|
||||
@@ -342,7 +341,7 @@ export class ComponentStorageManager {
|
||||
* @returns 组件位掩码
|
||||
*/
|
||||
public getComponentMask(entityId: number): BitMask64Data {
|
||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
|
||||
for (const [componentType, storage] of this.storages.entries()) {
|
||||
if (storage.hasComponent(entityId)) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getComponentTypeName } from '../../Decorators';
|
||||
/**
|
||||
* 组件类型定义
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type ComponentType<T extends Component = Component> = new (...args: any[]) => T;
|
||||
|
||||
/**
|
||||
@@ -14,9 +15,9 @@ 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 componentTypes = new Map<ComponentType, number>();
|
||||
private static bitIndexToType = new Map<number, ComponentType>();
|
||||
private static componentNameToType = new Map<string, ComponentType>();
|
||||
private static componentNameToId = new Map<string, number>();
|
||||
private static maskCache = new Map<string, BitMask64Data>();
|
||||
private static nextBitIndex = 0;
|
||||
@@ -102,7 +103,7 @@ export class ComponentRegistry {
|
||||
* @param componentName 组件名称
|
||||
* @returns 组件类型构造函数
|
||||
*/
|
||||
public static getComponentType(componentName: string): Function | null {
|
||||
public static getComponentType(componentName: string): ComponentType | null {
|
||||
return this.componentNameToType.get(componentName) || null;
|
||||
}
|
||||
|
||||
@@ -110,7 +111,7 @@ export class ComponentRegistry {
|
||||
* 获取所有已注册的组件类型
|
||||
* @returns 组件类型映射
|
||||
*/
|
||||
public static getAllRegisteredTypes(): Map<Function, number> {
|
||||
public static getAllRegisteredTypes(): Map<ComponentType, number> {
|
||||
return new Map(this.componentTypes);
|
||||
}
|
||||
|
||||
@@ -118,7 +119,7 @@ export class ComponentRegistry {
|
||||
* 获取所有组件名称到类型的映射
|
||||
* @returns 名称到类型的映射
|
||||
*/
|
||||
public static getAllComponentNames(): Map<string, Function> {
|
||||
public static getAllComponentNames(): Map<string, ComponentType> {
|
||||
return new Map(this.componentNameToType);
|
||||
}
|
||||
|
||||
@@ -181,7 +182,7 @@ export class ComponentRegistry {
|
||||
return this.maskCache.get(cacheKey)!;
|
||||
}
|
||||
|
||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
for (const name of componentNames) {
|
||||
const componentId = this.getComponentId(name);
|
||||
if (componentId !== undefined) {
|
||||
|
||||
@@ -127,7 +127,7 @@ export class EventBus implements IEventBus {
|
||||
handler: (data: T) => Promise<void>,
|
||||
config: IEventListenerConfig = {}
|
||||
): string {
|
||||
return this.on(eventType, handler as any, { ...config, async: true });
|
||||
return this.on(eventType, handler as (data: T) => void, { ...config, async: true });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -466,4 +466,3 @@ export class GlobalEventBus {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@ import { createLogger } from '../../Utils/Logger';
|
||||
/**
|
||||
* 事件处理器函数类型
|
||||
*/
|
||||
export type EventHandler<T = any> = (event: T) => void;
|
||||
export type EventHandler<T = unknown> = (event: T) => void;
|
||||
|
||||
/**
|
||||
* 异步事件处理器函数类型
|
||||
*/
|
||||
export type AsyncEventHandler<T = any> = (event: T) => Promise<void>;
|
||||
export type AsyncEventHandler<T = unknown> = (event: T) => Promise<void>;
|
||||
|
||||
/**
|
||||
* 事件监听器配置
|
||||
@@ -21,13 +21,13 @@ export interface EventListenerConfig {
|
||||
/** 是否异步执行 */
|
||||
async?: boolean;
|
||||
/** 执行上下文 */
|
||||
context?: any;
|
||||
context?: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部事件监听器
|
||||
*/
|
||||
interface InternalEventListener<T = any> {
|
||||
interface InternalEventListener<T = unknown> {
|
||||
handler: EventHandler<T> | AsyncEventHandler<T>;
|
||||
config: EventListenerConfig;
|
||||
id: string;
|
||||
@@ -71,8 +71,8 @@ export class TypeSafeEventSystem {
|
||||
private static readonly _logger = createLogger('EventSystem');
|
||||
private listeners = new Map<string, InternalEventListener[]>();
|
||||
private stats = new Map<string, EventStats>();
|
||||
private batchQueue = new Map<string, any[]>();
|
||||
private batchTimers = new Map<string, number>();
|
||||
private batchQueue = new Map<string, unknown[]>();
|
||||
private batchTimers = new Map<string, ReturnType<typeof setTimeout>>();
|
||||
private batchConfigs = new Map<string, EventBatchConfig>();
|
||||
private nextListenerId = 0;
|
||||
private isEnabled = true;
|
||||
@@ -133,7 +133,7 @@ export class TypeSafeEventSystem {
|
||||
const listeners = this.listeners.get(eventType);
|
||||
if (!listeners) return false;
|
||||
|
||||
const index = listeners.findIndex(l => l.id === listenerId);
|
||||
const index = listeners.findIndex((l) => l.id === listenerId);
|
||||
if (index === -1) return false;
|
||||
|
||||
listeners.splice(index, 1);
|
||||
@@ -353,7 +353,7 @@ export class TypeSafeEventSystem {
|
||||
id: listenerId
|
||||
};
|
||||
|
||||
listeners.push(listener);
|
||||
listeners.push(listener as InternalEventListener);
|
||||
|
||||
// 初始化统计信息
|
||||
if (!this.stats.has(eventType)) {
|
||||
@@ -379,8 +379,8 @@ export class TypeSafeEventSystem {
|
||||
const sortedListeners = this.sortListenersByPriority(listeners);
|
||||
|
||||
// 分离同步和异步监听器
|
||||
const syncListeners = sortedListeners.filter(l => !l.config.async);
|
||||
const asyncListeners = sortedListeners.filter(l => l.config.async);
|
||||
const syncListeners = sortedListeners.filter((l) => !l.config.async);
|
||||
const asyncListeners = sortedListeners.filter((l) => l.config.async);
|
||||
|
||||
// 执行同步监听器
|
||||
for (const listener of syncListeners) {
|
||||
@@ -447,7 +447,7 @@ export class TypeSafeEventSystem {
|
||||
if (!listeners) return;
|
||||
|
||||
for (const id of listenerIds) {
|
||||
const index = listeners.findIndex(l => l.id === id);
|
||||
const index = listeners.findIndex((l) => l.id === id);
|
||||
if (index !== -1) {
|
||||
listeners.splice(index, 1);
|
||||
}
|
||||
@@ -488,7 +488,7 @@ export class TypeSafeEventSystem {
|
||||
this.flushBatch(eventType);
|
||||
}, config.delay);
|
||||
|
||||
this.batchTimers.set(eventType, timer as any);
|
||||
this.batchTimers.set(eventType, timer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,4 +578,3 @@ export class TypeSafeEventSystem {
|
||||
*/
|
||||
export const GlobalEventSystem = new TypeSafeEventSystem();
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ export class ECSFluentAPI {
|
||||
componentStats: Map<string, unknown>;
|
||||
queryStats: unknown;
|
||||
eventStats: Map<string, unknown>;
|
||||
} {
|
||||
} {
|
||||
return {
|
||||
entityCount: this.scene.entities.count,
|
||||
systemCount: this.scene.systems.length,
|
||||
|
||||
@@ -15,8 +15,8 @@ export class EntityBuilder {
|
||||
this.scene = scene;
|
||||
this.storageManager = storageManager;
|
||||
const id = scene.identifierPool.checkOut();
|
||||
this.entity = new Entity("", id);
|
||||
this.entity.scene = this.scene as any;
|
||||
this.entity = new Entity('', id);
|
||||
this.entity.scene = this.scene;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export { QuerySystem } from '../QuerySystem';
|
||||
export { ECSFluentAPI, createECSAPI } from '../FluentAPI';
|
||||
|
||||
@@ -131,7 +131,7 @@ export class QuerySystem {
|
||||
if (entities.length === 0) return;
|
||||
|
||||
// 使用Set来快速检查重复
|
||||
const existingIds = new Set(this.entities.map(e => e.id));
|
||||
const existingIds = new Set(this.entities.map((e) => e.id));
|
||||
let addedCount = 0;
|
||||
|
||||
for (const entity of entities) {
|
||||
@@ -679,7 +679,7 @@ export class QuerySystem {
|
||||
}
|
||||
|
||||
// 多组件查询:使用排序后的类型名称创建键
|
||||
const sortKey = componentTypes.map(t => {
|
||||
const sortKey = componentTypes.map((t) => {
|
||||
const name = getComponentTypeName(t);
|
||||
return name;
|
||||
}).sort().join(',');
|
||||
@@ -810,7 +810,7 @@ export class QuerySystem {
|
||||
*/
|
||||
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
|
||||
// 生成缓存键
|
||||
const cacheKey = componentTypes.map(t => {
|
||||
const cacheKey = componentTypes.map((t) => {
|
||||
return getComponentTypeName(t);
|
||||
}).sort().join(',');
|
||||
|
||||
@@ -821,7 +821,7 @@ export class QuerySystem {
|
||||
}
|
||||
|
||||
// 使用ComponentRegistry而不是ComponentTypeManager,确保bitIndex一致
|
||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
for (const type of componentTypes) {
|
||||
// 确保组件已注册
|
||||
if (!ComponentRegistry.isRegistered(type)) {
|
||||
@@ -843,11 +843,31 @@ export class QuerySystem {
|
||||
return this._version;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有实体
|
||||
*
|
||||
* 返回场景中的所有实体,不进行任何过滤。
|
||||
*
|
||||
* @returns 所有实体的只读数组
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const allEntities = scene.querySystem.queryAllEntities();
|
||||
* console.log(`场景中共有 ${allEntities.length} 个实体`);
|
||||
* ```
|
||||
*/
|
||||
public queryAllEntities(): readonly Entity[] {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有实体
|
||||
*
|
||||
* @deprecated 使用 queryAllEntities() 代替,以保持命名一致性
|
||||
* @see {@link queryAllEntities}
|
||||
*/
|
||||
public getAllEntities(): readonly Entity[] {
|
||||
return this.entities;
|
||||
return this.queryAllEntities();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -875,13 +895,17 @@ export class QuerySystem {
|
||||
cacheHitRate: string;
|
||||
};
|
||||
optimizationStats: {
|
||||
archetypeSystem: any;
|
||||
archetypeSystem: Array<{
|
||||
id: BitMask64Data;
|
||||
componentTypes: string[];
|
||||
entityCount: number;
|
||||
}>;
|
||||
};
|
||||
cacheStats: {
|
||||
size: number;
|
||||
hitRate: string;
|
||||
};
|
||||
} {
|
||||
} {
|
||||
return {
|
||||
entityCount: this.entities.length,
|
||||
indexStats: {
|
||||
@@ -895,9 +919,9 @@ export class QuerySystem {
|
||||
(this.queryStats.cacheHits / this.queryStats.totalQueries * 100).toFixed(2) + '%' : '0%'
|
||||
},
|
||||
optimizationStats: {
|
||||
archetypeSystem: this.archetypeSystem.getAllArchetypes().map(a => ({
|
||||
archetypeSystem: this.archetypeSystem.getAllArchetypes().map((a) => ({
|
||||
id: a.id,
|
||||
componentTypes: a.componentTypes.map(t => getComponentTypeName(t)),
|
||||
componentTypes: a.componentTypes.map((t) => getComponentTypeName(t)),
|
||||
entityCount: a.entities.size
|
||||
}))
|
||||
},
|
||||
@@ -1023,7 +1047,7 @@ export class QuerySystem {
|
||||
}
|
||||
case QueryConditionType.NONE: {
|
||||
const mask = this.createComponentMask(componentTypes);
|
||||
return this.entities.filter(entity =>
|
||||
return this.entities.filter((entity) =>
|
||||
BitMask64Utils.hasNone(entity.componentMask, mask)
|
||||
);
|
||||
}
|
||||
@@ -1241,7 +1265,7 @@ export class QueryBuilder {
|
||||
* 创建组件掩码
|
||||
*/
|
||||
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
|
||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
for (const type of componentTypes) {
|
||||
try {
|
||||
const bitMask = ComponentRegistry.getBitMask(type);
|
||||
|
||||
@@ -136,7 +136,7 @@ export class ReactiveQuery {
|
||||
private generateQueryId(): string {
|
||||
const typeStr = this._condition.type;
|
||||
const componentsStr = this._condition.componentTypes
|
||||
.map(t => t.name)
|
||||
.map((t) => t.name)
|
||||
.sort()
|
||||
.join(',');
|
||||
return `${typeStr}:${componentsStr}`;
|
||||
|
||||
@@ -39,15 +39,22 @@ interface IWeakRefConstructor {
|
||||
new <T extends object>(target: T): IWeakRef<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 包含 WeakRef 的全局对象类型
|
||||
*/
|
||||
interface GlobalWithWeakRef {
|
||||
WeakRef?: IWeakRefConstructor;
|
||||
}
|
||||
|
||||
/**
|
||||
* WeakRef 实现
|
||||
*
|
||||
* 优先使用原生 WeakRef,不支持时降级到 Polyfill
|
||||
*/
|
||||
const WeakRefImpl: IWeakRefConstructor = (
|
||||
(typeof globalThis !== 'undefined' && (globalThis as any).WeakRef) ||
|
||||
(typeof global !== 'undefined' && (global as any).WeakRef) ||
|
||||
(typeof window !== 'undefined' && (window as any).WeakRef) ||
|
||||
(typeof globalThis !== 'undefined' && (globalThis as GlobalWithWeakRef).WeakRef) ||
|
||||
(typeof global !== 'undefined' && (global as unknown as GlobalWithWeakRef).WeakRef) ||
|
||||
(typeof window !== 'undefined' && (window as unknown as GlobalWithWeakRef).WeakRef) ||
|
||||
WeakRefPolyfill
|
||||
) as IWeakRefConstructor;
|
||||
|
||||
@@ -174,6 +181,8 @@ export class ReferenceTracker {
|
||||
for (const record of validRecords) {
|
||||
const component = record.component.deref();
|
||||
if (component) {
|
||||
// 使用 any 进行动态属性访问,因为无法静态验证所有可能的组件属性
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(component as any)[record.propertyKey] = null;
|
||||
}
|
||||
}
|
||||
@@ -287,7 +296,7 @@ export class ReferenceTracker {
|
||||
* 获取调试信息
|
||||
*/
|
||||
public getDebugInfo(): object {
|
||||
const info: Record<string, any> = {};
|
||||
const info: Record<string, unknown> = {};
|
||||
|
||||
for (const [entityId, records] of this._references.entries()) {
|
||||
const validRecords = [];
|
||||
|
||||
@@ -2,12 +2,42 @@ import { Component } from '../Component';
|
||||
import { ComponentType } from './ComponentStorage';
|
||||
import { createLogger } from '../../Utils/Logger';
|
||||
|
||||
/**
|
||||
* 装饰器目标类型,用于存储元数据
|
||||
*/
|
||||
interface DecoratorTarget {
|
||||
constructor: ComponentTypeWithMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* 带有元数据的组件类型
|
||||
*/
|
||||
interface ComponentTypeWithMetadata {
|
||||
__enableSoA?: boolean;
|
||||
__highPrecisionFields?: Set<string>;
|
||||
__float64Fields?: Set<string>;
|
||||
__float32Fields?: Set<string>;
|
||||
__int32Fields?: Set<string>;
|
||||
__uint32Fields?: Set<string>;
|
||||
__int16Fields?: Set<string>;
|
||||
__uint16Fields?: Set<string>;
|
||||
__int8Fields?: Set<string>;
|
||||
__uint8Fields?: Set<string>;
|
||||
__uint8ClampedFields?: Set<string>;
|
||||
__serializeMapFields?: Set<string>;
|
||||
__serializeSetFields?: Set<string>;
|
||||
__serializeArrayFields?: Set<string>;
|
||||
__deepCopyFields?: Set<string>;
|
||||
__autoTypedFields?: Map<string, Record<string, unknown>>;
|
||||
__bigIntFields?: Set<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用SoA优化装饰器
|
||||
* 默认关闭SoA,只有在大规模批量操作场景下才建议开启
|
||||
*/
|
||||
export function EnableSoA<T extends ComponentType>(target: T): T {
|
||||
(target as any).__enableSoA = true;
|
||||
(target as unknown as { __enableSoA: boolean }).__enableSoA = true;
|
||||
return target;
|
||||
}
|
||||
|
||||
@@ -16,7 +46,7 @@ export function EnableSoA<T extends ComponentType>(target: T): T {
|
||||
* 高精度数值装饰器
|
||||
* 标记字段需要保持完整精度,存储为复杂对象而非TypedArray
|
||||
*/
|
||||
export function HighPrecision(target: any, propertyKey: string | symbol): void {
|
||||
export function HighPrecision(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__highPrecisionFields) {
|
||||
target.constructor.__highPrecisionFields = new Set();
|
||||
@@ -28,7 +58,7 @@ export function HighPrecision(target: any, propertyKey: string | symbol): void {
|
||||
* 64位浮点数装饰器
|
||||
* 标记字段使用Float64Array存储(更高精度但更多内存)
|
||||
*/
|
||||
export function Float64(target: any, propertyKey: string | symbol): void {
|
||||
export function Float64(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__float64Fields) {
|
||||
target.constructor.__float64Fields = new Set();
|
||||
@@ -40,7 +70,7 @@ export function Float64(target: any, propertyKey: string | symbol): void {
|
||||
* 32位浮点数装饰器
|
||||
* 标记字段使用Float32Array存储(默认类型,平衡性能和精度)
|
||||
*/
|
||||
export function Float32(target: any, propertyKey: string | symbol): void {
|
||||
export function Float32(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__float32Fields) {
|
||||
target.constructor.__float32Fields = new Set();
|
||||
@@ -52,7 +82,7 @@ export function Float32(target: any, propertyKey: string | symbol): void {
|
||||
* 32位整数装饰器
|
||||
* 标记字段使用Int32Array存储(适用于整数值)
|
||||
*/
|
||||
export function Int32(target: any, propertyKey: string | symbol): void {
|
||||
export function Int32(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__int32Fields) {
|
||||
target.constructor.__int32Fields = new Set();
|
||||
@@ -64,7 +94,7 @@ export function Int32(target: any, propertyKey: string | symbol): void {
|
||||
* 32位无符号整数装饰器
|
||||
* 标记字段使用Uint32Array存储(适用于无符号整数,如ID、标志位等)
|
||||
*/
|
||||
export function Uint32(target: any, propertyKey: string | symbol): void {
|
||||
export function Uint32(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__uint32Fields) {
|
||||
target.constructor.__uint32Fields = new Set();
|
||||
@@ -76,7 +106,7 @@ export function Uint32(target: any, propertyKey: string | symbol): void {
|
||||
* 16位整数装饰器
|
||||
* 标记字段使用Int16Array存储(适用于小范围整数)
|
||||
*/
|
||||
export function Int16(target: any, propertyKey: string | symbol): void {
|
||||
export function Int16(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__int16Fields) {
|
||||
target.constructor.__int16Fields = new Set();
|
||||
@@ -88,7 +118,7 @@ export function Int16(target: any, propertyKey: string | symbol): void {
|
||||
* 16位无符号整数装饰器
|
||||
* 标记字段使用Uint16Array存储(适用于小范围无符号整数)
|
||||
*/
|
||||
export function Uint16(target: any, propertyKey: string | symbol): void {
|
||||
export function Uint16(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__uint16Fields) {
|
||||
target.constructor.__uint16Fields = new Set();
|
||||
@@ -100,7 +130,7 @@ export function Uint16(target: any, propertyKey: string | symbol): void {
|
||||
* 8位整数装饰器
|
||||
* 标记字段使用Int8Array存储(适用于很小的整数值)
|
||||
*/
|
||||
export function Int8(target: any, propertyKey: string | symbol): void {
|
||||
export function Int8(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__int8Fields) {
|
||||
target.constructor.__int8Fields = new Set();
|
||||
@@ -112,7 +142,7 @@ export function Int8(target: any, propertyKey: string | symbol): void {
|
||||
* 8位无符号整数装饰器
|
||||
* 标记字段使用Uint8Array存储(适用于字节值、布尔标志等)
|
||||
*/
|
||||
export function Uint8(target: any, propertyKey: string | symbol): void {
|
||||
export function Uint8(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__uint8Fields) {
|
||||
target.constructor.__uint8Fields = new Set();
|
||||
@@ -124,7 +154,7 @@ export function Uint8(target: any, propertyKey: string | symbol): void {
|
||||
* 8位夹紧整数装饰器
|
||||
* 标记字段使用Uint8ClampedArray存储(适用于颜色值等需要夹紧的数据)
|
||||
*/
|
||||
export function Uint8Clamped(target: any, propertyKey: string | symbol): void {
|
||||
export function Uint8Clamped(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__uint8ClampedFields) {
|
||||
target.constructor.__uint8ClampedFields = new Set();
|
||||
@@ -137,7 +167,7 @@ export function Uint8Clamped(target: any, propertyKey: string | symbol): void {
|
||||
* 序列化Map装饰器
|
||||
* 标记Map字段需要序列化/反序列化存储
|
||||
*/
|
||||
export function SerializeMap(target: any, propertyKey: string | symbol): void {
|
||||
export function SerializeMap(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__serializeMapFields) {
|
||||
target.constructor.__serializeMapFields = new Set();
|
||||
@@ -149,7 +179,7 @@ export function SerializeMap(target: any, propertyKey: string | symbol): void {
|
||||
* 序列化Set装饰器
|
||||
* 标记Set字段需要序列化/反序列化存储
|
||||
*/
|
||||
export function SerializeSet(target: any, propertyKey: string | symbol): void {
|
||||
export function SerializeSet(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__serializeSetFields) {
|
||||
target.constructor.__serializeSetFields = new Set();
|
||||
@@ -161,7 +191,7 @@ export function SerializeSet(target: any, propertyKey: string | symbol): void {
|
||||
* 序列化Array装饰器
|
||||
* 标记Array字段需要序列化/反序列化存储
|
||||
*/
|
||||
export function SerializeArray(target: any, propertyKey: string | symbol): void {
|
||||
export function SerializeArray(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__serializeArrayFields) {
|
||||
target.constructor.__serializeArrayFields = new Set();
|
||||
@@ -173,7 +203,7 @@ export function SerializeArray(target: any, propertyKey: string | symbol): void
|
||||
* 深拷贝装饰器
|
||||
* 标记字段需要深拷贝处理(适用于嵌套对象)
|
||||
*/
|
||||
export function DeepCopy(target: any, propertyKey: string | symbol): void {
|
||||
export function DeepCopy(target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__deepCopyFields) {
|
||||
target.constructor.__deepCopyFields = new Set();
|
||||
@@ -197,7 +227,7 @@ export function AutoTyped(options?: {
|
||||
precision?: boolean;
|
||||
signed?: boolean;
|
||||
}) {
|
||||
return function (target: any, propertyKey: string | symbol): void {
|
||||
return function (target: DecoratorTarget, propertyKey: string | symbol): void {
|
||||
const key = String(propertyKey);
|
||||
if (!target.constructor.__autoTypedFields) {
|
||||
target.constructor.__autoTypedFields = new Map();
|
||||
@@ -214,6 +244,7 @@ export class TypeInference {
|
||||
/**
|
||||
* 根据数值范围推断最优的TypedArray类型
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public static inferOptimalType(value: any, options: {
|
||||
minValue?: number;
|
||||
maxValue?: number;
|
||||
@@ -338,7 +369,7 @@ export class SoAStorage<T extends Component> {
|
||||
private fields = new Map<string, SupportedTypedArray>();
|
||||
private stringFields = new Map<string, string[]>(); // 专门存储字符串
|
||||
private serializedFields = new Map<string, string[]>(); // 序列化存储Map/Set/Array
|
||||
private complexFields = new Map<number, Map<string, any>>(); // 存储复杂对象
|
||||
private complexFields = new Map<number, Map<string, unknown>>(); // 存储复杂对象
|
||||
private entityToIndex = new Map<number, number>();
|
||||
private indexToEntity: number[] = [];
|
||||
private freeIndices: number[] = [];
|
||||
@@ -353,24 +384,24 @@ export class SoAStorage<T extends Component> {
|
||||
|
||||
private initializeFields(componentType: ComponentType<T>): void {
|
||||
const instance = new componentType();
|
||||
const highPrecisionFields = (componentType as any).__highPrecisionFields || new Set();
|
||||
const float64Fields = (componentType as any).__float64Fields || new Set();
|
||||
const float32Fields = (componentType as any).__float32Fields || new Set();
|
||||
const int32Fields = (componentType as any).__int32Fields || new Set();
|
||||
const uint32Fields = (componentType as any).__uint32Fields || new Set();
|
||||
const int16Fields = (componentType as any).__int16Fields || new Set();
|
||||
const uint16Fields = (componentType as any).__uint16Fields || new Set();
|
||||
const int8Fields = (componentType as any).__int8Fields || new Set();
|
||||
const uint8Fields = (componentType as any).__uint8Fields || new Set();
|
||||
const uint8ClampedFields = (componentType as any).__uint8ClampedFields || new Set();
|
||||
const autoTypedFields = (componentType as any).__autoTypedFields || new Map();
|
||||
const serializeMapFields = (componentType as any).__serializeMapFields || new Set();
|
||||
const serializeSetFields = (componentType as any).__serializeSetFields || new Set();
|
||||
const serializeArrayFields = (componentType as any).__serializeArrayFields || new Set();
|
||||
// const deepCopyFields = (componentType as any).__deepCopyFields || new Set(); // 未使用,但保留供future使用
|
||||
const highPrecisionFields = (componentType as unknown as ComponentTypeWithMetadata).__highPrecisionFields || new Set();
|
||||
const float64Fields = (componentType as unknown as ComponentTypeWithMetadata).__float64Fields || new Set();
|
||||
const float32Fields = (componentType as unknown as ComponentTypeWithMetadata).__float32Fields || new Set();
|
||||
const int32Fields = (componentType as unknown as ComponentTypeWithMetadata).__int32Fields || new Set();
|
||||
const uint32Fields = (componentType as unknown as ComponentTypeWithMetadata).__uint32Fields || new Set();
|
||||
const int16Fields = (componentType as unknown as ComponentTypeWithMetadata).__int16Fields || new Set();
|
||||
const uint16Fields = (componentType as unknown as ComponentTypeWithMetadata).__uint16Fields || new Set();
|
||||
const int8Fields = (componentType as unknown as ComponentTypeWithMetadata).__int8Fields || new Set();
|
||||
const uint8Fields = (componentType as unknown as ComponentTypeWithMetadata).__uint8Fields || new Set();
|
||||
const uint8ClampedFields = (componentType as unknown as ComponentTypeWithMetadata).__uint8ClampedFields || new Set();
|
||||
const autoTypedFields = (componentType as unknown as ComponentTypeWithMetadata).__autoTypedFields || new Map();
|
||||
const serializeMapFields = (componentType as unknown as ComponentTypeWithMetadata).__serializeMapFields || new Set();
|
||||
const serializeSetFields = (componentType as unknown as ComponentTypeWithMetadata).__serializeSetFields || new Set();
|
||||
const serializeArrayFields = (componentType as unknown as ComponentTypeWithMetadata).__serializeArrayFields || new Set();
|
||||
// const deepCopyFields = (componentType as unknown as ComponentTypeWithMetadata).__deepCopyFields || new Set(); // 未使用,但保留供future使用
|
||||
|
||||
for (const key in instance) {
|
||||
if (instance.hasOwnProperty(key) && key !== 'id') {
|
||||
if (Object.prototype.hasOwnProperty.call(instance, key) && key !== 'id') {
|
||||
const value = (instance as any)[key];
|
||||
const type = typeof value;
|
||||
|
||||
@@ -473,7 +504,7 @@ export class SoAStorage<T extends Component> {
|
||||
|
||||
// 处理所有字段
|
||||
for (const key in component) {
|
||||
if (component.hasOwnProperty(key) && key !== 'id') {
|
||||
if (Object.prototype.hasOwnProperty.call(component, key) && key !== 'id') {
|
||||
const value = (component as any)[key];
|
||||
const type = typeof value;
|
||||
|
||||
@@ -578,7 +609,7 @@ export class SoAStorage<T extends Component> {
|
||||
}
|
||||
|
||||
if (obj instanceof Array) {
|
||||
return obj.map(item => this.deepClone(item));
|
||||
return obj.map((item) => this.deepClone(item));
|
||||
}
|
||||
|
||||
if (obj instanceof Map) {
|
||||
@@ -600,7 +631,7 @@ export class SoAStorage<T extends Component> {
|
||||
// 普通对象
|
||||
const cloned: any = {};
|
||||
for (const key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
cloned[key] = this.deepClone(obj[key]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type {Component} from '../Component';
|
||||
import type {EntitySystem} from '../Systems';
|
||||
import {ComponentType} from "../../Types";
|
||||
import type { Component } from '../Component';
|
||||
import type { EntitySystem } from '../Systems';
|
||||
import { ComponentType } from '../../Types';
|
||||
|
||||
/**
|
||||
* 存储组件类型名称的Symbol键
|
||||
|
||||
@@ -28,7 +28,6 @@ export class EntityComparer {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 游戏实体类
|
||||
*
|
||||
@@ -103,7 +102,16 @@ export class Entity {
|
||||
/**
|
||||
* 销毁状态标志
|
||||
*/
|
||||
public _isDestroyed: boolean = false;
|
||||
private _destroyed: boolean = false;
|
||||
|
||||
/**
|
||||
* 设置销毁状态(仅供框架内部使用)
|
||||
*
|
||||
* @internal 此方法仅用于批量销毁优化,不应在外部调用
|
||||
*/
|
||||
public setDestroyed(value: boolean): void {
|
||||
this._destroyed = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 父实体引用
|
||||
@@ -161,7 +169,7 @@ export class Entity {
|
||||
* @returns 如果实体已被销毁则返回true
|
||||
*/
|
||||
public get isDestroyed(): boolean {
|
||||
return this._isDestroyed;
|
||||
return this._destroyed;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -394,11 +402,11 @@ export class Entity {
|
||||
const componentType = component.constructor as ComponentType<T>;
|
||||
|
||||
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) {
|
||||
throw new Error(`Scene does not have componentStorageManager`);
|
||||
throw new Error('Scene does not have componentStorageManager');
|
||||
}
|
||||
|
||||
if (this.hasComponent(componentType)) {
|
||||
@@ -465,8 +473,6 @@ export class Entity {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 检查实体是否拥有指定类型的组件
|
||||
*
|
||||
@@ -646,7 +652,6 @@ export class Entity {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取所有指定类型的组件
|
||||
*
|
||||
@@ -700,7 +705,7 @@ export class Entity {
|
||||
*/
|
||||
public addChild(child: Entity): Entity {
|
||||
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) {
|
||||
@@ -898,11 +903,11 @@ export class Entity {
|
||||
* 移除所有组件、子实体并标记为已销毁
|
||||
*/
|
||||
public destroy(): void {
|
||||
if (this._isDestroyed) {
|
||||
if (this._destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._isDestroyed = true;
|
||||
this._destroyed = true;
|
||||
|
||||
if (this.scene && this.scene.referenceTracker) {
|
||||
this.scene.referenceTracker.clearReferencesTo(this.id);
|
||||
@@ -949,7 +954,7 @@ export class Entity {
|
||||
collectChildren(this);
|
||||
|
||||
for (const entity of toDestroy) {
|
||||
entity._isDestroyed = true;
|
||||
entity.setDestroyed(true);
|
||||
}
|
||||
|
||||
for (const entity of toDestroy) {
|
||||
@@ -1007,20 +1012,20 @@ export class Entity {
|
||||
childIds: number[];
|
||||
depth: number;
|
||||
cacheBuilt: boolean;
|
||||
} {
|
||||
} {
|
||||
return {
|
||||
name: this.name,
|
||||
id: this.id,
|
||||
enabled: this._enabled,
|
||||
active: this._active,
|
||||
activeInHierarchy: this.activeInHierarchy,
|
||||
destroyed: this._isDestroyed,
|
||||
destroyed: this._destroyed,
|
||||
componentCount: this.components.length,
|
||||
componentTypes: this.components.map(c => getComponentInstanceTypeName(c)),
|
||||
componentTypes: this.components.map((c) => getComponentInstanceTypeName(c)),
|
||||
componentMask: BitMask64Utils.toString(this._componentMask, 2), // 二进制表示
|
||||
parentId: this._parent?.id || null,
|
||||
childCount: this._children.length,
|
||||
childIds: this._children.map(c => c.id),
|
||||
childIds: this._children.map((c) => c.id),
|
||||
depth: this.getDepth(),
|
||||
cacheBuilt: this._componentCache !== null
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import { TypeSafeEventSystem } from './Core/EventSystem';
|
||||
import { EventBus } from './Core/EventBus';
|
||||
import { ReferenceTracker } from './Core/ReferenceTracker';
|
||||
import { IScene, ISceneConfig } from './IScene';
|
||||
import { getComponentInstanceTypeName, getSystemInstanceTypeName, getSystemMetadata } from "./Decorators";
|
||||
import { getComponentInstanceTypeName, getSystemInstanceTypeName, getSystemMetadata } from './Decorators';
|
||||
import { TypedQueryBuilder } from './Core/Query/TypedQuery';
|
||||
import { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer';
|
||||
import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer';
|
||||
@@ -30,7 +30,7 @@ export class Scene implements IScene {
|
||||
*
|
||||
* 用于标识和调试的友好名称。
|
||||
*/
|
||||
public name: string = "";
|
||||
public name: string = '';
|
||||
|
||||
/**
|
||||
* 场景自定义数据
|
||||
@@ -338,7 +338,7 @@ export class Scene implements IScene {
|
||||
* @param name 实体名称
|
||||
*/
|
||||
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 });
|
||||
|
||||
@@ -384,7 +384,7 @@ export class Scene implements IScene {
|
||||
* @param namePrefix 实体名称前缀
|
||||
* @returns 创建的实体列表
|
||||
*/
|
||||
public createEntities(count: number, namePrefix: string = "Entity"): Entity[] {
|
||||
public createEntities(count: number, namePrefix: string = 'Entity'): Entity[] {
|
||||
const entities: Entity[] = [];
|
||||
|
||||
// 批量创建实体对象,不立即添加到系统
|
||||
@@ -416,7 +416,7 @@ export class Scene implements IScene {
|
||||
if (entities.length === 0) return;
|
||||
|
||||
for (const entity of entities) {
|
||||
entity._isDestroyed = true;
|
||||
entity.setDestroyed(true);
|
||||
}
|
||||
|
||||
for (const entity of entities) {
|
||||
@@ -609,7 +609,7 @@ export class Scene implements IScene {
|
||||
} else {
|
||||
this.logger.warn(
|
||||
`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;
|
||||
}
|
||||
@@ -750,7 +750,7 @@ export class Scene implements IScene {
|
||||
entityCount: number;
|
||||
processorCount: number;
|
||||
componentStorageStats: Map<string, any>;
|
||||
} {
|
||||
} {
|
||||
return {
|
||||
entityCount: this.entities.count,
|
||||
processorCount: this.systems.length,
|
||||
@@ -779,20 +779,20 @@ export class Scene implements IScene {
|
||||
entityCount: number;
|
||||
}>;
|
||||
componentStats: Map<string, any>;
|
||||
} {
|
||||
} {
|
||||
const systems = this.systems;
|
||||
return {
|
||||
name: this.name || this.constructor.name,
|
||||
entityCount: this.entities.count,
|
||||
processorCount: systems.length,
|
||||
isRunning: this._didSceneBegin,
|
||||
entities: this.entities.buffer.map(entity => ({
|
||||
entities: this.entities.buffer.map((entity) => ({
|
||||
name: entity.name,
|
||||
id: entity.id,
|
||||
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),
|
||||
updateOrder: processor.updateOrder,
|
||||
entityCount: (processor as any)._entities?.length || 0
|
||||
|
||||
@@ -212,7 +212,7 @@ export class ComponentSerializer {
|
||||
|
||||
// 数组
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(item => this.serializeValue(item));
|
||||
return value.map((item) => this.serializeValue(item));
|
||||
}
|
||||
|
||||
// Map (如果没有使用@SerializeMap装饰器)
|
||||
@@ -276,7 +276,7 @@ export class ComponentSerializer {
|
||||
|
||||
// 数组
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(item => this.deserializeValue(item));
|
||||
return value.map((item) => this.deserializeValue(item));
|
||||
}
|
||||
|
||||
// 普通对象
|
||||
@@ -340,10 +340,10 @@ export class ComponentSerializer {
|
||||
return {
|
||||
type: metadata.options.typeId || getComponentTypeName(componentType),
|
||||
version: metadata.options.version,
|
||||
fields: Array.from(metadata.fields.keys()).map(k =>
|
||||
fields: Array.from(metadata.fields.keys()).map((k) =>
|
||||
typeof k === 'symbol' ? k.toString() : k
|
||||
),
|
||||
ignoredFields: Array.from(metadata.ignoredFields).map(k =>
|
||||
ignoredFields: Array.from(metadata.ignoredFields).map((k) =>
|
||||
typeof k === 'symbol' ? k.toString() : k
|
||||
),
|
||||
isSerializable: true
|
||||
|
||||
@@ -696,22 +696,22 @@ export class IncrementalSerializer {
|
||||
componentChanges: incremental.componentChanges.length,
|
||||
sceneDataChanges: incremental.sceneDataChanges.length,
|
||||
addedEntities: incremental.entityChanges.filter(
|
||||
c => c.operation === ChangeOperation.EntityAdded
|
||||
(c) => c.operation === ChangeOperation.EntityAdded
|
||||
).length,
|
||||
removedEntities: incremental.entityChanges.filter(
|
||||
c => c.operation === ChangeOperation.EntityRemoved
|
||||
(c) => c.operation === ChangeOperation.EntityRemoved
|
||||
).length,
|
||||
updatedEntities: incremental.entityChanges.filter(
|
||||
c => c.operation === ChangeOperation.EntityUpdated
|
||||
(c) => c.operation === ChangeOperation.EntityUpdated
|
||||
).length,
|
||||
addedComponents: incremental.componentChanges.filter(
|
||||
c => c.operation === ChangeOperation.ComponentAdded
|
||||
(c) => c.operation === ChangeOperation.ComponentAdded
|
||||
).length,
|
||||
removedComponents: incremental.componentChanges.filter(
|
||||
c => c.operation === ChangeOperation.ComponentRemoved
|
||||
(c) => c.operation === ChangeOperation.ComponentRemoved
|
||||
).length,
|
||||
updatedComponents: incremental.componentChanges.filter(
|
||||
c => c.operation === ChangeOperation.ComponentUpdated
|
||||
(c) => c.operation === ChangeOperation.ComponentUpdated
|
||||
).length
|
||||
};
|
||||
}
|
||||
|
||||
@@ -363,14 +363,14 @@ export class SceneSerializer {
|
||||
|
||||
// 数组
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(item => this.serializeValue(item));
|
||||
return value.map((item) => this.serializeValue(item));
|
||||
}
|
||||
|
||||
// 普通对象
|
||||
if (type === 'object') {
|
||||
const result: Record<string, any> = {};
|
||||
for (const key in value) {
|
||||
if (value.hasOwnProperty(key)) {
|
||||
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
||||
result[key] = this.serializeValue(value[key]);
|
||||
}
|
||||
}
|
||||
@@ -409,14 +409,14 @@ export class SceneSerializer {
|
||||
|
||||
// 数组
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(item => this.deserializeValue(item));
|
||||
return value.map((item) => this.deserializeValue(item));
|
||||
}
|
||||
|
||||
// 普通对象
|
||||
if (type === 'object') {
|
||||
const result: Record<string, any> = {};
|
||||
for (const key in value) {
|
||||
if (value.hasOwnProperty(key)) {
|
||||
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
||||
result[key] = this.deserializeValue(value[key]);
|
||||
}
|
||||
}
|
||||
@@ -437,8 +437,8 @@ export class SceneSerializer {
|
||||
const componentTypeSet = new Set(options.components);
|
||||
|
||||
// 只返回拥有指定组件的实体
|
||||
return entities.filter(entity => {
|
||||
return Array.from(entity.components).some(component =>
|
||||
return entities.filter((entity) => {
|
||||
return Array.from(entity.components).some((component) =>
|
||||
componentTypeSet.has(component.constructor as ComponentType)
|
||||
);
|
||||
});
|
||||
|
||||
@@ -127,7 +127,7 @@ export class VersionMigrationManager {
|
||||
return component;
|
||||
}
|
||||
|
||||
let migratedData = { ...component };
|
||||
const migratedData = { ...component };
|
||||
let version = currentVersion;
|
||||
|
||||
// 执行迁移链
|
||||
@@ -193,12 +193,12 @@ export class VersionMigrationManager {
|
||||
private static migrateSceneComponents(scene: SerializedScene): SerializedScene {
|
||||
const migratedScene = { ...scene };
|
||||
|
||||
migratedScene.entities = scene.entities.map(entity => ({
|
||||
migratedScene.entities = scene.entities.map((entity) => ({
|
||||
...entity,
|
||||
components: entity.components.map(component => {
|
||||
components: entity.components.map((component) => {
|
||||
// 查找组件的目标版本
|
||||
const typeInfo = scene.componentTypeRegistry.find(
|
||||
t => t.typeName === component.type
|
||||
(t) => t.typeName === component.type
|
||||
);
|
||||
|
||||
if (typeInfo && typeInfo.version !== component.version) {
|
||||
@@ -220,10 +220,10 @@ export class VersionMigrationManager {
|
||||
entities: any[],
|
||||
typeRegistry: Array<{ typeName: string; version: number }>
|
||||
): any[] {
|
||||
return entities.map(entity => ({
|
||||
return entities.map((entity) => ({
|
||||
...entity,
|
||||
components: entity.components.map((component: SerializedComponent) => {
|
||||
const typeInfo = typeRegistry.find(t => t.typeName === component.type);
|
||||
const typeInfo = typeRegistry.find((t) => t.typeName === component.type);
|
||||
|
||||
if (typeInfo && typeInfo.version !== component.version) {
|
||||
return this.migrateComponent(component, typeInfo.version);
|
||||
|
||||
@@ -9,6 +9,7 @@ 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 type { ComponentType } from '../Core/ComponentStorage';
|
||||
|
||||
/**
|
||||
* 事件监听器记录
|
||||
@@ -259,8 +260,11 @@ export abstract class EntitySystem<
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除实体缓存(内部使用)
|
||||
* 当Scene中的实体发生变化时调用
|
||||
* 清除实体缓存
|
||||
*
|
||||
* 当 Scene 中的实体发生变化时调用,使系统的实体缓存失效。
|
||||
*
|
||||
* @internal 框架内部使用,不应在外部代码中直接调用
|
||||
*/
|
||||
public clearEntityCache(): void {
|
||||
this._entityCache.invalidate();
|
||||
@@ -299,7 +303,7 @@ export abstract class EntitySystem<
|
||||
|
||||
// 空条件返回所有实体
|
||||
if (this._matcher.isEmpty()) {
|
||||
currentEntities = querySystem.getAllEntities();
|
||||
currentEntities = querySystem.queryAllEntities();
|
||||
} else if (this.isSingleCondition(condition)) {
|
||||
// 单一条件优化查询
|
||||
currentEntities = this.executeSingleConditionQuery(condition, querySystem);
|
||||
@@ -403,7 +407,7 @@ export abstract class EntitySystem<
|
||||
// 6. 应用none条件 (差集)
|
||||
if (condition.none.length > 0) {
|
||||
if (!resultIds) {
|
||||
resultIds = this.extractEntityIds(querySystem.getAllEntities());
|
||||
resultIds = this.extractEntityIds(querySystem.queryAllEntities());
|
||||
}
|
||||
|
||||
const noneResult = querySystem.queryAny(...condition.none);
|
||||
@@ -411,16 +415,23 @@ export abstract class EntitySystem<
|
||||
resultIds = this.differenceIdSets(resultIds, noneIds);
|
||||
}
|
||||
|
||||
return resultIds ? this.idSetToEntityArray(resultIds, querySystem.getAllEntities()) : [];
|
||||
return resultIds ? this.idSetToEntityArray(resultIds, querySystem.queryAllEntities()) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取实体ID集合
|
||||
*
|
||||
* 使用位运算 | 0 强制转换为 32 位整数,帮助 JavaScript 引擎的 JIT 编译器
|
||||
* 进行整数优化,在大规模实体集合操作时可以提供微小的性能提升。
|
||||
*
|
||||
* @param entities 实体数组
|
||||
* @returns 包含所有实体ID的集合
|
||||
*/
|
||||
private extractEntityIds(entities: readonly Entity[]): Set<number> {
|
||||
const len = entities.length;
|
||||
const idSet = new Set<number>();
|
||||
|
||||
// 使用位运算 | 0 进行整数优化(JIT 友好)
|
||||
for (let i = 0; i < len; i = (i + 1) | 0) {
|
||||
idSet.add(entities[i]!.id | 0);
|
||||
}
|
||||
@@ -482,6 +493,12 @@ export abstract class EntitySystem<
|
||||
|
||||
/**
|
||||
* 重建实体ID映射
|
||||
*
|
||||
* 重新构建从实体ID到实体引用的映射表。使用位运算优化性能。
|
||||
*
|
||||
* @param allEntities 所有实体的数组
|
||||
* @param version QuerySystem 的版本号,用于缓存失效判断
|
||||
* @returns 重建后的实体ID映射表
|
||||
*/
|
||||
private rebuildEntityIdMap(allEntities: readonly Entity[], version: number): Map<number, Entity> {
|
||||
let entityMap = this._entityIdMap;
|
||||
@@ -493,6 +510,7 @@ export abstract class EntitySystem<
|
||||
}
|
||||
|
||||
const len = allEntities.length;
|
||||
// 使用位运算 | 0 进行整数优化(JIT 友好)
|
||||
for (let i = 0; i < len; i = (i + 1) | 0) {
|
||||
const entity = allEntities[i]!;
|
||||
entityMap.set(entity.id | 0, entity);
|
||||
@@ -506,6 +524,12 @@ export abstract class EntitySystem<
|
||||
|
||||
/**
|
||||
* 从ID集合构建Entity数组
|
||||
*
|
||||
* 将实体ID集合转换为实体引用数组。跳过无效的实体ID(已被删除的实体)。
|
||||
*
|
||||
* @param idSet 实体ID集合
|
||||
* @param allEntities 所有实体的数组(用于构建映射表)
|
||||
* @returns 实体引用数组
|
||||
*/
|
||||
private idSetToEntityArray(idSet: Set<number>, allEntities: readonly Entity[]): readonly Entity[] {
|
||||
const entityMap = this.getEntityIdMap(allEntities);
|
||||
@@ -518,10 +542,12 @@ export abstract class EntitySystem<
|
||||
const entity = entityMap.get(id);
|
||||
if (entity !== undefined) {
|
||||
result[index] = entity;
|
||||
// 使用位运算 | 0 进行整数优化(JIT 友好)
|
||||
index = (index + 1) | 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有无效ID,调整数组长度
|
||||
if (index < size) {
|
||||
result.length = index;
|
||||
}
|
||||
@@ -786,7 +812,7 @@ export abstract class EntitySystem<
|
||||
this._eventListeners.push({
|
||||
eventSystem: this.scene.eventSystem,
|
||||
eventType,
|
||||
handler,
|
||||
handler: handler as EventHandler,
|
||||
listenerRef
|
||||
});
|
||||
}
|
||||
@@ -803,7 +829,7 @@ export abstract class EntitySystem<
|
||||
handler: EventHandler<T>
|
||||
): void {
|
||||
const listenerIndex = this._eventListeners.findIndex(
|
||||
listener => listener.eventType === eventType && listener.handler === handler
|
||||
(listener) => listener.eventType === eventType && listener.handler === handler
|
||||
);
|
||||
|
||||
if (listenerIndex >= 0) {
|
||||
@@ -891,7 +917,7 @@ export abstract class EntitySystem<
|
||||
entity: Entity,
|
||||
componentType: T
|
||||
): ComponentInstance<T> {
|
||||
const component = entity.getComponent(componentType as any);
|
||||
const component = entity.getComponent(componentType as ComponentType);
|
||||
if (!component) {
|
||||
throw new Error(
|
||||
`Component ${componentType.name} not found on entity ${entity.name} in ${this.systemName}`
|
||||
@@ -929,7 +955,7 @@ export abstract class EntitySystem<
|
||||
): { [K in keyof T]: ComponentInstance<T[K]> } {
|
||||
return components.map((type) =>
|
||||
this.requireComponent(entity, type)
|
||||
) as any;
|
||||
) as { [K in keyof T]: ComponentInstance<T[K]> };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -414,7 +414,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
${sharedProcessFunctionBody}
|
||||
};
|
||||
userProcessFunction(sharedFloatArray, startIndex, endIndex, deltaTime, systemConfig);
|
||||
` : ``}
|
||||
` : ''}
|
||||
}
|
||||
`;
|
||||
}
|
||||
@@ -494,7 +494,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
const deltaTime = Time.deltaTime;
|
||||
|
||||
// 3. Worker执行阶段
|
||||
const promises = batches.map(batch =>
|
||||
const promises = batches.map((batch) =>
|
||||
this.workerPool!.execute({
|
||||
entities: batch,
|
||||
deltaTime,
|
||||
@@ -525,7 +525,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
*/
|
||||
private processSynchronously(entities: readonly Entity[]): void {
|
||||
// 1. 数据提取阶段
|
||||
const entityData = entities.map(entity => this.extractEntityData(entity));
|
||||
const entityData = entities.map((entity) => this.extractEntityData(entity));
|
||||
|
||||
// 2. 主线程处理阶段
|
||||
const deltaTime = Time.deltaTime;
|
||||
@@ -534,7 +534,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
// 3. 结果应用阶段
|
||||
// 处理Promise返回值
|
||||
if (results && typeof (results as any).then === 'function') {
|
||||
(results as Promise<TEntityData[]>).then(finalResults => {
|
||||
(results as Promise<TEntityData[]>).then((finalResults) => {
|
||||
entities.forEach((entity, index) => {
|
||||
this.applyResult(entity, finalResults[index]!);
|
||||
});
|
||||
@@ -813,7 +813,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
||||
sharedArrayBufferSupported: boolean;
|
||||
sharedArrayBufferEnabled: boolean;
|
||||
currentMode: 'shared-buffer' | 'worker' | 'sync';
|
||||
} {
|
||||
} {
|
||||
let currentMode: 'shared-buffer' | 'worker' | 'sync' = 'sync';
|
||||
|
||||
if (this.config.enableWorker && this.workerPool) {
|
||||
|
||||
@@ -69,7 +69,7 @@ export class BitMask64Utils {
|
||||
return maskSegments.some((seg, index) => {
|
||||
const bitsSeg = bitsSegments[index];
|
||||
return bitsSeg && ((seg[SegmentPart.LOW] & bitsSeg[SegmentPart.LOW]) !== 0 || (seg[SegmentPart.HIGH] & bitsSeg[SegmentPart.HIGH]) !== 0);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,7 +145,7 @@ export class BitMask64Utils {
|
||||
return baseIsZero;
|
||||
}
|
||||
// 额外检查扩展区域是否都为0
|
||||
return mask.segments.every(seg => seg[SegmentPart.LOW] === 0 && seg[SegmentPart.HIGH] === 0);
|
||||
return mask.segments.every((seg) => seg[SegmentPart.LOW] === 0 && seg[SegmentPart.HIGH] === 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -155,7 +155,7 @@ export class BitMask64Utils {
|
||||
* @returns 如果两个掩码完全相等则返回true
|
||||
*/
|
||||
public static equals(a: BitMask64Data, b: BitMask64Data): boolean {
|
||||
let baseEquals = a.base[SegmentPart.LOW] === b.base[SegmentPart.LOW] && a.base[SegmentPart.HIGH] === b.base[SegmentPart.HIGH];
|
||||
const baseEquals = a.base[SegmentPart.LOW] === b.base[SegmentPart.LOW] && a.base[SegmentPart.HIGH] === b.base[SegmentPart.HIGH];
|
||||
// base不相等,或ab都没有扩展区域位,直接返回base比较结果
|
||||
if(!baseEquals || (!a.segments && !b.segments)) return baseEquals;
|
||||
// 不能假设a,b的segments都存在或长度相同.
|
||||
@@ -355,7 +355,7 @@ export class BitMask64Utils {
|
||||
if(!source.segments || source.segments.length == 0) return;
|
||||
// 没有拓展段,则直接复制数组
|
||||
if(!target.segments){
|
||||
target.segments = source.segments.map(seg => [...seg]);
|
||||
target.segments = source.segments.map((seg) => [...seg]);
|
||||
return;
|
||||
}
|
||||
// source有扩展段,target扩展段不足,则补充长度
|
||||
@@ -382,7 +382,7 @@ export class BitMask64Utils {
|
||||
public static clone(mask: BitMask64Data): BitMask64Data {
|
||||
return {
|
||||
base: mask.base.slice() as BitMask64Segment,
|
||||
...(mask.segments && { segments: mask.segments.map(seg => [...seg] as BitMask64Segment) })
|
||||
...(mask.segments && { segments: mask.segments.map((seg) => [...seg] as BitMask64Segment) })
|
||||
};
|
||||
}
|
||||
|
||||
@@ -414,8 +414,8 @@ export class BitMask64Utils {
|
||||
for (let i = -1; i < totalLength; i++) {
|
||||
let segResult = '';
|
||||
const bitMaskData = i == -1 ? mask.base : mask.segments![i]!;
|
||||
let hi = bitMaskData[SegmentPart.HIGH];
|
||||
let lo = bitMaskData[SegmentPart.LOW];
|
||||
const hi = bitMaskData[SegmentPart.HIGH];
|
||||
const lo = bitMaskData[SegmentPart.LOW];
|
||||
if(radix == 2){
|
||||
const hiBits = hi.toString(2).padStart(32, '0');
|
||||
const loBits = lo.toString(2).padStart(32, '0');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BitMask64Data } from "./BigIntCompatibility";
|
||||
import { BitMask64Data } from './BigIntCompatibility';
|
||||
|
||||
// FlatHashMapFast.ts
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ export class ComponentSparseSet {
|
||||
this.removeEntity(entity);
|
||||
}
|
||||
|
||||
let componentMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
const componentMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
const entityComponents = new Set<ComponentType>();
|
||||
|
||||
// 分析实体组件并构建位掩码
|
||||
@@ -169,7 +169,7 @@ export class ComponentSparseSet {
|
||||
}
|
||||
|
||||
// 构建目标位掩码
|
||||
let targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
const targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
for (const componentType of componentTypes) {
|
||||
if (!ComponentRegistry.isRegistered(componentType)) {
|
||||
return new Set<Entity>(); // 未注册的组件类型,结果为空
|
||||
@@ -209,7 +209,7 @@ export class ComponentSparseSet {
|
||||
}
|
||||
|
||||
// 构建目标位掩码
|
||||
let targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
const targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||
for (const componentType of componentTypes) {
|
||||
if (ComponentRegistry.isRegistered(componentType)) {
|
||||
const bitMask = ComponentRegistry.getBitMask(componentType);
|
||||
@@ -272,14 +272,26 @@ export class ComponentSparseSet {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有实体
|
||||
* 查询所有实体
|
||||
*
|
||||
* 返回拥有此组件的所有实体。
|
||||
*
|
||||
* @returns 所有实体的数组
|
||||
*/
|
||||
public getAllEntities(): Entity[] {
|
||||
public queryAllEntities(): Entity[] {
|
||||
return this._entities.toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有实体
|
||||
*
|
||||
* @deprecated 使用 queryAllEntities() 代替,以保持命名一致性
|
||||
* @see {@link queryAllEntities}
|
||||
*/
|
||||
public getAllEntities(): Entity[] {
|
||||
return this.queryAllEntities();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取实体数量
|
||||
*/
|
||||
@@ -327,7 +339,7 @@ export class ComponentSparseSet {
|
||||
masksMemory: number;
|
||||
mappingsMemory: number;
|
||||
totalMemory: number;
|
||||
} {
|
||||
} {
|
||||
const entitiesStats = this._entities.getMemoryStats();
|
||||
const masksMemory = this._componentMasks.length * 16; // 估计每个BigInt 16字节
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ export class EntityList {
|
||||
pendingAdd: number;
|
||||
pendingRemove: number;
|
||||
nameIndexSize: number;
|
||||
} {
|
||||
} {
|
||||
let activeCount = 0;
|
||||
for (const entity of this.buffer) {
|
||||
if (entity.enabled && !entity.isDestroyed) {
|
||||
|
||||
@@ -117,8 +117,8 @@ export class IdentifierPool {
|
||||
if (this._nextAvailableIndex > IdentifierPool.MAX_INDEX) {
|
||||
throw new Error(
|
||||
`实体索引已达到框架设计限制 (${IdentifierPool.MAX_INDEX})。` +
|
||||
`这意味着您已经分配了超过65535个不同的实体索引。` +
|
||||
`这是16位索引设计的限制,考虑优化实体回收策略或升级到64位ID设计。`
|
||||
'这意味着您已经分配了超过65535个不同的实体索引。' +
|
||||
'这是16位索引设计的限制,考虑优化实体回收策略或升级到64位ID设计。'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ export class IdentifierPool {
|
||||
|
||||
// 检查是否已经在待回收队列中
|
||||
const alreadyPending = this._pendingRecycle.some(
|
||||
item => item.index === index && item.generation === generation
|
||||
(item) => item.index === index && item.generation === generation
|
||||
);
|
||||
|
||||
if (alreadyPending) {
|
||||
@@ -217,7 +217,7 @@ export class IdentifierPool {
|
||||
averageGeneration: number;
|
||||
/** 世代存储大小 */
|
||||
generationStorageSize: number;
|
||||
} {
|
||||
} {
|
||||
// 计算平均世代版本
|
||||
let totalGeneration = 0;
|
||||
let generationCount = 0;
|
||||
|
||||
@@ -267,15 +267,15 @@ export class Matcher {
|
||||
const parts: string[] = [];
|
||||
|
||||
if (this.condition.all.length > 0) {
|
||||
parts.push(`all(${this.condition.all.map(t => getComponentTypeName(t)).join(', ')})`);
|
||||
parts.push(`all(${this.condition.all.map((t) => getComponentTypeName(t)).join(', ')})`);
|
||||
}
|
||||
|
||||
if (this.condition.any.length > 0) {
|
||||
parts.push(`any(${this.condition.any.map(t => getComponentTypeName(t)).join(', ')})`);
|
||||
parts.push(`any(${this.condition.any.map((t) => getComponentTypeName(t)).join(', ')})`);
|
||||
}
|
||||
|
||||
if (this.condition.none.length > 0) {
|
||||
parts.push(`none(${this.condition.none.map(t => getComponentTypeName(t)).join(', ')})`);
|
||||
parts.push(`none(${this.condition.none.map((t) => getComponentTypeName(t)).join(', ')})`);
|
||||
}
|
||||
|
||||
if (this.condition.tag !== undefined) {
|
||||
|
||||
@@ -267,7 +267,7 @@ export class SparseSet<T> {
|
||||
denseArraySize: number;
|
||||
sparseMapSize: number;
|
||||
totalMemory: number;
|
||||
} {
|
||||
} {
|
||||
const denseArraySize = this._dense.length * 8; // 估计每个引用8字节
|
||||
const sparseMapSize = this._sparse.size * 16; // 估计每个Map条目16字节
|
||||
|
||||
|
||||
@@ -408,7 +408,7 @@ export class World {
|
||||
globalSystemCount: this._globalSystems.length,
|
||||
createdAt: this._createdAt,
|
||||
config: { ...this._config },
|
||||
scenes: Array.from(this._scenes.keys()).map(sceneId => ({
|
||||
scenes: Array.from(this._scenes.keys()).map((sceneId) => ({
|
||||
id: sceneId,
|
||||
isActive: this._activeScenes.has(sceneId),
|
||||
name: this._scenes.get(sceneId)?.name || sceneId
|
||||
|
||||
@@ -444,7 +444,7 @@ export class WorldManager implements IService {
|
||||
|
||||
// 检查是否所有Scene都是空的
|
||||
const allScenes = world.getAllScenes();
|
||||
const hasEntities = allScenes.some(scene =>
|
||||
const hasEntities = allScenes.some((scene) =>
|
||||
scene.entities && scene.entities.count > 0
|
||||
);
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ export class PlatformManager {
|
||||
platformSupportsSharedArrayBuffer: boolean;
|
||||
platformMaxWorkerCount: number;
|
||||
platformLimitations: any;
|
||||
} {
|
||||
} {
|
||||
if (!this.adapter) {
|
||||
return {
|
||||
platformSupportsWorker: false,
|
||||
|
||||
@@ -208,8 +208,8 @@ export class DebugPlugin implements IPlugin, IService {
|
||||
return {
|
||||
name: scene.name,
|
||||
entityCount: entities.length,
|
||||
systems: systems.map(sys => this.getSystemInfo(sys)),
|
||||
entities: entities.map(entity => this.getEntityInfo(entity))
|
||||
systems: systems.map((sys) => this.getSystemInfo(sys)),
|
||||
entities: entities.map((entity) => this.getEntityInfo(entity))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -246,7 +246,7 @@ export class DebugPlugin implements IPlugin, IService {
|
||||
enabled: entity.enabled,
|
||||
tag: entity.tag,
|
||||
componentCount: components.length,
|
||||
components: components.map(comp => this.getComponentInfo(comp))
|
||||
components: components.map((comp) => this.getComponentInfo(comp))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ export class DebugPlugin implements IPlugin, IService {
|
||||
|
||||
if (filter.hasComponent) {
|
||||
const hasComp = entity.components.some(
|
||||
c => c.constructor.name === filter.hasComponent
|
||||
(c) => c.constructor.name === filter.hasComponent
|
||||
);
|
||||
if (!hasComp) {
|
||||
continue;
|
||||
|
||||
@@ -47,8 +47,8 @@ export class ComponentDataCollector {
|
||||
});
|
||||
|
||||
// 获取池利用率信息
|
||||
let poolUtilizations = new Map<string, number>();
|
||||
let poolSizes = new Map<string, number>();
|
||||
const poolUtilizations = new Map<string, number>();
|
||||
const poolSizes = new Map<string, number>();
|
||||
|
||||
try {
|
||||
const poolManager = ComponentPoolManager.getInstance();
|
||||
|
||||
@@ -135,7 +135,7 @@ export class DebugManager implements IService, IUpdatable {
|
||||
* 格式化日志消息
|
||||
*/
|
||||
private formatLogMessage(args: unknown[]): string {
|
||||
return args.map(arg => {
|
||||
return args.map((arg) => {
|
||||
if (typeof arg === 'string') return arg;
|
||||
if (arg instanceof Error) return `${arg.name}: ${arg.message}`;
|
||||
if (arg === null) return 'null';
|
||||
@@ -173,7 +173,7 @@ export class DebugManager implements IService, IUpdatable {
|
||||
seen.add(value);
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
const result = value.map(item => stringify(item, depth + 1));
|
||||
const result = value.map((item) => stringify(item, depth + 1));
|
||||
seen.delete(value);
|
||||
return result;
|
||||
}
|
||||
@@ -436,9 +436,6 @@ export class DebugManager implements IService, IUpdatable {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 处理内存快照请求
|
||||
*/
|
||||
@@ -519,7 +516,7 @@ export class DebugManager implements IService, IUpdatable {
|
||||
jsHeapSizeLimit: number;
|
||||
} | null;
|
||||
detailedMemory?: unknown;
|
||||
} {
|
||||
} {
|
||||
const memoryInfo = {
|
||||
totalMemory: 0,
|
||||
usedMemory: 0,
|
||||
@@ -575,7 +572,6 @@ export class DebugManager implements IService, IUpdatable {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 收集组件内存统计(仅用于内存快照)
|
||||
*/
|
||||
@@ -672,7 +668,7 @@ export class DebugManager implements IService, IUpdatable {
|
||||
enabled: boolean;
|
||||
updateOrder: number;
|
||||
}>;
|
||||
} {
|
||||
} {
|
||||
const scene = this.sceneManager.currentScene;
|
||||
let totalSystemMemory = 0;
|
||||
const systemBreakdown: Array<{
|
||||
@@ -766,7 +762,7 @@ export class DebugManager implements IService, IUpdatable {
|
||||
utilization: number;
|
||||
hitRate?: number;
|
||||
}>;
|
||||
} {
|
||||
} {
|
||||
let totalPoolMemory = 0;
|
||||
const poolBreakdown: Array<{
|
||||
typeName: string;
|
||||
@@ -845,7 +841,7 @@ export class DebugManager implements IService, IUpdatable {
|
||||
samples: number;
|
||||
}>;
|
||||
error?: string;
|
||||
} {
|
||||
} {
|
||||
try {
|
||||
if (!this.performanceMonitor) {
|
||||
return { enabled: false };
|
||||
|
||||
@@ -182,17 +182,17 @@ export class EntityDataCollector {
|
||||
try {
|
||||
stats = entityList.getStats ? entityList.getStats() : this.calculateFallbackEntityStats(entityList);
|
||||
} catch (error) {
|
||||
return {
|
||||
totalEntities: 0,
|
||||
activeEntities: 0,
|
||||
pendingAdd: 0,
|
||||
pendingRemove: 0,
|
||||
entitiesPerArchetype: [],
|
||||
topEntitiesByComponents: [],
|
||||
entityHierarchy: [],
|
||||
entityDetailsMap: {}
|
||||
};
|
||||
}
|
||||
return {
|
||||
totalEntities: 0,
|
||||
activeEntities: 0,
|
||||
pendingAdd: 0,
|
||||
pendingRemove: 0,
|
||||
entitiesPerArchetype: [],
|
||||
topEntitiesByComponents: [],
|
||||
entityHierarchy: [],
|
||||
entityDetailsMap: {}
|
||||
};
|
||||
}
|
||||
|
||||
const archetypeData = this.collectArchetypeDataWithMemory(scene);
|
||||
|
||||
@@ -369,7 +369,6 @@ export class EntityDataCollector {
|
||||
}
|
||||
|
||||
|
||||
|
||||
private getArchetypeDistributionWithMemory(entityContainer: any): Array<{ signature: string; count: number; memory: number }> {
|
||||
const distribution = new Map<string, { count: number; memory: number; componentTypes: string[] }>();
|
||||
|
||||
@@ -437,7 +436,7 @@ export class EntityDataCollector {
|
||||
private calculateFallbackEntityStats(entityList: any): any {
|
||||
const allEntities = entityList.buffer || [];
|
||||
const activeEntities = allEntities.filter((entity: any) =>
|
||||
entity.enabled && !entity._isDestroyed
|
||||
entity.enabled && !entity.isDestroyed
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -694,7 +693,7 @@ export class EntityDataCollector {
|
||||
|
||||
try {
|
||||
const propertyKeys = Object.keys(component);
|
||||
propertyKeys.forEach(propertyKey => {
|
||||
propertyKeys.forEach((propertyKey) => {
|
||||
if (!propertyKey.startsWith('_') && propertyKey !== 'entity' && propertyKey !== 'constructor') {
|
||||
const propertyValue = (component as any)[propertyKey];
|
||||
if (propertyValue !== undefined && propertyValue !== null) {
|
||||
@@ -739,20 +738,20 @@ export class EntityDataCollector {
|
||||
const component = entity.components[componentIndex];
|
||||
const properties: Record<string, any> = {};
|
||||
|
||||
const propertyKeys = Object.keys(component);
|
||||
propertyKeys.forEach(propertyKey => {
|
||||
if (!propertyKey.startsWith('_') && propertyKey !== 'entity') {
|
||||
const propertyValue = (component as any)[propertyKey];
|
||||
if (propertyValue !== undefined && propertyValue !== null) {
|
||||
const propertyKeys = Object.keys(component);
|
||||
propertyKeys.forEach((propertyKey) => {
|
||||
if (!propertyKey.startsWith('_') && propertyKey !== 'entity') {
|
||||
const propertyValue = (component as any)[propertyKey];
|
||||
if (propertyValue !== undefined && propertyValue !== null) {
|
||||
properties[propertyKey] = this.formatPropertyValue(propertyValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return properties;
|
||||
} catch (error) {
|
||||
} catch (error) {
|
||||
return { _error: '属性提取失败' };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -786,7 +785,7 @@ export class EntityDataCollector {
|
||||
if (obj.length === 0) return [];
|
||||
|
||||
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 {
|
||||
_isLazyArray: true,
|
||||
_arrayLength: obj.length,
|
||||
@@ -795,7 +794,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);
|
||||
@@ -843,7 +842,7 @@ export class EntityDataCollector {
|
||||
const typeName = obj.constructor?.name || 'Object';
|
||||
const summary = this.getObjectSummary(obj, typeName);
|
||||
|
||||
return {
|
||||
return {
|
||||
_isLazyObject: true,
|
||||
_typeName: typeName,
|
||||
_summary: summary,
|
||||
|
||||
@@ -34,7 +34,7 @@ export class PerformanceDataCollector {
|
||||
}
|
||||
|
||||
// 计算ECS执行时间统计
|
||||
const history = this.frameTimeHistory.filter(t => t >= 0);
|
||||
const history = this.frameTimeHistory.filter((t) => t >= 0);
|
||||
const averageECSTime = history.length > 0 ? history.reduce((a, b) => a + b, 0) / history.length : ecsExecutionTimeMs;
|
||||
const minECSTime = history.length > 0 ? Math.min(...history) : ecsExecutionTimeMs;
|
||||
const maxECSTime = history.length > 0 ? Math.max(...history) : ecsExecutionTimeMs;
|
||||
@@ -100,7 +100,7 @@ export class PerformanceDataCollector {
|
||||
}
|
||||
|
||||
// 计算各系统占ECS总时间的百分比
|
||||
systemBreakdown.forEach(system => {
|
||||
systemBreakdown.forEach((system) => {
|
||||
system.percentage = totalTime > 0 ? (system.executionTime / totalTime * 100) : 0;
|
||||
});
|
||||
|
||||
|
||||
@@ -82,7 +82,8 @@ export class WebSocketManager {
|
||||
try {
|
||||
const message = typeof data === 'string' ? data : JSON.stringify(data);
|
||||
this.ws.send(message);
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
// 发送失败时静默忽略,WebSocket 断开会触发 error 事件
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +113,7 @@ export class WebSocketManager {
|
||||
this.reconnectAttempts++;
|
||||
|
||||
this.reconnectTimer = setTimeout(() => {
|
||||
this.connect().catch(_error => {
|
||||
this.connect().catch((_error) => {
|
||||
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
||||
this.scheduleReconnect();
|
||||
}
|
||||
@@ -130,7 +131,8 @@ export class WebSocketManager {
|
||||
if (this.messageHandler) {
|
||||
this.messageHandler(message);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (_error) {
|
||||
// 解析失败时静默忽略,避免非 JSON 消息导致错误
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
type EventHandler = (...args: unknown[]) => void;
|
||||
|
||||
/**
|
||||
* 用于包装事件的一个小类
|
||||
*/
|
||||
export class FuncPack<TContext = unknown> {
|
||||
/** 函数 */
|
||||
public func: Function;
|
||||
public func: EventHandler;
|
||||
/** 上下文 */
|
||||
public context: TContext;
|
||||
|
||||
constructor(func: Function, context: TContext) {
|
||||
constructor(func: EventHandler, context: TContext) {
|
||||
this.func = func;
|
||||
this.context = context;
|
||||
}
|
||||
@@ -29,7 +31,7 @@ export class Emitter<T, TContext = unknown> {
|
||||
* @param handler 监听函数
|
||||
* @param context 监听上下文
|
||||
*/
|
||||
public addObserver(eventType: T, handler: Function, context: TContext) {
|
||||
public addObserver(eventType: T, handler: EventHandler, context: TContext) {
|
||||
let list = this._messageTable.get(eventType);
|
||||
if (!list) {
|
||||
list = [];
|
||||
@@ -46,10 +48,10 @@ export class Emitter<T, TContext = unknown> {
|
||||
* @param eventType 事件类型
|
||||
* @param handler 事件函数
|
||||
*/
|
||||
public removeObserver(eventType: T, handler: Function) {
|
||||
let messageData = this._messageTable.get(eventType);
|
||||
public removeObserver(eventType: T, handler: EventHandler) {
|
||||
const messageData = this._messageTable.get(eventType);
|
||||
if (messageData) {
|
||||
let index = messageData.findIndex(data => data.func == handler);
|
||||
const index = messageData.findIndex((data) => data.func == handler);
|
||||
if (index != -1)
|
||||
messageData.splice(index, 1);
|
||||
}
|
||||
@@ -61,9 +63,9 @@ export class Emitter<T, TContext = unknown> {
|
||||
* @param data 事件数据
|
||||
*/
|
||||
public emit<TData = unknown>(eventType: T, ...data: TData[]) {
|
||||
let list = this._messageTable.get(eventType);
|
||||
const list = this._messageTable.get(eventType);
|
||||
if (list) {
|
||||
for (let observer of list) {
|
||||
for (const observer of list) {
|
||||
observer.func.call(observer.context, ...data);
|
||||
}
|
||||
}
|
||||
@@ -74,9 +76,9 @@ export class Emitter<T, TContext = unknown> {
|
||||
* @param eventType 事件类型
|
||||
* @param handler 事件函数
|
||||
*/
|
||||
public hasObserver(eventType: T, handler: Function): boolean {
|
||||
let list = this._messageTable.get(eventType);
|
||||
return list ? list.some(observer => observer.func === handler) : false;
|
||||
public hasObserver(eventType: T, handler: EventHandler): boolean {
|
||||
const list = this._messageTable.get(eventType);
|
||||
return list ? list.some((observer) => observer.func === handler) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Colors, LogLevel } from "./Constants";
|
||||
import { ILogger, LoggerColorConfig, LoggerConfig } from "./Types";
|
||||
import { Colors, LogLevel } from './Constants';
|
||||
import { ILogger, LoggerColorConfig, LoggerConfig } from './Types';
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ConsoleLogger } from "./ConsoleLogger";
|
||||
import { LogLevel } from "./Constants";
|
||||
import { ILogger, LoggerColorConfig } from "./Types";
|
||||
import { ConsoleLogger } from './ConsoleLogger';
|
||||
import { LogLevel } from './Constants';
|
||||
import { ILogger, LoggerColorConfig } from './Types';
|
||||
|
||||
/**
|
||||
* 日志管理器
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { LogLevel } from "./Constants";
|
||||
import type { LogLevel } from './Constants';
|
||||
|
||||
/**
|
||||
* 日志接口
|
||||
|
||||
@@ -276,12 +276,12 @@ export class PerformanceMonitor implements IService {
|
||||
*/
|
||||
public getPerformanceReport(): string {
|
||||
if (!this._isEnabled) {
|
||||
return "Performance monitoring is disabled.";
|
||||
return 'Performance monitoring is disabled.';
|
||||
}
|
||||
|
||||
const lines: string[] = [];
|
||||
lines.push("=== ECS Performance Report ===");
|
||||
lines.push("");
|
||||
lines.push('=== ECS Performance Report ===');
|
||||
lines.push('');
|
||||
|
||||
// 按平均执行时间排序
|
||||
const sortedSystems = Array.from(this._systemStats.entries())
|
||||
@@ -300,7 +300,7 @@ export class PerformanceMonitor implements IService {
|
||||
lines.push(` Per Entity: ${data.averageTimePerEntity.toFixed(4)}ms`);
|
||||
}
|
||||
|
||||
lines.push("");
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
// 总体统计
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { IPoolable, PoolStats } from './IPoolable';
|
||||
|
||||
type Constructor<T = unknown> = new (...args: unknown[]) => T;
|
||||
|
||||
/**
|
||||
* 高性能通用对象池
|
||||
* 支持任意类型的对象池化,包含详细的统计信息
|
||||
*/
|
||||
export class Pool<T extends IPoolable> {
|
||||
private static _pools = new Map<Function, Pool<any>>();
|
||||
private static _pools = new Map<Constructor, Pool<IPoolable>>();
|
||||
|
||||
private _objects: T[] = [];
|
||||
private _createFn: () => T;
|
||||
@@ -46,11 +48,11 @@ export class Pool<T extends IPoolable> {
|
||||
maxSize: number = 100,
|
||||
estimatedObjectSize: number = 1024
|
||||
): Pool<T> {
|
||||
let pool = this._pools.get(type);
|
||||
let pool = this._pools.get(type) as Pool<T> | undefined;
|
||||
|
||||
if (!pool) {
|
||||
pool = new Pool<T>(() => new type(), maxSize, estimatedObjectSize);
|
||||
this._pools.set(type, pool);
|
||||
this._pools.set(type, pool as Pool<IPoolable>);
|
||||
}
|
||||
|
||||
return pool;
|
||||
@@ -197,7 +199,7 @@ export class Pool<T extends IPoolable> {
|
||||
* 获取所有已注册的池类型
|
||||
* @returns 所有池类型的数组
|
||||
*/
|
||||
public static getAllPoolTypes(): Function[] {
|
||||
public static getAllPoolTypes(): Constructor[] {
|
||||
return Array.from(this._pools.keys());
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import type { IService } from '../../Core/ServiceContainer';
|
||||
* 统一管理所有对象池
|
||||
*/
|
||||
export class PoolManager implements IService {
|
||||
private pools = new Map<string, Pool<any>>();
|
||||
private pools = new Map<string, Pool<IPoolable>>();
|
||||
private autoCompactInterval = 60000; // 60秒
|
||||
private lastCompactTime = 0;
|
||||
|
||||
@@ -30,7 +30,7 @@ export class PoolManager implements IService {
|
||||
* @returns 池实例
|
||||
*/
|
||||
public getPool<T extends IPoolable>(name: string): Pool<T> | null {
|
||||
return this.pools.get(name) || null;
|
||||
return (this.pools.get(name) as Pool<T> | undefined) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,7 +30,7 @@ export class TimerManager implements IService, IUpdatable {
|
||||
* @param onTime
|
||||
*/
|
||||
public schedule<TContext = unknown>(timeInSeconds: number, repeats: boolean, context: TContext, onTime: (timer: ITimer<TContext>)=>void): Timer<TContext> {
|
||||
let timer = new Timer<TContext>();
|
||||
const timer = new Timer<TContext>();
|
||||
timer.initialize(timeInSeconds, repeats, context, onTime);
|
||||
this._timers.push(timer as Timer<unknown>);
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ describe('Component - 组件基类测试', () => {
|
||||
let scene: Scene;
|
||||
|
||||
beforeEach(() => {
|
||||
Component._idGenerator = 0;
|
||||
component = new TestComponent();
|
||||
scene = new Scene();
|
||||
entity = scene.createEntity('TestEntity');
|
||||
@@ -51,7 +50,7 @@ describe('Component - 组件基类测试', () => {
|
||||
});
|
||||
|
||||
test('组件ID应该递增分配', () => {
|
||||
const startId = Component._idGenerator;
|
||||
const startId = Component.nextComponentId;
|
||||
const component1 = new TestComponent();
|
||||
const component2 = new TestComponent();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user