style(core): 统一代码风格并强化命名规范

This commit is contained in:
YHH
2025-10-31 18:29:53 +08:00
parent 6778ccace4
commit 3e037f4ae0
106 changed files with 2054 additions and 1967 deletions
+24 -1
View File
@@ -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/",
+34 -34
View File
@@ -1,20 +1,20 @@
import { TimerManager } from './Utils/Timers/TimerManager';
import { ITimer } from './Utils/Timers/ITimer';
import { Timer } from './Utils/Timers/Timer';
import { Time } from './Utils/Time';
import { PerformanceMonitor } from './Utils/PerformanceMonitor';
import { PoolManager } from './Utils/Pool/PoolManager';
import { DebugManager } from './Utils/Debug';
import { ICoreConfig, IECSDebugConfig } from './Types';
import { createLogger } from './Utils/Logger';
import { SceneManager } from './ECS/SceneManager';
import { IScene } from './ECS/IScene';
import { ServiceContainer } from './Core/ServiceContainer';
import { PluginManager } from './Core/PluginManager';
import { IPlugin } from './Core/Plugin';
import { WorldManager } from './ECS/WorldManager';
import { DebugConfigService } from './Utils/Debug/DebugConfigService';
import { createInstance } from './Core/DI/Decorators';
import {TimerManager} from "./Utils/Timers/TimerManager";
import {ITimer} from "./Utils/Timers/ITimer";
import {Timer} from "./Utils/Timers/Timer";
import {Time} from "./Utils/Time";
import {PerformanceMonitor} from "./Utils/PerformanceMonitor";
import {PoolManager} from "./Utils/Pool/PoolManager";
import {DebugManager} from "./Utils/Debug";
import {ICoreConfig, IECSDebugConfig} from "./Types";
import {createLogger} from "./Utils/Logger";
import {SceneManager} from "./ECS/SceneManager";
import {IScene} from "./ECS/IScene";
import {ServiceContainer} from "./Core/ServiceContainer";
import {PluginManager} from "./Core/PluginManager";
import {IPlugin} from "./Core/Plugin";
import {WorldManager} from "./ECS/WorldManager";
import {DebugConfigService} from "./Utils/Debug/DebugConfigService";
import {createInstance} from "./Core/DI/Decorators";
/**
* 游戏引擎核心类
@@ -67,7 +67,7 @@ export class Core {
/**
* Core专用日志器
*/
private static _logger = createLogger('Core');
private static _logger = createLogger("Core");
/**
* 实体系统启用状态
@@ -246,7 +246,7 @@ export class Core {
*/
public static get services(): ServiceContainer {
if (!this._instance) {
throw new Error('Core实例未创建,请先调用Core.create()');
throw new Error("Core实例未创建,请先调用Core.create()");
}
return this._instance._serviceContainer;
}
@@ -270,7 +270,7 @@ export class Core {
*/
public static get worldManager(): WorldManager {
if (!this._instance) {
throw new Error('Core实例未创建,请先调用Core.create()');
throw new Error("Core实例未创建,请先调用Core.create()");
}
return this._instance._worldManager;
}
@@ -302,12 +302,12 @@ export class Core {
public static create(config: ICoreConfig | boolean = true): Core {
if (this._instance == null) {
// 向后兼容:如果传入boolean,转换为配置对象
const coreConfig: ICoreConfig = typeof config === 'boolean'
? { debug: config, enableEntitySystems: true }
const coreConfig: ICoreConfig = typeof config === "boolean"
? {debug: config, enableEntitySystems: true}
: config;
this._instance = new Core(coreConfig);
} else {
this._logger.warn('Core实例已创建,返回现有实例');
this._logger.warn("Core实例已创建,返回现有实例");
}
return this._instance;
}
@@ -457,10 +457,10 @@ export class Core {
*/
public static schedule<TContext = unknown>(timeInSeconds: number, repeats: boolean = false, context?: TContext, onTime?: (timer: ITimer<TContext>) => void): Timer<TContext> {
if (!this._instance) {
throw new Error('Core实例未创建,请先调用Core.create()');
throw new Error("Core实例未创建,请先调用Core.create()");
}
if (!onTime) {
throw new Error('onTime callback is required');
throw new Error("onTime callback is required");
}
return this._instance._timerManager.schedule(timeInSeconds, repeats, context as TContext, onTime);
}
@@ -549,7 +549,7 @@ export class Core {
*/
public static async installPlugin(plugin: IPlugin): Promise<void> {
if (!this._instance) {
throw new Error('Core实例未创建,请先调用Core.create()');
throw new Error("Core实例未创建,请先调用Core.create()");
}
await this._instance._pluginManager.install(plugin);
@@ -568,7 +568,7 @@ export class Core {
*/
public static async uninstallPlugin(name: string): Promise<void> {
if (!this._instance) {
throw new Error('Core实例未创建,请先调用Core.create()');
throw new Error("Core实例未创建,请先调用Core.create()");
}
await this._instance._pluginManager.uninstall(name);
@@ -624,7 +624,7 @@ export class Core {
*/
protected initialize() {
// 核心系统初始化
Core._logger.info('Core initialized', {
Core._logger.info("Core initialized", {
debug: this.debug,
entitySystemsEnabled: Core.entitySystemsEnabled,
debugEnabled: this._config.debugConfig?.enabled || false
@@ -640,20 +640,20 @@ export class Core {
if (Core.paused) return;
// 开始性能监控
const frameStartTime = this._performanceMonitor.startMonitoring('Core.update');
const frameStartTime = this._performanceMonitor.startMonitoring("Core.update");
// 更新时间系统
Time.update(deltaTime);
// 更新FPS监控(如果性能监控器支持)
if ('updateFPS' in this._performanceMonitor && typeof this._performanceMonitor.updateFPS === 'function') {
if ("updateFPS" in this._performanceMonitor && typeof this._performanceMonitor.updateFPS === "function") {
this._performanceMonitor.updateFPS(Time.deltaTime);
}
// 更新所有可更新的服务
const servicesStartTime = this._performanceMonitor.startMonitoring('Services.update');
const servicesStartTime = this._performanceMonitor.startMonitoring("Services.update");
this._serviceContainer.updateAll(deltaTime);
this._performanceMonitor.endMonitoring('Services.update', servicesStartTime, this._serviceContainer.getUpdatableCount());
this._performanceMonitor.endMonitoring("Services.update", servicesStartTime, this._serviceContainer.getUpdatableCount());
// 更新对象池管理器
this._poolManager.update();
@@ -665,7 +665,7 @@ export class Core {
this._worldManager.updateAll();
// 结束性能监控
this._performanceMonitor.endMonitoring('Core.update', frameStartTime);
this._performanceMonitor.endMonitoring("Core.update", frameStartTime);
}
/**
@@ -684,7 +684,7 @@ export class Core {
// 清理所有服务
this._instance._serviceContainer.clear();
Core._logger.info('Core destroyed');
Core._logger.info("Core destroyed");
// 清空实例引用,允许重新创建Core实例
this._instance = null;
+11 -11
View File
@@ -4,8 +4,8 @@
* 提供 @Injectable、@Inject 和 @Updatable 装饰器,用于标记可注入的类和依赖注入点
*/
import type { ServiceContainer } from '../ServiceContainer';
import type { IService, ServiceType } from '../ServiceContainer';
import type {ServiceContainer} from "../ServiceContainer";
import type {IService, ServiceType} from "../ServiceContainer";
/**
* 依赖注入元数据存储
@@ -76,13 +76,13 @@ 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,
dependencies: [],
...(existing?.properties && { properties: existing.properties })
...(existing?.properties && {properties: existing.properties})
});
} as ClassDecorator;
}
@@ -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') {
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."
);
}
@@ -246,10 +246,10 @@ export function createInstance<T>(
if (serviceType) {
// 如果有显式的@Inject标记,使用标记的类型
if (typeof serviceType === 'string' || typeof serviceType === 'symbol') {
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 +338,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."
);
}
+2 -2
View File
@@ -17,6 +17,6 @@ export {
createInstance,
injectProperties,
registerInjectable
} from './Decorators';
} from "./Decorators";
export type { InjectableMetadata, UpdatableMetadata } from './Decorators';
export type {InjectableMetadata, UpdatableMetadata} from "./Decorators";
+5 -5
View File
@@ -1,5 +1,5 @@
import type { Core } from '../Core';
import type { ServiceContainer } from './ServiceContainer';
import type {Core} from "../Core";
import type {ServiceContainer} from "./ServiceContainer";
/**
* 插件状态
@@ -8,17 +8,17 @@ export enum PluginState {
/**
* 未安装
*/
NotInstalled = 'not_installed',
NotInstalled = "not_installed",
/**
* 已安装
*/
Installed = 'installed',
Installed = "installed",
/**
* 安装失败
*/
Failed = 'failed'
Failed = "failed"
}
/**
+11 -11
View File
@@ -1,10 +1,10 @@
import { IPlugin, IPluginMetadata, PluginState } from './Plugin';
import type { IService } from './ServiceContainer';
import type { Core } from '../Core';
import type { ServiceContainer } from './ServiceContainer';
import { createLogger } from '../Utils/Logger';
import {IPlugin, IPluginMetadata, PluginState} from "./Plugin";
import type {IService} from "./ServiceContainer";
import type {Core} from "../Core";
import type {ServiceContainer} from "./ServiceContainer";
import {createLogger} from "../Utils/Logger";
const logger = createLogger('PluginManager');
const logger = createLogger("PluginManager");
/**
* 插件管理器
@@ -57,7 +57,7 @@ export class PluginManager implements IService {
public initialize(core: Core, services: ServiceContainer): void {
this._core = core;
this._services = services;
logger.info('PluginManager initialized');
logger.info("PluginManager initialized");
}
/**
@@ -70,7 +70,7 @@ export class PluginManager implements IService {
*/
public async install(plugin: IPlugin): Promise<void> {
if (!this._core || !this._services) {
throw new Error('PluginManager not initialized. Call initialize() first.');
throw new Error("PluginManager not initialized. Call initialize() first.");
}
// 检查是否已安装
@@ -213,7 +213,7 @@ export class PluginManager implements IService {
if (missingDeps.length > 0) {
throw new Error(
`Plugin ${plugin.name} has unmet dependencies: ${missingDeps.join(', ')}`
`Plugin ${plugin.name} has unmet dependencies: ${missingDeps.join(", ")}`
);
}
}
@@ -235,7 +235,7 @@ export class PluginManager implements IService {
if (dependents.length > 0) {
throw new Error(
`Cannot uninstall plugin ${name}: it is required by ${dependents.join(', ')}`
`Cannot uninstall plugin ${name}: it is required by ${dependents.join(", ")}`
);
}
}
@@ -261,6 +261,6 @@ export class PluginManager implements IService {
this._core = null;
this._services = null;
logger.info('PluginManager disposed');
logger.info("PluginManager disposed");
}
}
+13 -13
View File
@@ -1,7 +1,7 @@
import { createLogger } from '../Utils/Logger';
import { isUpdatable as checkUpdatable, getUpdatableMetadata } from './DI';
import {createLogger} from "../Utils/Logger";
import {isUpdatable as checkUpdatable, getUpdatableMetadata} from "./DI";
const logger = createLogger('ServiceContainer');
const logger = createLogger("ServiceContainer");
/**
* 服务基础接口
@@ -30,12 +30,12 @@ export enum ServiceLifetime {
/**
* 单例模式 - 整个应用生命周期内只有一个实例
*/
Singleton = 'singleton',
Singleton = "singleton",
/**
* 瞬时模式 - 每次请求都创建新实例
*/
Transient = 'transient'
Transient = "transient"
}
/**
@@ -139,7 +139,7 @@ export class ServiceContainer {
this._services.set(type as ServiceType<IService>, {
type: type as ServiceType<IService>,
...(factory && { factory: factory as (container: ServiceContainer) => IService }),
...(factory && {factory: factory as (container: ServiceContainer) => IService}),
lifetime: ServiceLifetime.Singleton
});
@@ -171,7 +171,7 @@ export class ServiceContainer {
this._services.set(type as ServiceType<IService>, {
type: type as ServiceType<IService>,
...(factory && { factory: factory as (container: ServiceContainer) => IService }),
...(factory && {factory: factory as (container: ServiceContainer) => IService}),
lifetime: ServiceLifetime.Transient
});
@@ -208,7 +208,7 @@ export class ServiceContainer {
if (checkUpdatable(type)) {
const metadata = getUpdatableMetadata(type);
const priority = metadata?.priority ?? 0;
this._updatableServices.push({ instance, priority });
this._updatableServices.push({instance, priority});
// 按优先级排序(数值越小越先执行)
this._updatableServices.sort((a, b) => a.priority - b.priority);
@@ -240,7 +240,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}`);
}
@@ -272,7 +272,7 @@ export class ServiceContainer {
if (checkUpdatable(registration.type)) {
const metadata = getUpdatableMetadata(registration.type);
const priority = metadata?.priority ?? 0;
this._updatableServices.push({ instance, priority });
this._updatableServices.push({instance, priority});
// 按优先级排序(数值越小越先执行)
this._updatableServices.sort((a, b) => a.priority - b.priority);
@@ -337,7 +337,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);
}
@@ -363,7 +363,7 @@ export class ServiceContainer {
this._services.clear();
this._updatableServices = [];
logger.debug('Cleared all services');
logger.debug("Cleared all services");
}
/**
@@ -391,7 +391,7 @@ export class ServiceContainer {
* ```
*/
public updateAll(deltaTime?: number): void {
for (const { instance } of this._updatableServices) {
for (const {instance} of this._updatableServices) {
(instance as IService & { update: (deltaTime?: number) => void }).update(deltaTime);
}
}
+12 -3
View File
@@ -1,4 +1,4 @@
import type { IComponent } from '../Types';
import type {IComponent} from "../Types";
/**
* 游戏组件基类
@@ -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++;
}
/**
+20 -20
View File
@@ -1,7 +1,7 @@
import { Entity } from '../Entity';
import { ComponentType, ComponentRegistry } from './ComponentStorage';
import { BitMask64Data, BitMask64Utils } from "../Utils";
import { BitMaskHashMap } from "../Utils/BitMaskHashMap";
import {Entity} from "../Entity";
import {ComponentType, ComponentRegistry} from "./ComponentStorage";
import {BitMask64Data, BitMask64Utils} from "../Utils";
import {BitMaskHashMap} from "../Utils/BitMaskHashMap";
/**
* 原型标识符
@@ -32,7 +32,7 @@ export interface ArchetypeQueryResult {
/**
* Archetype系统
*
*
* 根据实体的组件组合将实体分组到不同的原型中,提供高效的查询性能。
*/
export class ArchetypeSystem {
@@ -50,7 +50,7 @@ export class ArchetypeSystem {
/** 所有原型 */
private _allArchetypes: Archetype[] = [];
/**
* 添加实体到原型系统
*/
@@ -66,7 +66,7 @@ export class ArchetypeSystem {
archetype.entities.add(entity);
this._entityToArchetype.set(entity, archetype);
}
/**
* 从原型系统中移除实体
*/
@@ -118,7 +118,7 @@ export class ArchetypeSystem {
this._entityToArchetype.set(entity, newArchetype);
}
/**
* 查询包含指定组件组合的原型
*
@@ -126,18 +126,18 @@ export class ArchetypeSystem {
* @param operation 查询操作类型:'AND'(包含所有)或 'OR'(包含任意)
* @returns 匹配的原型列表及实体总数
*/
public queryArchetypes(componentTypes: ComponentType[], operation: 'AND' | 'OR' = 'AND'): ArchetypeQueryResult {
public queryArchetypes(componentTypes: ComponentType[], operation: "AND" | "OR" = "AND"): ArchetypeQueryResult {
const matchingArchetypes: Archetype[] = [];
let totalEntities = 0;
if (operation === 'AND') {
if (operation === "AND") {
if (componentTypes.length === 0) {
for (const archetype of this._allArchetypes) {
matchingArchetypes.push(archetype);
totalEntities += archetype.entities.size;
}
return { archetypes: matchingArchetypes, totalEntities };
return {archetypes: matchingArchetypes, totalEntities};
}
if (componentTypes.length === 1) {
@@ -148,7 +148,7 @@ export class ArchetypeSystem {
totalEntities += archetype.entities.size;
}
}
return { archetypes: matchingArchetypes, totalEntities };
return {archetypes: matchingArchetypes, totalEntities};
}
let smallestSet: Set<Archetype> | undefined;
@@ -157,7 +157,7 @@ export class ArchetypeSystem {
for (const componentType of componentTypes) {
const archetypes = this._componentToArchetypes.get(componentType);
if (!archetypes || archetypes.size === 0) {
return { archetypes: [], totalEntities: 0 };
return {archetypes: [], totalEntities: 0};
}
if (archetypes.size < smallestSize) {
smallestSize = archetypes.size;
@@ -198,14 +198,14 @@ export class ArchetypeSystem {
totalEntities
};
}
/**
* 获取实体所属的原型
*/
public getEntityArchetype(entity: Entity): Archetype | undefined {
return this._entityToArchetype.get(entity);
}
/**
* 获取所有原型
*/
@@ -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,18 +258,18 @@ 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;
}
/**
* 生成原型ID
* 使用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);
@@ -279,7 +279,7 @@ export class ArchetypeSystem {
}
return mask;
}
/**
* 创建新原型
*/
+8 -8
View File
@@ -1,4 +1,4 @@
import { Component } from '../Component';
import {Component} from "../Component";
/**
* 组件对象池,用于复用组件实例以减少内存分配
@@ -183,7 +183,7 @@ export class ComponentPoolManager {
acquireComponent<T extends Component>(componentName: string): T | null {
const pool = this.pools.get(componentName);
this.trackUsage(componentName, 'create');
this.trackUsage(componentName, "create");
return pool ? (pool.acquire() as T) : null;
}
@@ -194,7 +194,7 @@ export class ComponentPoolManager {
releaseComponent<T extends Component>(componentName: string, component: T): void {
const pool = this.pools.get(componentName);
this.trackUsage(componentName, 'release');
this.trackUsage(componentName, "release");
if (pool) {
pool.release(component);
@@ -204,7 +204,7 @@ export class ComponentPoolManager {
/**
* 追踪使用情况
*/
private trackUsage(componentName: string, action: 'create' | 'release'): void {
private trackUsage(componentName: string, action: "create" | "release"): void {
let tracker = this.usageTracker.get(componentName);
if (!tracker) {
@@ -216,7 +216,7 @@ export class ComponentPoolManager {
this.usageTracker.set(componentName, tracker);
}
if (action === 'create') {
if (action === "create") {
tracker.createCount++;
} else {
tracker.releaseCount++;
@@ -289,12 +289,12 @@ export class ComponentPoolManager {
*/
getGlobalStats(): Array<{
componentName: string;
poolStats: ReturnType<ComponentPool<Component>['getStats']>;
poolStats: ReturnType<ComponentPool<Component>["getStats"]>;
usage: ComponentUsageTracker | undefined;
}> {
const stats: Array<{
componentName: string;
poolStats: ReturnType<ComponentPool<Component>['getStats']>;
poolStats: ReturnType<ComponentPool<Component>["getStats"]>;
usage: ComponentUsageTracker | undefined;
}> = [];
@@ -356,4 +356,4 @@ export class ComponentPoolManager {
return maxSize > 0 ? (used / maxSize * 100) : 0;
}
}
}
+16 -17
View File
@@ -1,13 +1,12 @@
import { Component } from '../Component';
import { BitMask64Utils, BitMask64Data } from '../Utils/BigIntCompatibility';
import { SoAStorage, SupportedTypedArray } from './SoAStorage';
import { createLogger } from '../../Utils/Logger';
import { getComponentTypeName } from '../Decorators';
import { ComponentRegistry, ComponentType } from './ComponentStorage/ComponentRegistry';
import {Component} from "../Component";
import {BitMask64Utils, BitMask64Data} from "../Utils/BigIntCompatibility";
import {SoAStorage, SupportedTypedArray} from "./SoAStorage";
import {createLogger} from "../../Utils/Logger";
import {getComponentTypeName} from "../Decorators";
import {ComponentRegistry, ComponentType} from "./ComponentStorage/ComponentRegistry";
// 导出核心类型
export { ComponentRegistry, ComponentType };
export {ComponentRegistry, ComponentType};
/**
@@ -21,7 +20,7 @@ export class ComponentStorage<T extends Component> {
constructor(componentType: ComponentType<T>) {
this.componentType = componentType;
// 确保组件类型已注册
if (!ComponentRegistry.isRegistered(componentType)) {
ComponentRegistry.register(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; // 永远无空洞
@@ -172,7 +171,7 @@ export class ComponentStorage<T extends Component> {
* 管理所有组件类型的存储器
*/
export class ComponentStorageManager {
private static readonly _logger = createLogger('ComponentStorage');
private static readonly _logger = createLogger("ComponentStorage");
private storages = new Map<Function, ComponentStorage<Component> | SoAStorage<Component>>();
/**
@@ -342,15 +341,15 @@ 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)) {
const componentMask = ComponentRegistry.getBitMask(componentType as ComponentType);
BitMask64Utils.orInPlace(mask, componentMask);
}
}
return mask;
}
@@ -360,12 +359,12 @@ export class ComponentStorageManager {
*/
public getAllStats(): Map<string, { totalSlots: number; usedSlots: number; freeSlots: number; fragmentation: number }> {
const stats = new Map<string, { totalSlots: number; usedSlots: number; freeSlots: number; fragmentation: number }>();
for (const [componentType, storage] of this.storages.entries()) {
const typeName = getComponentTypeName(componentType as ComponentType);
stats.set(typeName, storage.getStats());
}
return stats;
}
@@ -378,4 +377,4 @@ export class ComponentStorageManager {
}
this.storages.clear();
}
}
}
@@ -1,7 +1,7 @@
import { Component } from '../../Component';
import { BitMask64Utils, BitMask64Data } from '../../Utils/BigIntCompatibility';
import { createLogger } from '../../../Utils/Logger';
import { getComponentTypeName } from '../../Decorators';
import {Component} from "../../Component";
import {BitMask64Utils, BitMask64Data} from "../../Utils/BigIntCompatibility";
import {createLogger} from "../../../Utils/Logger";
import {getComponentTypeName} from "../../Decorators";
/**
* 组件类型定义
@@ -13,10 +13,10 @@ 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>();
protected static readonly _logger = createLogger("ComponentStorage");
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;
@@ -153,7 +153,7 @@ export class ComponentRegistry {
*/
public static createSingleComponentMask(componentName: string): BitMask64Data {
const cacheKey = `single:${componentName}`;
if (this.maskCache.has(cacheKey)) {
return this.maskCache.get(cacheKey)!;
}
@@ -175,13 +175,13 @@ export class ComponentRegistry {
*/
public static createComponentMask(componentNames: string[]): BitMask64Data {
const sortedNames = [...componentNames].sort();
const cacheKey = `multi:${sortedNames.join(',')}`;
const cacheKey = `multi:${sortedNames.join(",")}`;
if (this.maskCache.has(cacheKey)) {
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) {
@@ -212,4 +212,4 @@ export class ComponentRegistry {
this.maskCache.clear();
this.nextBitIndex = 0;
}
}
}
+68 -69
View File
@@ -1,6 +1,6 @@
import {
IEventBus,
IEventListenerConfig,
import {
IEventBus,
IEventListenerConfig,
IEventStats,
IEventData,
IEntityEventData,
@@ -8,34 +8,34 @@ import {
ISystemEventData,
ISceneEventData,
IPerformanceEventData
} from '../../Types';
import { createLogger } from '../../Utils/Logger';
import {
TypeSafeEventSystem,
EventListenerConfig,
EventStats
} from './EventSystem';
} from "../../Types";
import {createLogger} from "../../Utils/Logger";
import {
TypeSafeEventSystem,
EventListenerConfig,
EventStats
} from "./EventSystem";
import {
ECSEventType,
EventPriority,
EventTypeValidator
} from '../CoreEvents';
} from "../CoreEvents";
/**
* 增强的事件总线实现
* 基于TypeSafeEventSystem,提供类型安全的事件发布订阅机制
*/
export class EventBus implements IEventBus {
private static readonly _logger = createLogger('EventBus');
private static readonly _logger = createLogger("EventBus");
private eventSystem: TypeSafeEventSystem;
private eventIdCounter = 0;
private isDebugMode = false;
constructor(debugMode: boolean = false) {
this.eventSystem = new TypeSafeEventSystem();
this.isDebugMode = debugMode;
}
/**
* 发射事件
* @param eventType 事件类型
@@ -53,7 +53,7 @@ export class EventBus implements IEventBus {
this.eventSystem.emitSync(eventType, finalData);
}
/**
* 异步发射事件
* @param eventType 事件类型
@@ -71,7 +71,7 @@ export class EventBus implements IEventBus {
await this.eventSystem.emit(eventType, finalData);
}
/**
* 监听事件
* @param eventType 事件类型
@@ -80,26 +80,26 @@ export class EventBus implements IEventBus {
* @returns 监听器ID
*/
public on<T>(
eventType: string,
handler: (data: T) => void,
eventType: string,
handler: (data: T) => void,
config: IEventListenerConfig = {}
): string {
this.validateEventType(eventType);
const eventConfig: EventListenerConfig = {
once: config.once || false,
priority: config.priority || EventPriority.NORMAL,
async: config.async || false,
context: config.context
};
if (this.isDebugMode) {
EventBus._logger.info(`添加监听器: ${eventType}`, eventConfig);
}
return this.eventSystem.on(eventType, handler, eventConfig);
}
/**
* 监听事件(一次性)
* @param eventType 事件类型
@@ -108,13 +108,13 @@ export class EventBus implements IEventBus {
* @returns 监听器ID
*/
public once<T>(
eventType: string,
handler: (data: T) => void,
eventType: string,
handler: (data: T) => void,
config: IEventListenerConfig = {}
): string {
return this.on(eventType, handler, { ...config, once: true });
return this.on(eventType, handler, {...config, once: true});
}
/**
* 异步监听事件
* @param eventType 事件类型
@@ -123,13 +123,13 @@ export class EventBus implements IEventBus {
* @returns 监听器ID
*/
public onAsync<T>(
eventType: string,
handler: (data: T) => Promise<void>,
eventType: string,
handler: (data: T) => Promise<void>,
config: IEventListenerConfig = {}
): string {
return this.on(eventType, handler as any, { ...config, async: true });
return this.on(eventType, handler as any, {...config, async: true});
}
/**
* 移除事件监听器
* @param eventType 事件类型
@@ -139,10 +139,10 @@ export class EventBus implements IEventBus {
if (this.isDebugMode) {
EventBus._logger.info(`移除监听器: ${listenerId} 事件: ${eventType}`);
}
return this.eventSystem.off(eventType, listenerId);
}
/**
* 移除指定事件类型的所有监听器
* @param eventType 事件类型
@@ -151,10 +151,10 @@ export class EventBus implements IEventBus {
if (this.isDebugMode) {
EventBus._logger.info(`移除所有监听器: ${eventType}`);
}
this.eventSystem.offAll(eventType);
}
/**
* 检查是否有指定事件的监听器
* @param eventType 事件类型
@@ -162,14 +162,14 @@ export class EventBus implements IEventBus {
public hasListeners(eventType: string): boolean {
return this.eventSystem.hasListeners(eventType);
}
/**
* 获取事件统计信息
* @param eventType 事件类型(可选)
*/
public getStats(eventType?: string): IEventStats | Map<string, IEventStats> {
const stats = this.eventSystem.getStats(eventType);
if (stats instanceof Map) {
// 转换Map中的每个EventStats为IEventStats
const result = new Map<string, IEventStats>();
@@ -181,18 +181,18 @@ export class EventBus implements IEventBus {
return this.convertEventStats(stats);
}
}
/**
* 清空所有监听器
*/
public clear(): void {
if (this.isDebugMode) {
EventBus._logger.info('清空所有监听器');
EventBus._logger.info("清空所有监听器");
}
this.eventSystem.clear();
}
/**
* 启用或禁用事件系统
* @param enabled 是否启用
@@ -200,7 +200,7 @@ export class EventBus implements IEventBus {
public setEnabled(enabled: boolean): void {
this.eventSystem.setEnabled(enabled);
}
/**
* 设置调试模式
* @param debug 是否启用调试
@@ -208,7 +208,7 @@ export class EventBus implements IEventBus {
public setDebugMode(debug: boolean): void {
this.isDebugMode = debug;
}
/**
* 设置最大监听器数量
* @param max 最大数量
@@ -216,7 +216,7 @@ export class EventBus implements IEventBus {
public setMaxListeners(max: number): void {
this.eventSystem.setMaxListeners(max);
}
/**
* 获取监听器数量
* @param eventType 事件类型
@@ -224,7 +224,7 @@ export class EventBus implements IEventBus {
public getListenerCount(eventType: string): number {
return this.eventSystem.getListenerCount(eventType);
}
/**
* 设置事件批处理配置
* @param eventType 事件类型
@@ -238,7 +238,7 @@ export class EventBus implements IEventBus {
enabled: true
});
}
/**
* 刷新指定事件的批处理队列
* @param eventType 事件类型
@@ -246,7 +246,7 @@ export class EventBus implements IEventBus {
public flushBatch(eventType: string): void {
this.eventSystem.flushBatch(eventType);
}
/**
* 重置事件统计
* @param eventType 事件类型(可选)
@@ -254,9 +254,9 @@ export class EventBus implements IEventBus {
public resetStats(eventType?: string): void {
this.eventSystem.resetStats(eventType);
}
// 便捷方法:发射预定义的ECS事件
/**
* 发射实体创建事件
* @param entityData 实体事件数据
@@ -320,59 +320,59 @@ export class EventBus implements IEventBus {
public emitPerformanceWarning(performanceData: IPerformanceEventData): void {
this.emit(ECSEventType.PERFORMANCE_WARNING, performanceData);
}
// 便捷方法:监听预定义的ECS事件
/**
* 监听实体创建事件
* @param handler 事件处理器
* @param config 监听器配置
*/
public onEntityCreated(
handler: (data: IEntityEventData) => void,
handler: (data: IEntityEventData) => void,
config?: IEventListenerConfig
): string {
return this.on(ECSEventType.ENTITY_CREATED, handler, config);
}
/**
* 监听组件添加事件
* @param handler 事件处理器
* @param config 监听器配置
*/
public onComponentAdded(
handler: (data: IComponentEventData) => void,
handler: (data: IComponentEventData) => void,
config?: IEventListenerConfig
): string {
return this.on(ECSEventType.COMPONENT_ADDED, handler, config);
}
/**
* 监听系统错误事件
* @param handler 事件处理器
* @param config 监听器配置
*/
public onSystemError(
handler: (data: ISystemEventData) => void,
handler: (data: ISystemEventData) => void,
config?: IEventListenerConfig
): string {
return this.on(ECSEventType.SYSTEM_ERROR, handler, config);
}
/**
* 监听性能警告事件
* @param handler 事件处理器
* @param config 监听器配置
*/
public onPerformanceWarning(
handler: (data: IPerformanceEventData) => void,
handler: (data: IPerformanceEventData) => void,
config?: IEventListenerConfig
): string {
return this.on(ECSEventType.PERFORMANCE_WARNING, handler, config);
}
// 私有方法
/**
* 验证事件类型(仅在debug模式下执行,提升性能)
* @param eventType 事件类型
@@ -387,7 +387,7 @@ export class EventBus implements IEventBus {
}
}
}
/**
* 增强事件数据
* @param eventType 事件类型
@@ -399,12 +399,12 @@ export class EventBus implements IEventBus {
return {
timestamp: Date.now(),
eventId: `${eventType}_${++this.eventIdCounter}`,
source: 'EventBus'
source: "EventBus"
} as T & IEventData;
}
const enhanced = data as T & IEventData;
// 如果数据还没有基础事件属性,添加它们
if (!enhanced.timestamp) {
enhanced.timestamp = Date.now();
@@ -413,12 +413,12 @@ export class EventBus implements IEventBus {
enhanced.eventId = `${eventType}_${++this.eventIdCounter}`;
}
if (!enhanced.source) {
enhanced.source = 'EventBus';
enhanced.source = "EventBus";
}
return enhanced;
}
/**
* 转换EventStats为IEventStats
* @param stats EventStats实例
@@ -441,7 +441,7 @@ export class EventBus implements IEventBus {
*/
export class GlobalEventBus {
private static instance: EventBus;
/**
* 获取全局事件总线实例
* @param debugMode 是否启用调试模式
@@ -452,7 +452,7 @@ export class GlobalEventBus {
}
return this.instance;
}
/**
* 重置全局事件总线实例
* @param debugMode 是否启用调试模式
@@ -466,4 +466,3 @@ export class GlobalEventBus {
}
}
+9 -10
View File
@@ -1,4 +1,4 @@
import { createLogger } from '../../Utils/Logger';
import {createLogger} from "../../Utils/Logger";
/**
* 事件处理器函数类型
@@ -68,7 +68,7 @@ export interface EventBatchConfig {
* 支持同步/异步事件、优先级、批处理等功能
*/
export class TypeSafeEventSystem {
private static readonly _logger = createLogger('EventSystem');
private static readonly _logger = createLogger("EventSystem");
private listeners = new Map<string, InternalEventListener[]>();
private stats = new Map<string, EventStats>();
private batchQueue = new Map<string, any[]>();
@@ -105,7 +105,7 @@ export class TypeSafeEventSystem {
handler: EventHandler<T>,
config: EventListenerConfig = {}
): string {
return this.addListener(eventType, handler, { ...config, once: true });
return this.addListener(eventType, handler, {...config, once: true});
}
/**
@@ -120,7 +120,7 @@ export class TypeSafeEventSystem {
handler: AsyncEventHandler<T>,
config: EventListenerConfig = {}
): string {
return this.addListener(eventType, handler, { ...config, async: true });
return this.addListener(eventType, handler, {...config, async: 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);
@@ -340,7 +340,7 @@ export class TypeSafeEventSystem {
// 检查监听器数量限制
if (listeners.length >= this.maxListeners) {
TypeSafeEventSystem._logger.warn(`事件类型 ${eventType} 的监听器数量超过最大限制 (${this.maxListeners})`);
return '';
return "";
}
const listenerId = `listener_${this.nextListenerId++}`;
@@ -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);
}
@@ -578,4 +578,3 @@ export class TypeSafeEventSystem {
*/
export const GlobalEventSystem = new TypeSafeEventSystem();
+2 -2
View File
@@ -1,2 +1,2 @@
export { EventBus, GlobalEventBus } from '../EventBus';
export { TypeSafeEventSystem, EventListenerConfig, EventStats } from '../EventSystem';
export {EventBus, GlobalEventBus} from "../EventBus";
export {TypeSafeEventSystem, EventListenerConfig, EventStats} from "../EventSystem";
+1 -1
View File
@@ -8,4 +8,4 @@ export {
createECSAPI,
initializeECS,
ECS
} from './FluentAPI/index';
} from "./FluentAPI/index";
@@ -1,4 +1,4 @@
import { Component } from '../../Component';
import {Component} from "../../Component";
/**
* - API创建组件
@@ -52,4 +52,4 @@ export class ComponentBuilder<T extends Component> {
public build(): T {
return this.component;
}
}
}
@@ -1,13 +1,13 @@
import { Entity } from '../../Entity';
import { Component } from '../../Component';
import { IScene } from '../../IScene';
import { ComponentType } from '../ComponentStorage';
import { QuerySystem, QueryBuilder } from '../QuerySystem';
import { TypeSafeEventSystem } from '../EventSystem';
import { EntityBuilder } from './EntityBuilder';
import { SceneBuilder } from './SceneBuilder';
import { ComponentBuilder } from './ComponentBuilder';
import { EntityBatchOperator } from './EntityBatchOperator';
import {Entity} from "../../Entity";
import {Component} from "../../Component";
import {IScene} from "../../IScene";
import {ComponentType} from "../ComponentStorage";
import {QuerySystem, QueryBuilder} from "../QuerySystem";
import {TypeSafeEventSystem} from "../EventSystem";
import {EntityBuilder} from "./EntityBuilder";
import {SceneBuilder} from "./SceneBuilder";
import {ComponentBuilder} from "./ComponentBuilder";
import {EntityBatchOperator} from "./EntityBatchOperator";
/**
* ECS流式API主入口
@@ -47,7 +47,7 @@ export class ECSFluentAPI {
* @returns
*/
public createComponent<T extends Component>(
componentClass: new (...args: unknown[]) => T,
componentClass: new (...args: unknown[]) => T,
...args: unknown[]
): ComponentBuilder<T> {
return new ComponentBuilder(componentClass, ...args);
@@ -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,
@@ -183,8 +183,8 @@ export class ECSFluentAPI {
* @returns ECS流式API实例
*/
export function createECSAPI(
scene: IScene,
querySystem: QuerySystem,
scene: IScene,
querySystem: QuerySystem,
eventSystem: TypeSafeEventSystem
): ECSFluentAPI {
return new ECSFluentAPI(scene, querySystem, eventSystem);
@@ -202,9 +202,9 @@ export let ECS: ECSFluentAPI;
* @param eventSystem
*/
export function initializeECS(
scene: IScene,
querySystem: QuerySystem,
scene: IScene,
querySystem: QuerySystem,
eventSystem: TypeSafeEventSystem
): void {
ECS = createECSAPI(scene, querySystem, eventSystem);
}
}
@@ -1,6 +1,6 @@
import { Entity } from '../../Entity';
import { Component } from '../../Component';
import { ComponentType } from '../ComponentStorage';
import {Entity} from "../../Entity";
import {Component} from "../../Component";
import {ComponentType} from "../ComponentStorage";
/**
*
@@ -95,4 +95,4 @@ export class EntityBatchOperator {
public count(): number {
return this.entities.length;
}
}
}
@@ -1,7 +1,7 @@
import { Entity } from '../../Entity';
import { Component } from '../../Component';
import { IScene } from '../../IScene';
import { ComponentType, ComponentStorageManager } from '../ComponentStorage';
import {Entity} from "../../Entity";
import {Component} from "../../Component";
import {IScene} from "../../IScene";
import {ComponentType, ComponentStorageManager} from "../ComponentStorage";
/**
* - API创建和配置实体
@@ -92,7 +92,7 @@ export class EntityBuilder {
* @returns
*/
public configure<T extends Component>(
componentType: ComponentType<T>,
componentType: ComponentType<T>,
configurator: (component: T) => void
): EntityBuilder {
const component = this.entity.getComponent(componentType);
@@ -199,4 +199,4 @@ export class EntityBuilder {
newBuilder.entity = this.entity; // 实际应该是深度克隆
return newBuilder;
}
}
}
@@ -1,7 +1,7 @@
import { Entity } from '../../Entity';
import { Scene } from '../../Scene';
import { EntitySystem } from '../../Systems/EntitySystem';
import { EntityBuilder } from './EntityBuilder';
import {Entity} from "../../Entity";
import {Scene} from "../../Scene";
import {EntitySystem} from "../../Systems/EntitySystem";
import {EntityBuilder} from "./EntityBuilder";
/**
* - API创建和配置场景
@@ -87,4 +87,4 @@ export class SceneBuilder {
public build(): Scene {
return this.scene;
}
}
}
@@ -1,5 +1,5 @@
export { EntityBuilder } from './EntityBuilder';
export { SceneBuilder } from './SceneBuilder';
export { ComponentBuilder } from './ComponentBuilder';
export { EntityBatchOperator } from './EntityBatchOperator';
export { ECSFluentAPI, createECSAPI, initializeECS, ECS } from './ECSFluentAPI';
export {EntityBuilder} from "./EntityBuilder";
export {SceneBuilder} from "./SceneBuilder";
export {ComponentBuilder} from "./ComponentBuilder";
export {EntityBatchOperator} from "./EntityBatchOperator";
export {ECSFluentAPI, createECSAPI, initializeECS, ECS} from "./ECSFluentAPI";
@@ -4,9 +4,9 @@
* TypeScript类型推断
*/
import type { Entity } from '../../Entity';
import type { ComponentConstructor } from '../../../Types/TypeHelpers';
import { Matcher, type QueryCondition } from '../../Utils/Matcher';
import type {Entity} from "../../Entity";
import type {ComponentConstructor} from "../../../Types/TypeHelpers";
import {Matcher, type QueryCondition} from "../../Utils/Matcher";
/**
*
@@ -326,8 +326,8 @@ export class TypedQueryBuilder<
all: [...this._all] as ComponentConstructor[],
any: [...this._any] as ComponentConstructor[],
none: [...this._none] as ComponentConstructor[],
...(this._tag !== undefined && { tag: this._tag }),
...(this._name !== undefined && { name: this._name })
...(this._tag !== undefined && {tag: this._tag}),
...(this._name !== undefined && {name: this._name})
};
}
+2 -3
View File
@@ -1,3 +1,2 @@
export { QuerySystem } from '../QuerySystem';
export { ECSFluentAPI, createECSAPI } from '../FluentAPI';
export {QuerySystem} from "../QuerySystem";
export {ECSFluentAPI, createECSAPI} from "../FluentAPI";
+85 -65
View File
@@ -1,14 +1,14 @@
import { Entity } from '../Entity';
import { Component } from '../Component';
import { ComponentRegistry, ComponentType } from './ComponentStorage';
import { BitMask64Utils, BitMask64Data } from '../Utils/BigIntCompatibility';
import { createLogger } from '../../Utils/Logger';
import { getComponentTypeName } from '../Decorators';
import { Archetype, ArchetypeSystem } from './ArchetypeSystem';
import { ReactiveQuery, ReactiveQueryConfig } from './ReactiveQuery';
import { QueryCondition, QueryConditionType, QueryResult } from './QueryTypes';
import {Entity} from "../Entity";
import {Component} from "../Component";
import {ComponentRegistry, ComponentType} from "./ComponentStorage";
import {BitMask64Utils, BitMask64Data} from "../Utils/BigIntCompatibility";
import {createLogger} from "../../Utils/Logger";
import {getComponentTypeName} from "../Decorators";
import {Archetype, ArchetypeSystem} from "./ArchetypeSystem";
import {ReactiveQuery, ReactiveQueryConfig} from "./ReactiveQuery";
import {QueryCondition, QueryConditionType, QueryResult} from "./QueryTypes";
export { QueryCondition, QueryConditionType, QueryResult };
export {QueryCondition, QueryConditionType, QueryResult};
/**
*
@@ -30,20 +30,20 @@ interface QueryCacheEntry {
/**
*
*
*
*
*
*
* @example
* ```typescript
* // 查询所有包含Position和Velocity组件的实体
* const movingEntities = querySystem.queryAll(PositionComponent, VelocityComponent);
*
*
* // 查询特定标签的实体
* const playerEntities = querySystem.queryByTag(PLAYER_TAG);
* ```
*/
export class QuerySystem {
private _logger = createLogger('QuerySystem');
private _logger = createLogger("QuerySystem");
private entities: Entity[] = [];
private entityIndex: EntityIndex;
@@ -92,10 +92,10 @@ export class QuerySystem {
/**
*
*
*
*
*
*
*
* @param entity
* @param deferCacheClear
*/
@@ -121,17 +121,17 @@ export class QuerySystem {
/**
*
*
*
*
* 使Set来避免O(n)
*
*
* @param entities
*/
public addEntities(entities: Entity[]): void {
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) {
@@ -155,10 +155,10 @@ export class QuerySystem {
/**
*
*
*
*
* 使
*
*
* @param entities
*/
public addEntitiesUnchecked(entities: Entity[]): void {
@@ -437,13 +437,13 @@ export class QuerySystem {
/**
*
*
*
*
* 使
*
*
* @param tag
* @returns
*
*
* @example
* ```typescript
* // 查询所有玩家实体
@@ -485,13 +485,13 @@ export class QuerySystem {
/**
*
*
*
*
* 使
*
*
* @param name
* @returns
*
*
* @example
* ```typescript
* // 查找名为"Player"的实体
@@ -533,13 +533,13 @@ export class QuerySystem {
/**
*
*
*
*
*
*
*
* @param componentType
* @returns
*
*
* @example
* ```typescript
* // 查询所有具有位置组件的实体
@@ -550,7 +550,7 @@ export class QuerySystem {
const startTime = performance.now();
this.queryStats.totalQueries++;
const cacheKey = this.generateCacheKey('component', [componentType]);
const cacheKey = this.generateCacheKey("component", [componentType]);
// 检查缓存
const cached = this.getFromCache(cacheKey);
@@ -627,7 +627,7 @@ export class QuerySystem {
// 如果还是太满,移除最少使用的条目
if (this.queryCache.size >= this.cacheMaxSize) {
let minHitCount = Infinity;
let oldestKey = '';
let oldestKey = "";
let oldestTimestamp = Infinity;
// 单次遍历找到最少使用或最旧的条目
@@ -679,10 +679,10 @@ export class QuerySystem {
}
// 多组件查询:使用排序后的类型名称创建键
const sortKey = componentTypes.map(t => {
const sortKey = componentTypes.map((t) => {
const name = getComponentTypeName(t);
return name;
}).sort().join(',');
}).sort().join(",");
const fullKey = `${prefix}:${sortKey}`;
@@ -729,7 +729,7 @@ export class QuerySystem {
config?: ReactiveQueryConfig
): ReactiveQuery {
if (!componentTypes || componentTypes.length === 0) {
throw new Error('组件类型列表不能为空');
throw new Error("组件类型列表不能为空");
}
const mask = this.createComponentMask(componentTypes);
@@ -747,7 +747,7 @@ export class QuerySystem {
);
query.initializeWith(initialEntities);
const cacheKey = this.generateCacheKey('all', componentTypes);
const cacheKey = this.generateCacheKey("all", componentTypes);
this._reactiveQueries.set(cacheKey, query);
for (const type of componentTypes) {
@@ -810,9 +810,9 @@ export class QuerySystem {
*/
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
// 生成缓存键
const cacheKey = componentTypes.map(t => {
const cacheKey = componentTypes.map((t) => {
return getComponentTypeName(t);
}).sort().join(',');
}).sort().join(",");
// 检查缓存
const cached = this.componentMaskCache.get(cacheKey);
@@ -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)) {
@@ -842,20 +842,40 @@ export class QuerySystem {
public get version(): number {
return this._version;
}
/**
*
*
*
*
*
* @returns
*
* @example
* ```typescript
* const allEntities = scene.querySystem.queryAllEntities();
* console.log(`场景中共有 ${allEntities.length} 个实体`);
* ```
*/
public getAllEntities(): readonly Entity[] {
public queryAllEntities(): readonly Entity[] {
return this.entities;
}
/**
*
*
* @deprecated 使 queryAllEntities()
* @see {@link queryAllEntities}
*/
public getAllEntities(): readonly Entity[] {
return this.queryAllEntities();
}
/**
*
*
*
*
*
*
*
* @returns
*/
public getStats(): {
@@ -881,7 +901,7 @@ export class QuerySystem {
size: number;
hitRate: string;
};
} {
} {
return {
entityCount: this.entities.length,
indexStats: {
@@ -892,19 +912,19 @@ export class QuerySystem {
queryStats: {
...this.queryStats,
cacheHitRate: this.queryStats.totalQueries > 0 ?
(this.queryStats.cacheHits / this.queryStats.totalQueries * 100).toFixed(2) + '%' : '0%'
(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
}))
},
cacheStats: {
size: this._reactiveQueries.size,
hitRate: this.queryStats.totalQueries > 0 ?
(this.queryStats.cacheHits / this.queryStats.totalQueries * 100).toFixed(2) + '%' : '0%'
(this.queryStats.cacheHits / this.queryStats.totalQueries * 100).toFixed(2) + "%" : "0%"
}
};
}
@@ -1002,7 +1022,7 @@ export class QuerySystem {
): Entity[] {
switch (queryType) {
case QueryConditionType.ALL: {
const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, 'AND');
const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, "AND");
const entities: Entity[] = [];
for (const archetype of archetypeResult.archetypes) {
for (const entity of archetype.entities) {
@@ -1012,7 +1032,7 @@ export class QuerySystem {
return entities;
}
case QueryConditionType.ANY: {
const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, 'OR');
const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, "OR");
const entities: Entity[] = [];
for (const archetype of archetypeResult.archetypes) {
for (const entity of archetype.entities) {
@@ -1023,7 +1043,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)
);
}
@@ -1139,10 +1159,10 @@ export class QuerySystem {
/**
*
*
*
* API来构建复杂的实体查询条件
*
*
*
* @example
* ```typescript
* const result = new QueryBuilder(querySystem)
@@ -1152,7 +1172,7 @@ export class QuerySystem {
* ```
*/
export class QueryBuilder {
private _logger = createLogger('QueryBuilder');
private _logger = createLogger("QueryBuilder");
private conditions: QueryCondition[] = [];
private querySystem: QuerySystem;
@@ -1162,7 +1182,7 @@ export class QueryBuilder {
/**
* "必须包含所有组件"
*
*
* @param componentTypes
* @returns
*/
@@ -1177,7 +1197,7 @@ export class QueryBuilder {
/**
* "必须包含任意组件"
*
*
* @param componentTypes
* @returns
*/
@@ -1192,7 +1212,7 @@ export class QueryBuilder {
/**
* "不能包含任何组件"
*
*
* @param componentTypes
* @returns
*/
@@ -1207,9 +1227,9 @@ export class QueryBuilder {
/**
*
*
*
*
*
*
* @returns
*/
public execute(): QueryResult {
@@ -1241,7 +1261,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);
@@ -1255,13 +1275,13 @@ export class QueryBuilder {
/**
*
*
*
*
*
*
* @returns
*/
public reset(): QueryBuilder {
this.conditions = [];
return this;
}
}
}
+6 -6
View File
@@ -1,17 +1,17 @@
import { ComponentType } from './ComponentStorage';
import { BitMask64Data } from '../Utils/BigIntCompatibility';
import { Entity } from '../Entity';
import {ComponentType} from "./ComponentStorage";
import {BitMask64Data} from "../Utils/BigIntCompatibility";
import {Entity} from "../Entity";
/**
*
*/
export enum QueryConditionType {
/** 必须包含所有指定组件 */
ALL = 'all',
ALL = "all",
/** 必须包含任意一个指定组件 */
ANY = 'any',
ANY = "any",
/** 不能包含任何指定组件 */
NONE = 'none'
NONE = "none"
}
/**
+16 -16
View File
@@ -1,20 +1,20 @@
import { Entity } from '../Entity';
import { QueryCondition, QueryConditionType } from './QueryTypes';
import { BitMask64Utils } from '../Utils/BigIntCompatibility';
import { createLogger } from '../../Utils/Logger';
import {Entity} from "../Entity";
import {QueryCondition, QueryConditionType} from "./QueryTypes";
import {BitMask64Utils} from "../Utils/BigIntCompatibility";
import {createLogger} from "../../Utils/Logger";
const logger = createLogger('ReactiveQuery');
const logger = createLogger("ReactiveQuery");
/**
*
*/
export enum ReactiveQueryChangeType {
/** 实体添加到查询结果 */
ADDED = 'added',
ADDED = "added",
/** 实体从查询结果移除 */
REMOVED = 'removed',
REMOVED = "removed",
/** 查询结果批量更新 */
BATCH_UPDATE = 'batch_update'
BATCH_UPDATE = "batch_update"
}
/**
@@ -136,9 +136,9 @@ 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(',');
.join(",");
return `${typeStr}:${componentsStr}`;
}
@@ -153,8 +153,8 @@ export class ReactiveQuery {
throw new Error(`Cannot subscribe to disposed ReactiveQuery ${this._id}`);
}
if (typeof listener !== 'function') {
throw new TypeError('Listener must be a function');
if (typeof listener !== "function") {
throw new TypeError("Listener must be a function");
}
this._listeners.push(listener);
@@ -239,7 +239,7 @@ export class ReactiveQuery {
// 通知监听器
if (this._config.enableBatchMode) {
this.addToBatch('added', entity);
this.addToBatch("added", entity);
} else {
this.notifyListeners({
type: ReactiveQueryChangeType.ADDED,
@@ -276,7 +276,7 @@ export class ReactiveQuery {
// 通知监听器
if (this._config.enableBatchMode) {
this.addToBatch('removed', entity);
this.addToBatch("removed", entity);
} else {
this.notifyListeners({
type: ReactiveQueryChangeType.REMOVED,
@@ -337,8 +337,8 @@ export class ReactiveQuery {
/**
*
*/
private addToBatch(type: 'added' | 'removed', entity: Entity): void {
if (type === 'added') {
private addToBatch(type: "added" | "removed", entity: Entity): void {
if (type === "added") {
this._batchChanges.added.push(entity);
} else {
this._batchChanges.removed.push(entity);
@@ -1,6 +1,6 @@
import { Component } from '../Component';
import type { Entity } from '../Entity';
import type { IScene } from '../IScene';
import {Component} from "../Component";
import type {Entity} from "../Entity";
import type {IScene} from "../IScene";
/**
* WeakRef
@@ -45,9 +45,9 @@ interface IWeakRefConstructor {
* 使 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 any).WeakRef) ||
(typeof global !== "undefined" && (global as any).WeakRef) ||
(typeof window !== "undefined" && (window as any).WeakRef) ||
WeakRefPolyfill
) as IWeakRefConstructor;
+109 -109
View File
@@ -1,6 +1,6 @@
import { Component } from '../Component';
import { ComponentType } from './ComponentStorage';
import { createLogger } from '../../Utils/Logger';
import {Component} from "../Component";
import {ComponentType} from "./ComponentStorage";
import {createLogger} from "../../Utils/Logger";
/**
* SoA优化装饰器
@@ -222,23 +222,23 @@ export class TypeInference {
} = {}): string {
const type = typeof value;
if (type === 'boolean') {
return 'uint8'; // 布尔值使用最小的无符号整数
if (type === "boolean") {
return "uint8"; // 布尔值使用最小的无符号整数
}
if (type !== 'number') {
return 'float32'; // 非数值类型默认使用Float32
if (type !== "number") {
return "float32"; // 非数值类型默认使用Float32
}
const { minValue, maxValue, precision, signed } = options;
const {minValue, maxValue, precision, signed} = options;
// 如果显式要求精度,使用浮点数
if (precision === true) {
// 检查是否需要双精度
if (Math.abs(value) > 3.4028235e+38 || (minValue !== undefined && Math.abs(minValue) > 3.4028235e+38) || (maxValue !== undefined && Math.abs(maxValue) > 3.4028235e+38)) {
return 'float64';
return "float64";
}
return 'float32';
return "float32";
}
// 如果显式禁用精度,或者是整数值,尝试使用整数数组
@@ -251,48 +251,48 @@ export class TypeInference {
if (needsSigned) {
// 有符号整数
if (actualMin >= -128 && actualMax <= 127) {
return 'int8';
return "int8";
} else if (actualMin >= -32768 && actualMax <= 32767) {
return 'int16';
return "int16";
} else if (actualMin >= -2147483648 && actualMax <= 2147483647) {
return 'int32';
return "int32";
} else {
return 'float64'; // 超出int32范围,使用双精度浮点
return "float64"; // 超出int32范围,使用双精度浮点
}
} else {
// 无符号整数
if (actualMax <= 255) {
return 'uint8';
return "uint8";
} else if (actualMax <= 65535) {
return 'uint16';
return "uint16";
} else if (actualMax <= 4294967295) {
return 'uint32';
return "uint32";
} else {
return 'float64'; // 超出uint32范围,使用双精度浮点
return "float64"; // 超出uint32范围,使用双精度浮点
}
}
}
// 默认情况:检查是否为小数
if (!Number.isInteger(value)) {
return 'float32';
return "float32";
}
// 整数值,但没有指定范围,根据值的大小选择
if (value >= 0 && value <= 255) {
return 'uint8';
return "uint8";
} else if (value >= -128 && value <= 127) {
return 'int8';
return "int8";
} else if (value >= 0 && value <= 65535) {
return 'uint16';
return "uint16";
} else if (value >= -32768 && value <= 32767) {
return 'int16';
return "int16";
} else if (value >= 0 && value <= 4294967295) {
return 'uint32';
return "uint32";
} else if (value >= -2147483648 && value <= 2147483647) {
return 'int32';
return "int32";
} else {
return 'float64';
return "float64";
}
}
@@ -301,15 +301,15 @@ export class TypeInference {
*/
public static getTypedArrayConstructor(typeName: string): typeof Float32Array | typeof Float64Array | typeof Int32Array | typeof Uint32Array | typeof Int16Array | typeof Uint16Array | typeof Int8Array | typeof Uint8Array | typeof Uint8ClampedArray {
switch (typeName) {
case 'float32': return Float32Array;
case 'float64': return Float64Array;
case 'int32': return Int32Array;
case 'uint32': return Uint32Array;
case 'int16': return Int16Array;
case 'uint16': return Uint16Array;
case 'int8': return Int8Array;
case 'uint8': return Uint8Array;
case 'uint8clamped': return Uint8ClampedArray;
case "float32": return Float32Array;
case "float64": return Float64Array;
case "int32": return Int32Array;
case "uint32": return Uint32Array;
case "int16": return Int16Array;
case "uint16": return Uint16Array;
case "int8": return Int8Array;
case "uint8": return Uint8Array;
case "uint8clamped": return Uint8ClampedArray;
default: return Float32Array;
}
}
@@ -334,7 +334,7 @@ export type SupportedTypedArray =
* 使Structure of Arrays存储模式
*/
export class SoAStorage<T extends Component> {
private static readonly _logger = createLogger('SoAStorage');
private static readonly _logger = createLogger("SoAStorage");
private fields = new Map<string, SupportedTypedArray>();
private stringFields = new Map<string, string[]>(); // 专门存储字符串
private serializedFields = new Map<string, string[]>(); // 序列化存储Map/Set/Array
@@ -345,12 +345,12 @@ export class SoAStorage<T extends Component> {
private _size = 0;
private _capacity = 1000;
public readonly type: ComponentType<T>;
constructor(componentType: ComponentType<T>) {
this.type = componentType;
this.initializeFields(componentType);
}
private initializeFields(componentType: ComponentType<T>): void {
const instance = new componentType();
const highPrecisionFields = (componentType as any).__highPrecisionFields || new Set();
@@ -368,13 +368,13 @@ export class SoAStorage<T extends Component> {
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使用
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;
if (type === 'number') {
if (type === "number") {
if (highPrecisionFields.has(key)) {
// 标记为高精度,作为复杂对象处理
// 不添加到fields,会在updateComponentAtIndex中自动添加到complexFields
@@ -416,7 +416,7 @@ export class SoAStorage<T extends Component> {
// 默认使用Float32Array
this.fields.set(key, new Float32Array(this._capacity));
}
} else if (type === 'boolean') {
} else if (type === "boolean") {
// 布尔值默认使用Uint8Array存储为0/1(更节省内存)
if (uint8Fields.has(key) || (!float32Fields.has(key) && !float64Fields.has(key))) {
this.fields.set(key, new Uint8Array(this._capacity));
@@ -424,10 +424,10 @@ export class SoAStorage<T extends Component> {
// 兼容性:如果显式指定浮点类型则使用原有方式
this.fields.set(key, new Float32Array(this._capacity));
}
} else if (type === 'string') {
} else if (type === "string") {
// 字符串专门处理
this.stringFields.set(key, new Array(this._capacity));
} else if (type === 'object' && value !== null) {
} else if (type === "object" && value !== null) {
// 处理集合类型
if (serializeMapFields.has(key) || serializeSetFields.has(key) || serializeArrayFields.has(key)) {
// 序列化存储
@@ -438,14 +438,14 @@ export class SoAStorage<T extends Component> {
}
}
}
public addComponent(entityId: number, component: T): void {
if (this.entityToIndex.has(entityId)) {
const index = this.entityToIndex.get(entityId)!;
this.updateComponentAtIndex(index, component);
return;
}
let index: number;
if (this.freeIndices.length > 0) {
index = this.freeIndices.pop()!;
@@ -455,13 +455,13 @@ export class SoAStorage<T extends Component> {
this.resize(this._capacity * 2);
}
}
this.entityToIndex.set(entityId, index);
this.indexToEntity[index] = entityId;
this.updateComponentAtIndex(index, component);
this._size++;
}
private updateComponentAtIndex(index: number, component: T): void {
const entityId = this.indexToEntity[index]!;
const complexFieldMap = new Map<string, any>();
@@ -470,14 +470,14 @@ export class SoAStorage<T extends Component> {
const serializeSetFields = (this.type as any).__serializeSetFields || new Set();
const serializeArrayFields = (this.type as any).__serializeArrayFields || new Set();
const deepCopyFields = (this.type as any).__deepCopyFields || new Set();
// 处理所有字段
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;
if (type === 'number') {
if (type === "number") {
if (highPrecisionFields.has(key) || !this.fields.has(key)) {
// 标记为高精度或未在TypedArray中的数值作为复杂对象存储
complexFieldMap.set(key, value);
@@ -486,8 +486,8 @@ export class SoAStorage<T extends Component> {
const array = this.fields.get(key)!;
array[index] = value;
}
} else if (type === 'boolean' && this.fields.has(key)) {
// 布尔值存储到TypedArray
} else if (type === "boolean" && this.fields.has(key)) {
// 布尔值存储到TypedArray
const array = this.fields.get(key)!;
array[index] = value ? 1 : 0;
} else if (this.stringFields.has(key)) {
@@ -509,13 +509,13 @@ export class SoAStorage<T extends Component> {
}
}
}
// 存储复杂字段
if (complexFieldMap.size > 0) {
this.complexFields.set(entityId, complexFieldMap);
}
}
/**
* JSON字符串
*/
@@ -536,17 +536,17 @@ export class SoAStorage<T extends Component> {
}
} catch (error) {
SoAStorage._logger.warn(`SoA序列化字段 ${key} 失败:`, error);
return '{}';
return "{}";
}
}
/**
* JSON字符串为值
*/
private deserializeValue(serialized: string, key: string, mapFields: Set<string>, setFields: Set<string>, arrayFields: Set<string>): any {
try {
const parsed = JSON.parse(serialized);
if (mapFields.has(key)) {
// 恢复Map
return new Map(parsed);
@@ -564,23 +564,23 @@ export class SoAStorage<T extends Component> {
return null;
}
}
/**
*
*/
private deepClone(obj: any): any {
if (obj === null || typeof obj !== 'object') {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
return obj.map(item => this.deepClone(item));
return obj.map((item) => this.deepClone(item));
}
if (obj instanceof Map) {
const cloned = new Map();
for (const [key, value] of obj.entries()) {
@@ -588,7 +588,7 @@ export class SoAStorage<T extends Component> {
}
return cloned;
}
if (obj instanceof Set) {
const cloned = new Set();
for (const value of obj.values()) {
@@ -596,46 +596,46 @@ export class SoAStorage<T extends Component> {
}
return cloned;
}
// 普通对象
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]);
}
}
return cloned;
}
public getComponent(entityId: number): T | null {
const index = this.entityToIndex.get(entityId);
if (index === undefined) {
return null;
}
// 创建真正的组件实例以保持兼容性
const component = new this.type() as any;
const serializeMapFields = (this.type as any).__serializeMapFields || new Set();
const serializeSetFields = (this.type as any).__serializeSetFields || new Set();
const serializeArrayFields = (this.type as any).__serializeArrayFields || new Set();
// 恢复数值字段
for (const [fieldName, array] of this.fields.entries()) {
const value = array[index];
const fieldType = this.getFieldType(fieldName);
if (fieldType === 'boolean') {
if (fieldType === "boolean") {
component[fieldName] = value === 1;
} else {
component[fieldName] = value;
}
}
// 恢复字符串字段
for (const [fieldName, stringArray] of this.stringFields.entries()) {
component[fieldName] = stringArray[index];
}
// 恢复序列化字段
for (const [fieldName, serializedArray] of this.serializedFields.entries()) {
const serialized = serializedArray[index];
@@ -643,7 +643,7 @@ export class SoAStorage<T extends Component> {
component[fieldName] = this.deserializeValue(serialized, fieldName, serializeMapFields, serializeSetFields, serializeArrayFields);
}
}
// 恢复复杂字段
const complexFieldMap = this.complexFields.get(entityId);
if (complexFieldMap) {
@@ -651,39 +651,39 @@ export class SoAStorage<T extends Component> {
component[fieldName] = value;
}
}
return component as T;
}
private getFieldType(fieldName: string): string {
// 通过创建临时实例检查字段类型
const tempInstance = new this.type();
const value = (tempInstance as any)[fieldName];
return typeof value;
}
public hasComponent(entityId: number): boolean {
return this.entityToIndex.has(entityId);
}
public removeComponent(entityId: number): T | null {
const index = this.entityToIndex.get(entityId);
if (index === undefined) {
return null;
}
// 获取组件副本以便返回
const component = this.getComponent(entityId);
// 清理复杂字段
this.complexFields.delete(entityId);
this.entityToIndex.delete(entityId);
this.freeIndices.push(index);
this._size--;
return component;
}
private resize(newCapacity: number): void {
// 调整数值字段的TypedArray
for (const [fieldName, oldArray] of this.fields.entries()) {
@@ -716,7 +716,7 @@ export class SoAStorage<T extends Component> {
newArray.set(oldArray);
this.fields.set(fieldName, newArray);
}
// 调整字符串字段的数组
for (const [fieldName, oldArray] of this.stringFields.entries()) {
const newArray = new Array(newCapacity);
@@ -725,7 +725,7 @@ export class SoAStorage<T extends Component> {
}
this.stringFields.set(fieldName, newArray);
}
// 调整序列化字段的数组
for (const [fieldName, oldArray] of this.serializedFields.entries()) {
const newArray = new Array(newCapacity);
@@ -734,14 +734,14 @@ export class SoAStorage<T extends Component> {
}
this.serializedFields.set(fieldName, newArray);
}
this._capacity = newCapacity;
}
public getActiveIndices(): number[] {
return Array.from(this.entityToIndex.values());
}
public getFieldArray(fieldName: string): SupportedTypedArray | null {
return this.fields.get(fieldName) || null;
}
@@ -749,38 +749,38 @@ export class SoAStorage<T extends Component> {
public getTypedFieldArray<K extends keyof T>(fieldName: K): SupportedTypedArray | null {
return this.fields.get(String(fieldName)) || null;
}
public getEntityIndex(entityId: number): number | undefined {
return this.entityToIndex.get(entityId);
}
public getEntityIdByIndex(index: number): number | undefined {
return this.indexToEntity[index];
}
public size(): number {
return this._size;
}
public clear(): void {
this.entityToIndex.clear();
this.indexToEntity = [];
this.freeIndices = [];
this.complexFields.clear();
this._size = 0;
// 重置数值字段数组
for (const array of this.fields.values()) {
array.fill(0);
}
// 重置字符串字段数组
for (const stringArray of this.stringFields.values()) {
for (let i = 0; i < stringArray.length; i++) {
stringArray[i] = undefined as any;
}
}
// 重置序列化字段数组
for (const serializedArray of this.serializedFields.values()) {
for (let i = 0; i < serializedArray.length; i++) {
@@ -854,37 +854,37 @@ export class SoAStorage<T extends Component> {
if (array instanceof Float32Array) {
bytesPerElement = 4;
typeName = 'float32';
typeName = "float32";
} else if (array instanceof Float64Array) {
bytesPerElement = 8;
typeName = 'float64';
typeName = "float64";
} else if (array instanceof Int32Array) {
bytesPerElement = 4;
typeName = 'int32';
typeName = "int32";
} else if (array instanceof Uint32Array) {
bytesPerElement = 4;
typeName = 'uint32';
typeName = "uint32";
} else if (array instanceof Int16Array) {
bytesPerElement = 2;
typeName = 'int16';
typeName = "int16";
} else if (array instanceof Uint16Array) {
bytesPerElement = 2;
typeName = 'uint16';
typeName = "uint16";
} else if (array instanceof Int8Array) {
bytesPerElement = 1;
typeName = 'int8';
typeName = "int8";
} else if (array instanceof Uint8Array) {
bytesPerElement = 1;
typeName = 'uint8';
typeName = "uint8";
} else if (array instanceof Uint8ClampedArray) {
bytesPerElement = 1;
typeName = 'uint8clamped';
typeName = "uint8clamped";
} else {
// 默认回退
bytesPerElement = 4;
typeName = 'unknown';
typeName = "unknown";
}
const memory = array.length * bytesPerElement;
totalMemory += memory;
@@ -914,4 +914,4 @@ export class SoAStorage<T extends Component> {
const activeIndices = this.getActiveIndices();
operation(this.fields, activeIndices);
}
}
}
+3 -3
View File
@@ -1,3 +1,3 @@
export { ComponentPool, ComponentPoolManager } from '../ComponentPool';
export { ComponentStorage, ComponentRegistry } from '../ComponentStorage';
export { EnableSoA, HighPrecision, Float64, Float32, Int32, SerializeMap, SoAStorage } from '../SoAStorage';
export {ComponentPool, ComponentPoolManager} from "../ComponentPool";
export {ComponentStorage, ComponentRegistry} from "../ComponentStorage";
export {EnableSoA, HighPrecision, Float64, Float32, Int32, SerializeMap, SoAStorage} from "../SoAStorage";
@@ -46,4 +46,4 @@ export {
// 类型定义
SupportedTypedArray
} from './SoAStorage';
} from "./SoAStorage";
+65 -65
View File
@@ -6,75 +6,75 @@
*/
export enum ECSEventType {
// 实体相关事件
ENTITY_CREATED = 'entity:created',
ENTITY_DESTROYED = 'entity:destroyed',
ENTITY_ENABLED = 'entity:enabled',
ENTITY_DISABLED = 'entity:disabled',
ENTITY_TAG_ADDED = 'entity:tag:added',
ENTITY_TAG_REMOVED = 'entity:tag:removed',
ENTITY_NAME_CHANGED = 'entity:name:changed',
ENTITY_CREATED = "entity:created",
ENTITY_DESTROYED = "entity:destroyed",
ENTITY_ENABLED = "entity:enabled",
ENTITY_DISABLED = "entity:disabled",
ENTITY_TAG_ADDED = "entity:tag:added",
ENTITY_TAG_REMOVED = "entity:tag:removed",
ENTITY_NAME_CHANGED = "entity:name:changed",
// 组件相关事件
COMPONENT_ADDED = 'component:added',
COMPONENT_REMOVED = 'component:removed',
COMPONENT_MODIFIED = 'component:modified',
COMPONENT_ENABLED = 'component:enabled',
COMPONENT_DISABLED = 'component:disabled',
COMPONENT_ADDED = "component:added",
COMPONENT_REMOVED = "component:removed",
COMPONENT_MODIFIED = "component:modified",
COMPONENT_ENABLED = "component:enabled",
COMPONENT_DISABLED = "component:disabled",
// 系统相关事件
SYSTEM_ADDED = 'system:added',
SYSTEM_REMOVED = 'system:removed',
SYSTEM_ENABLED = 'system:enabled',
SYSTEM_DISABLED = 'system:disabled',
SYSTEM_PROCESSING_START = 'system:processing:start',
SYSTEM_PROCESSING_END = 'system:processing:end',
SYSTEM_ERROR = 'system:error',
SYSTEM_ADDED = "system:added",
SYSTEM_REMOVED = "system:removed",
SYSTEM_ENABLED = "system:enabled",
SYSTEM_DISABLED = "system:disabled",
SYSTEM_PROCESSING_START = "system:processing:start",
SYSTEM_PROCESSING_END = "system:processing:end",
SYSTEM_ERROR = "system:error",
// 场景相关事件
SCENE_CREATED = 'scene:created',
SCENE_DESTROYED = 'scene:destroyed',
SCENE_ACTIVATED = 'scene:activated',
SCENE_DEACTIVATED = 'scene:deactivated',
SCENE_PAUSED = 'scene:paused',
SCENE_RESUMED = 'scene:resumed',
SCENE_CREATED = "scene:created",
SCENE_DESTROYED = "scene:destroyed",
SCENE_ACTIVATED = "scene:activated",
SCENE_DEACTIVATED = "scene:deactivated",
SCENE_PAUSED = "scene:paused",
SCENE_RESUMED = "scene:resumed",
// 查询相关事件
QUERY_EXECUTED = 'query:executed',
QUERY_CACHE_HIT = 'query:cache:hit',
QUERY_CACHE_MISS = 'query:cache:miss',
QUERY_OPTIMIZED = 'query:optimized',
QUERY_EXECUTED = "query:executed",
QUERY_CACHE_HIT = "query:cache:hit",
QUERY_CACHE_MISS = "query:cache:miss",
QUERY_OPTIMIZED = "query:optimized",
// 性能相关事件
PERFORMANCE_WARNING = 'performance:warning',
PERFORMANCE_CRITICAL = 'performance:critical',
MEMORY_USAGE_HIGH = 'memory:usage:high',
FRAME_RATE_DROP = 'frame:rate:drop',
PERFORMANCE_WARNING = "performance:warning",
PERFORMANCE_CRITICAL = "performance:critical",
MEMORY_USAGE_HIGH = "memory:usage:high",
FRAME_RATE_DROP = "frame:rate:drop",
// 索引相关事件
INDEX_CREATED = 'index:created',
INDEX_UPDATED = 'index:updated',
INDEX_OPTIMIZED = 'index:optimized',
INDEX_CREATED = "index:created",
INDEX_UPDATED = "index:updated",
INDEX_OPTIMIZED = "index:optimized",
// Archetype相关事件
ARCHETYPE_CREATED = 'archetype:created',
ARCHETYPE_ENTITY_ADDED = 'archetype:entity:added',
ARCHETYPE_ENTITY_REMOVED = 'archetype:entity:removed',
ARCHETYPE_CREATED = "archetype:created",
ARCHETYPE_ENTITY_ADDED = "archetype:entity:added",
ARCHETYPE_ENTITY_REMOVED = "archetype:entity:removed",
// 脏标记相关事件
DIRTY_MARK_ADDED = 'dirty:mark:added',
DIRTY_BATCH_PROCESSED = 'dirty:batch:processed',
DIRTY_MARK_ADDED = "dirty:mark:added",
DIRTY_BATCH_PROCESSED = "dirty:batch:processed",
// 错误和警告事件
ERROR_OCCURRED = 'error:occurred',
WARNING_ISSUED = 'warning:issued',
ERROR_OCCURRED = "error:occurred",
WARNING_ISSUED = "warning:issued",
// 生命周期事件
FRAMEWORK_INITIALIZED = 'framework:initialized',
FRAMEWORK_SHUTDOWN = 'framework:shutdown',
FRAMEWORK_INITIALIZED = "framework:initialized",
FRAMEWORK_SHUTDOWN = "framework:shutdown",
// 调试相关事件
DEBUG_INFO = 'debug:info',
DEBUG_STATS_UPDATED = 'debug:stats:updated'
DEBUG_INFO = "debug:info",
DEBUG_STATS_UPDATED = "debug:stats:updated"
}
/**
@@ -105,7 +105,7 @@ export const EVENT_TYPES = {
TAG_REMOVED: ECSEventType.ENTITY_TAG_REMOVED,
NAME_CHANGED: ECSEventType.ENTITY_NAME_CHANGED
},
// 组件事件
COMPONENT: {
ADDED: ECSEventType.COMPONENT_ADDED,
@@ -114,7 +114,7 @@ export const EVENT_TYPES = {
ENABLED: ECSEventType.COMPONENT_ENABLED,
DISABLED: ECSEventType.COMPONENT_DISABLED
},
// 系统事件
SYSTEM: {
ADDED: ECSEventType.SYSTEM_ADDED,
@@ -125,7 +125,7 @@ export const EVENT_TYPES = {
PROCESSING_END: ECSEventType.SYSTEM_PROCESSING_END,
ERROR: ECSEventType.SYSTEM_ERROR
},
// 性能事件
PERFORMANCE: {
WARNING: ECSEventType.PERFORMANCE_WARNING,
@@ -147,7 +147,7 @@ export class EventTypeValidator {
...Object.values(EVENT_TYPES.SYSTEM),
...Object.values(EVENT_TYPES.PERFORMANCE)
]);
/**
*
* @param eventType
@@ -156,7 +156,7 @@ export class EventTypeValidator {
public static isValid(eventType: string): boolean {
return this.validTypes.has(eventType);
}
/**
*
* @returns
@@ -164,7 +164,7 @@ export class EventTypeValidator {
public static getAllValidTypes(): string[] {
return Array.from(this.validTypes);
}
/**
*
* @param eventType
@@ -172,7 +172,7 @@ export class EventTypeValidator {
public static addCustomType(eventType: string): void {
this.validTypes.add(eventType);
}
/**
*
* @param eventType
@@ -1,19 +1,19 @@
import type { Entity } from '../Entity';
import type { Component } from '../Component';
import { getSceneByEntityId } from '../Core/ReferenceTracker';
import { createLogger } from '../../Utils/Logger';
import type {Entity} from "../Entity";
import type {Component} from "../Component";
import {getSceneByEntityId} from "../Core/ReferenceTracker";
import {createLogger} from "../../Utils/Logger";
const logger = createLogger('EntityRefDecorator');
const logger = createLogger("EntityRefDecorator");
/**
* EntityRef元数据的Symbol键
*/
export const ENTITY_REF_METADATA = Symbol('EntityRefMetadata');
export const ENTITY_REF_METADATA = Symbol("EntityRefMetadata");
/**
* EntityRef值存储的Symbol键
*/
const ENTITY_REF_VALUES = Symbol('EntityRefValues');
const ENTITY_REF_VALUES = Symbol("EntityRefValues");
/**
* EntityRef元数据
@@ -66,7 +66,7 @@ export function EntityRef(): PropertyDecorator {
constructor[ENTITY_REF_METADATA] = metadata;
}
const propKeyString = typeof propertyKey === 'symbol' ? propertyKey.toString() : propertyKey;
const propKeyString = typeof propertyKey === "symbol" ? propertyKey.toString() : propertyKey;
metadata.properties.add(propKeyString);
Object.defineProperty(target, propertyKey, {
@@ -97,7 +97,7 @@ export function EntityRef(): PropertyDecorator {
if (newValue) {
if (newValue.scene !== scene) {
logger.error(`Cannot reference Entity from different Scene. Entity: ${newValue.name}, Scene: ${newValue.scene?.name || 'null'}`);
logger.error(`Cannot reference Entity from different Scene. Entity: ${newValue.name}, Scene: ${newValue.scene?.name || "null"}`);
return;
}
@@ -129,7 +129,7 @@ export function getEntityRefMetadata(component: any): EntityRefMetadata | null {
return null;
}
const constructor = typeof component === 'function'
const constructor = typeof component === "function"
? component
: component.constructor;
@@ -1,21 +1,21 @@
import type {Component} from '../Component';
import type {EntitySystem} from '../Systems';
import type {Component} from "../Component";
import type {EntitySystem} from "../Systems";
import {ComponentType} from "../../Types";
/**
* Symbol键
*/
export const COMPONENT_TYPE_NAME = Symbol('ComponentTypeName');
export const COMPONENT_TYPE_NAME = Symbol("ComponentTypeName");
/**
* Symbol键
*/
export const SYSTEM_TYPE_NAME = Symbol('SystemTypeName');
export const SYSTEM_TYPE_NAME = Symbol("SystemTypeName");
/**
*
*
*
*
* @param typeName
* @example
* ```typescript
@@ -28,13 +28,13 @@ export const SYSTEM_TYPE_NAME = Symbol('SystemTypeName');
*/
export function ECSComponent(typeName: string) {
return function <T extends new (...args: any[]) => Component>(target: T): T {
if (!typeName || typeof typeName !== 'string') {
throw new Error('ECSComponent装饰器必须提供有效的类型名称');
if (!typeName || typeof typeName !== "string") {
throw new Error("ECSComponent装饰器必须提供有效的类型名称");
}
// 在构造函数上存储类型名称
(target as any)[COMPONENT_TYPE_NAME] = typeName;
return target;
};
}
@@ -82,8 +82,8 @@ export interface SystemMetadata {
*/
export function ECSSystem(typeName: string, metadata?: SystemMetadata) {
return function <T extends new (...args: any[]) => EntitySystem>(target: T): T {
if (!typeName || typeof typeName !== 'string') {
throw new Error('ECSSystem装饰器必须提供有效的类型名称');
if (!typeName || typeof typeName !== "string") {
throw new Error("ECSSystem装饰器必须提供有效的类型名称");
}
// 在构造函数上存储类型名称
@@ -107,7 +107,7 @@ export function getSystemMetadata(systemType: new (...args: any[]) => EntitySyst
/**
* 使
*
*
* @param componentType
* @returns
*/
@@ -119,14 +119,14 @@ export function getComponentTypeName(
if (decoratorName) {
return decoratorName;
}
// 回退到constructor.name
return componentType.name || 'UnknownComponent';
return componentType.name || "UnknownComponent";
}
/**
* 使
*
*
* @param systemType
* @returns
*/
@@ -138,14 +138,14 @@ export function getSystemTypeName<T extends EntitySystem>(
if (decoratorName) {
return decoratorName;
}
// 回退到constructor.name
return systemType.name || 'UnknownSystem';
return systemType.name || "UnknownSystem";
}
/**
*
*
*
* @param component
* @returns
*/
@@ -155,7 +155,7 @@ export function getComponentInstanceTypeName(component: Component): string {
/**
*
*
*
* @param system
* @returns
*/
+4 -4
View File
@@ -8,15 +8,15 @@ export {
getSystemMetadata,
COMPONENT_TYPE_NAME,
SYSTEM_TYPE_NAME
} from './TypeDecorators';
} from "./TypeDecorators";
export type { SystemMetadata } from './TypeDecorators';
export type {SystemMetadata} from "./TypeDecorators";
export {
EntityRef,
getEntityRefMetadata,
hasEntityRef,
ENTITY_REF_METADATA
} from './EntityRefDecorator';
} from "./EntityRefDecorator";
export type { EntityRefMetadata } from './EntityRefDecorator';
export type {EntityRefMetadata} from "./EntityRefDecorator";
+81 -76
View File
@@ -1,20 +1,20 @@
import { Component } from './Component';
import { ComponentRegistry, ComponentType } from './Core/ComponentStorage';
import { EventBus } from './Core/EventBus';
import { BitMask64Utils, BitMask64Data } from './Utils/BigIntCompatibility';
import { createLogger } from '../Utils/Logger';
import { getComponentInstanceTypeName, getComponentTypeName } from './Decorators';
import type { IScene } from './IScene';
import {Component} from "./Component";
import {ComponentRegistry, ComponentType} from "./Core/ComponentStorage";
import {EventBus} from "./Core/EventBus";
import {BitMask64Utils, BitMask64Data} from "./Utils/BigIntCompatibility";
import {createLogger} from "../Utils/Logger";
import {getComponentInstanceTypeName, getComponentTypeName} from "./Decorators";
import type {IScene} from "./IScene";
/**
*
*
*
* ID比较
*/
export class EntityComparer {
/**
*
*
*
* @param self -
* @param other -
* @returns self优先级更高other优先级更高0
@@ -28,28 +28,27 @@ export class EntityComparer {
}
/**
*
*
*
* ECS架构中的实体Entity
*
*
*
*
* @example
* ```typescript
* // 创建实体
* const entity = new Entity("Player", 1);
*
*
* // 添加组件
* const healthComponent = entity.addComponent(new HealthComponent(100));
*
*
* // 获取组件
* const health = entity.getComponent(HealthComponent);
*
*
* // 添加位置组件
* entity.addComponent(new PositionComponent(100, 200));
*
*
* // 添加子实体
* const weapon = new Entity("Weapon", 2);
* entity.addChild(weapon);
@@ -59,13 +58,13 @@ export class Entity {
/**
* Entity专用日志器
*/
private static _logger = createLogger('Entity');
private static _logger = createLogger("Entity");
/**
*
*/
public static entityComparer: EntityComparer = new EntityComparer();
/**
* 线
*
@@ -84,17 +83,17 @@ export class Entity {
entity.scene.clearSystemEntityCaches();
}
}
/**
*
*/
public name: string;
/**
*
*/
public readonly id: number;
/**
*
*/
@@ -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;
}
/**
@@ -218,7 +226,7 @@ export class Entity {
/**
*
*
*
* @returns
*/
public get children(): readonly Entity[] {
@@ -227,7 +235,7 @@ export class Entity {
/**
*
*
*
* @returns
*/
public get childCount(): number {
@@ -236,7 +244,7 @@ export class Entity {
/**
*
*
*
* @returns true
*/
public get active(): boolean {
@@ -245,9 +253,9 @@ export class Entity {
/**
*
*
*
*
*
*
* @param value -
*/
public set active(value: boolean) {
@@ -259,9 +267,9 @@ export class Entity {
/**
*
*
*
* true
*
*
* @returns
*/
public get activeInHierarchy(): boolean {
@@ -272,7 +280,7 @@ export class Entity {
/**
*
*
*
* @returns
*/
public get tag(): number {
@@ -281,7 +289,7 @@ export class Entity {
/**
*
*
*
* @param value -
*/
public set tag(value: number) {
@@ -290,7 +298,7 @@ export class Entity {
/**
*
*
*
* @returns true
*/
public get enabled(): boolean {
@@ -299,7 +307,7 @@ export class Entity {
/**
*
*
*
* @param value -
*/
public set enabled(value: boolean) {
@@ -308,7 +316,7 @@ export class Entity {
/**
*
*
*
* @returns
*/
public get updateOrder(): number {
@@ -317,7 +325,7 @@ export class Entity {
/**
*
*
*
* @param value -
*/
public set updateOrder(value: number) {
@@ -326,7 +334,7 @@ export class Entity {
/**
*
*
*
* @returns
*/
public get componentMask(): BitMask64Data {
@@ -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)) {
@@ -418,7 +426,7 @@ export class Entity {
if (Entity.eventBus) {
Entity.eventBus.emitComponentAdded({
timestamp: Date.now(),
source: 'Entity',
source: "Entity",
entityId: this.id,
entityName: this.name,
entityTag: this.tag?.toString(),
@@ -465,8 +473,6 @@ export class Entity {
}
/**
*
*
@@ -485,7 +491,7 @@ export class Entity {
if (!ComponentRegistry.isRegistered(type)) {
return false;
}
const mask = ComponentRegistry.getBitMask(type);
return BitMask64Utils.hasAny(this._componentMask, mask);
}
@@ -555,7 +561,7 @@ export class Entity {
if (Entity.eventBus) {
Entity.eventBus.emitComponentRemoved({
timestamp: Date.now(),
source: 'Entity',
source: "Entity",
entityId: this.id,
entityName: this.name,
entityTag: this.tag?.toString(),
@@ -570,7 +576,7 @@ export class Entity {
/**
*
*
*
* @param type -
* @returns null
*/
@@ -611,13 +617,13 @@ export class Entity {
/**
*
*
*
* @param components -
* @returns
*/
public addComponents<T extends Component>(components: T[]): T[] {
const addedComponents: T[] = [];
for (const component of components) {
try {
addedComponents.push(this.addComponent(component));
@@ -625,28 +631,27 @@ export class Entity {
Entity._logger.warn(`添加组件失败 ${getComponentInstanceTypeName(component)}:`, error);
}
}
return addedComponents;
}
/**
*
*
*
* @param componentTypes -
* @returns
*/
public removeComponentsByTypes<T extends Component>(componentTypes: ComponentType<T>[]): (T | null)[] {
const removedComponents: (T | null)[] = [];
for (const componentType of componentTypes) {
removedComponents.push(this.removeComponentByType(componentType));
}
return removedComponents;
}
/**
*
*
@@ -694,7 +699,7 @@ export class Entity {
/**
*
*
*
* @param child -
* @returns
*/
@@ -724,7 +729,7 @@ export class Entity {
/**
*
*
*
* @param child -
* @returns
*/
@@ -745,7 +750,7 @@ export class Entity {
*/
public removeAllChildren(): void {
const childrenToRemove = [...this._children];
for (const child of childrenToRemove) {
this.removeChild(child);
}
@@ -753,7 +758,7 @@ export class Entity {
/**
*
*
*
* @param name -
* @param recursive -
* @returns null
@@ -779,7 +784,7 @@ export class Entity {
/**
*
*
*
* @param tag -
* @param recursive -
* @returns
@@ -804,7 +809,7 @@ export class Entity {
/**
*
*
*
* @returns
*/
public getRoot(): Entity {
@@ -817,7 +822,7 @@ export class Entity {
/**
*
*
*
* @param entity -
* @returns true
*/
@@ -834,7 +839,7 @@ export class Entity {
/**
*
*
*
* @param entity -
* @returns true
*/
@@ -844,7 +849,7 @@ export class Entity {
/**
*
*
*
* @returns 0
*/
public getDepth(): number {
@@ -859,7 +864,7 @@ export class Entity {
/**
*
*
*
* @param callback -
* @param recursive -
*/
@@ -877,14 +882,14 @@ export class Entity {
*/
private onActiveChanged(): void {
for (const component of this.components) {
if ('onActiveChanged' in component && typeof component.onActiveChanged === 'function') {
if ("onActiveChanged" in component && typeof component.onActiveChanged === "function") {
(component as any).onActiveChanged();
}
}
if (this.scene && this.scene.eventSystem) {
this.scene.eventSystem.emitSync('entity:activeChanged', {
entity: this,
this.scene.eventSystem.emitSync("entity:activeChanged", {
entity: this,
active: this._active,
activeInHierarchy: this.activeInHierarchy
});
@@ -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) {
@@ -970,7 +975,7 @@ export class Entity {
/**
*
*
*
* @param other -
* @returns
*/
@@ -980,7 +985,7 @@ export class Entity {
/**
*
*
*
* @returns
*/
public toString(): string {
@@ -989,7 +994,7 @@ export class Entity {
/**
*
*
*
* @returns
*/
public getDebugInfo(): {
@@ -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
};
+15 -15
View File
@@ -1,15 +1,15 @@
import { Entity } from './Entity';
import { EntityList } from './Utils/EntityList';
import { IdentifierPool } from './Utils/IdentifierPool';
import { EntitySystem } from './Systems/EntitySystem';
import { ComponentStorageManager } from './Core/ComponentStorage';
import { QuerySystem } from './Core/QuerySystem';
import { TypeSafeEventSystem } from './Core/EventSystem';
import type { ReferenceTracker } from './Core/ReferenceTracker';
import type { ServiceContainer, ServiceType } from '../Core/ServiceContainer';
import type { TypedQueryBuilder } from './Core/Query/TypedQuery';
import type { SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer';
import type { IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer';
import {Entity} from "./Entity";
import {EntityList} from "./Utils/EntityList";
import {IdentifierPool} from "./Utils/IdentifierPool";
import {EntitySystem} from "./Systems/EntitySystem";
import {ComponentStorageManager} from "./Core/ComponentStorage";
import {QuerySystem} from "./Core/QuerySystem";
import {TypeSafeEventSystem} from "./Core/EventSystem";
import type {ReferenceTracker} from "./Core/ReferenceTracker";
import type {ServiceContainer, ServiceType} from "../Core/ServiceContainer";
import type {TypedQueryBuilder} from "./Core/Query/TypedQuery";
import type {SceneSerializationOptions, SceneDeserializationOptions} from "./Serialization/SceneSerializer";
import type {IncrementalSnapshot, IncrementalSerializationOptions} from "./Serialization/IncrementalSerializer";
/**
*
@@ -50,12 +50,12 @@ export interface IScene {
*
*/
readonly identifierPool: IdentifierPool;
/**
*
*/
readonly componentStorageManager: ComponentStorageManager;
/**
*
*/
@@ -316,4 +316,4 @@ export interface ISceneConfig {
*
*/
name?: string;
}
}
+50 -50
View File
@@ -1,22 +1,22 @@
import { Entity } from './Entity';
import { EntityList } from './Utils/EntityList';
import { IdentifierPool } from './Utils/IdentifierPool';
import { EntitySystem } from './Systems/EntitySystem';
import { ComponentStorageManager, ComponentRegistry } from './Core/ComponentStorage';
import { QuerySystem } from './Core/QuerySystem';
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 { TypedQueryBuilder } from './Core/Query/TypedQuery';
import { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer';
import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer';
import { ComponentPoolManager } from './Core/ComponentPool';
import { PerformanceMonitor } from '../Utils/PerformanceMonitor';
import { ServiceContainer, type ServiceType } from '../Core/ServiceContainer';
import { createInstance, isInjectable, injectProperties } from '../Core/DI';
import { createLogger } from '../Utils/Logger';
import {Entity} from "./Entity";
import {EntityList} from "./Utils/EntityList";
import {IdentifierPool} from "./Utils/IdentifierPool";
import {EntitySystem} from "./Systems/EntitySystem";
import {ComponentStorageManager, ComponentRegistry} from "./Core/ComponentStorage";
import {QuerySystem} from "./Core/QuerySystem";
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 {TypedQueryBuilder} from "./Core/Query/TypedQuery";
import {SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions} from "./Serialization/SceneSerializer";
import {IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions} from "./Serialization/IncrementalSerializer";
import {ComponentPoolManager} from "./Core/ComponentPool";
import {PerformanceMonitor} from "../Utils/PerformanceMonitor";
import {ServiceContainer, type ServiceType} from "../Core/ServiceContainer";
import {createInstance, isInjectable, injectProperties} from "../Core/DI";
import {createLogger} from "../Utils/Logger";
/**
*
@@ -45,25 +45,25 @@ export class Scene implements IScene {
*
*/
public readonly entities: EntityList;
/**
* ID池
*
*
*
*/
public readonly identifierPool: IdentifierPool;
/**
*
*
*
*
*/
public readonly componentStorageManager: ComponentStorageManager;
/**
*
*
*
*
*/
public readonly querySystem: QuerySystem;
@@ -207,7 +207,7 @@ export class Scene implements IScene {
this.eventSystem = new TypeSafeEventSystem();
this.referenceTracker = new ReferenceTracker();
this._services = new ServiceContainer();
this.logger = createLogger('Scene');
this.logger = createLogger("Scene");
if (config?.name) {
this.name = config.name;
@@ -219,7 +219,7 @@ export class Scene implements IScene {
if (Entity.eventBus) {
Entity.eventBus.onComponentAdded((data: unknown) => {
this.eventSystem.emitSync('component:added', data);
this.eventSystem.emitSync("component:added", data);
});
}
}
@@ -239,7 +239,7 @@ export class Scene implements IScene {
/**
*
*
*
*
*/
public initialize(): void {
@@ -247,7 +247,7 @@ export class Scene implements IScene {
/**
*
*
*
*
*/
public onStart(): void {
@@ -255,7 +255,7 @@ export class Scene implements IScene {
/**
*
*
*
*
*/
public unload(): void {
@@ -338,10 +338,10 @@ export class Scene implements IScene {
* @param name
*/
public createEntity(name: string) {
let entity = new Entity(name, this.identifierPool.checkOut());
this.eventSystem.emitSync('entity:created', { entityName: name, entity, scene: this });
const entity = new Entity(name, this.identifierPool.checkOut());
this.eventSystem.emitSync("entity:created", {entityName: name, entity, scene: this});
return this.addEntity(entity);
}
@@ -373,7 +373,7 @@ export class Scene implements IScene {
}
// 触发实体添加事件
this.eventSystem.emitSync('entity:added', { entity, scene: this });
this.eventSystem.emitSync("entity:added", {entity, scene: this});
return entity;
}
@@ -386,25 +386,25 @@ export class Scene implements IScene {
*/
public createEntities(count: number, namePrefix: string = "Entity"): Entity[] {
const entities: Entity[] = [];
// 批量创建实体对象,不立即添加到系统
for (let i = 0; i < count; i++) {
const entity = new Entity(`${namePrefix}_${i}`, this.identifierPool.checkOut());
entity.scene = this;
entities.push(entity);
}
// 批量添加到实体列表
for (const entity of entities) {
this.entities.add(entity);
}
// 批量添加到查询系统(无重复检查,性能最优)
this.querySystem.addEntitiesUnchecked(entities);
// 批量触发事件(可选,减少事件开销)
this.eventSystem.emitSync('entities:batch_added', { entities, scene: this, count });
this.eventSystem.emitSync("entities:batch_added", {entities, scene: this, count});
return entities;
}
@@ -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) {
@@ -583,7 +583,7 @@ export class Scene implements IScene {
let system: T;
let constructor: any;
if (typeof systemTypeOrInstance === 'function') {
if (typeof systemTypeOrInstance === "function") {
constructor = systemTypeOrInstance;
if (this._services.isRegistered(constructor)) {
@@ -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
@@ -907,7 +907,7 @@ export class Scene implements IScene {
*/
public serializeIncremental(options?: IncrementalSerializationOptions): IncrementalSnapshot {
if (!this._incrementalBaseSnapshot) {
throw new Error('必须先调用 createIncrementalSnapshot() 创建基础快照');
throw new Error("必须先调用 createIncrementalSnapshot() 创建基础快照");
}
return IncrementalSerializer.computeIncremental(
@@ -941,7 +941,7 @@ export class Scene implements IScene {
incremental: IncrementalSnapshot | string | Uint8Array,
componentRegistry?: Map<string, any>
): void {
const isSerializedData = typeof incremental === 'string' ||
const isSerializedData = typeof incremental === "string" ||
incremental instanceof Uint8Array;
const snapshot = isSerializedData
@@ -996,4 +996,4 @@ export class Scene implements IScene {
public hasIncrementalSnapshot(): boolean {
return this._incrementalBaseSnapshot !== undefined;
}
}
}
+12 -12
View File
@@ -1,10 +1,10 @@
import { IScene } from './IScene';
import { ECSFluentAPI, createECSAPI } from './Core/FluentAPI';
import { Time } from '../Utils/Time';
import { createLogger } from '../Utils/Logger';
import type { IService } from '../Core/ServiceContainer';
import { World } from './World';
import { PerformanceMonitor } from '../Utils/PerformanceMonitor';
import {IScene} from "./IScene";
import {ECSFluentAPI, createECSAPI} from "./Core/FluentAPI";
import {Time} from "../Utils/Time";
import {createLogger} from "../Utils/Logger";
import type {IService} from "../Core/ServiceContainer";
import {World} from "./World";
import {PerformanceMonitor} from "../Utils/PerformanceMonitor";
/**
*
@@ -67,7 +67,7 @@ export class SceneManager implements IService {
/**
*
*/
private _logger = createLogger('SceneManager');
private _logger = createLogger("SceneManager");
/**
*
@@ -82,10 +82,10 @@ export class SceneManager implements IService {
/**
* ID
*/
private static readonly DEFAULT_SCENE_ID = '__main__';
private static readonly DEFAULT_SCENE_ID = "__main__";
constructor(performanceMonitor?: PerformanceMonitor) {
this._defaultWorld = new World({ name: '__default__' });
this._defaultWorld = new World({name: "__default__"});
this._defaultWorld.start();
this._performanceMonitor = performanceMonitor || null;
}
@@ -238,13 +238,13 @@ export class SceneManager implements IService {
*
*/
public destroy(): void {
this._logger.info('SceneManager destroying');
this._logger.info("SceneManager destroying");
this._defaultWorld.destroy();
this._nextScene = null;
this._ecsAPI = null;
this._logger.info('SceneManager destroyed');
this._logger.info("SceneManager destroyed");
}
/**
@@ -4,12 +4,12 @@
*
*/
import { Component } from '../Component';
import { ComponentType } from '../Core/ComponentStorage';
import { getComponentTypeName } from '../Decorators';
import {Component} from "../Component";
import {ComponentType} from "../Core/ComponentStorage";
import {getComponentTypeName} from "../Decorators";
import {
getSerializationMetadata
} from './SerializationDecorators';
} from "./SerializationDecorators";
/**
*
@@ -22,9 +22,9 @@ export type SerializableValue =
| undefined
| SerializableValue[]
| { [key: string]: SerializableValue }
| { __type: 'Date'; value: string }
| { __type: 'Map'; value: Array<[SerializableValue, SerializableValue]> }
| { __type: 'Set'; value: SerializableValue[] };
| { __type: "Date"; value: string }
| { __type: "Map"; value: Array<[SerializableValue, SerializableValue]> }
| { __type: "Set"; value: SerializableValue[] };
/**
*
@@ -70,7 +70,7 @@ export class ComponentSerializer {
// 序列化标记的字段
for (const [fieldName, options] of metadata.fields) {
const fieldKey = typeof fieldName === 'symbol' ? fieldName.toString() : fieldName;
const fieldKey = typeof fieldName === "symbol" ? fieldName.toString() : fieldName;
const value = (component as unknown as Record<string | symbol, SerializableValue>)[fieldName];
// 跳过忽略的字段
@@ -125,7 +125,7 @@ export class ComponentSerializer {
// 反序列化字段
for (const [fieldName, options] of metadata.fields) {
const fieldKey = typeof fieldName === 'symbol' ? fieldName.toString() : fieldName;
const fieldKey = typeof fieldName === "symbol" ? fieldName.toString() : fieldName;
const key = options.alias || fieldKey;
const serializedValue = serializedData.data[key];
@@ -198,27 +198,27 @@ export class ComponentSerializer {
// 基本类型
const type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean') {
if (type === "string" || type === "number" || type === "boolean") {
return value;
}
// 日期
if (value instanceof Date) {
return {
__type: 'Date',
__type: "Date",
value: value.toISOString()
};
}
// 数组
if (Array.isArray(value)) {
return value.map(item => this.serializeValue(item));
return value.map((item) => this.serializeValue(item));
}
// Map (如果没有使用@SerializeMap装饰器)
if (value instanceof Map) {
return {
__type: 'Map',
__type: "Map",
value: Array.from(value.entries())
};
}
@@ -226,13 +226,13 @@ export class ComponentSerializer {
// Set
if (value instanceof Set) {
return {
__type: 'Set',
__type: "Set",
value: Array.from(value)
};
}
// 普通对象
if (type === 'object' && typeof value === 'object' && !Array.isArray(value)) {
if (type === "object" && typeof value === "object" && !Array.isArray(value)) {
const result: Record<string, SerializableValue> = {};
const obj = value as Record<string, SerializableValue>;
for (const key in obj) {
@@ -257,30 +257,30 @@ export class ComponentSerializer {
// 基本类型直接返回
const type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean') {
if (type === "string" || type === "number" || type === "boolean") {
return value;
}
// 处理特殊类型标记
if (type === 'object' && typeof value === 'object' && '__type' in value) {
if (type === "object" && typeof value === "object" && "__type" in value) {
const typedValue = value as { __type: string; value: SerializableValue };
switch (typedValue.__type) {
case 'Date':
return { __type: 'Date', value: typeof typedValue.value === 'string' ? typedValue.value : String(typedValue.value) };
case 'Map':
return { __type: 'Map', value: typedValue.value as Array<[SerializableValue, SerializableValue]> };
case 'Set':
return { __type: 'Set', value: typedValue.value as SerializableValue[] };
case "Date":
return {__type: "Date", value: typeof typedValue.value === "string" ? typedValue.value : String(typedValue.value)};
case "Map":
return {__type: "Map", value: typedValue.value as Array<[SerializableValue, SerializableValue]>};
case "Set":
return {__type: "Set", value: typedValue.value as SerializableValue[]};
}
}
// 数组
if (Array.isArray(value)) {
return value.map(item => this.deserializeValue(item));
return value.map((item) => this.deserializeValue(item));
}
// 普通对象
if (type === 'object' && typeof value === 'object' && !Array.isArray(value)) {
if (type === "object" && typeof value === "object" && !Array.isArray(value)) {
const result: Record<string, SerializableValue> = {};
const obj = value as Record<string, SerializableValue>;
for (const key in obj) {
@@ -325,7 +325,7 @@ export class ComponentSerializer {
if (!metadata) {
return {
type: 'unknown',
type: "unknown",
version: 0,
fields: [],
ignoredFields: [],
@@ -333,18 +333,18 @@ export class ComponentSerializer {
};
}
const componentType = typeof component === 'function'
const componentType = typeof component === "function"
? component
: (component.constructor as ComponentType);
return {
type: metadata.options.typeId || getComponentTypeName(componentType),
version: metadata.options.version,
fields: Array.from(metadata.fields.keys()).map(k =>
typeof k === 'symbol' ? k.toString() : k
fields: Array.from(metadata.fields.keys()).map((k) =>
typeof k === "symbol" ? k.toString() : k
),
ignoredFields: Array.from(metadata.ignoredFields).map(k =>
typeof k === 'symbol' ? k.toString() : k
ignoredFields: Array.from(metadata.ignoredFields).map((k) =>
typeof k === "symbol" ? k.toString() : k
),
isSerializable: true
};
@@ -4,10 +4,10 @@
*
*/
import { Entity } from '../Entity';
import { ComponentType } from '../Core/ComponentStorage';
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
import { IScene } from '../IScene';
import {Entity} from "../Entity";
import {ComponentType} from "../Core/ComponentStorage";
import {ComponentSerializer, SerializedComponent} from "./ComponentSerializer";
import {IScene} from "../IScene";
/**
*
@@ -5,31 +5,31 @@
*
*/
import type { IScene } from '../IScene';
import { Entity } from '../Entity';
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
import { SerializedEntity } from './EntitySerializer';
import { ComponentType } from '../Core/ComponentStorage';
import { BinarySerializer } from '../../Utils/BinarySerializer';
import type {IScene} from "../IScene";
import {Entity} from "../Entity";
import {ComponentSerializer, SerializedComponent} from "./ComponentSerializer";
import {SerializedEntity} from "./EntitySerializer";
import {ComponentType} from "../Core/ComponentStorage";
import {BinarySerializer} from "../../Utils/BinarySerializer";
/**
*
*/
export enum ChangeOperation {
/** 添加新实体 */
EntityAdded = 'entity_added',
EntityAdded = "entity_added",
/** 删除实体 */
EntityRemoved = 'entity_removed',
EntityRemoved = "entity_removed",
/** 实体属性更新 */
EntityUpdated = 'entity_updated',
EntityUpdated = "entity_updated",
/** 添加组件 */
ComponentAdded = 'component_added',
ComponentAdded = "component_added",
/** 删除组件 */
ComponentRemoved = 'component_removed',
ComponentRemoved = "component_removed",
/** 组件数据更新 */
ComponentUpdated = 'component_updated',
ComponentUpdated = "component_updated",
/** 场景数据更新 */
SceneDataUpdated = 'scene_data_updated'
SceneDataUpdated = "scene_data_updated"
}
/**
@@ -120,7 +120,7 @@ interface SceneSnapshot {
/**
*
*/
export type IncrementalSerializationFormat = 'json' | 'binary';
export type IncrementalSerializationFormat = "json" | "binary";
/**
*
@@ -203,7 +203,7 @@ export class IncrementalSerializer {
active: entity.active,
enabled: entity.enabled,
updateOrder: entity.updateOrder,
...(entity.parent && { parentId: entity.parent.id })
...(entity.parent && {parentId: entity.parent.id})
});
// 快照组件
@@ -285,7 +285,7 @@ export class IncrementalSerializer {
active: entity.active,
enabled: entity.enabled,
updateOrder: entity.updateOrder,
...(entity.parent && { parentId: entity.parent.id }),
...(entity.parent && {parentId: entity.parent.id}),
components: [],
children: []
}
@@ -324,7 +324,7 @@ export class IncrementalSerializer {
active: entity.active,
enabled: entity.enabled,
updateOrder: entity.updateOrder,
...(entity.parent && { parentId: entity.parent.id })
...(entity.parent && {parentId: entity.parent.id})
}
});
}
@@ -511,7 +511,7 @@ export class IncrementalSerializer {
private static applyEntityAdded(scene: IScene, change: EntityChange): void {
if (!change.entityData) return;
const entity = new Entity(change.entityName || 'Entity', change.entityId);
const entity = new Entity(change.entityName || "Entity", change.entityId);
entity.tag = change.entityData.tag || 0;
entity.active = change.entityData.active ?? true;
entity.enabled = change.entityData.enabled ?? true;
@@ -632,12 +632,12 @@ export class IncrementalSerializer {
options?: { format?: IncrementalSerializationFormat; pretty?: boolean }
): string | Uint8Array {
const opts = {
format: 'json' as IncrementalSerializationFormat,
format: "json" as IncrementalSerializationFormat,
pretty: false,
...options
};
if (opts.format === 'binary') {
if (opts.format === "binary") {
return BinarySerializer.encode(incremental);
} else {
return opts.pretty
@@ -662,7 +662,7 @@ export class IncrementalSerializer {
* ```
*/
public static deserializeIncremental(data: string | Uint8Array): IncrementalSnapshot {
if (typeof data === 'string') {
if (typeof data === "string") {
return JSON.parse(data);
} else {
return BinarySerializer.decode(data) as IncrementalSnapshot;
@@ -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
};
}
@@ -4,23 +4,23 @@
*
*/
import type { IScene } from '../IScene';
import { Entity } from '../Entity';
import { ComponentType, ComponentRegistry } from '../Core/ComponentStorage';
import { EntitySerializer, SerializedEntity } from './EntitySerializer';
import { getComponentTypeName } from '../Decorators';
import { getSerializationMetadata } from './SerializationDecorators';
import { BinarySerializer } from '../../Utils/BinarySerializer';
import type {IScene} from "../IScene";
import {Entity} from "../Entity";
import {ComponentType, ComponentRegistry} from "../Core/ComponentStorage";
import {EntitySerializer, SerializedEntity} from "./EntitySerializer";
import {getComponentTypeName} from "../Decorators";
import {getSerializationMetadata} from "./SerializationDecorators";
import {BinarySerializer} from "../../Utils/BinarySerializer";
/**
*
*/
export type SerializationFormat = 'json' | 'binary';
export type SerializationFormat = "json" | "binary";
/**
*
*/
export type DeserializationStrategy = 'merge' | 'replace';
export type DeserializationStrategy = "merge" | "replace";
/**
*
@@ -158,7 +158,7 @@ export class SceneSerializer {
public static serialize(scene: IScene, options?: SceneSerializationOptions): string | Uint8Array {
const opts: SceneSerializationOptions = {
systems: false,
format: 'json',
format: "json",
pretty: true,
includeMetadata: true,
...options
@@ -199,7 +199,7 @@ export class SceneSerializer {
};
}
if (opts.format === 'json') {
if (opts.format === "json") {
return opts.pretty
? JSON.stringify(serializedScene, null, 2)
: JSON.stringify(serializedScene);
@@ -221,14 +221,14 @@ export class SceneSerializer {
options?: SceneDeserializationOptions
): void {
const opts: SceneDeserializationOptions = {
strategy: 'replace',
strategy: "replace",
preserveIds: false,
...options
};
let serializedScene: SerializedScene;
try {
if (typeof saveData === 'string') {
if (typeof saveData === "string") {
serializedScene = JSON.parse(saveData);
} else {
serializedScene = BinarySerializer.decode(saveData) as SerializedScene;
@@ -250,7 +250,7 @@ export class SceneSerializer {
const componentRegistry = opts.componentRegistry || this.getGlobalComponentRegistry();
// 根据策略处理场景
if (opts.strategy === 'replace') {
if (opts.strategy === "replace") {
// 清空场景
scene.destroyAllEntities();
}
@@ -342,35 +342,35 @@ export class SceneSerializer {
// 基本类型
const type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean') {
if (type === "string" || type === "number" || type === "boolean") {
return value;
}
// Date
if (value instanceof Date) {
return { __type: 'Date', value: value.toISOString() };
return {__type: "Date", value: value.toISOString()};
}
// Map
if (value instanceof Map) {
return { __type: 'Map', value: Array.from(value.entries()) };
return {__type: "Map", value: Array.from(value.entries())};
}
// Set
if (value instanceof Set) {
return { __type: 'Set', value: Array.from(value) };
return {__type: "Set", value: Array.from(value)};
}
// 数组
if (Array.isArray(value)) {
return value.map(item => this.serializeValue(item));
return value.map((item) => this.serializeValue(item));
}
// 普通对象
if (type === 'object') {
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]);
}
}
@@ -391,32 +391,32 @@ export class SceneSerializer {
// 基本类型
const type = typeof value;
if (type === 'string' || type === 'number' || type === 'boolean') {
if (type === "string" || type === "number" || type === "boolean") {
return value;
}
// 处理特殊类型标记
if (type === 'object' && value.__type) {
if (type === "object" && value.__type) {
switch (value.__type) {
case 'Date':
case "Date":
return new Date(value.value);
case 'Map':
case "Map":
return new Map(value.value);
case 'Set':
case "Set":
return new Set(value.value);
}
}
// 数组
if (Array.isArray(value)) {
return value.map(item => this.deserializeValue(item));
return value.map((item) => this.deserializeValue(item));
}
// 普通对象
if (type === 'object') {
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)
);
});
@@ -499,21 +499,21 @@ export class SceneSerializer {
const data = JSON.parse(saveData);
if (!data.version) {
errors.push('Missing version field');
errors.push("Missing version field");
}
if (!data.entities || !Array.isArray(data.entities)) {
errors.push('Missing or invalid entities field');
errors.push("Missing or invalid entities field");
}
if (!data.componentTypeRegistry || !Array.isArray(data.componentTypeRegistry)) {
errors.push('Missing or invalid componentTypeRegistry field');
errors.push("Missing or invalid componentTypeRegistry field");
}
return {
valid: errors.length === 0,
version: data.version,
...(errors.length > 0 && { errors })
...(errors.length > 0 && {errors})
};
} catch (error) {
return {
@@ -542,7 +542,7 @@ export class SceneSerializer {
return {
name: data.name,
version: data.version,
...(data.timestamp !== undefined && { timestamp: data.timestamp }),
...(data.timestamp !== undefined && {timestamp: data.timestamp}),
entityCount: data.metadata?.entityCount || data.entities.length,
componentTypeCount: data.componentTypeRegistry.length
};
@@ -4,14 +4,14 @@
*
*/
import { Component } from '../Component';
import {Component} from "../Component";
/**
* Symbol键
*/
export const SERIALIZABLE_METADATA = Symbol('SerializableMetadata');
export const SERIALIZE_FIELD = Symbol('SerializeField');
export const SERIALIZE_OPTIONS = Symbol('SerializeOptions');
export const SERIALIZABLE_METADATA = Symbol("SerializableMetadata");
export const SERIALIZE_FIELD = Symbol("SerializeField");
export const SERIALIZE_OPTIONS = Symbol("SerializeOptions");
/**
*
@@ -76,8 +76,8 @@ export interface SerializationMetadata {
*/
export function Serializable(options: SerializableOptions) {
return function <T extends new (...args: any[]) => Component>(target: T): T {
if (!options || typeof options.version !== 'number') {
throw new Error('Serializable装饰器必须提供有效的版本号');
if (!options || typeof options.version !== "number") {
throw new Error("Serializable装饰器必须提供有效的版本号");
}
// 初始化或获取现有元数据
@@ -121,7 +121,7 @@ export function Serialize(options?: FieldSerializeOptions) {
let metadata: SerializationMetadata = constructor[SERIALIZABLE_METADATA];
if (!metadata) {
metadata = {
options: { version: 1 }, // 默认版本
options: {version: 1}, // 默认版本
fields: new Map(),
ignoredFields: new Set()
};
@@ -212,7 +212,7 @@ export function IgnoreSerialization() {
let metadata: SerializationMetadata = constructor[SERIALIZABLE_METADATA];
if (!metadata) {
metadata = {
options: { version: 1 },
options: {version: 1},
fields: new Map(),
ignoredFields: new Set()
};
@@ -236,7 +236,7 @@ export function getSerializationMetadata(componentClass: any): SerializationMeta
}
// 如果是实例,获取其构造函数
const constructor = typeof componentClass === 'function'
const constructor = typeof componentClass === "function"
? componentClass
: componentClass.constructor;
@@ -4,8 +4,8 @@
*
*/
import { SerializedComponent } from './ComponentSerializer';
import { SerializedScene } from './SceneSerializer';
import {SerializedComponent} from "./ComponentSerializer";
import {SerializedScene} from "./SceneSerializer";
/**
*
@@ -127,7 +127,7 @@ export class VersionMigrationManager {
return component;
}
let migratedData = { ...component };
const migratedData = {...component};
let version = currentVersion;
// 执行迁移链
@@ -163,7 +163,7 @@ export class VersionMigrationManager {
return scene; // 版本相同,无需迁移
}
let migratedScene = { ...scene };
let migratedScene = {...scene};
let version = currentVersion;
// 执行场景级迁移
@@ -191,14 +191,14 @@ export class VersionMigrationManager {
*
*/
private static migrateSceneComponents(scene: SerializedScene): SerializedScene {
const migratedScene = { ...scene };
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);
+12 -12
View File
@@ -16,24 +16,24 @@ export {
SERIALIZABLE_METADATA,
SERIALIZE_FIELD,
SERIALIZE_OPTIONS
} from './SerializationDecorators';
} from "./SerializationDecorators";
export type {
SerializableOptions,
FieldSerializeOptions,
SerializationMetadata
} from './SerializationDecorators';
} from "./SerializationDecorators";
// 组件序列化器
export { ComponentSerializer } from './ComponentSerializer';
export type { SerializedComponent } from './ComponentSerializer';
export {ComponentSerializer} from "./ComponentSerializer";
export type {SerializedComponent} from "./ComponentSerializer";
// 实体序列化器
export { EntitySerializer } from './EntitySerializer';
export type { SerializedEntity } from './EntitySerializer';
export {EntitySerializer} from "./EntitySerializer";
export type {SerializedEntity} from "./EntitySerializer";
// 场景序列化器
export { SceneSerializer } from './SceneSerializer';
export {SceneSerializer} from "./SceneSerializer";
export type {
SerializedScene,
SerializationFormat,
@@ -41,17 +41,17 @@ export type {
MigrationFunction,
SceneSerializationOptions,
SceneDeserializationOptions
} from './SceneSerializer';
} from "./SceneSerializer";
// 版本迁移
export { VersionMigrationManager, MigrationBuilder } from './VersionMigration';
export {VersionMigrationManager, MigrationBuilder} from "./VersionMigration";
export type {
ComponentMigrationFunction,
SceneMigrationFunction
} from './VersionMigration';
} from "./VersionMigration";
// 增量序列化
export { IncrementalSerializer, ChangeOperation } from './IncrementalSerializer';
export {IncrementalSerializer, ChangeOperation} from "./IncrementalSerializer";
export type {
IncrementalSnapshot,
IncrementalSerializationOptions,
@@ -59,4 +59,4 @@ export type {
EntityChange,
ComponentChange,
SceneDataChange
} from './IncrementalSerializer';
} from "./IncrementalSerializer";
+59 -33
View File
@@ -1,14 +1,15 @@
import { Entity } from '../Entity';
import { PerformanceMonitor } from '../../Utils/PerformanceMonitor';
import { Matcher, type QueryCondition } from '../Utils/Matcher';
import type { Scene } from '../Scene';
import type { ISystemBase } from '../../Types';
import type { QuerySystem } from '../Core/QuerySystem';
import { getSystemInstanceTypeName } from '../Decorators';
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 {Entity} from "../Entity";
import {PerformanceMonitor} from "../../Utils/PerformanceMonitor";
import {Matcher, type QueryCondition} from "../Utils/Matcher";
import type {Scene} from "../Scene";
import type {ISystemBase} from "../../Types";
import type {QuerySystem} from "../Core/QuerySystem";
import {getSystemInstanceTypeName} from "../Decorators";
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";
/**
*
@@ -251,7 +252,7 @@ export abstract class EntitySystem<
/**
*
*
*
*
*/
protected onInitialize(): void {
@@ -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;
}
@@ -531,7 +557,7 @@ export abstract class EntitySystem<
/**
*
*
*
* 使ID集合的单次扫描算法进行复杂查询
*/
private executeComplexQuery(condition: QueryCondition, querySystem: QuerySystem): readonly Entity[] {
@@ -590,7 +616,7 @@ export abstract class EntitySystem<
/**
*
*
*
*
*/
protected onBegin(): void {
@@ -599,9 +625,9 @@ export abstract class EntitySystem<
/**
*
*
*
*
*
*
* @param entities
*/
protected process(_entities: readonly Entity[]): void {
@@ -610,9 +636,9 @@ export abstract class EntitySystem<
/**
*
*
*
*
*
*
* @param entities
*/
protected lateProcess(_entities: readonly Entity[]): void {
@@ -621,7 +647,7 @@ export abstract class EntitySystem<
/**
*
*
*
*
*/
protected onEnd(): void {
@@ -630,10 +656,10 @@ export abstract class EntitySystem<
/**
*
*
*
*
*
*
*
* @returns truefalse
*/
protected onCheckProcessing(): boolean {
@@ -667,13 +693,13 @@ export abstract class EntitySystem<
/**
*
*
*
* @returns
*/
public toString(): string {
const entityCount = this.entities.length;
const perfData = this.getPerformanceData();
const perfInfo = perfData ? ` (${perfData.executionTime.toFixed(2)}ms)` : '';
const perfInfo = perfData ? ` (${perfData.executionTime.toFixed(2)}ms)` : "";
return `${this._systemName}[${entityCount} entities]${perfInfo}`;
}
@@ -711,9 +737,9 @@ export abstract class EntitySystem<
/**
*
*
*
*
*
*
* @param entity
*/
protected onAdded(_entity: Entity): void {
@@ -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]> };
}
/**
@@ -1,6 +1,6 @@
import { EntitySystem } from './EntitySystem';
import { Matcher } from '../Utils/Matcher';
import { Time } from '../../Utils/Time';
import {EntitySystem} from "./EntitySystem";
import {Matcher} from "../Utils/Matcher";
import {Time} from "../../Utils/Time";
/**
*
@@ -55,4 +55,4 @@ export abstract class IntervalSystem extends EntitySystem {
protected getIntervalDelta(): number {
return this.interval + this.intervalRemainder;
}
}
}
@@ -1,6 +1,6 @@
import { EntitySystem } from './EntitySystem';
import { Entity } from '../Entity';
import { Matcher } from '../Utils/Matcher';
import {EntitySystem} from "./EntitySystem";
import {Entity} from "../Entity";
import {Matcher} from "../Utils/Matcher";
/**
*
@@ -8,7 +8,7 @@ import { Matcher } from '../Utils/Matcher';
*
*/
export abstract class PassiveSystem extends EntitySystem {
constructor(matcher?: Matcher) {
super(matcher);
}
@@ -1,6 +1,6 @@
import { EntitySystem } from './EntitySystem';
import { Entity } from '../Entity';
import { Matcher } from '../Utils/Matcher';
import {EntitySystem} from "./EntitySystem";
import {Entity} from "../Entity";
import {Matcher} from "../Utils/Matcher";
/**
*
@@ -8,7 +8,7 @@ import { Matcher } from '../Utils/Matcher';
* processSystem方法
*/
export abstract class ProcessingSystem extends EntitySystem {
constructor(matcher?: Matcher) {
super(matcher);
}
@@ -1,10 +1,10 @@
import { Entity } from '../Entity';
import { EntitySystem } from './EntitySystem';
import { Matcher } from '../Utils/Matcher';
import { Time } from '../../Utils/Time';
import { PlatformManager } from '../../Platform/PlatformManager';
import type { IPlatformAdapter, PlatformWorker } from '../../Platform/IPlatformAdapter';
import { getSystemInstanceTypeName } from '../Decorators';
import {Entity} from "../Entity";
import {EntitySystem} from "./EntitySystem";
import {Matcher} from "../Utils/Matcher";
import {Time} from "../../Utils/Time";
import {PlatformManager} from "../../Platform/PlatformManager";
import type {IPlatformAdapter, PlatformWorker} from "../../Platform/IPlatformAdapter";
import {getSystemInstanceTypeName} from "../Decorators";
/**
* Worker处理函数类型
@@ -188,7 +188,7 @@ export type SharedArrayBufferProcessFunction = (
* ```
*/
export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem {
protected config: Required<Omit<WorkerSystemConfig, 'systemConfig' | 'entitiesPerWorker'>> & {
protected config: Required<Omit<WorkerSystemConfig, "systemConfig" | "entitiesPerWorker">> & {
systemConfig?: any;
entitiesPerWorker?: number;
};
@@ -197,7 +197,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
protected sharedBuffer: SharedArrayBuffer | null = null;
protected sharedFloatArray: Float32Array | null = null;
private platformAdapter: IPlatformAdapter;
private hasLoggedSyncMode = false;
private hasLoggedSyncMode = false;
constructor(matcher?: Matcher, config: WorkerSystemConfig = {}) {
super(matcher);
@@ -219,7 +219,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
enableWorker: config.enableWorker ?? true,
workerCount: validatedWorkerCount,
systemConfig: config.systemConfig,
...(config.entitiesPerWorker !== undefined && { entitiesPerWorker: config.entitiesPerWorker }),
...(config.entitiesPerWorker !== undefined && {entitiesPerWorker: config.entitiesPerWorker}),
useSharedArrayBuffer: config.useSharedArrayBuffer ?? this.isSharedArrayBufferSupported(),
entityDataSize: config.entityDataSize ?? this.getDefaultEntityDataSize(),
maxEntities: config.maxEntities ?? 10000
@@ -305,7 +305,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
// 在WorkerEntitySystem中处理平台相关逻辑
const workers: PlatformWorker[] = [];
const platformConfig = this.platformAdapter.getPlatformConfig();
const fullScript = (platformConfig.workerScriptPrefix || '') + script;
const fullScript = (platformConfig.workerScriptPrefix || "") + script;
for (let i = 0; i < this.config.workerCount; i++) {
try {
@@ -336,7 +336,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
// 提取函数体部分(去掉方法签名)
const functionBodyMatch = methodStr.match(/\{([\s\S]*)\}/);
if (!functionBodyMatch) {
throw new Error('无法解析workerProcess方法');
throw new Error("无法解析workerProcess方法");
}
const functionBody = functionBodyMatch[1];
@@ -344,13 +344,13 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
// 获取SharedArrayBuffer处理函数的字符串
const sharedProcessMethod = this.getSharedArrayBufferProcessFunction?.() || null;
let sharedProcessFunctionBody = '';
let sharedProcessFunctionBody = "";
if (sharedProcessMethod) {
const sharedMethodStr = sharedProcessMethod.toString();
const sharedFunctionBodyMatch = sharedMethodStr.match(/\{([\s\S]*)\}/);
if (sharedFunctionBodyMatch) {
sharedProcessFunctionBody = sharedFunctionBodyMatch[1] ?? '';
sharedProcessFunctionBody = sharedFunctionBodyMatch[1] ?? "";
}
}
@@ -414,7 +414,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
${sharedProcessFunctionBody}
};
userProcessFunction(sharedFloatArray, startIndex, endIndex, deltaTime, systemConfig);
` : ``}
` : ""}
}
`;
}
@@ -465,7 +465,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
*/
private async processWithSharedArrayBuffer(entities: readonly Entity[]): Promise<void> {
if (!this.sharedFloatArray) {
throw new Error('SharedArrayBuffer not initialized');
throw new Error("SharedArrayBuffer not initialized");
}
// 1. 将实体数据写入SharedArrayBuffer
@@ -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;
@@ -533,8 +533,8 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
// 3. 结果应用阶段
// 处理Promise返回值
if (results && typeof (results as any).then === 'function') {
(results as Promise<TEntityData[]>).then(finalResults => {
if (results && typeof (results as any).then === "function") {
(results as Promise<TEntityData[]>).then((finalResults) => {
entities.forEach((entity, index) => {
this.applyResult(entity, finalResults[index]!);
});
@@ -721,7 +721,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
* Worker配置
*/
public updateConfig(newConfig: Partial<WorkerSystemConfig>): void {
const oldConfig = { ...this.config };
const oldConfig = {...this.config};
// 如果更新了workerCount,需要验证并调整
if (newConfig.workerCount !== undefined) {
@@ -812,22 +812,22 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
isProcessing: boolean;
sharedArrayBufferSupported: boolean;
sharedArrayBufferEnabled: boolean;
currentMode: 'shared-buffer' | 'worker' | 'sync';
} {
let currentMode: 'shared-buffer' | 'worker' | 'sync' = 'sync';
currentMode: "shared-buffer" | "worker" | "sync";
} {
let currentMode: "shared-buffer" | "worker" | "sync" = "sync";
if (this.config.enableWorker && this.workerPool) {
if (this.config.useSharedArrayBuffer && this.sharedFloatArray && this.isSharedArrayBufferSupported()) {
currentMode = 'shared-buffer';
currentMode = "shared-buffer";
} else {
currentMode = 'worker';
currentMode = "worker";
}
}
return {
enabled: this.config.enableWorker,
workerCount: this.config.workerCount,
...(this.config.entitiesPerWorker !== undefined && { entitiesPerWorker: this.config.entitiesPerWorker }),
...(this.config.entitiesPerWorker !== undefined && {entitiesPerWorker: this.config.entitiesPerWorker}),
maxSystemWorkerCount: this.getMaxSystemWorkerCount(),
isProcessing: this.isProcessing,
sharedArrayBufferSupported: this.isSharedArrayBufferSupported(),
@@ -890,7 +890,7 @@ class PlatformWorkerPool {
return new Promise((resolve, reject) => {
const task = {
id: `shared-task-${++this.taskCounter}`,
data: { ...data, type: 'shared' },
data: {...data, type: "shared"},
resolve: () => resolve(), // SharedArrayBuffer不需要返回数据
reject
};
+6 -6
View File
@@ -1,13 +1,13 @@
// ECS系统导出
export { EntitySystem } from './EntitySystem';
export { ProcessingSystem } from './ProcessingSystem';
export { PassiveSystem } from './PassiveSystem';
export { IntervalSystem } from './IntervalSystem';
export { WorkerEntitySystem } from './WorkerEntitySystem';
export {EntitySystem} from "./EntitySystem";
export {ProcessingSystem} from "./ProcessingSystem";
export {PassiveSystem} from "./PassiveSystem";
export {IntervalSystem} from "./IntervalSystem";
export {WorkerEntitySystem} from "./WorkerEntitySystem";
// Worker系统相关类型导出
export type {
WorkerProcessFunction,
WorkerSystemConfig,
SharedArrayBufferProcessFunction
} from './WorkerEntitySystem';
} from "./WorkerEntitySystem";
+4 -4
View File
@@ -4,10 +4,10 @@
* Entity类
*/
import { Entity } from './Entity';
import type { Component } from './Component';
import type { ComponentType } from './Core/ComponentStorage';
import type { ComponentConstructor, ComponentInstance } from '../Types/TypeHelpers';
import {Entity} from "./Entity";
import type {Component} from "./Component";
import type {ComponentType} from "./Core/ComponentStorage";
import type {ComponentConstructor, ComponentInstance} from "../Types/TypeHelpers";
/**
*
@@ -25,7 +25,7 @@ export interface BitMask64Data {
export class BitMask64Utils {
/** 零掩码常量,所有位都为0 */
public static readonly ZERO: Readonly<BitMask64Data> = { base: [0, 0] };
public static readonly ZERO: Readonly<BitMask64Data> = {base: [0, 0]};
/**
* 64
@@ -37,7 +37,7 @@ export class BitMask64Utils {
if (bitIndex < 0) {
throw new Error(`Bit index ${bitIndex} out of range [0, ∞)`);
}
const mask: BitMask64Data = { base: [0, 0] };
const mask: BitMask64Data = {base: [0, 0]};
BitMask64Utils.setBit(mask, bitIndex);
return mask;
}
@@ -48,7 +48,7 @@ export class BitMask64Utils {
* @returns 32320
*/
public static fromNumber(value: number): BitMask64Data {
return { base: [value >>> 0, 0] };
return {base: [value >>> 0, 0]};
}
/**
@@ -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)})
};
}
@@ -396,7 +396,7 @@ export class BitMask64Utils {
public static toString(mask: BitMask64Data, radix: 2 | 16 = 2, printHead: boolean = false): string {
if(radix != 2 && radix != 16) radix = 2;
const totalLength = mask.segments?.length ?? 0;
let result: string = '';
let result: string = "";
if(printHead){
let paddingLength = 0;
if(radix === 2){
@@ -405,38 +405,38 @@ export class BitMask64Utils {
paddingLength = 16 + 2 + 1;
}
for (let i = 0; i <= totalLength; i++) {
const title = i === 0 ? '0 (Base):' : `${i} (${64 * i}):`;
const title = i === 0 ? "0 (Base):" : `${i} (${64 * i}):`;
result += title.toString().padEnd(paddingLength);
}
result += '\n';
result += "\n";
}
for (let i = -1; i < totalLength; i++) {
let segResult = '';
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');
segResult = hiBits + '_' + loBits; //高低位之间使用_隔离
const hiBits = hi.toString(2).padStart(32, "0");
const loBits = lo.toString(2).padStart(32, "0");
segResult = hiBits + "_" + loBits; //高低位之间使用_隔离
}else{
let hiBits = hi ? hi.toString(16).toUpperCase() : '';
let hiBits = hi ? hi.toString(16).toUpperCase() : "";
if(printHead){
// 存在标头,则输出高位之前需要补齐位数
hiBits = hiBits.padStart(8, '0');
hiBits = hiBits.padStart(8, "0");
}
let loBits = lo.toString(16).toUpperCase();
if(hiBits){
// 存在高位 则输出低位之前需要补齐位数
loBits = loBits.padStart(8, '0');
loBits = loBits.padStart(8, "0");
}
segResult = '0x' + hiBits + loBits;
segResult = "0x" + hiBits + loBits;
}
if(i === -1)
result += segResult;
else
result += ' ' + segResult; // 不同段之间使用空格隔离
result += " " + segResult; // 不同段之间使用空格隔离
}
return result;
}
@@ -493,4 +493,4 @@ export class BitMask64Utils {
return segments[targetSegIndex] ?? null;
}
}
}
}
@@ -1,4 +1,4 @@
import { BitMask64Data } from "./BigIntCompatibility";
import {BitMask64Data} from "./BigIntCompatibility";
// FlatHashMapFast.ts
+28 -28
View File
@@ -1,4 +1,4 @@
import { SegmentPart, BitMask64Data, BitMask64Utils } from './BigIntCompatibility';
import {SegmentPart, BitMask64Data, BitMask64Utils} from "./BigIntCompatibility";
/**
*
@@ -13,11 +13,11 @@ export class Bits {
* @param initialValue BitMask64Data对象
*/
constructor(initialValue?: BitMask64Data | number | string) {
if (initialValue && typeof initialValue === 'object') {
if (initialValue && typeof initialValue === "object") {
this._value = BitMask64Utils.clone(initialValue);
} else if (typeof initialValue === 'number') {
} else if (typeof initialValue === "number") {
this._value = BitMask64Utils.fromNumber(initialValue);
} else if (typeof initialValue === 'string') {
} else if (typeof initialValue === "string") {
const num = parseInt(initialValue, 10);
this._value = BitMask64Utils.fromNumber(num);
} else {
@@ -33,7 +33,7 @@ export class Bits {
*/
public set(index: number): void {
if (index < 0) {
throw new Error('Bit index cannot be negative');
throw new Error("Bit index cannot be negative");
}
BitMask64Utils.setBit(this._value, index);
@@ -46,7 +46,7 @@ export class Bits {
*/
public clear(index: number): void {
if (index < 0) {
throw new Error('Bit index cannot be negative');
throw new Error("Bit index cannot be negative");
}
BitMask64Utils.clearBit(this._value, index);
@@ -156,10 +156,10 @@ export class Bits {
if (maxBits > 64) {
maxBits = 64;
}
const result = new Bits();
BitMask64Utils.copy(this._value, result._value);
if (maxBits <= 32) {
const mask = (1 << maxBits) - 1;
result._value.base[SegmentPart.LOW] = (~result._value.base[SegmentPart.LOW]) & mask;
@@ -174,7 +174,7 @@ export class Bits {
result._value.base[SegmentPart.HIGH] = ~result._value.base[SegmentPart.HIGH];
}
}
return result;
}
@@ -207,9 +207,9 @@ export class Bits {
* @param value BitMask64Data对象
*/
public setValue(value: BitMask64Data | number | string): void {
if (typeof value === 'object') {
if (typeof value === "object") {
BitMask64Utils.copy(value, this._value);
} else if (typeof value === 'number') {
} else if (typeof value === "number") {
this._value = BitMask64Utils.fromNumber(value);
} else {
const num = parseInt(value, 10);
@@ -228,7 +228,7 @@ export class Bits {
bits.push(i.toString());
}
}
return `Bits[${bits.join(', ')}]`;
return `Bits[${bits.join(", ")}]`;
}
/**
@@ -240,11 +240,11 @@ export class Bits {
if(maxBits == 0){
maxBits = 64 + (this._value.segments ? this._value.segments.length * 64 : 0);
}
let result = '';
let result = "";
for (let i = maxBits - 1; i >= 0; i--) {
result += this.get(i) ? '1' : '0';
result += this.get(i) ? "1" : "0";
if (i % 8 === 0 && i > 0) {
result += ' ';
result += " ";
}
}
return result;
@@ -264,17 +264,17 @@ export class Bits {
* @returns
*/
public static fromBinaryString(binaryString: string): Bits {
const cleanString = binaryString.replace(/\s/g, '');
const cleanString = binaryString.replace(/\s/g, "");
let data: BitMask64Data;
if (cleanString.length <= 32) {
const num = parseInt(cleanString, 2);
data = { base: [num >>> 0, 0] };
data = {base: [num >>> 0, 0]};
} else {
const loBits = cleanString.substring(cleanString.length - 32);
const hiBits = cleanString.substring(0, cleanString.length - 32);
const lo = parseInt(loBits, 2);
const hi = parseInt(hiBits, 2);
data = { base: [lo >>> 0, hi >>> 0] };
data = {base: [lo >>> 0, hi >>> 0]};
}
return new Bits(data);
}
@@ -285,17 +285,17 @@ export class Bits {
* @returns
*/
public static fromHexString(hexString: string): Bits {
const cleanString = hexString.replace(/^0x/i, '');
const cleanString = hexString.replace(/^0x/i, "");
let data: BitMask64Data;
if (cleanString.length <= 8) {
const num = parseInt(cleanString, 16);
data = { base: [num >>> 0, 0] };
data = {base: [num >>> 0, 0]};
} else {
const loBits = cleanString.substring(cleanString.length - 8);
const hiBits = cleanString.substring(0, cleanString.length - 8);
const lo = parseInt(loBits, 16);
const hi = parseInt(hiBits, 16);
data = { base: [lo >>> 0, hi >>> 0] };
data = {base: [lo >>> 0, hi >>> 0]};
}
return new Bits(data);
}
@@ -317,7 +317,7 @@ export class Bits {
if (BitMask64Utils.isZero(this._value)) {
return -1;
}
if (this._value.base[SegmentPart.HIGH] !== 0) {
for (let i = 31; i >= 0; i--) {
if ((this._value.base[SegmentPart.HIGH] & (1 << i)) !== 0) {
@@ -325,13 +325,13 @@ export class Bits {
}
}
}
for (let i = 31; i >= 0; i--) {
if ((this._value.base[SegmentPart.LOW] & (1 << i)) !== 0) {
return i;
}
}
return -1;
}
@@ -343,19 +343,19 @@ export class Bits {
if (BitMask64Utils.isZero(this._value)) {
return -1;
}
for (let i = 0; i < 32; i++) {
if ((this._value.base[SegmentPart.LOW] & (1 << i)) !== 0) {
return i;
}
}
for (let i = 0; i < 32; i++) {
if ((this._value.base[SegmentPart.HIGH] & (1 << i)) !== 0) {
return i + 32;
}
}
return -1;
}
}
}
+101 -89
View File
@@ -1,20 +1,20 @@
import { Entity } from '../Entity';
import { ComponentType, ComponentRegistry } from '../Core/ComponentStorage';
import { BitMask64Utils, BitMask64Data } from './BigIntCompatibility';
import { SparseSet } from './SparseSet';
import { Pool } from '../../Utils/Pool/Pool';
import { IPoolable } from '../../Utils/Pool/IPoolable';
import {Entity} from "../Entity";
import {ComponentType, ComponentRegistry} from "../Core/ComponentStorage";
import {BitMask64Utils, BitMask64Data} from "./BigIntCompatibility";
import {SparseSet} from "./SparseSet";
import {Pool} from "../../Utils/Pool/Pool";
import {IPoolable} from "../../Utils/Pool/IPoolable";
/**
*
*
*
* IPoolable接口
*/
class PoolableEntitySet extends Set<Entity> implements IPoolable {
constructor(..._args: unknown[]) {
super();
}
reset(): void {
this.clear();
}
@@ -22,9 +22,9 @@ class PoolableEntitySet extends Set<Entity> implements IPoolable {
/**
*
*
*
*
*
*
*
* -
* -
@@ -33,42 +33,42 @@ class PoolableEntitySet extends Set<Entity> implements IPoolable {
export class ComponentSparseSet {
/**
*
*
*
* O(1)
*/
private _entities: SparseSet<Entity>;
/**
*
*
*
*
*
*/
private _componentMasks: BitMask64Data[] = [];
/**
*
*
*
*
*/
private _componentToEntities = new Map<ComponentType, PoolableEntitySet>();
/**
*
*
*
* 使core库的Pool系统来管理PoolableEntitySet对象的复用
*/
private static _entitySetPool = Pool.getPool(PoolableEntitySet, 50, 512);
constructor() {
this._entities = new SparseSet<Entity>();
}
/**
*
*
*
*
*
*
* @param entity
*/
public addEntity(entity: Entity): void {
@@ -76,44 +76,44 @@ export class ComponentSparseSet {
if (this._entities.has(entity)) {
this.removeEntity(entity);
}
let componentMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
const componentMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
const entityComponents = new Set<ComponentType>();
// 分析实体组件并构建位掩码
for (const component of entity.components) {
const componentType = component.constructor as ComponentType;
entityComponents.add(componentType);
// 确保组件类型已注册
if (!ComponentRegistry.isRegistered(componentType)) {
ComponentRegistry.register(componentType);
}
// 获取组件位掩码并合并
const bitMask = ComponentRegistry.getBitMask(componentType);
BitMask64Utils.orInPlace(componentMask, bitMask);
}
// 添加实体到稀疏集合
this._entities.add(entity);
const entityIndex = this._entities.getIndex(entity)!;
// 确保位掩码数组有足够空间
while (this._componentMasks.length <= entityIndex) {
this._componentMasks.push(BitMask64Utils.clone(BitMask64Utils.ZERO));
}
this._componentMasks[entityIndex] = componentMask;
// 更新组件类型到实体的映射
this.updateComponentMappings(entity, entityComponents, true);
}
/**
*
*
*
*
*
*
* @param entity
*/
public removeEntity(entity: Entity): void {
@@ -121,16 +121,16 @@ export class ComponentSparseSet {
if (entityIndex === undefined) {
return; // 实体不存在
}
// 获取实体的组件类型集合
const entityComponents = this.getEntityComponentTypes(entity);
// 更新组件类型到实体的映射
this.updateComponentMappings(entity, entityComponents, false);
// 从稀疏集合中移除实体
this._entities.remove(entity);
// 维护位掩码数组的紧凑性
const lastIndex = this._componentMasks.length - 1;
if (entityIndex !== lastIndex) {
@@ -139,10 +139,10 @@ export class ComponentSparseSet {
}
this._componentMasks.pop();
}
/**
*
*
*
* @param componentType
* @returns
*/
@@ -150,12 +150,12 @@ export class ComponentSparseSet {
const entities = this._componentToEntities.get(componentType);
return entities ? new Set(entities) : new Set<Entity>();
}
/**
* AND操作
*
*
*
*
*
* @param componentTypes
* @returns
*/
@@ -163,13 +163,13 @@ export class ComponentSparseSet {
if (componentTypes.length === 0) {
return new Set<Entity>();
}
if (componentTypes.length === 1) {
return this.queryByComponent(componentTypes[0]!);
}
// 构建目标位掩码
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>(); // 未注册的组件类型,结果为空
@@ -177,9 +177,9 @@ export class ComponentSparseSet {
const bitMask = ComponentRegistry.getBitMask(componentType);
BitMask64Utils.orInPlace(targetMask, bitMask);
}
const result = ComponentSparseSet._entitySetPool.obtain();
// 遍历所有实体,检查位掩码匹配
this._entities.forEach((entity, index) => {
const entityMask = this._componentMasks[index]!;
@@ -187,15 +187,15 @@ export class ComponentSparseSet {
result.add(entity);
}
});
return result;
}
/**
* OR操作
*
*
*
*
*
* @param componentTypes
* @returns
*/
@@ -203,26 +203,26 @@ export class ComponentSparseSet {
if (componentTypes.length === 0) {
return new Set<Entity>();
}
if (componentTypes.length === 1) {
return this.queryByComponent(componentTypes[0]!);
}
// 构建目标位掩码
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);
BitMask64Utils.orInPlace(targetMask, bitMask);
}
}
if (BitMask64Utils.equals(targetMask, BitMask64Utils.ZERO)) {
return new Set<Entity>(); // 没有有效的组件类型
}
const result = ComponentSparseSet._entitySetPool.obtain();
// 遍历所有实体,检查位掩码匹配
this._entities.forEach((entity, index) => {
const entityMask = this._componentMasks[index]!;
@@ -230,13 +230,13 @@ export class ComponentSparseSet {
result.add(entity);
}
});
return result;
}
/**
*
*
*
* @param entity
* @param componentType
* @returns
@@ -246,20 +246,20 @@ export class ComponentSparseSet {
if (entityIndex === undefined) {
return false;
}
if (!ComponentRegistry.isRegistered(componentType)) {
return false;
}
const entityMask = this._componentMasks[entityIndex]!;
const componentMask = ComponentRegistry.getBitMask(componentType);
return BitMask64Utils.hasAny(entityMask, componentMask);
}
/**
*
*
*
* @param entity
* @returns undefined
*/
@@ -270,33 +270,45 @@ export class ComponentSparseSet {
}
return this._componentMasks[entityIndex];
}
/**
*
*
*
*
*
*
* @returns
*/
public getAllEntities(): Entity[] {
public queryAllEntities(): Entity[] {
return this._entities.toArray();
}
/**
*
*
* @deprecated 使 queryAllEntities()
* @see {@link queryAllEntities}
*/
public getAllEntities(): Entity[] {
return this.queryAllEntities();
}
/**
*
*/
public get size(): number {
return this._entities.size;
}
/**
*
*/
public get isEmpty(): boolean {
return this._entities.isEmpty;
}
/**
*
*
*
* @param callback
*/
public forEach(callback: (entity: Entity, mask: BitMask64Data, index: number) => void): void {
@@ -304,21 +316,21 @@ export class ComponentSparseSet {
callback(entity, this._componentMasks[index]!, index);
});
}
/**
*
*/
public clear(): void {
this._entities.clear();
this._componentMasks.length = 0;
// 清理时将所有持有的实体集合返回到池中
for (const entitySet of this._componentToEntities.values()) {
ComponentSparseSet._entitySetPool.release(entitySet);
}
this._componentToEntities.clear();
}
/**
* 使
*/
@@ -327,15 +339,15 @@ export class ComponentSparseSet {
masksMemory: number;
mappingsMemory: number;
totalMemory: number;
} {
} {
const entitiesStats = this._entities.getMemoryStats();
const masksMemory = this._componentMasks.length * 16; // 估计每个BigInt 16字节
let mappingsMemory = this._componentToEntities.size * 16; // Map条目开销
for (const entitySet of this._componentToEntities.values()) {
mappingsMemory += entitySet.size * 8; // 每个实体引用8字节
}
return {
entitiesMemory: entitiesStats.totalMemory,
masksMemory,
@@ -343,7 +355,7 @@ export class ComponentSparseSet {
totalMemory: entitiesStats.totalMemory + masksMemory + mappingsMemory
};
}
/**
*
*/
@@ -352,12 +364,12 @@ export class ComponentSparseSet {
if (!this._entities.validate()) {
return false;
}
// 检查位掩码数组长度一致性
if (this._componentMasks.length !== this._entities.size) {
return false;
}
// 检查组件映射的一致性
const allMappedEntities = new Set<Entity>();
for (const entitySet of this._componentToEntities.values()) {
@@ -365,17 +377,17 @@ export class ComponentSparseSet {
allMappedEntities.add(entity);
}
}
// 验证映射中的实体都在稀疏集合中
for (const entity of allMappedEntities) {
if (!this._entities.has(entity)) {
return false;
}
}
return true;
}
/**
*
*/
@@ -386,18 +398,18 @@ export class ComponentSparseSet {
}
return componentTypes;
}
/**
*
*/
private updateComponentMappings(
entity: Entity,
componentTypes: Set<ComponentType>,
entity: Entity,
componentTypes: Set<ComponentType>,
add: boolean
): void {
for (const componentType of componentTypes) {
let entities = this._componentToEntities.get(componentType);
if (add) {
if (!entities) {
entities = ComponentSparseSet._entitySetPool.obtain();
@@ -415,5 +427,5 @@ export class ComponentSparseSet {
}
}
}
}
}
+14 -14
View File
@@ -1,5 +1,5 @@
import { Entity } from '../Entity';
import { Component } from '../Component';
import {Entity} from "../Entity";
import {Component} from "../Component";
/**
*
@@ -45,7 +45,7 @@ export class EntityList {
this.buffer.push(entity);
this._idToEntity.set(entity.id, entity);
// 更新名称索引
this.updateNameIndex(entity, true);
}
@@ -67,10 +67,10 @@ export class EntityList {
if (index !== -1) {
this.buffer.splice(index, 1);
this._idToEntity.delete(entity.id);
// 更新名称索引
this.updateNameIndex(entity, false);
// 回收实体ID到ID池
if (this._scene && this._scene.identifierPool) {
this._scene.identifierPool.checkIn(entity.id);
@@ -84,19 +84,19 @@ export class EntityList {
public removeAllEntities(): void {
// 收集所有实体ID用于回收
const idsToRecycle: number[] = [];
for (let i = this.buffer.length - 1; i >= 0; i--) {
idsToRecycle.push(this.buffer[i]!.id);
this.buffer[i]!.destroy();
}
// 批量回收ID
if (this._scene && this._scene.identifierPool) {
for (const id of idsToRecycle) {
this._scene.identifierPool.checkIn(id);
}
}
this.buffer.length = 0;
this._idToEntity.clear();
this._nameToEntities.clear();
@@ -170,13 +170,13 @@ export class EntityList {
*/
public findEntitiesByTag(tag: number): Entity[] {
const result: Entity[] = [];
for (const entity of this.buffer) {
if (entity.tag === tag) {
result.push(entity);
}
}
return result;
}
@@ -187,13 +187,13 @@ export class EntityList {
*/
public findEntitiesWithComponent<T extends Component>(componentType: new (...args: any[]) => T): Entity[] {
const result: Entity[] = [];
for (const entity of this.buffer) {
if (entity.hasComponent(componentType)) {
result.push(entity);
}
}
return result;
}
@@ -243,7 +243,7 @@ export class EntityList {
const index = entities.indexOf(entity);
if (index !== -1) {
entities.splice(index, 1);
// 如果数组为空,删除映射
if (entities.length === 0) {
this._nameToEntities.delete(entity.name);
@@ -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) {
@@ -1,13 +1,13 @@
import { EntitySystem } from '../Systems/EntitySystem';
import { createLogger } from '../../Utils/Logger';
import { getSystemInstanceTypeName } from '../Decorators';
import {EntitySystem} from "../Systems/EntitySystem";
import {createLogger} from "../../Utils/Logger";
import {getSystemInstanceTypeName} from "../Decorators";
/**
*
*
*/
export class EntityProcessorList {
private static readonly _logger = createLogger('EntityProcessorList');
private static readonly _logger = createLogger("EntityProcessorList");
private _processors: EntitySystem[] = [];
private _isDirty = false;
@@ -53,7 +53,7 @@ export class EntityProcessorList {
/**
*
*
*
*
*/
public begin(): void {
+64 -64
View File
@@ -1,22 +1,22 @@
/**
* ID池管理器
*
*
* ID的分配和回收
* ID由索引和版本组成ID被回收时版本会递增
*
*
* 65535166553516
* 42亿ID组合ECS大规模实体需求
*
*
* @example
* ```typescript
* const pool = new IdentifierPool();
*
*
* // 分配ID
* const id = pool.checkOut(); // 例如: 65536 (版本1,索引0)
*
*
* // 回收ID
* pool.checkIn(id);
*
*
* // 验证ID是否有效
* const isValid = pool.isValid(id); // false,因为版本已递增
* ```
@@ -26,18 +26,18 @@ export class IdentifierPool {
*
*/
private _nextAvailableIndex = 0;
/**
*
*/
private _freeIndices: number[] = [];
/**
*
* Map
*/
private _generations = new Map<number, number>();
/**
*
* ID
@@ -47,30 +47,30 @@ export class IdentifierPool {
generation: number;
timestamp: number;
}> = [];
/**
*
*/
private _recycleDelay: number = 100;
/**
* 16
* 16 + 16 = 32ID
*
*/
private static readonly MAX_INDEX = 0xFFFF; // 65535
/**
* 16
*/
private static readonly MAX_GENERATION = 0xFFFF; // 65535
/**
*
*
*/
private _expansionBlockSize: number;
/**
*
*/
@@ -83,32 +83,32 @@ export class IdentifierPool {
/**
*
*
*
* @param recycleDelay 100ms
* @param expansionBlockSize 1024
*/
constructor(recycleDelay: number = 100, expansionBlockSize: number = 1024) {
this._recycleDelay = recycleDelay;
this._expansionBlockSize = expansionBlockSize;
// 预分配第一个块的世代信息
this._preAllocateGenerations(0, this._expansionBlockSize);
}
/**
* ID
*
*
* 32ID1616
*
*
* @returns ID
* @throws {Error}
*/
public checkOut(): number {
// 处理延迟回收队列
this._processDelayedRecycle();
let index: number;
if (this._freeIndices.length > 0) {
// 重用回收的索引
index = this._freeIndices.pop()!;
@@ -117,69 +117,69 @@ export class IdentifierPool {
if (this._nextAvailableIndex > IdentifierPool.MAX_INDEX) {
throw new Error(
`实体索引已达到框架设计限制 (${IdentifierPool.MAX_INDEX})。` +
`这意味着您已经分配了超过65535个不同的实体索引。` +
`这是16位索引设计的限制,考虑优化实体回收策略或升级到64位ID设计。`
"这意味着您已经分配了超过65535个不同的实体索引。" +
"这是16位索引设计的限制,考虑优化实体回收策略或升级到64位ID设计。"
);
}
index = this._nextAvailableIndex++;
// 按需扩展世代存储
this._ensureGenerationCapacity(index);
}
const generation = this._generations.get(index) || 1;
this._stats.totalAllocated++;
this._stats.currentActive++;
return this._packId(index, generation);
}
/**
* ID
*
*
* ID的有效性后
* ID不会立即可重用
*
*
* @param id ID
* @returns ID是否有效且未被重复回收
*/
public checkIn(id: number): boolean {
const index = this._unpackIndex(id);
const generation = this._unpackGeneration(id);
// 验证ID有效性
if (!this._isValidId(index, generation)) {
return false;
}
// 检查是否已经在待回收队列中
const alreadyPending = this._pendingRecycle.some(
item => item.index === index && item.generation === generation
(item) => item.index === index && item.generation === generation
);
if (alreadyPending) {
return false; // 已经在回收队列中,拒绝重复回收
}
// 加入延迟回收队列
this._pendingRecycle.push({
index,
generation,
timestamp: Date.now()
});
this._stats.currentActive--;
this._stats.totalRecycled++;
return true;
}
/**
* ID是否有效
*
*
* ID的索引和世代版本是否匹配当前状态
*
*
* @param id ID
* @returns ID是否有效
*/
@@ -191,7 +191,7 @@ export class IdentifierPool {
/**
*
*
*
* @returns
*/
public getStats(): {
@@ -217,20 +217,20 @@ export class IdentifierPool {
averageGeneration: number;
/** 世代存储大小 */
generationStorageSize: number;
} {
} {
// 计算平均世代版本
let totalGeneration = 0;
let generationCount = 0;
for (const [index, generation] of this._generations) {
if (index < this._nextAvailableIndex) {
totalGeneration += generation;
generationCount++;
}
}
const averageGeneration = generationCount > 0
? totalGeneration / generationCount
const averageGeneration = generationCount > 0
? totalGeneration / generationCount
: 1;
return {
@@ -250,7 +250,7 @@ export class IdentifierPool {
/**
*
*
*
*
*
*/
@@ -260,19 +260,19 @@ export class IdentifierPool {
/**
*
*
*
*
*
*
* @param forceAll
* @private
*/
private _processDelayedRecycle(forceAll: boolean = false): void {
if (this._pendingRecycle.length === 0) return;
const now = Date.now();
const readyToRecycle: typeof this._pendingRecycle = [];
const stillPending: typeof this._pendingRecycle = [];
// 分离已到期和未到期的项
for (const item of this._pendingRecycle) {
if (forceAll || now - item.timestamp >= this._recycleDelay) {
@@ -281,33 +281,33 @@ export class IdentifierPool {
stillPending.push(item);
}
}
// 处理到期的回收项
for (const item of readyToRecycle) {
// 再次验证ID有效性(防止重复回收)
if (this._isValidId(item.index, item.generation)) {
// 递增世代版本
let newGeneration = item.generation + 1;
// 防止世代版本溢出
if (newGeneration > IdentifierPool.MAX_GENERATION) {
newGeneration = 1; // 重置为1而不是0
}
this._generations.set(item.index, newGeneration);
// 添加到空闲列表
this._freeIndices.push(item.index);
}
}
// 更新待回收队列
this._pendingRecycle = stillPending;
}
/**
*
*
*
* @param startIndex
* @param count
* @private
@@ -324,7 +324,7 @@ export class IdentifierPool {
/**
*
*
*
* @param index
* @private
*/
@@ -332,7 +332,7 @@ export class IdentifierPool {
if (!this._generations.has(index)) {
// 计算需要扩展的起始位置
const expansionStart = Math.floor(index / this._expansionBlockSize) * this._expansionBlockSize;
// 预分配一个块
this._preAllocateGenerations(expansionStart, this._expansionBlockSize);
}
@@ -340,7 +340,7 @@ export class IdentifierPool {
/**
* 使
*
*
* @returns 使
* @private
*/
@@ -348,13 +348,13 @@ export class IdentifierPool {
const generationMapSize = this._generations.size * 16; // Map overhead + number pair
const freeIndicesSize = this._freeIndices.length * 8;
const pendingRecycleSize = this._pendingRecycle.length * 32;
return generationMapSize + freeIndicesSize + pendingRecycleSize;
}
/**
* 32ID
*
*
* @param index 16
* @param generation 16
* @returns 32ID
@@ -366,7 +366,7 @@ export class IdentifierPool {
/**
* ID中解包索引
*
*
* @param id 32ID
* @returns 16
* @private
@@ -377,7 +377,7 @@ export class IdentifierPool {
/**
* ID中解包世代版本
*
*
* @param id 32ID
* @returns 16
* @private
@@ -388,7 +388,7 @@ export class IdentifierPool {
/**
* ID有效性检查
*
*
* @param index
* @param generation
* @returns
@@ -398,8 +398,8 @@ export class IdentifierPool {
if (index < 0 || index >= this._nextAvailableIndex) {
return false;
}
const currentGeneration = this._generations.get(index);
return currentGeneration !== undefined && currentGeneration === generation;
}
}
}
+22 -22
View File
@@ -1,5 +1,5 @@
import { ComponentType } from '../Core/ComponentStorage';
import { getComponentTypeName } from '../Decorators';
import {ComponentType} from "../Core/ComponentStorage";
import {getComponentTypeName} from "../Decorators";
/**
*
@@ -15,15 +15,15 @@ export interface QueryCondition {
/**
*
*
*
*
*
*
* @example
* ```typescript
* const matcher = Matcher.all(Position, Velocity)
* .any(Health, Shield)
* .none(Dead);
*
*
* // 获取查询条件
* const condition = matcher.getCondition();
* ```
@@ -209,9 +209,9 @@ export class Matcher {
all: [...this.condition.all],
any: [...this.condition.any],
none: [...this.condition.none],
...(this.condition.tag !== undefined && { tag: this.condition.tag }),
...(this.condition.name !== undefined && { name: this.condition.name }),
...(this.condition.component !== undefined && { component: this.condition.component })
...(this.condition.tag !== undefined && {tag: this.condition.tag}),
...(this.condition.name !== undefined && {name: this.condition.name}),
...(this.condition.component !== undefined && {component: this.condition.component})
};
}
@@ -219,8 +219,8 @@ export class Matcher {
*
*/
public isEmpty(): boolean {
return this.condition.all.length === 0 &&
this.condition.any.length === 0 &&
return this.condition.all.length === 0 &&
this.condition.any.length === 0 &&
this.condition.none.length === 0 &&
this.condition.tag === undefined &&
this.condition.name === undefined &&
@@ -265,32 +265,32 @@ export class Matcher {
*/
public toString(): string {
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) {
parts.push(`tag(${this.condition.tag})`);
}
if (this.condition.name !== undefined) {
parts.push(`name(${this.condition.name})`);
}
if (this.condition.component !== undefined) {
parts.push(`component(${getComponentTypeName(this.condition.component)})`);
}
return `Matcher[${parts.join(' & ')}]`;
return `Matcher[${parts.join(" & ")}]`;
}
}
}
+55 -55
View File
@@ -1,22 +1,22 @@
/**
*
*
*
* O(1)
* 使访
*
*
* @template T
*
*
* @example
* ```typescript
* const sparseSet = new SparseSet<Entity>();
*
*
* sparseSet.add(entity1);
* sparseSet.add(entity2);
*
*
* if (sparseSet.has(entity1)) {
* sparseSet.remove(entity1);
* }
*
*
* sparseSet.forEach((entity, index) => {
* console.log(`Entity at index ${index}: ${entity.name}`);
* });
@@ -25,21 +25,21 @@
export class SparseSet<T> {
/**
*
*
*
*
*/
private _dense: T[] = [];
/**
*
*
*
* O(1)
*/
private _sparse = new Map<T, number>();
/**
*
*
*
* @param item
* @returns false表示元素已存在
*/
@@ -47,21 +47,21 @@ export class SparseSet<T> {
if (this._sparse.has(item)) {
return false; // 元素已存在
}
const index = this._dense.length;
this._dense.push(item);
this._sparse.set(item, index);
return true;
}
/**
*
*
*
* 使swap-and-pop技术保持数组紧凑性
* 1.
* 2.
* 3.
*
*
* @param item
* @returns false表示元素不存在
*/
@@ -70,72 +70,72 @@ export class SparseSet<T> {
if (index === undefined) {
return false; // 元素不存在
}
const lastIndex = this._dense.length - 1;
// 如果不是最后一个元素,则与最后一个元素交换
if (index !== lastIndex) {
const lastItem = this._dense[lastIndex]!;
this._dense[index] = lastItem;
this._sparse.set(lastItem, index);
}
// 移除最后一个元素
this._dense.pop();
this._sparse.delete(item);
return true;
}
/**
*
*
*
* @param item
* @returns
*/
public has(item: T): boolean {
return this._sparse.has(item);
}
/**
*
*
*
* @param item
* @returns undefined
*/
public getIndex(item: T): number | undefined {
return this._sparse.get(item);
}
/**
*
*
*
* @param index
* @returns undefined
*/
public getByIndex(index: number): T | undefined {
return this._dense[index];
}
/**
*
*/
public get size(): number {
return this._dense.length;
}
/**
*
*/
public get isEmpty(): boolean {
return this._dense.length === 0;
}
/**
*
*
*
*
*
*
*
* @param callback
*/
public forEach(callback: (item: T, index: number) => void): void {
@@ -143,10 +143,10 @@ export class SparseSet<T> {
callback(this._dense[i]!, i);
}
}
/**
*
*
*
* @param callback
* @returns
*/
@@ -157,10 +157,10 @@ export class SparseSet<T> {
}
return result;
}
/**
*
*
*
* @param predicate
* @returns
*/
@@ -173,10 +173,10 @@ export class SparseSet<T> {
}
return result;
}
/**
*
*
*
* @param predicate
* @returns undefined
*/
@@ -188,10 +188,10 @@ export class SparseSet<T> {
}
return undefined;
}
/**
*
*
*
* @param predicate
* @returns
*/
@@ -203,10 +203,10 @@ export class SparseSet<T> {
}
return false;
}
/**
*
*
*
* @param predicate
* @returns
*/
@@ -218,26 +218,26 @@ export class SparseSet<T> {
}
return true;
}
/**
*
*
*
*
*/
public getDenseArray(): readonly T[] {
return [...this._dense];
}
/**
* 使
*
*
*
* 使
*/
public getDenseArrayUnsafe(): readonly T[] {
return this._dense;
}
/**
*
*/
@@ -245,21 +245,21 @@ export class SparseSet<T> {
this._dense.length = 0;
this._sparse.clear();
}
/**
*
*/
public toArray(): T[] {
return [...this._dense];
}
/**
* Set
*/
public toSet(): Set<T> {
return new Set(this._dense);
}
/**
* 使
*/
@@ -267,20 +267,20 @@ 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字节
return {
denseArraySize,
sparseMapSize,
totalMemory: denseArraySize + sparseMapSize
};
}
/**
*
*
*
*
*/
public validate(): boolean {
@@ -288,7 +288,7 @@ export class SparseSet<T> {
if (this._dense.length !== this._sparse.size) {
return false;
}
// 检查映射关系的正确性
for (let i = 0; i < this._dense.length; i++) {
const item = this._dense[i]!;
@@ -297,14 +297,14 @@ export class SparseSet<T> {
return false;
}
}
// 检查稀疏映射中的所有项都在密集数组中
for (const [item, index] of this._sparse) {
if (index >= this._dense.length || this._dense[index] !== item) {
return false;
}
}
return true;
}
}
}
+8 -8
View File
@@ -1,9 +1,9 @@
// ECS工具类导出
export { EntityList } from './EntityList';
export { EntityProcessorList } from './EntityProcessorList';
export { IdentifierPool } from './IdentifierPool';
export { Matcher } from './Matcher';
export { Bits } from './Bits';
export { BitMask64Utils, BitMask64Data } from './BigIntCompatibility';
export { SparseSet } from './SparseSet';
export { ComponentSparseSet } from './ComponentSparseSet';
export {EntityList} from "./EntityList";
export {EntityProcessorList} from "./EntityProcessorList";
export {IdentifierPool} from "./IdentifierPool";
export {Matcher} from "./Matcher";
export {Bits} from "./Bits";
export {BitMask64Utils, BitMask64Data} from "./BigIntCompatibility";
export {SparseSet} from "./SparseSet";
export {ComponentSparseSet} from "./ComponentSparseSet";
+35 -35
View File
@@ -1,8 +1,8 @@
import { IScene } from './IScene';
import { Scene } from './Scene';
import { createLogger } from '../Utils/Logger';
import {IScene} from "./IScene";
import {Scene} from "./Scene";
import {createLogger} from "../Utils/Logger";
const logger = createLogger('World');
const logger = createLogger("World");
/**
*
@@ -13,22 +13,22 @@ export interface IGlobalSystem {
*
*/
readonly name: string;
/**
*
*/
initialize?(): void;
/**
*
*/
update(deltaTime?: number): void;
/**
*
*/
reset?(): void;
/**
*
*/
@@ -43,17 +43,17 @@ export interface IWorldConfig {
* World名称
*/
name?: string;
/**
*
*/
debug?: boolean;
/**
* Scene数量限制
*/
maxScenes?: number;
/**
* Scene
*/
@@ -62,22 +62,22 @@ export interface IWorldConfig {
/**
* World类 - ECS世界管理器
*
*
* World是Scene的容器World可以管理多个Scene
*
* - World
* -
* -
*
*
* @example
* ```typescript
* // 创建游戏房间的World
* const roomWorld = new World({ name: 'Room_001' });
*
*
* // 在World中创建Scene
* const gameScene = roomWorld.createScene('game', new Scene());
* const uiScene = roomWorld.createScene('ui', new Scene());
*
*
* // 更新整个World
* roomWorld.update(deltaTime);
* ```
@@ -93,13 +93,13 @@ export class World {
constructor(config: IWorldConfig = {}) {
this._config = {
name: 'World',
name: "World",
debug: false,
maxScenes: 10,
autoCleanup: true,
...config
};
this.name = this._config.name!;
this._createdAt = Date.now();
}
@@ -120,12 +120,12 @@ export class World {
// 如果没有提供Scene实例,创建默认Scene
const scene = sceneInstance || (new Scene() as unknown as T);
// 设置Scene的标识
if ('id' in scene) {
if ("id" in scene) {
(scene as any).id = sceneId;
}
if ('name' in scene && !scene.name) {
if ("name" in scene && !scene.name) {
scene.name = sceneId;
}
@@ -154,7 +154,7 @@ export class World {
// 清理Scene资源
scene.end();
this._scenes.delete(sceneId);
logger.info(`从World '${this.name}' 中移除Scene: ${sceneId}`);
return true;
}
@@ -244,7 +244,7 @@ export class World {
if (system.initialize) {
system.initialize();
}
logger.debug(`在World '${this.name}' 中添加全局System: ${system.name}`);
return system;
}
@@ -262,7 +262,7 @@ export class World {
if (system.reset) {
system.reset();
}
logger.debug(`从World '${this.name}' 中移除全局System: ${system.name}`);
return true;
}
@@ -290,14 +290,14 @@ export class World {
}
this._isActive = true;
// 启动所有全局System
for (const system of this._globalSystems) {
if (system.initialize) {
system.initialize();
}
}
logger.info(`启动World: ${this.name}`);
}
@@ -407,8 +407,8 @@ export class World {
activeSceneCount: this._activeScenes.size,
globalSystemCount: this._globalSystems.length,
createdAt: this._createdAt,
config: { ...this._config },
scenes: Array.from(this._scenes.keys()).map(sceneId => ({
config: {...this._config},
scenes: Array.from(this._scenes.keys()).map((sceneId) => ({
id: sceneId,
isActive: this._activeScenes.has(sceneId),
name: this._scenes.get(sceneId)?.name || sceneId
@@ -454,8 +454,8 @@ export class World {
const cleanupThreshold = 5 * 60 * 1000; // 5分钟
for (const [sceneId, scene] of this._scenes) {
if (!this._activeScenes.has(sceneId) &&
scene.entities &&
if (!this._activeScenes.has(sceneId) &&
scene.entities &&
scene.entities.count === 0 &&
(currentTime - this._createdAt) > cleanupThreshold) {
return true;
@@ -472,15 +472,15 @@ export class World {
const sceneIds = Array.from(this._scenes.keys());
const currentTime = Date.now();
const cleanupThreshold = 5 * 60 * 1000; // 5分钟
for (const sceneId of sceneIds) {
const scene = this._scenes.get(sceneId);
if (scene &&
!this._activeScenes.has(sceneId) &&
scene.entities &&
if (scene &&
!this._activeScenes.has(sceneId) &&
scene.entities &&
scene.entities.count === 0 &&
(currentTime - this._createdAt) > cleanupThreshold) {
this.removeScene(sceneId);
logger.debug(`自动清理空Scene: ${sceneId} from World ${this.name}`);
}
@@ -509,4 +509,4 @@ export class World {
public get createdAt(): number {
return this._createdAt;
}
}
}
+27 -27
View File
@@ -1,8 +1,8 @@
import { World, IWorldConfig } from './World';
import { createLogger } from '../Utils/Logger';
import type { IService } from '../Core/ServiceContainer';
import {World, IWorldConfig} from "./World";
import {createLogger} from "../Utils/Logger";
import type {IService} from "../Core/ServiceContainer";
const logger = createLogger('WorldManager');
const logger = createLogger("WorldManager");
/**
* WorldManager配置接口
@@ -12,17 +12,17 @@ export interface IWorldManagerConfig {
* World数量
*/
maxWorlds?: number;
/**
* World
*/
autoCleanup?: boolean;
/**
*
*/
cleanupInterval?: number;
/**
*
*/
@@ -81,7 +81,7 @@ export class WorldManager implements IService {
// 默认启动运行状态
this._isRunning = true;
logger.info('WorldManager已初始化', {
logger.info("WorldManager已初始化", {
maxWorlds: this._config.maxWorlds,
autoCleanup: this._config.autoCleanup,
cleanupInterval: this._config.cleanupInterval
@@ -96,8 +96,8 @@ export class WorldManager implements IService {
* World
*/
public createWorld(worldId: string, config?: IWorldConfig): World {
if (!worldId || typeof worldId !== 'string' || worldId.trim() === '') {
throw new Error('World ID不能为空');
if (!worldId || typeof worldId !== "string" || worldId.trim() === "") {
throw new Error("World ID不能为空");
}
if (this._worlds.has(worldId)) {
@@ -110,9 +110,9 @@ export class WorldManager implements IService {
const worldConfig: IWorldConfig = {
name: worldId,
...(this._config.debug !== undefined && { debug: this._config.debug }),
...(config?.maxScenes !== undefined && { maxScenes: config.maxScenes }),
...(config?.autoCleanup !== undefined && { autoCleanup: config.autoCleanup })
...(this._config.debug !== undefined && {debug: this._config.debug}),
...(config?.maxScenes !== undefined && {maxScenes: config.maxScenes}),
...(config?.autoCleanup !== undefined && {autoCleanup: config.autoCleanup})
};
const world = new World(worldConfig);
@@ -242,12 +242,12 @@ export class WorldManager implements IService {
*/
public startAll(): void {
this._isRunning = true;
for (const worldId of this._worlds.keys()) {
this.setWorldActive(worldId, true);
}
logger.info('启动所有World');
logger.info("启动所有World");
}
/**
@@ -255,12 +255,12 @@ export class WorldManager implements IService {
*/
public stopAll(): void {
this._isRunning = false;
for (const worldId of this._activeWorlds) {
this.setWorldActive(worldId, false);
}
logger.info('停止所有World');
logger.info("停止所有World");
}
/**
@@ -302,7 +302,7 @@ export class WorldManager implements IService {
totalSystems: 0,
memoryUsage: 0,
isRunning: this._isRunning,
config: { ...this._config },
config: {...this._config},
worlds: [] as any[]
};
@@ -367,7 +367,7 @@ export class WorldManager implements IService {
* WorldManager
*/
public destroy(): void {
logger.info('正在销毁WorldManager...');
logger.info("正在销毁WorldManager...");
// 停止清理定时器
this.stopCleanupTimer();
@@ -385,7 +385,7 @@ export class WorldManager implements IService {
this._activeWorlds.clear();
this._isRunning = false;
logger.info('WorldManager已销毁');
logger.info("WorldManager已销毁");
}
/**
@@ -420,7 +420,7 @@ export class WorldManager implements IService {
if (this._cleanupTimer) {
clearInterval(this._cleanupTimer);
this._cleanupTimer = null;
logger.debug('停止World清理定时器');
logger.debug("停止World清理定时器");
}
}
@@ -432,7 +432,7 @@ export class WorldManager implements IService {
// 1. World未激活
// 2. 没有Scene或所有Scene都是空的
// 3. 创建时间超过10分钟
if (world.isActive) {
return false;
}
@@ -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
);
@@ -483,6 +483,6 @@ export class WorldManager implements IService {
*
*/
public get config(): IWorldManagerConfig {
return { ...this._config };
return {...this._config};
}
}
}
+20 -20
View File
@@ -1,20 +1,20 @@
export { Entity } from './Entity';
export { Component } from './Component';
export { ECSEventType, EventPriority, EVENT_TYPES, EventTypeValidator } from './CoreEvents';
export * from './Systems';
export * from './Utils';
export * from './Decorators';
export { Scene } from './Scene';
export { IScene, ISceneFactory, ISceneConfig } from './IScene';
export { SceneManager } from './SceneManager';
export { World, IWorldConfig } from './World';
export { WorldManager, IWorldManagerConfig } from './WorldManager';
export * from './Core/Events';
export * from './Core/Query';
export * from './Core/Storage';
export * from './Core/StorageDecorators';
export * from './Serialization';
export { ReferenceTracker, getSceneByEntityId } from './Core/ReferenceTracker';
export type { EntityRefRecord } from './Core/ReferenceTracker';
export { ReactiveQuery, ReactiveQueryChangeType } from './Core/ReactiveQuery';
export type { ReactiveQueryChange, ReactiveQueryListener, ReactiveQueryConfig } from './Core/ReactiveQuery';
export {Entity} from "./Entity";
export {Component} from "./Component";
export {ECSEventType, EventPriority, EVENT_TYPES, EventTypeValidator} from "./CoreEvents";
export * from "./Systems";
export * from "./Utils";
export * from "./Decorators";
export {Scene} from "./Scene";
export {IScene, ISceneFactory, ISceneConfig} from "./IScene";
export {SceneManager} from "./SceneManager";
export {World, IWorldConfig} from "./World";
export {WorldManager, IWorldManagerConfig} from "./WorldManager";
export * from "./Core/Events";
export * from "./Core/Query";
export * from "./Core/Storage";
export * from "./Core/StorageDecorators";
export * from "./Serialization";
export {ReferenceTracker, getSceneByEntityId} from "./Core/ReferenceTracker";
export type {EntityRefRecord} from "./Core/ReferenceTracker";
export {ReactiveQuery, ReactiveQueryChangeType} from "./Core/ReactiveQuery";
export type {ReactiveQueryChange, ReactiveQueryListener, ReactiveQueryConfig} from "./Core/ReactiveQuery";
@@ -64,12 +64,12 @@ export interface WorkerCreationOptions {
/**
* Worker类型
*/
type?: 'classic' | 'module';
type?: "classic" | "module";
/**
*
*/
credentials?: 'omit' | 'same-origin' | 'include';
credentials?: "omit" | "same-origin" | "include";
/**
* Worker名称
@@ -104,7 +104,7 @@ export interface PlatformWorker {
/**
* Worker状态
*/
readonly state: 'running' | 'terminated';
readonly state: "running" | "terminated";
}
/**
@@ -179,7 +179,7 @@ export interface PlatformDetectionResult {
/**
*
*/
platform: 'browser' | 'wechat-minigame' | 'bytedance-minigame' | 'alipay-minigame' | 'baidu-minigame' | 'nodejs' | 'unknown';
platform: "browser" | "wechat-minigame" | "bytedance-minigame" | "alipay-minigame" | "baidu-minigame" | "nodejs" | "unknown";
/**
*
+78 -78
View File
@@ -1,4 +1,4 @@
import type { PlatformDetectionResult } from './IPlatformAdapter';
import type {PlatformDetectionResult} from "./IPlatformAdapter";
/**
*
@@ -10,96 +10,96 @@ export class PlatformDetector {
*/
public static detect(): PlatformDetectionResult {
const features: string[] = [];
let platform: PlatformDetectionResult['platform'] = 'unknown';
let platform: PlatformDetectionResult["platform"] = "unknown";
let confident = false;
let adapterClass: string | undefined;
// 检查全局对象和API
if (typeof globalThis !== 'undefined') {
features.push('globalThis');
if (typeof globalThis !== "undefined") {
features.push("globalThis");
}
if (typeof window !== 'undefined') {
features.push('window');
if (typeof window !== "undefined") {
features.push("window");
}
if (typeof self !== 'undefined') {
features.push('self');
if (typeof self !== "undefined") {
features.push("self");
}
// 检测Node.js环境(优先级最高,因为Node.js可能包含全局对象模拟)
if (this.isNodeJS()) {
platform = 'nodejs';
platform = "nodejs";
confident = true;
adapterClass = 'NodeAdapter';
features.push('nodejs', 'process', 'require');
adapterClass = "NodeAdapter";
features.push("nodejs", "process", "require");
}
// 检测微信小游戏环境
else if (this.isWeChatMiniGame()) {
platform = 'wechat-minigame';
platform = "wechat-minigame";
confident = true;
adapterClass = 'WeChatMiniGameAdapter';
features.push('wx', 'wechat-minigame');
adapterClass = "WeChatMiniGameAdapter";
features.push("wx", "wechat-minigame");
}
// 检测字节跳动小游戏环境
else if (this.isByteDanceMiniGame()) {
platform = 'bytedance-minigame';
platform = "bytedance-minigame";
confident = true;
adapterClass = 'ByteDanceMiniGameAdapter';
features.push('tt', 'bytedance-minigame');
adapterClass = "ByteDanceMiniGameAdapter";
features.push("tt", "bytedance-minigame");
}
// 检测支付宝小游戏环境
else if (this.isAlipayMiniGame()) {
platform = 'alipay-minigame';
platform = "alipay-minigame";
confident = true;
adapterClass = 'AlipayMiniGameAdapter';
features.push('my', 'alipay-minigame');
adapterClass = "AlipayMiniGameAdapter";
features.push("my", "alipay-minigame");
}
// 检测百度小游戏环境
else if (this.isBaiduMiniGame()) {
platform = 'baidu-minigame';
platform = "baidu-minigame";
confident = true;
adapterClass = 'BaiduMiniGameAdapter';
features.push('swan', 'baidu-minigame');
adapterClass = "BaiduMiniGameAdapter";
features.push("swan", "baidu-minigame");
}
// 检测浏览器环境
else if (this.isBrowser()) {
platform = 'browser';
platform = "browser";
confident = true;
adapterClass = 'BrowserAdapter';
features.push('browser');
adapterClass = "BrowserAdapter";
features.push("browser");
}
// 添加功能检测特征
if (typeof Worker !== 'undefined') {
features.push('Worker');
if (typeof Worker !== "undefined") {
features.push("Worker");
}
if (typeof SharedArrayBuffer !== 'undefined') {
features.push('SharedArrayBuffer');
if (typeof SharedArrayBuffer !== "undefined") {
features.push("SharedArrayBuffer");
}
if (typeof navigator !== 'undefined' && navigator.hardwareConcurrency) {
features.push('hardwareConcurrency');
if (typeof navigator !== "undefined" && navigator.hardwareConcurrency) {
features.push("hardwareConcurrency");
}
if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
features.push('performance.now');
if (typeof performance !== "undefined" && typeof performance.now === "function") {
features.push("performance.now");
}
if (typeof Blob !== 'undefined') {
features.push('Blob');
if (typeof Blob !== "undefined") {
features.push("Blob");
}
if (typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function') {
features.push('URL.createObjectURL');
if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
features.push("URL.createObjectURL");
}
return {
platform,
confident,
features,
...(adapterClass && { adapterClass })
...(adapterClass && {adapterClass})
};
}
@@ -108,7 +108,7 @@ export class PlatformDetector {
*/
private static isWeChatMiniGame(): boolean {
// 检查wx全局对象
if (typeof (globalThis as any).wx !== 'undefined') {
if (typeof (globalThis as any).wx !== "undefined") {
const wx = (globalThis as any).wx;
// 检查微信小游戏特有的API
return !!(wx.getSystemInfo && wx.createCanvas && wx.createImage);
@@ -121,7 +121,7 @@ export class PlatformDetector {
*/
private static isByteDanceMiniGame(): boolean {
// 检查tt全局对象
if (typeof (globalThis as any).tt !== 'undefined') {
if (typeof (globalThis as any).tt !== "undefined") {
const tt = (globalThis as any).tt;
// 检查字节跳动小游戏特有的API
return !!(tt.getSystemInfo && tt.createCanvas && tt.createImage);
@@ -136,15 +136,15 @@ export class PlatformDetector {
try {
// 检查Node.js特有的全局对象和模块
return !!(
typeof process !== 'undefined' &&
typeof process !== "undefined" &&
process.versions &&
process.versions.node &&
typeof require !== 'undefined' &&
typeof module !== 'undefined' &&
typeof exports !== 'undefined' &&
typeof require !== "undefined" &&
typeof module !== "undefined" &&
typeof exports !== "undefined" &&
// 确保不是在浏览器环境中的Node.js模拟
typeof window === 'undefined' &&
typeof document === 'undefined'
typeof window === "undefined" &&
typeof document === "undefined"
);
} catch {
return false;
@@ -156,7 +156,7 @@ export class PlatformDetector {
*/
private static isAlipayMiniGame(): boolean {
// 检查my全局对象
if (typeof (globalThis as any).my !== 'undefined') {
if (typeof (globalThis as any).my !== "undefined") {
const my = (globalThis as any).my;
// 检查支付宝小游戏特有的API
return !!(my.getSystemInfo && my.createCanvas);
@@ -169,7 +169,7 @@ export class PlatformDetector {
*/
private static isBaiduMiniGame(): boolean {
// 检查swan全局对象
if (typeof (globalThis as any).swan !== 'undefined') {
if (typeof (globalThis as any).swan !== "undefined") {
const swan = (globalThis as any).swan;
// 检查百度小游戏特有的API
return !!(swan.getSystemInfo && swan.createCanvas);
@@ -182,9 +182,9 @@ export class PlatformDetector {
*/
private static isBrowser(): boolean {
// 检查浏览器特有的对象和API
return typeof window !== 'undefined' &&
typeof document !== 'undefined' &&
typeof navigator !== 'undefined' &&
return typeof window !== "undefined" &&
typeof document !== "undefined" &&
typeof navigator !== "undefined" &&
window.location !== undefined;
}
@@ -195,44 +195,44 @@ export class PlatformDetector {
const info: Record<string, any> = {};
// 基础检测
info['userAgent'] = typeof navigator !== 'undefined' ? navigator.userAgent : 'unknown';
info['platform'] = typeof navigator !== 'undefined' ? navigator.platform : 'unknown';
info["userAgent"] = typeof navigator !== "undefined" ? navigator.userAgent : "unknown";
info["platform"] = typeof navigator !== "undefined" ? navigator.platform : "unknown";
// 全局对象检测
info['globalObjects'] = {
window: typeof window !== 'undefined',
document: typeof document !== 'undefined',
navigator: typeof navigator !== 'undefined',
wx: typeof (globalThis as any).wx !== 'undefined',
tt: typeof (globalThis as any).tt !== 'undefined',
my: typeof (globalThis as any).my !== 'undefined',
swan: typeof (globalThis as any).swan !== 'undefined'
info["globalObjects"] = {
window: typeof window !== "undefined",
document: typeof document !== "undefined",
navigator: typeof navigator !== "undefined",
wx: typeof (globalThis as any).wx !== "undefined",
tt: typeof (globalThis as any).tt !== "undefined",
my: typeof (globalThis as any).my !== "undefined",
swan: typeof (globalThis as any).swan !== "undefined"
};
// Worker相关检测
info['workerSupport'] = {
Worker: typeof Worker !== 'undefined',
SharedWorker: typeof SharedWorker !== 'undefined',
ServiceWorker: typeof navigator !== 'undefined' && 'serviceWorker' in navigator,
SharedArrayBuffer: typeof SharedArrayBuffer !== 'undefined',
crossOriginIsolated: typeof self !== 'undefined' ? self.crossOriginIsolated : false
info["workerSupport"] = {
Worker: typeof Worker !== "undefined",
SharedWorker: typeof SharedWorker !== "undefined",
ServiceWorker: typeof navigator !== "undefined" && "serviceWorker" in navigator,
SharedArrayBuffer: typeof SharedArrayBuffer !== "undefined",
crossOriginIsolated: typeof self !== "undefined" ? self.crossOriginIsolated : false
};
// 性能相关检测
info['performance'] = {
performanceNow: typeof performance !== 'undefined' && typeof performance.now === 'function',
hardwareConcurrency: typeof navigator !== 'undefined' ? navigator.hardwareConcurrency : undefined
info["performance"] = {
performanceNow: typeof performance !== "undefined" && typeof performance.now === "function",
hardwareConcurrency: typeof navigator !== "undefined" ? navigator.hardwareConcurrency : undefined
};
// 其他API检测
info['apiSupport'] = {
Blob: typeof Blob !== 'undefined',
URL: typeof URL !== 'undefined',
createObjectURL: typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function',
ArrayBuffer: typeof ArrayBuffer !== 'undefined',
TypedArrays: typeof Float32Array !== 'undefined'
info["apiSupport"] = {
Blob: typeof Blob !== "undefined",
URL: typeof URL !== "undefined",
createObjectURL: typeof URL !== "undefined" && typeof URL.createObjectURL === "function",
ArrayBuffer: typeof ArrayBuffer !== "undefined",
TypedArrays: typeof Float32Array !== "undefined"
};
return info;
}
}
}
+13 -13
View File
@@ -1,5 +1,5 @@
import type { IPlatformAdapter } from './IPlatformAdapter';
import { createLogger, type ILogger } from '../Utils/Logger';
import type {IPlatformAdapter} from "./IPlatformAdapter";
import {createLogger, type ILogger} from "../Utils/Logger";
/**
*
@@ -11,7 +11,7 @@ export class PlatformManager {
private readonly logger: ILogger;
private constructor() {
this.logger = createLogger('PlatformManager');
this.logger = createLogger("PlatformManager");
}
/**
@@ -29,7 +29,7 @@ export class PlatformManager {
*/
public getAdapter(): IPlatformAdapter {
if (!this.adapter) {
throw new Error('平台适配器未注册,请调用 registerAdapter() 注册适配器');
throw new Error("平台适配器未注册,请调用 registerAdapter() 注册适配器");
}
return this.adapter;
}
@@ -70,19 +70,19 @@ export class PlatformManager {
/**
*
*/
public supportsFeature(feature: 'worker' | 'shared-array-buffer' | 'transferable-objects' | 'module-worker'): boolean {
public supportsFeature(feature: "worker" | "shared-array-buffer" | "transferable-objects" | "module-worker"): boolean {
if (!this.adapter) return false;
const config = this.adapter.getPlatformConfig();
switch (feature) {
case 'worker':
case "worker":
return this.adapter.isWorkerSupported();
case 'shared-array-buffer':
case "shared-array-buffer":
return this.adapter.isSharedArrayBufferSupported();
case 'transferable-objects':
case "transferable-objects":
return config.supportsTransferableObjects;
case 'module-worker':
case "module-worker":
return config.supportsModuleWorker;
default:
return false;
@@ -98,7 +98,7 @@ export class PlatformManager {
platformSupportsSharedArrayBuffer: boolean;
platformMaxWorkerCount: number;
platformLimitations: any;
} {
} {
if (!this.adapter) {
return {
platformSupportsWorker: false,
@@ -123,15 +123,15 @@ export class PlatformManager {
*/
public async getFullPlatformConfig(): Promise<any> {
if (!this.adapter) {
throw new Error('平台适配器未注册');
throw new Error("平台适配器未注册");
}
// 如果适配器支持异步获取配置,使用异步方法
if (typeof this.adapter.getPlatformConfigAsync === 'function') {
if (typeof this.adapter.getPlatformConfigAsync === "function") {
return await this.adapter.getPlatformConfigAsync();
}
// 否则返回同步配置
return this.adapter.getPlatformConfig();
}
}
}
+7 -7
View File
@@ -9,17 +9,17 @@ export type {
WorkerCreationOptions,
PlatformConfig,
PlatformDetectionResult
} from './IPlatformAdapter';
} from "./IPlatformAdapter";
// 平台检测器
export { PlatformDetector } from './PlatformDetector';
export {PlatformDetector} from "./PlatformDetector";
// 平台管理器
export { PlatformManager } from './PlatformManager';
export {PlatformManager} from "./PlatformManager";
// 内部导入用于便利函数
import { PlatformManager } from './PlatformManager';
import type { IPlatformAdapter } from './IPlatformAdapter';
import {PlatformManager} from "./PlatformManager";
import type {IPlatformAdapter} from "./IPlatformAdapter";
// 便利函数
export function registerPlatformAdapter(adapter: IPlatformAdapter) {
@@ -38,10 +38,10 @@ export function getFullPlatformConfig() {
return PlatformManager.getInstance().getFullPlatformConfig();
}
export function supportsFeature(feature: 'worker' | 'shared-array-buffer' | 'transferable-objects' | 'module-worker') {
export function supportsFeature(feature: "worker" | "shared-array-buffer" | "transferable-objects" | "module-worker") {
return PlatformManager.getInstance().supportsFeature(feature);
}
export function hasAdapter() {
return PlatformManager.getInstance().hasAdapter();
}
}
+32 -32
View File
@@ -1,15 +1,15 @@
import type { Core } from '../Core';
import type { ServiceContainer } from '../Core/ServiceContainer';
import { IPlugin } from '../Core/Plugin';
import { createLogger } from '../Utils/Logger';
import type { IScene } from '../ECS/IScene';
import type { Entity } from '../ECS/Entity';
import type { EntitySystem } from '../ECS/Systems/EntitySystem';
import { WorldManager } from '../ECS/WorldManager';
import { Injectable } from '../Core/DI/Decorators';
import type { IService } from '../Core/ServiceContainer';
import type {Core} from "../Core";
import type {ServiceContainer} from "../Core/ServiceContainer";
import {IPlugin} from "../Core/Plugin";
import {createLogger} from "../Utils/Logger";
import type {IScene} from "../ECS/IScene";
import type {Entity} from "../ECS/Entity";
import type {EntitySystem} from "../ECS/Systems/EntitySystem";
import {WorldManager} from "../ECS/WorldManager";
import {Injectable} from "../Core/DI/Decorators";
import type {IService} from "../Core/ServiceContainer";
const logger = createLogger('DebugPlugin');
const logger = createLogger("DebugPlugin");
/**
* ECS
@@ -91,8 +91,8 @@ export interface ComponentDebugInfo {
*/
@Injectable()
export class DebugPlugin implements IPlugin, IService {
readonly name = '@esengine/debug-plugin';
readonly version = '1.0.0';
readonly name = "@esengine/debug-plugin";
readonly version = "1.0.0";
private worldManager: WorldManager | null = null;
private updateInterval: number;
@@ -115,7 +115,7 @@ export class DebugPlugin implements IPlugin, IService {
async install(_core: Core, services: ServiceContainer): Promise<void> {
this.worldManager = services.resolve(WorldManager);
logger.info('ECS Debug Plugin installed');
logger.info("ECS Debug Plugin installed");
if (this.autoStart) {
this.start();
@@ -129,7 +129,7 @@ export class DebugPlugin implements IPlugin, IService {
this.stop();
this.worldManager = null;
logger.info('ECS Debug Plugin uninstalled');
logger.info("ECS Debug Plugin uninstalled");
}
/**
@@ -145,11 +145,11 @@ export class DebugPlugin implements IPlugin, IService {
*/
public start(): void {
if (this.updateTimer) {
logger.warn('Debug monitoring already started');
logger.warn("Debug monitoring already started");
return;
}
logger.info('Starting debug monitoring');
logger.info("Starting debug monitoring");
this.updateTimer = setInterval(() => {
this.logStats();
@@ -163,7 +163,7 @@ export class DebugPlugin implements IPlugin, IService {
if (this.updateTimer) {
clearInterval(this.updateTimer);
this.updateTimer = null;
logger.info('Debug monitoring stopped');
logger.info("Debug monitoring stopped");
}
}
@@ -172,7 +172,7 @@ export class DebugPlugin implements IPlugin, IService {
*/
public getStats(): ECSDebugStats {
if (!this.worldManager) {
throw new Error('Plugin not installed');
throw new Error("Plugin not installed");
}
const scenes: SceneDebugInfo[] = [];
@@ -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))
};
}
@@ -230,7 +230,7 @@ export class DebugPlugin implements IPlugin, IService {
enabled: system.enabled,
updateOrder: system.updateOrder,
entityCount: system.entities.length,
...(performance !== undefined && { performance })
...(performance !== undefined && {performance})
};
}
@@ -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))
};
}
@@ -258,15 +258,15 @@ export class DebugPlugin implements IPlugin, IService {
const data: any = {};
for (const key of Object.keys(component)) {
if (!key.startsWith('_')) {
if (!key.startsWith("_")) {
const value = component[key];
if (typeof value !== 'function') {
if (typeof value !== "function") {
data[key] = value;
}
}
}
return { type, data };
return {type, data};
}
/**
@@ -281,7 +281,7 @@ export class DebugPlugin implements IPlugin, IService {
hasComponent?: string;
}): EntityDebugInfo[] {
if (!this.worldManager) {
throw new Error('Plugin not installed');
throw new Error("Plugin not installed");
}
const results: EntityDebugInfo[] = [];
@@ -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;
@@ -325,7 +325,7 @@ export class DebugPlugin implements IPlugin, IService {
private logStats(): void {
const stats = this.getStats();
logger.info('=== ECS Debug Stats ===');
logger.info("=== ECS Debug Stats ===");
logger.info(`Total Entities: ${stats.totalEntities}`);
logger.info(`Total Systems: ${stats.totalSystems}`);
logger.info(`Scenes: ${stats.scenes.length}`);
@@ -338,14 +338,14 @@ export class DebugPlugin implements IPlugin, IService {
for (const system of scene.systems) {
const perfStr = system.performance
? ` | Avg: ${system.performance.avgExecutionTime.toFixed(2)}ms, Max: ${system.performance.maxExecutionTime.toFixed(2)}ms`
: '';
: "";
logger.info(
` - ${system.name} (${system.enabled ? 'enabled' : 'disabled'}) | Entities: ${system.entityCount}${perfStr}`
` - ${system.name} (${system.enabled ? "enabled" : "disabled"}) | Entities: ${system.entityCount}${perfStr}`
);
}
}
logger.info('========================\n');
logger.info("========================\n");
}
/**
+1 -1
View File
@@ -1 +1 @@
export * from './DebugPlugin';
export * from "./DebugPlugin";
+1 -1
View File
@@ -16,5 +16,5 @@ export interface IUpdatable {
* IUpdatable接口
*/
export function isUpdatable(obj: any): obj is IUpdatable {
return obj && typeof obj.update === 'function';
return obj && typeof obj.update === "function";
}
+3 -3
View File
@@ -4,8 +4,8 @@
*
*/
import type { IComponent } from './index';
import { Component } from '../ECS/Component';
import type {IComponent} from "./index";
import {Component} from "../ECS/Component";
/**
*
@@ -240,7 +240,7 @@ export interface TypedQueryCondition<
export function isComponentType<T extends IComponent>(
value: any
): value is ComponentConstructor<T> {
return typeof value === 'function' && value.prototype instanceof Component;
return typeof value === "function" && value.prototype instanceof Component;
}
/**
+16 -16
View File
@@ -2,11 +2,11 @@
*
*/
import type { IWorldManagerConfig } from '../ECS';
import type {IWorldManagerConfig} from "../ECS";
// 导出TypeScript类型增强工具
export * from './TypeHelpers';
export * from './IUpdatable';
export * from "./TypeHelpers";
export * from "./IUpdatable";
/**
*
@@ -28,7 +28,7 @@ export interface IComponent {
/**
*
*
*
* EntitySystem类提供类型定义
*/
export interface ISystemBase {
@@ -38,7 +38,7 @@ export interface ISystemBase {
updateOrder: number;
/** 系统启用状态 */
enabled: boolean;
/** 系统初始化 */
initialize(): void;
/** 更新系统(主要处理阶段) */
@@ -49,7 +49,7 @@ export interface ISystemBase {
/**
*
*
*
*
*
*/
@@ -66,14 +66,14 @@ export interface IEventBus {
* @param data
*/
emit<T>(eventType: string, data: T): void;
/**
*
* @param eventType
* @param data
*/
emitAsync<T>(eventType: string, data: T): Promise<void>;
/**
*
* @param eventType
@@ -82,7 +82,7 @@ export interface IEventBus {
* @returns ID
*/
on<T>(eventType: string, handler: (data: T) => void, config?: IEventListenerConfig): string;
/**
*
* @param eventType
@@ -91,7 +91,7 @@ export interface IEventBus {
* @returns ID
*/
once<T>(eventType: string, handler: (data: T) => void, config?: IEventListenerConfig): string;
/**
*
* @param eventType
@@ -100,32 +100,32 @@ export interface IEventBus {
* @returns ID
*/
onAsync<T>(eventType: string, handler: (data: T) => Promise<void>, config?: IEventListenerConfig): string;
/**
*
* @param eventType
* @param listenerId ID
*/
off(eventType: string, listenerId: string): boolean;
/**
*
* @param eventType
*/
offAll(eventType: string): void;
/**
*
* @param eventType
*/
hasListeners(eventType: string): boolean;
/**
*
* @param eventType
*/
getStats(eventType?: string): IEventStats | Map<string, IEventStats>;
/**
*
*/
@@ -499,4 +499,4 @@ export interface ISceneDebugData {
sceneMemory: number;
/** 场景启动时间 */
sceneUptime: number;
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { strToU8, strFromU8, zlibSync, unzlibSync } from 'fflate';
import {strToU8, strFromU8, zlibSync, unzlibSync} from "fflate";
/**
*
@@ -1,7 +1,7 @@
import { IComponentDebugData } from '../../Types';
import { ComponentPoolManager } from '../../ECS/Core/ComponentPool';
import { getComponentInstanceTypeName } from '../../ECS/Decorators';
import { IScene } from '../../ECS/IScene';
import {IComponentDebugData} from "../../Types";
import {ComponentPoolManager} from "../../ECS/Core/ComponentPool";
import {getComponentInstanceTypeName} from "../../ECS/Decorators";
import {IScene} from "../../ECS/IScene";
/**
*
@@ -38,7 +38,7 @@ export class ComponentDataCollector {
if (entity.components) {
entity.components.forEach((component: any) => {
const typeName = getComponentInstanceTypeName(component);
const stats = componentStats.get(typeName) || { count: 0, entities: 0 };
const stats = componentStats.get(typeName) || {count: 0, entities: 0};
stats.count++;
totalInstances++;
componentStats.set(typeName, stats);
@@ -47,18 +47,18 @@ 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();
const poolStats = poolManager.getPoolStats();
const utilizations = poolManager.getPoolUtilization();
for (const [typeName, stats] of poolStats.entries()) {
poolSizes.set(typeName, stats.maxSize);
}
for (const [typeName, util] of utilizations.entries()) {
poolUtilizations.set(typeName, util.utilization);
}
@@ -74,7 +74,7 @@ export class ComponentDataCollector {
const poolUtilization = poolUtilizations.get(typeName) || 0;
// 使用预估的基础内存大小,避免每帧计算
const memoryPerInstance = this.getEstimatedComponentSize(typeName, scene);
return {
typeName,
instanceCount: stats.count,
@@ -97,12 +97,12 @@ export class ComponentDataCollector {
}
if (!scene) return 64;
const entityList = (scene as any).entities;
if (!entityList?.buffer) return 64;
let calculatedSize = 64;
try {
for (const entity of entityList.buffer) {
if (entity.components) {
@@ -116,51 +116,51 @@ export class ComponentDataCollector {
} catch (error) {
calculatedSize = 64;
}
ComponentDataCollector.componentSizeCache.set(typeName, calculatedSize);
return calculatedSize;
}
private calculateQuickObjectSize(obj: any): number {
if (!obj || typeof obj !== 'object') return 8;
if (!obj || typeof obj !== "object") return 8;
let size = 32;
const visited = new WeakSet();
const calculate = (item: any, depth: number = 0): number => {
if (!item || typeof item !== 'object' || visited.has(item) || depth > 3) {
if (!item || typeof item !== "object" || visited.has(item) || depth > 3) {
return 0;
}
visited.add(item);
let itemSize = 0;
try {
const keys = Object.keys(item);
for (let i = 0; i < Math.min(keys.length, 20); i++) {
const key = keys[i];
if (!key || key === 'entity' || key === '_entity' || key === 'constructor') continue;
if (!key || key === "entity" || key === "_entity" || key === "constructor") continue;
const value = item[key];
itemSize += key.length * 2;
if (typeof value === 'string') {
if (typeof value === "string") {
itemSize += Math.min(value.length * 2, 200);
} else if (typeof value === 'number') {
} else if (typeof value === "number") {
itemSize += 8;
} else if (typeof value === 'boolean') {
} else if (typeof value === "boolean") {
itemSize += 4;
} else if (typeof value === 'object' && value !== null) {
} else if (typeof value === "object" && value !== null) {
itemSize += calculate(value, depth + 1);
}
}
} catch (error) {
return 32;
}
return itemSize;
};
size += calculate(obj);
return Math.max(size, 32);
}
@@ -176,7 +176,7 @@ export class ComponentDataCollector {
const entityList = (scene as any).entities;
if (!entityList?.buffer) return this.getEstimatedComponentSize(typeName, scene);
try {
// 找到第一个包含此组件的实体,分析组件大小
for (const entity of entityList.buffer) {
@@ -190,7 +190,7 @@ export class ComponentDataCollector {
} catch (error) {
// 忽略错误,使用估算值
}
return this.getEstimatedComponentSize(typeName, scene);
}
@@ -201,23 +201,23 @@ export class ComponentDataCollector {
private estimateObjectSize(obj: any, visited = new WeakSet(), depth = 0): number {
if (obj === null || obj === undefined || depth > 10) return 0;
if (visited.has(obj)) return 0;
let size = 0;
const type = typeof obj;
switch (type) {
case 'boolean':
case "boolean":
size = 4;
break;
case 'number':
case "number":
size = 8;
break;
case 'string':
case "string":
size = 24 + Math.min(obj.length * 2, 1000);
break;
case 'object':
case "object":
visited.add(obj);
if (Array.isArray(obj)) {
size = 40 + (obj.length * 8);
const maxElements = Math.min(obj.length, 50);
@@ -226,21 +226,21 @@ export class ComponentDataCollector {
}
} else {
size = 32;
try {
const ownKeys = Object.getOwnPropertyNames(obj);
const maxProps = Math.min(ownKeys.length, 30);
for (let i = 0; i < maxProps; i++) {
const key = ownKeys[i];
if (!key) continue;
if (key === 'constructor' ||
key === '__proto__' ||
key === 'entity' ||
key === '_entity' ||
key.startsWith('_cc_') ||
key.startsWith('__')) {
if (key === "constructor" ||
key === "__proto__" ||
key === "entity" ||
key === "_entity" ||
key.startsWith("_cc_") ||
key.startsWith("__")) {
continue;
}
@@ -263,11 +263,11 @@ export class ComponentDataCollector {
default:
size = 8;
}
return Math.ceil(size / 8) * 8;
}
public static clearCache(): void {
ComponentDataCollector.componentSizeCache.clear();
}
}
}
@@ -1,6 +1,6 @@
import { IECSDebugConfig } from '../../Types';
import { Injectable } from '../../Core/DI/Decorators';
import type { IService } from '../../Core/ServiceContainer';
import {IECSDebugConfig} from "../../Types";
import {Injectable} from "../../Core/DI/Decorators";
import type {IService} from "../../Core/ServiceContainer";
/**
*
@@ -14,7 +14,7 @@ export class DebugConfigService implements IService {
constructor() {
this._config = {
enabled: false,
websocketUrl: '',
websocketUrl: "",
debugFrameRate: 30,
autoReconnect: true,
channels: {
+82 -86
View File
@@ -1,20 +1,20 @@
import { IECSDebugConfig, IECSDebugData } from '../../Types';
import { EntityDataCollector } from './EntityDataCollector';
import { SystemDataCollector } from './SystemDataCollector';
import { PerformanceDataCollector } from './PerformanceDataCollector';
import { ComponentDataCollector } from './ComponentDataCollector';
import { SceneDataCollector } from './SceneDataCollector';
import { WebSocketManager } from './WebSocketManager';
import { Component } from '../../ECS/Component';
import { ComponentPoolManager } from '../../ECS/Core/ComponentPool';
import { Pool } from '../../Utils/Pool';
import { getComponentInstanceTypeName, getSystemInstanceTypeName } from '../../ECS/Decorators';
import type { IService } from '../../Core/ServiceContainer';
import type { IUpdatable } from '../../Types/IUpdatable';
import { SceneManager } from '../../ECS/SceneManager';
import { PerformanceMonitor } from '../PerformanceMonitor';
import { Injectable, Inject, Updatable } from '../../Core/DI/Decorators';
import { DebugConfigService } from './DebugConfigService';
import {IECSDebugConfig, IECSDebugData} from "../../Types";
import {EntityDataCollector} from "./EntityDataCollector";
import {SystemDataCollector} from "./SystemDataCollector";
import {PerformanceDataCollector} from "./PerformanceDataCollector";
import {ComponentDataCollector} from "./ComponentDataCollector";
import {SceneDataCollector} from "./SceneDataCollector";
import {WebSocketManager} from "./WebSocketManager";
import {Component} from "../../ECS/Component";
import {ComponentPoolManager} from "../../ECS/Core/ComponentPool";
import {Pool} from "../../Utils/Pool";
import {getComponentInstanceTypeName, getSystemInstanceTypeName} from "../../ECS/Decorators";
import type {IService} from "../../Core/ServiceContainer";
import type {IUpdatable} from "../../Types/IUpdatable";
import {SceneManager} from "../../ECS/SceneManager";
import {PerformanceMonitor} from "../PerformanceMonitor";
import {Injectable, Inject, Updatable} from "../../Core/DI/Decorators";
import {DebugConfigService} from "./DebugConfigService";
/**
*
@@ -106,27 +106,27 @@ export class DebugManager implements IService, IUpdatable {
*/
private interceptConsole(): void {
console.log = (...args: unknown[]) => {
this.sendLog('info', this.formatLogMessage(args));
this.sendLog("info", this.formatLogMessage(args));
this.originalConsole.log(...args);
};
console.debug = (...args: unknown[]) => {
this.sendLog('debug', this.formatLogMessage(args));
this.sendLog("debug", this.formatLogMessage(args));
this.originalConsole.debug(...args);
};
console.info = (...args: unknown[]) => {
this.sendLog('info', this.formatLogMessage(args));
this.sendLog("info", this.formatLogMessage(args));
this.originalConsole.info(...args);
};
console.warn = (...args: unknown[]) => {
this.sendLog('warn', this.formatLogMessage(args));
this.sendLog("warn", this.formatLogMessage(args));
this.originalConsole.warn(...args);
};
console.error = (...args: unknown[]) => {
this.sendLog('error', this.formatLogMessage(args));
this.sendLog("error", this.formatLogMessage(args));
this.originalConsole.error(...args);
};
}
@@ -135,12 +135,12 @@ export class DebugManager implements IService, IUpdatable {
*
*/
private formatLogMessage(args: unknown[]): string {
return args.map(arg => {
if (typeof arg === 'string') return 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';
if (arg === undefined) return 'undefined';
if (typeof arg === 'object') {
if (arg === null) return "null";
if (arg === undefined) return "undefined";
if (typeof arg === "object") {
try {
return this.safeStringify(arg, 6);
} catch {
@@ -148,7 +148,7 @@ export class DebugManager implements IService, IUpdatable {
}
}
return String(arg);
}).join(' ');
}).join(" ");
}
/**
@@ -160,20 +160,20 @@ export class DebugManager implements IService, IUpdatable {
const stringify = (value: any, depth: number): any => {
if (value === null) return null;
if (value === undefined) return undefined;
if (typeof value !== 'object') return value;
if (typeof value !== "object") return value;
if (depth >= maxDepth) {
return '[Max Depth Reached]';
return "[Max Depth Reached]";
}
if (seen.has(value)) {
return '[Circular]';
return "[Circular]";
}
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;
}
@@ -201,7 +201,7 @@ export class DebugManager implements IService, IUpdatable {
try {
this.webSocketManager.send({
type: 'log',
type: "log",
data: {
level,
message,
@@ -263,35 +263,35 @@ export class DebugManager implements IService, IUpdatable {
private handleMessage(message: any): void {
try {
switch (message.type) {
case 'capture_memory_snapshot':
case "capture_memory_snapshot":
this.handleMemorySnapshotRequest();
break;
case 'config_update':
case "config_update":
if (message.config) {
this.updateConfig({ ...this.config, ...message.config });
this.updateConfig({...this.config, ...message.config});
}
break;
case 'expand_lazy_object':
case "expand_lazy_object":
this.handleExpandLazyObjectRequest(message);
break;
case 'get_component_properties':
case "get_component_properties":
this.handleGetComponentPropertiesRequest(message);
break;
case 'get_raw_entity_list':
case "get_raw_entity_list":
this.handleGetRawEntityListRequest(message);
break;
case 'get_entity_details':
case "get_entity_details":
this.handleGetEntityDetailsRequest(message);
break;
case 'ping':
case "ping":
this.webSocketManager.send({
type: 'pong',
type: "pong",
timestamp: Date.now()
});
break;
@@ -304,7 +304,7 @@ export class DebugManager implements IService, IUpdatable {
// console.error('[ECS Debug] 处理消息失败:', error);
if (message.requestId) {
this.webSocketManager.send({
type: 'error_response',
type: "error_response",
requestId: message.requestId,
error: error instanceof Error ? error.message : String(error)
});
@@ -317,13 +317,13 @@ export class DebugManager implements IService, IUpdatable {
*/
private handleExpandLazyObjectRequest(message: any): void {
try {
const { entityId, componentIndex, propertyPath, requestId } = message;
const {entityId, componentIndex, propertyPath, requestId} = message;
if (entityId === undefined || componentIndex === undefined || !propertyPath) {
this.webSocketManager.send({
type: 'expand_lazy_object_response',
type: "expand_lazy_object_response",
requestId,
error: '缺少必要参数'
error: "缺少必要参数"
});
return;
}
@@ -332,13 +332,13 @@ export class DebugManager implements IService, IUpdatable {
const expandedData = this.entityCollector.expandLazyObject(entityId, componentIndex, propertyPath, scene);
this.webSocketManager.send({
type: 'expand_lazy_object_response',
type: "expand_lazy_object_response",
requestId,
data: expandedData
});
} catch (error) {
this.webSocketManager.send({
type: 'expand_lazy_object_response',
type: "expand_lazy_object_response",
requestId: message.requestId,
error: error instanceof Error ? error.message : String(error)
});
@@ -350,13 +350,13 @@ export class DebugManager implements IService, IUpdatable {
*/
private handleGetComponentPropertiesRequest(message: any): void {
try {
const { entityId, componentIndex, requestId } = message;
const {entityId, componentIndex, requestId} = message;
if (entityId === undefined || componentIndex === undefined) {
this.webSocketManager.send({
type: 'get_component_properties_response',
type: "get_component_properties_response",
requestId,
error: '缺少必要参数'
error: "缺少必要参数"
});
return;
}
@@ -365,13 +365,13 @@ export class DebugManager implements IService, IUpdatable {
const properties = this.entityCollector.getComponentProperties(entityId, componentIndex, scene);
this.webSocketManager.send({
type: 'get_component_properties_response',
type: "get_component_properties_response",
requestId,
data: properties
});
} catch (error) {
this.webSocketManager.send({
type: 'get_component_properties_response',
type: "get_component_properties_response",
requestId: message.requestId,
error: error instanceof Error ? error.message : String(error)
});
@@ -383,19 +383,19 @@ export class DebugManager implements IService, IUpdatable {
*/
private handleGetRawEntityListRequest(message: any): void {
try {
const { requestId } = message;
const {requestId} = message;
const scene = this.sceneManager.currentScene;
const rawEntityList = this.entityCollector.getRawEntityList(scene);
this.webSocketManager.send({
type: 'get_raw_entity_list_response',
type: "get_raw_entity_list_response",
requestId,
data: rawEntityList
});
} catch (error) {
this.webSocketManager.send({
type: 'get_raw_entity_list_response',
type: "get_raw_entity_list_response",
requestId: message.requestId,
error: error instanceof Error ? error.message : String(error)
});
@@ -407,13 +407,13 @@ export class DebugManager implements IService, IUpdatable {
*/
private handleGetEntityDetailsRequest(message: any): void {
try {
const { entityId, requestId } = message;
const {entityId, requestId} = message;
if (entityId === undefined) {
this.webSocketManager.send({
type: 'get_entity_details_response',
type: "get_entity_details_response",
requestId,
error: '缺少实体ID参数'
error: "缺少实体ID参数"
});
return;
}
@@ -422,13 +422,13 @@ export class DebugManager implements IService, IUpdatable {
const entityDetails = this.entityCollector.getEntityDetails(entityId, scene);
this.webSocketManager.send({
type: 'get_entity_details_response',
type: "get_entity_details_response",
requestId,
data: entityDetails
});
} catch (error) {
this.webSocketManager.send({
type: 'get_entity_details_response',
type: "get_entity_details_response",
requestId: message.requestId,
error: error instanceof Error ? error.message : String(error)
});
@@ -436,9 +436,6 @@ export class DebugManager implements IService, IUpdatable {
}
/**
*
*/
@@ -446,13 +443,13 @@ export class DebugManager implements IService, IUpdatable {
try {
const memorySnapshot = this.captureMemorySnapshot();
this.webSocketManager.send({
type: 'memory_snapshot_response',
type: "memory_snapshot_response",
data: memorySnapshot
});
} catch (error) {
this.webSocketManager.send({
type: 'memory_snapshot_error',
error: error instanceof Error ? error.message : '内存快照捕获失败'
type: "memory_snapshot_error",
error: error instanceof Error ? error.message : "内存快照捕获失败"
});
}
}
@@ -469,7 +466,7 @@ export class DebugManager implements IService, IUpdatable {
// 使用专门的内存计算方法收集实体数据
const entityData = this.entityCollector.collectEntityDataWithMemory(scene);
const componentMemoryStats = scene?.entities ? this.collectComponentMemoryStats(scene.entities) : { totalMemory: 0, componentTypes: 0, totalInstances: 0, breakdown: [] };
const componentMemoryStats = scene?.entities ? this.collectComponentMemoryStats(scene.entities) : {totalMemory: 0, componentTypes: 0, totalInstances: 0, breakdown: []};
const systemMemoryStats = this.collectSystemMemoryStats();
const poolMemoryStats = this.collectPoolMemoryStats();
const performanceStats = this.collectPerformanceStats();
@@ -479,7 +476,7 @@ export class DebugManager implements IService, IUpdatable {
return {
timestamp,
version: '2.0',
version: "2.0",
summary: {
totalEntities: entityData.totalEntities,
totalMemoryUsage: baseMemoryInfo.usedMemory,
@@ -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<{
@@ -720,7 +716,7 @@ export class DebugManager implements IService, IUpdatable {
}
private calculateQuickSystemSize(system: unknown): number {
if (!system || typeof system !== 'object') return 64;
if (!system || typeof system !== "object") return 64;
let size = 128;
@@ -728,20 +724,20 @@ export class DebugManager implements IService, IUpdatable {
const keys = Object.keys(system);
for (let i = 0; i < Math.min(keys.length, 15); i++) {
const key = keys[i];
if (!key || key === 'entities' || key === 'scene' || key === 'constructor') continue;
if (!key || key === "entities" || key === "scene" || key === "constructor") continue;
const value = (system as Record<string, unknown>)[key];
size += key.length * 2;
if (typeof value === 'string') {
if (typeof value === "string") {
size += Math.min(value.length * 2, 100);
} else if (typeof value === 'number') {
} else if (typeof value === "number") {
size += 8;
} else if (typeof value === 'boolean') {
} else if (typeof value === "boolean") {
size += 4;
} else if (Array.isArray(value)) {
size += 40 + Math.min(value.length * 8, 200);
} else if (typeof value === 'object' && value !== null) {
} else if (typeof value === "object" && value !== null) {
size += 64;
}
}
@@ -766,7 +762,7 @@ export class DebugManager implements IService, IUpdatable {
utilization: number;
hitRate?: number;
}>;
} {
} {
let totalPoolMemory = 0;
const poolBreakdown: Array<{
typeName: string;
@@ -845,10 +841,10 @@ export class DebugManager implements IService, IUpdatable {
samples: number;
}>;
error?: string;
} {
} {
try {
if (!this.performanceMonitor) {
return { enabled: false };
return {enabled: false};
}
const stats = this.performanceMonitor.getAllSystemStats();
@@ -869,7 +865,7 @@ export class DebugManager implements IService, IUpdatable {
}).sort((a, b) => b.averageTime - a.averageTime).slice(0, 5)
};
} catch (error: unknown) {
return { enabled: false, error: error instanceof Error ? error.message : String(error) };
return {enabled: false, error: error instanceof Error ? error.message : String(error)};
}
}
@@ -883,10 +879,10 @@ export class DebugManager implements IService, IUpdatable {
const debugData: IECSDebugData = {
timestamp: currentTime,
frameworkVersion: '1.0.0', // 可以从package.json读取
frameworkVersion: "1.0.0", // 可以从package.json读取
isRunning: this.isRunning,
frameworkLoaded: true,
currentScene: scene?.name || 'Unknown'
currentScene: scene?.name || "Unknown"
};
// 根据配置收集各种数据
@@ -937,7 +933,7 @@ export class DebugManager implements IService, IUpdatable {
const debugData = this.getDebugData();
// 包装成调试面板期望的消息格式
const message = {
type: 'debug_data',
type: "debug_data",
data: debugData
};
this.webSocketManager.send(message);
@@ -959,4 +955,4 @@ export class DebugManager implements IService, IUpdatable {
console.warn = this.originalConsole.warn;
console.error = this.originalConsole.error;
}
}
}
@@ -1,8 +1,8 @@
import { IEntityDebugData } from '../../Types';
import { Entity } from '../../ECS/Entity';
import { Component } from '../../ECS/Component';
import { getComponentInstanceTypeName } from '../../ECS/Decorators';
import { IScene } from '../../ECS/IScene';
import {IEntityDebugData} from "../../Types";
import {Entity} from "../../ECS/Entity";
import {Component} from "../../ECS/Component";
import {getComponentInstanceTypeName} from "../../ECS/Decorators";
import {IScene} from "../../ECS/IScene";
/**
*
@@ -39,7 +39,7 @@ export class EntityDataCollector {
}
const archetypeData = this.collectArchetypeData(scene);
return {
totalEntities: stats.totalEntities,
activeEntities: stats.activeEntities,
@@ -129,7 +129,7 @@ export class EntityDataCollector {
} catch (error) {
return {
error: `获取实体详情失败: ${error instanceof Error ? error.message : String(error)}`,
scene: '获取失败',
scene: "获取失败",
components: [],
componentCount: 0,
componentTypes: []
@@ -138,29 +138,29 @@ export class EntityDataCollector {
}
private getSceneInfo(scene: any): { name: string; type: string } {
let sceneName = '当前场景';
let sceneType = 'Scene';
let sceneName = "当前场景";
let sceneType = "Scene";
try {
if (scene.name && typeof scene.name === 'string' && scene.name.trim()) {
if (scene.name && typeof scene.name === "string" && scene.name.trim()) {
sceneName = scene.name.trim();
} else if (scene.constructor && scene.constructor.name) {
sceneName = scene.constructor.name;
sceneType = scene.constructor.name;
} else if (scene._name && typeof scene._name === 'string' && scene._name.trim()) {
} else if (scene._name && typeof scene._name === "string" && scene._name.trim()) {
sceneName = scene._name.trim();
} else {
const sceneClassName = Object.getPrototypeOf(scene)?.constructor?.name;
if (sceneClassName && sceneClassName !== 'Object') {
if (sceneClassName && sceneClassName !== "Object") {
sceneName = sceneClassName;
sceneType = sceneClassName;
}
}
} catch (error) {
sceneName = '场景名获取失败';
sceneName = "场景名获取失败";
}
return { name: sceneName, type: sceneType };
return {name: sceneName, type: sceneType};
}
@@ -182,20 +182,20 @@ 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);
return {
totalEntities: stats.totalEntities,
activeEntities: stats.activeEntities,
@@ -213,11 +213,11 @@ export class EntityDataCollector {
distribution: Array<{ signature: string; count: number; memory: number }>;
topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>;
} {
if (scene && scene.archetypeSystem && typeof scene.archetypeSystem.getAllArchetypes === 'function') {
if (scene && scene.archetypeSystem && typeof scene.archetypeSystem.getAllArchetypes === "function") {
return this.extractArchetypeStatistics(scene.archetypeSystem);
}
const entityContainer = { entities: scene.entities?.buffer || [] };
const entityContainer = {entities: scene.entities?.buffer || []};
return {
distribution: this.getArchetypeDistributionFast(entityContainer),
topEntities: this.getTopEntitiesByComponentsFast(entityContainer)
@@ -230,13 +230,13 @@ export class EntityDataCollector {
if (entityContainer && entityContainer.entities) {
entityContainer.entities.forEach((entity: any) => {
const componentTypes = entity.components?.map((comp: any) => getComponentInstanceTypeName(comp)) || [];
const signature = componentTypes.length > 0 ? componentTypes.sort().join(', ') : '无组件';
const signature = componentTypes.length > 0 ? componentTypes.sort().join(", ") : "无组件";
const existing = distribution.get(signature);
if (existing) {
existing.count++;
} else {
distribution.set(signature, { count: 1, componentTypes });
distribution.set(signature, {count: 1, componentTypes});
}
});
}
@@ -271,11 +271,11 @@ export class EntityDataCollector {
distribution: Array<{ signature: string; count: number; memory: number }>;
topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>;
} {
if (scene && scene.archetypeSystem && typeof scene.archetypeSystem.getAllArchetypes === 'function') {
if (scene && scene.archetypeSystem && typeof scene.archetypeSystem.getAllArchetypes === "function") {
return this.extractArchetypeStatisticsWithMemory(scene.archetypeSystem);
}
const entityContainer = { entities: scene.entities?.buffer || [] };
const entityContainer = {entities: scene.entities?.buffer || []};
return {
distribution: this.getArchetypeDistributionWithMemory(entityContainer),
topEntities: this.getTopEntitiesByComponentsWithMemory(entityContainer)
@@ -292,9 +292,9 @@ export class EntityDataCollector {
const topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }> = [];
archetypes.forEach((archetype: any) => {
const signature = archetype.componentTypes?.map((type: any) => type.name).join(',') || 'Unknown';
const signature = archetype.componentTypes?.map((type: any) => type.name).join(",") || "Unknown";
const entityCount = archetype.entities?.length || 0;
distribution.push({
signature,
count: entityCount,
@@ -316,7 +316,7 @@ export class EntityDataCollector {
distribution.sort((a, b) => b.count - a.count);
topEntities.sort((a, b) => b.componentCount - a.componentCount);
return { distribution, topEntities };
return {distribution, topEntities};
}
@@ -329,18 +329,18 @@ export class EntityDataCollector {
const topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }> = [];
archetypes.forEach((archetype: any) => {
const signature = archetype.componentTypes?.map((type: any) => type.name).join(',') || 'Unknown';
const signature = archetype.componentTypes?.map((type: any) => type.name).join(",") || "Unknown";
const entityCount = archetype.entities?.length || 0;
let actualMemory = 0;
if (archetype.entities && archetype.entities.length > 0) {
const sampleSize = Math.min(5, archetype.entities.length);
let sampleMemory = 0;
for (let i = 0; i < sampleSize; i++) {
sampleMemory += this.estimateEntityMemoryUsage(archetype.entities[i]);
}
actualMemory = (sampleMemory / sampleSize) * entityCount;
}
@@ -365,18 +365,17 @@ export class EntityDataCollector {
distribution.sort((a, b) => b.count - a.count);
topEntities.sort((a, b) => b.componentCount - a.componentCount);
return { distribution, topEntities };
return {distribution, topEntities};
}
private getArchetypeDistributionWithMemory(entityContainer: any): Array<{ signature: string; count: number; memory: number }> {
const distribution = new Map<string, { count: number; memory: number; componentTypes: string[] }>();
if (entityContainer && entityContainer.entities) {
entityContainer.entities.forEach((entity: any) => {
const componentTypes = entity.components?.map((comp: any) => getComponentInstanceTypeName(comp)) || [];
const signature = componentTypes.length > 0 ? componentTypes.sort().join(', ') : '无组件';
const signature = componentTypes.length > 0 ? componentTypes.sort().join(", ") : "无组件";
const existing = distribution.get(signature);
let memory = this.estimateEntityMemoryUsage(entity);
@@ -389,7 +388,7 @@ export class EntityDataCollector {
existing.count++;
existing.memory += memory;
} else {
distribution.set(signature, { count: 1, memory, componentTypes });
distribution.set(signature, {count: 1, memory, componentTypes});
}
});
}
@@ -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 {
@@ -454,14 +453,14 @@ export class EntityDataCollector {
try {
let totalSize = 0;
const entitySize = this.calculateObjectSize(entity, ['components', 'children', 'parent']);
const entitySize = this.calculateObjectSize(entity, ["components", "children", "parent"]);
if (!isNaN(entitySize) && entitySize > 0) {
totalSize += entitySize;
}
if (entity.components && Array.isArray(entity.components)) {
entity.components.forEach((component: any) => {
const componentSize = this.calculateObjectSize(component, ['entity']);
const componentSize = this.calculateObjectSize(component, ["entity"]);
if (!isNaN(componentSize) && componentSize > 0) {
totalSize += componentSize;
}
@@ -475,57 +474,57 @@ export class EntityDataCollector {
}
public calculateObjectSize(obj: any, excludeKeys: string[] = []): number {
if (!obj || typeof obj !== 'object') return 0;
if (!obj || typeof obj !== "object") return 0;
const visited = new WeakSet();
const maxDepth = 2;
const calculate = (item: any, depth: number = 0): number => {
if (!item || typeof item !== 'object' || depth >= maxDepth) {
if (!item || typeof item !== "object" || depth >= maxDepth) {
return 0;
}
if (visited.has(item)) return 0;
visited.add(item);
let itemSize = 32;
try {
const keys = Object.keys(item);
const maxKeys = Math.min(keys.length, 20);
for (let i = 0; i < maxKeys; i++) {
const key = keys[i];
if (!key || excludeKeys.includes(key) ||
key === 'constructor' ||
key === '__proto__' ||
key.startsWith('_cc_') ||
key.startsWith('__')) {
key === "constructor" ||
key === "__proto__" ||
key.startsWith("_cc_") ||
key.startsWith("__")) {
continue;
}
const value = item[key];
itemSize += key.length * 2;
if (typeof value === 'string') {
if (typeof value === "string") {
itemSize += Math.min(value.length * 2, 200);
} else if (typeof value === 'number') {
} else if (typeof value === "number") {
itemSize += 8;
} else if (typeof value === 'boolean') {
} else if (typeof value === "boolean") {
itemSize += 4;
} else if (Array.isArray(value)) {
itemSize += 40 + Math.min(value.length * 8, 160);
} else if (typeof value === 'object' && value !== null) {
} else if (typeof value === "object" && value !== null) {
itemSize += calculate(value, depth + 1);
}
}
} catch (error) {
return 64;
}
return itemSize;
};
try {
const size = calculate(obj);
return Math.max(size, 32);
@@ -596,7 +595,7 @@ export class EntityDataCollector {
}
// 优先使用Entity的getDebugInfo方法
if (typeof entity.getDebugInfo === 'function') {
if (typeof entity.getDebugInfo === "function") {
const debugInfo = entity.getDebugInfo();
node = {
...node,
@@ -630,7 +629,7 @@ export class EntityDataCollector {
entity.getDebugInfo() :
this.buildFallbackEntityInfo(entity, scene);
const componentCacheStats = (entity as any).getComponentCacheStats ?
const componentCacheStats = (entity as any).getComponentCacheStats ?
(entity as any).getComponentCacheStats() : null;
const componentDetails = this.extractComponentDetails(entity.components);
@@ -639,7 +638,7 @@ export class EntityDataCollector {
...baseDebugInfo,
parentName: entity.parent?.name || null,
components: componentDetails,
componentTypes: baseDebugInfo.componentTypes ||
componentTypes: baseDebugInfo.componentTypes ||
componentDetails.map((comp) => comp.typeName),
cachePerformance: componentCacheStats ? {
hitRate: componentCacheStats.cacheStats.hitRate,
@@ -658,7 +657,7 @@ export class EntityDataCollector {
*/
private buildFallbackEntityInfo(entity: Entity, scene?: IScene | null): any {
const sceneInfo = this.getSceneInfo(scene);
return {
name: entity.name || `Entity_${entity.id}`,
id: entity.id,
@@ -671,7 +670,7 @@ export class EntityDataCollector {
sceneType: sceneInfo.type,
componentCount: entity.components.length,
componentTypes: entity.components.map((component: Component) => getComponentInstanceTypeName(component)),
componentMask: entity.componentMask?.toString() || '0',
componentMask: entity.componentMask?.toString() || "0",
parentId: entity.parent?.id || null,
childCount: entity.children?.length || 0,
childIds: entity.children.map((child: Entity) => child.id) || [],
@@ -691,28 +690,28 @@ export class EntityDataCollector {
return components.map((component: Component) => {
const typeName = getComponentInstanceTypeName(component);
const properties: Record<string, any> = {};
try {
const propertyKeys = Object.keys(component);
propertyKeys.forEach(propertyKey => {
if (!propertyKey.startsWith('_') && propertyKey !== 'entity' && propertyKey !== 'constructor') {
propertyKeys.forEach((propertyKey) => {
if (!propertyKey.startsWith("_") && propertyKey !== "entity" && propertyKey !== "constructor") {
const propertyValue = (component as any)[propertyKey];
if (propertyValue !== undefined && propertyValue !== null) {
properties[propertyKey] = this.formatPropertyValue(propertyValue);
}
}
});
// 如果没有找到任何属性,添加一些调试信息
if (Object.keys(properties).length === 0) {
properties['_info'] = '该组件没有公开属性';
properties['_componentId'] = getComponentInstanceTypeName(component);
properties["_info"] = "该组件没有公开属性";
properties["_componentId"] = getComponentInstanceTypeName(component);
}
} catch (error) {
properties['_error'] = '属性提取失败';
properties['_componentId'] = getComponentInstanceTypeName(component);
properties["_error"] = "属性提取失败";
properties["_componentId"] = getComponentInstanceTypeName(component);
}
return {
typeName: typeName,
properties: properties
@@ -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) {
return { _error: '属性提取失败' };
}
} catch (error) {
return {_error: "属性提取失败"};
}
}
/**
@@ -763,8 +762,8 @@ export class EntityDataCollector {
return value;
}
if (typeof value !== 'object') {
if (typeof value === 'string' && value.length > 200) {
if (typeof value !== "object") {
if (typeof value === "string" && value.length > 200) {
return `[长字符串: ${value.length}字符] ${value.substring(0, 100)}...`;
}
return value;
@@ -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);
@@ -813,7 +812,7 @@ export class EntityDataCollector {
break;
}
if (key.startsWith('_') || key.startsWith('$') || typeof obj[key] === 'function') {
if (key.startsWith("_") || key.startsWith("$") || typeof obj[key] === "function") {
continue;
}
@@ -840,10 +839,10 @@ export class EntityDataCollector {
*/
private createLazyLoadPlaceholder(obj: any): any {
try {
const typeName = obj.constructor?.name || 'Object';
const typeName = obj.constructor?.name || "Object";
const summary = this.getObjectSummary(obj, typeName);
return {
return {
_isLazyObject: true,
_typeName: typeName,
_summary: summary,
@@ -852,7 +851,7 @@ export class EntityDataCollector {
} catch (error) {
return {
_isLazyObject: true,
_typeName: 'Unknown',
_typeName: "Unknown",
_summary: `无法分析的对象: ${error instanceof Error ? error.message : String(error)}`,
_objectId: Math.random().toString(36).substr(2, 9)
};
@@ -864,28 +863,28 @@ export class EntityDataCollector {
*/
private getObjectSummary(obj: any, typeName: string): string {
try {
if (typeName.toLowerCase().includes('vec') || typeName.toLowerCase().includes('vector')) {
if (typeName.toLowerCase().includes("vec") || typeName.toLowerCase().includes("vector")) {
if (obj.x !== undefined && obj.y !== undefined) {
const z = obj.z !== undefined ? obj.z : '';
return `${typeName}(${obj.x}, ${obj.y}${z ? ', ' + z : ''})`;
const z = obj.z !== undefined ? obj.z : "";
return `${typeName}(${obj.x}, ${obj.y}${z ? ", " + z : ""})`;
}
}
if (typeName.toLowerCase().includes('color')) {
if (typeName.toLowerCase().includes("color")) {
if (obj.r !== undefined && obj.g !== undefined && obj.b !== undefined) {
const a = obj.a !== undefined ? obj.a : 1;
return `${typeName}(${obj.r}, ${obj.g}, ${obj.b}, ${a})`;
}
}
if (typeName.toLowerCase().includes('node')) {
const name = obj.name || obj._name || '未命名';
if (typeName.toLowerCase().includes("node")) {
const name = obj.name || obj._name || "未命名";
return `${typeName}: ${name}`;
}
if (typeName.toLowerCase().includes('component')) {
const nodeName = obj.node?.name || obj.node?._name || '';
return `${typeName}${nodeName ? ` on ${nodeName}` : ''}`;
if (typeName.toLowerCase().includes("component")) {
const nodeName = obj.node?.name || obj.node?._name || "";
return `${typeName}${nodeName ? ` on ${nodeName}` : ""}`;
}
const keys = Object.keys(obj);
@@ -956,16 +955,16 @@ export class EntityDataCollector {
private getObjectByPath(root: any, path: string): any {
if (!path) return root;
const parts = path.split('.');
const parts = path.split(".");
let current = root;
for (const part of parts) {
if (current === null || current === undefined) return null;
// 处理数组索引
if (part.includes('[') && part.includes(']')) {
const arrayName = part.substring(0, part.indexOf('['));
const index = parseInt(part.substring(part.indexOf('[') + 1, part.indexOf(']')));
if (part.includes("[") && part.includes("]")) {
const arrayName = part.substring(0, part.indexOf("["));
const index = parseInt(part.substring(part.indexOf("[") + 1, part.indexOf("]")));
if (arrayName) {
current = current[arrayName];
@@ -983,4 +982,4 @@ export class EntityDataCollector {
return current;
}
}
}
@@ -1,5 +1,5 @@
import { IPerformanceDebugData } from '../../Types';
import { Time } from '../Time';
import {IPerformanceDebugData} from "../../Types";
import {Time} from "../Time";
/**
*
@@ -17,11 +17,11 @@ export class PerformanceDataCollector {
const frameTimeSeconds = Time.deltaTime;
const engineFrameTimeMs = frameTimeSeconds * 1000;
const currentFps = frameTimeSeconds > 0 ? Math.round(1 / frameTimeSeconds) : 0;
const ecsPerformanceData = this.getECSPerformanceData(performanceMonitor);
const ecsExecutionTimeMs = ecsPerformanceData.totalExecutionTime;
const ecsPercentage = engineFrameTimeMs > 0 ? (ecsExecutionTimeMs / engineFrameTimeMs * 100) : 0;
let memoryUsage = 0;
if ((performance as any).memory) {
memoryUsage = (performance as any).memory.usedJSHeapSize / 1024 / 1024;
@@ -32,9 +32,9 @@ export class PerformanceDataCollector {
if (this.frameTimeHistory.length > this.maxHistoryLength) {
this.frameTimeHistory.shift();
}
// 计算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;
@@ -61,7 +61,7 @@ export class PerformanceDataCollector {
private getECSPerformanceData(performanceMonitor: any): { totalExecutionTime: number; systemBreakdown: Array<any> } {
// 检查性能监视器是否存在
if (!performanceMonitor) {
return { totalExecutionTime: 0, systemBreakdown: [] };
return {totalExecutionTime: 0, systemBreakdown: []};
}
if (!performanceMonitor.enabled) {
@@ -71,26 +71,26 @@ export class PerformanceDataCollector {
} catch (error) {
// 如果无法启用,返回默认值
}
return { totalExecutionTime: 0, systemBreakdown: [] };
return {totalExecutionTime: 0, systemBreakdown: []};
}
try {
let totalTime = 0;
const systemBreakdown = [];
const stats = performanceMonitor.getAllSystemStats();
if (stats.size === 0) {
return { totalExecutionTime: 0, systemBreakdown: [] };
return {totalExecutionTime: 0, systemBreakdown: []};
}
// 计算各系统的执行时间
for (const [systemName, stat] of stats.entries()) {
// 使用最近的执行时间而不是平均时间,这样更能反映当前状态
const systemTime = stat.recentTimes && stat.recentTimes.length > 0 ?
stat.recentTimes[stat.recentTimes.length - 1] :
const systemTime = stat.recentTimes && stat.recentTimes.length > 0 ?
stat.recentTimes[stat.recentTimes.length - 1] :
(stat.averageTime || 0);
totalTime += systemTime;
systemBreakdown.push({
systemName: systemName,
@@ -98,21 +98,21 @@ export class PerformanceDataCollector {
percentage: 0 // 后面计算
});
}
// 计算各系统占ECS总时间的百分比
systemBreakdown.forEach(system => {
systemBreakdown.forEach((system) => {
system.percentage = totalTime > 0 ? (system.executionTime / totalTime * 100) : 0;
});
// 按执行时间排序
systemBreakdown.sort((a, b) => b.executionTime - a.executionTime);
return {
totalExecutionTime: totalTime,
systemBreakdown: systemBreakdown
};
} catch (error) {
return { totalExecutionTime: 0, systemBreakdown: [] };
return {totalExecutionTime: 0, systemBreakdown: []};
}
}
@@ -127,7 +127,7 @@ export class PerformanceDataCollector {
try {
const stats = performanceMonitor.getAllSystemStats();
const systemData = performanceMonitor.getAllSystemData();
return Array.from(stats.entries() as Iterable<[string, any]>).map(([systemName, stat]) => {
const data = systemData.get(systemName);
return {
@@ -167,7 +167,7 @@ export class PerformanceDataCollector {
memoryInfo.totalMemory = perfMemory.jsHeapSizeLimit || 512 * 1024 * 1024;
memoryInfo.usedMemory = perfMemory.usedJSHeapSize || 0;
memoryInfo.freeMemory = memoryInfo.totalMemory - memoryInfo.usedMemory;
// 检测GC:如果使用的内存突然大幅减少,可能发生了GC
if (this.lastMemoryCheck > 0) {
const memoryDrop = this.lastMemoryCheck - memoryInfo.usedMemory;
@@ -202,21 +202,21 @@ export class PerformanceDataCollector {
private updateGCCount(): number {
try {
// 尝试使用PerformanceObserver来检测GC
if (typeof PerformanceObserver !== 'undefined') {
if (typeof PerformanceObserver !== "undefined") {
// 这是一个简化的GC检测方法
// 实际的GC检测需要更复杂的逻辑
return this.gcCollections;
}
// 如果有其他GC检测API,可以在这里添加
if ((performance as any).measureUserAgentSpecificMemory) {
// 实验性API,可能不可用
return this.gcCollections;
}
return this.gcCollections;
} catch (error) {
return this.gcCollections;
}
}
}
}
@@ -1,5 +1,5 @@
import { ISceneDebugData } from '../../Types';
import { IScene } from '../../ECS/IScene';
import {ISceneDebugData} from "../../Types";
import {IScene} from "../../ECS/IScene";
/**
*
@@ -14,7 +14,7 @@ export class SceneDataCollector {
public collectSceneData(scene?: IScene | null): ISceneDebugData {
if (!scene) {
return {
currentSceneName: 'No Scene',
currentSceneName: "No Scene",
isInitialized: false,
sceneRunTime: 0,
sceneEntityCount: 0,
@@ -31,7 +31,7 @@ export class SceneDataCollector {
const entityProcessors = (scene as any).entityProcessors;
return {
currentSceneName: (scene as any).name || 'Unnamed Scene',
currentSceneName: (scene as any).name || "Unnamed Scene",
isInitialized: (scene as any)._didSceneBegin || false,
sceneRunTime: runTime,
sceneEntityCount: entityList?.buffer?.length || 0,
@@ -47,4 +47,4 @@ export class SceneDataCollector {
public setSceneStartTime(time: number): void {
this.sceneStartTime = time;
}
}
}
@@ -1,6 +1,6 @@
import { ISystemDebugData } from '../../Types';
import { getSystemInstanceTypeName } from '../../ECS/Decorators';
import { IScene } from '../../ECS/IScene';
import {ISystemDebugData} from "../../Types";
import {getSystemInstanceTypeName} from "../../ECS/Decorators";
import {IScene} from "../../ECS/IScene";
/**
*
@@ -28,11 +28,11 @@ export class SystemDataCollector {
}
const systems = entityProcessors.processors || [];
// 获取性能监控数据
let systemStats: Map<string, any> = new Map();
let systemData: Map<string, any> = new Map();
if (performanceMonitor) {
try {
systemStats = performanceMonitor.getAllSystemStats();
@@ -41,14 +41,14 @@ export class SystemDataCollector {
// 忽略错误,使用空的Map
}
}
return {
totalSystems: systems.length,
systemsInfo: systems.map((system: any) => {
const systemName = system.systemName || getSystemInstanceTypeName(system);
const stats = systemStats.get(systemName);
const data = systemData.get(systemName);
return {
name: systemName,
type: getSystemInstanceTypeName(system),
@@ -64,4 +64,4 @@ export class SystemDataCollector {
})
};
}
}
}
@@ -33,7 +33,7 @@ export class WebSocketManager {
return new Promise((resolve, reject) => {
try {
this.ws = new WebSocket(this.url);
this.ws.onopen = (event) => {
this.handleOpen(event);
resolve();
@@ -80,7 +80,7 @@ export class WebSocketManager {
}
try {
const message = typeof data === 'string' ? data : JSON.stringify(data);
const message = typeof data === "string" ? data : JSON.stringify(data);
this.ws.send(message);
} catch (error) {
}
@@ -112,7 +112,7 @@ export class WebSocketManager {
this.reconnectAttempts++;
this.reconnectTimer = setTimeout(() => {
this.connect().catch(_error => {
this.connect().catch((_error) => {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.scheduleReconnect();
}
@@ -137,7 +137,7 @@ export class WebSocketManager {
private handleOpen(event: Event): void {
this.isConnected = true;
this.reconnectAttempts = 0;
if (this.onOpen) {
this.onOpen(event);
}
@@ -145,11 +145,11 @@ export class WebSocketManager {
private handleClose(event: CloseEvent): void {
this.isConnected = false;
if (this.onClose) {
this.onClose(event);
}
if (this.autoReconnect && this.reconnectAttempts < this.maxReconnectAttempts) {
this.scheduleReconnect();
}
@@ -166,4 +166,4 @@ export class WebSocketManager {
this.onError(error);
}
}
}
}
+8 -8
View File
@@ -1,8 +1,8 @@
export { EntityDataCollector } from './EntityDataCollector';
export { SystemDataCollector } from './SystemDataCollector';
export { PerformanceDataCollector } from './PerformanceDataCollector';
export { ComponentDataCollector } from './ComponentDataCollector';
export { SceneDataCollector } from './SceneDataCollector';
export { WebSocketManager } from './WebSocketManager';
export { DebugManager } from './DebugManager';
export { DebugConfigService } from './DebugConfigService';
export {EntityDataCollector} from "./EntityDataCollector";
export {SystemDataCollector} from "./SystemDataCollector";
export {PerformanceDataCollector} from "./PerformanceDataCollector";
export {ComponentDataCollector} from "./ComponentDataCollector";
export {SceneDataCollector} from "./SceneDataCollector";
export {WebSocketManager} from "./WebSocketManager";
export {DebugManager} from "./DebugManager";
export {DebugConfigService} from "./DebugConfigService";
+6 -6
View File
@@ -47,9 +47,9 @@ export class Emitter<T, TContext = unknown> {
* @param handler
*/
public removeObserver(eventType: T, handler: Function) {
let messageData = this._messageTable.get(eventType);
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 +61,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);
}
}
@@ -75,8 +75,8 @@ export class Emitter<T, TContext = unknown> {
* @param handler
*/
public hasObserver(eventType: T, handler: Function): boolean {
let list = this._messageTable.get(eventType);
return list ? list.some(observer => observer.func === handler) : false;
const list = this._messageTable.get(eventType);
return list ? list.some((observer) => observer.func === handler) : false;
}
/**
@@ -12,4 +12,4 @@ export class NumberExtension {
if (value == undefined) return 0;
return Number(value);
}
}
}
@@ -11,4 +11,4 @@ export class TypeUtils {
public static getType(obj: any) {
return obj.constructor;
}
}
}
+2 -2
View File
@@ -1,3 +1,3 @@
// 扩展工具类导出
export { TypeUtils } from './TypeUtils';
export { NumberExtension } from './NumberExtension';
export {TypeUtils} from "./TypeUtils";
export {NumberExtension} from "./NumberExtension";
@@ -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";
/**
@@ -12,7 +12,7 @@ export class ConsoleLogger implements ILogger {
this._config = {
level: LogLevel.Info,
enableTimestamp: true,
enableColors: typeof window === 'undefined',
enableColors: typeof window === "undefined",
...config
};
}
@@ -138,7 +138,7 @@ export class ConsoleLogger implements ILogger {
*/
private outputToConsole(level: LogLevel, message: string, ...args: unknown[]): void {
const colors = this._config.enableColors ? this.getColors() : null;
switch (level) {
case LogLevel.Debug:
if (colors) {
+21 -21
View File
@@ -15,27 +15,27 @@ export enum LogLevel {
*/
export const Colors = {
// 基础颜色
BLACK: '\x1b[30m',
RED: '\x1b[31m',
GREEN: '\x1b[32m',
YELLOW: '\x1b[33m',
BLUE: '\x1b[34m',
MAGENTA: '\x1b[35m',
CYAN: '\x1b[36m',
WHITE: '\x1b[37m',
BLACK: "\x1b[30m",
RED: "\x1b[31m",
GREEN: "\x1b[32m",
YELLOW: "\x1b[33m",
BLUE: "\x1b[34m",
MAGENTA: "\x1b[35m",
CYAN: "\x1b[36m",
WHITE: "\x1b[37m",
// 亮色版本
BRIGHT_BLACK: '\x1b[90m',
BRIGHT_RED: '\x1b[91m',
BRIGHT_GREEN: '\x1b[92m',
BRIGHT_YELLOW: '\x1b[93m',
BRIGHT_BLUE: '\x1b[94m',
BRIGHT_MAGENTA: '\x1b[95m',
BRIGHT_CYAN: '\x1b[96m',
BRIGHT_WHITE: '\x1b[97m',
BRIGHT_BLACK: "\x1b[90m",
BRIGHT_RED: "\x1b[91m",
BRIGHT_GREEN: "\x1b[92m",
BRIGHT_YELLOW: "\x1b[93m",
BRIGHT_BLUE: "\x1b[94m",
BRIGHT_MAGENTA: "\x1b[95m",
BRIGHT_CYAN: "\x1b[96m",
BRIGHT_WHITE: "\x1b[97m",
// 特殊
RESET: '\x1b[0m',
BOLD: '\x1b[1m',
UNDERLINE: '\x1b[4m'
RESET: "\x1b[0m",
BOLD: "\x1b[1m",
UNDERLINE: "\x1b[4m"
} as const;
@@ -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";
/**
*
@@ -26,7 +26,7 @@ export class LoggerManager {
if (this._loggerFactory) {
return this._loggerFactory();
}
return new ConsoleLogger({ level: this._defaultLevel });
return new ConsoleLogger({level: this._defaultLevel});
}
/**
@@ -53,7 +53,7 @@ export class LoggerManager {
if (!this._loggers.has(name)) {
const logger = this._loggerFactory
? this._loggerFactory(name)
: new ConsoleLogger({ prefix: name, level: this._defaultLevel });
: new ConsoleLogger({prefix: name, level: this._defaultLevel});
this._loggers.set(name, logger);
}
@@ -136,8 +136,8 @@ export class LoggerManager {
public setLoggerFactory(factory: (name?: string) => ILogger): void {
if (this._defaultLogger || this._loggers.size > 0) {
console.warn(
'[LoggerManager] setLoggerFactory 应该在导入 ECS 模块之前调用。' +
'已创建的 logger 引用不会被更新。'
"[LoggerManager] setLoggerFactory 应该在导入 ECS 模块之前调用。" +
"已创建的 logger 引用不会被更新。"
);
}
@@ -186,7 +186,7 @@ export function setGlobalLogLevel(level: LogLevel): void {
}
/**
*
*
* @param factory
*/
export function setLoggerFactory(factory: (name?: string) => ILogger): void {
+1 -1
View File
@@ -1,4 +1,4 @@
import type { LogLevel } from "./Constants";
import type {LogLevel} from "./Constants";
/**
*
+4 -4
View File
@@ -1,4 +1,4 @@
export * from './ConsoleLogger';
export * from './Constants';
export * from './LoggerManager';
export * from './Types';
export * from "./ConsoleLogger";
export * from "./Constants";
export * from "./LoggerManager";
export * from "./Types";
+18 -18
View File
@@ -46,12 +46,12 @@ export interface PerformanceStats {
*
*/
export enum PerformanceWarningType {
HIGH_EXECUTION_TIME = 'high_execution_time',
HIGH_MEMORY_USAGE = 'high_memory_usage',
HIGH_CPU_USAGE = 'high_cpu_usage',
FREQUENT_GC = 'frequent_gc',
LOW_FPS = 'low_fps',
HIGH_ENTITY_COUNT = 'high_entity_count'
HIGH_EXECUTION_TIME = "high_execution_time",
HIGH_MEMORY_USAGE = "high_memory_usage",
HIGH_CPU_USAGE = "high_cpu_usage",
FREQUENT_GC = "frequent_gc",
LOW_FPS = "low_fps",
HIGH_ENTITY_COUNT = "high_entity_count"
}
/**
@@ -61,7 +61,7 @@ export interface PerformanceWarning {
type: PerformanceWarningType;
systemName: string;
message: string;
severity: 'low' | 'medium' | 'high' | 'critical';
severity: "low" | "medium" | "high" | "critical";
timestamp: number;
value: number;
threshold: number;
@@ -99,7 +99,7 @@ export interface PerformanceThresholds {
};
}
import type { IService } from '../Core/ServiceContainer';
import type {IService} from "../Core/ServiceContainer";
/**
*
@@ -183,7 +183,7 @@ export class PerformanceMonitor implements IService {
*/
private updateStats(systemName: string, executionTime: number): void {
let stats = this._systemStats.get(systemName);
if (!stats) {
stats = {
totalTime: 0,
@@ -231,7 +231,7 @@ export class PerformanceMonitor implements IService {
// 计算百分位数
const sortedTimes = [...stats.recentTimes].sort((a, b) => a - b);
const len = sortedTimes.length;
stats.percentile95 = sortedTimes[Math.floor(len * 0.95)] || 0;
stats.percentile99 = sortedTimes[Math.floor(len * 0.99)] || 0;
}
@@ -289,28 +289,28 @@ export class PerformanceMonitor implements IService {
for (const [systemName, stats] of sortedSystems) {
const data = this._systemData.get(systemName);
lines.push(`System: ${systemName}`);
lines.push(` Current: ${data?.executionTime.toFixed(2)}ms (${data?.entityCount} entities)`);
lines.push(` Average: ${stats.averageTime.toFixed(2)}ms`);
lines.push(` Min/Max: ${stats.minTime.toFixed(2)}ms / ${stats.maxTime.toFixed(2)}ms`);
lines.push(` Total: ${stats.totalTime.toFixed(2)}ms (${stats.executionCount} calls)`);
if (data?.averageTimePerEntity && data.averageTimePerEntity > 0) {
lines.push(` Per Entity: ${data.averageTimePerEntity.toFixed(4)}ms`);
}
lines.push("");
}
// 总体统计
const totalCurrentTime = Array.from(this._systemData.values())
.reduce((sum, data) => sum + data.executionTime, 0);
lines.push(`Total Frame Time: ${totalCurrentTime.toFixed(2)}ms`);
lines.push(`Systems Count: ${this._systemData.size}`);
return lines.join('\n');
return lines.join("\n");
}
/**
@@ -337,13 +337,13 @@ export class PerformanceMonitor implements IService {
*/
public getPerformanceWarnings(thresholdMs: number = 16.67): string[] {
const warnings: string[] = [];
for (const [systemName, data] of this._systemData.entries()) {
if (data.executionTime > thresholdMs) {
warnings.push(`${systemName}: ${data.executionTime.toFixed(2)}ms (>${thresholdMs}ms)`);
}
}
return warnings;
}
@@ -370,4 +370,4 @@ export class PerformanceMonitor implements IService {
this._systemStats.clear();
this._isEnabled = false;
}
}
}
+1 -1
View File
@@ -26,4 +26,4 @@ export interface PoolStats {
hitRate: number;
/** 内存使用估算(字节) */
estimatedMemoryUsage: number;
}
}
+31 -29
View File
@@ -1,12 +1,14 @@
import { IPoolable, PoolStats } from './IPoolable';
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;
private _maxSize: number;
@@ -42,17 +44,17 @@ export class Pool<T extends IPoolable> {
* @returns
*/
public static getPool<T extends IPoolable>(
type: new (...args: unknown[]) => T,
type: new (...args: unknown[]) => T,
maxSize: number = 100,
estimatedObjectSize: number = 1024
): Pool<T> {
let pool = this._pools.get(type);
if (!pool) {
pool = new Pool<T>(() => new type(), maxSize, estimatedObjectSize);
this._pools.set(type, pool);
}
return pool;
}
@@ -62,7 +64,7 @@ export class Pool<T extends IPoolable> {
*/
public obtain(): T {
this._stats.totalObtained++;
if (this._objects.length > 0) {
const obj = this._objects.pop()!;
this._stats.size--;
@@ -70,7 +72,7 @@ export class Pool<T extends IPoolable> {
this._updateMemoryUsage();
return obj;
}
// 池中没有可用对象,创建新对象
this._stats.totalCreated++;
this._updateHitRate();
@@ -83,9 +85,9 @@ export class Pool<T extends IPoolable> {
*/
public release(obj: T): void {
if (!obj) return;
this._stats.totalReleased++;
// 如果池未满,将对象放回池中
if (this._stats.size < this._maxSize) {
// 重置对象状态
@@ -102,7 +104,7 @@ export class Pool<T extends IPoolable> {
* @returns
*/
public getStats(): Readonly<PoolStats> {
return { ...this._stats };
return {...this._stats};
}
/**
@@ -113,7 +115,7 @@ export class Pool<T extends IPoolable> {
for (const obj of this._objects) {
obj.reset();
}
this._objects.length = 0;
this._stats.size = 0;
this._updateMemoryUsage();
@@ -125,7 +127,7 @@ export class Pool<T extends IPoolable> {
*/
public compact(targetSize?: number): void {
const target = targetSize ?? Math.floor(this._objects.length / 2);
while (this._objects.length > target) {
const obj = this._objects.pop();
if (obj) {
@@ -133,7 +135,7 @@ export class Pool<T extends IPoolable> {
this._stats.size--;
}
}
this._updateMemoryUsage();
}
@@ -143,7 +145,7 @@ export class Pool<T extends IPoolable> {
*/
public prewarm(count: number): void {
const actualCount = Math.min(count, this._maxSize - this._objects.length);
for (let i = 0; i < actualCount; i++) {
const obj = this._createFn();
obj.reset();
@@ -151,7 +153,7 @@ export class Pool<T extends IPoolable> {
this._stats.totalCreated++;
this._stats.size++;
}
this._updateMemoryUsage();
}
@@ -162,7 +164,7 @@ export class Pool<T extends IPoolable> {
public setMaxSize(maxSize: number): void {
this._maxSize = maxSize;
this._stats.maxSize = maxSize;
// 如果当前池大小超过新的最大值,进行压缩
if (this._objects.length > maxSize) {
this.compact(maxSize);
@@ -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());
}
@@ -207,12 +209,12 @@ export class Pool<T extends IPoolable> {
*/
public static getAllPoolStats(): Record<string, PoolStats> {
const stats: Record<string, PoolStats> = {};
for (const [type, pool] of this._pools) {
const typeName = type.name || type.toString();
stats[typeName] = pool.getStats();
}
return stats;
}
@@ -241,13 +243,13 @@ export class Pool<T extends IPoolable> {
*/
public static getGlobalStatsString(): string {
const stats = this.getAllPoolStats();
const lines: string[] = ['=== Object Pool Global Statistics ===', ''];
const lines: string[] = ["=== Object Pool Global Statistics ===", ""];
if (Object.keys(stats).length === 0) {
lines.push('No pools registered');
return lines.join('\n');
lines.push("No pools registered");
return lines.join("\n");
}
for (const [typeName, stat] of Object.entries(stats)) {
lines.push(`${typeName}:`);
lines.push(` Size: ${stat.size}/${stat.maxSize}`);
@@ -255,10 +257,10 @@ export class Pool<T extends IPoolable> {
lines.push(` Total Created: ${stat.totalCreated}`);
lines.push(` Total Obtained: ${stat.totalObtained}`);
lines.push(` Memory: ${(stat.estimatedMemoryUsage / 1024).toFixed(1)} KB`);
lines.push('');
lines.push("");
}
return lines.join('\n');
return lines.join("\n");
}
/**
@@ -279,4 +281,4 @@ export class Pool<T extends IPoolable> {
private _updateMemoryUsage(): void {
this._stats.estimatedMemoryUsage = this._stats.size * this._objectSize;
}
}
}
+22 -22
View File
@@ -1,6 +1,6 @@
import { IPoolable, PoolStats } from './IPoolable';
import { Pool } from './Pool';
import type { IService } from '../../Core/ServiceContainer';
import {IPoolable, PoolStats} from "./IPoolable";
import {Pool} from "./Pool";
import type {IService} from "../../Core/ServiceContainer";
/**
*
@@ -38,7 +38,7 @@ export class PoolManager implements IService {
*/
public update(): void {
const now = Date.now();
if (now - this.lastCompactTime > this.autoCompactInterval) {
this.compactAllPools();
this.lastCompactTime = now;
@@ -60,12 +60,12 @@ export class PoolManager implements IService {
estimatedObjectSize: number = 1024
): Pool<T> {
let pool = this.pools.get(name) as Pool<T>;
if (!pool) {
pool = new Pool(createFn, maxSize, estimatedObjectSize);
this.pools.set(name, pool);
}
return pool;
}
@@ -125,11 +125,11 @@ export class PoolManager implements IService {
*/
public getAllStats(): Map<string, PoolStats> {
const stats = new Map<string, PoolStats>();
for (const [name, pool] of this.pools) {
stats.set(name, pool.getStats());
}
return stats;
}
@@ -144,7 +144,7 @@ export class PoolManager implements IService {
let totalObtained = 0;
let totalReleased = 0;
let totalMemoryUsage = 0;
for (const pool of this.pools.values()) {
const stats = pool.getStats();
totalSize += stats.size;
@@ -154,9 +154,9 @@ export class PoolManager implements IService {
totalReleased += stats.totalReleased;
totalMemoryUsage += stats.estimatedMemoryUsage;
}
const hitRate = totalObtained === 0 ? 0 : (totalObtained - totalCreated) / totalObtained;
return {
size: totalSize,
maxSize: totalMaxSize,
@@ -173,29 +173,29 @@ export class PoolManager implements IService {
* @returns
*/
public getStatsString(): string {
const lines: string[] = ['=== Pool Manager Statistics ===', ''];
const lines: string[] = ["=== Pool Manager Statistics ===", ""];
if (this.pools.size === 0) {
lines.push('No pools registered');
return lines.join('\n');
lines.push("No pools registered");
return lines.join("\n");
}
const globalStats = this.getGlobalStats();
lines.push(`Total Pools: ${this.pools.size}`);
lines.push(`Global Hit Rate: ${(globalStats.hitRate * 100).toFixed(1)}%`);
lines.push(`Global Memory Usage: ${(globalStats.estimatedMemoryUsage / 1024).toFixed(1)} KB`);
lines.push('');
lines.push("");
for (const [name, pool] of this.pools) {
const stats = pool.getStats();
lines.push(`${name}:`);
lines.push(` Size: ${stats.size}/${stats.maxSize}`);
lines.push(` Hit Rate: ${(stats.hitRate * 100).toFixed(1)}%`);
lines.push(` Memory: ${(stats.estimatedMemoryUsage / 1024).toFixed(1)} KB`);
lines.push('');
lines.push("");
}
return lines.join('\n');
return lines.join("\n");
}
/**
@@ -233,4 +233,4 @@ export class PoolManager implements IService {
public dispose(): void {
this.reset();
}
}
}
+3 -3
View File
@@ -1,3 +1,3 @@
export * from './IPoolable';
export * from './Pool';
export * from './PoolManager';
export * from "./IPoolable";
export * from "./Pool";
export * from "./PoolManager";
+6 -6
View File
@@ -7,27 +7,27 @@ export class Time {
*
*/
public static deltaTime: number = 0;
/**
*
*/
public static unscaledDeltaTime: number = 0;
/**
*
*/
public static totalTime: number = 0;
/**
*
*/
public static unscaledTotalTime: number = 0;
/**
*
*/
public static timeScale: number = 1;
/**
*
*/
@@ -70,4 +70,4 @@ export class Time {
public static checkEvery(interval: number, lastTime: number): boolean {
return this.totalTime - lastTime >= interval;
}
}
}

Some files were not shown because too many files have changed in this diff Show More