style(core): 统一代码风格并强化命名规范
This commit is contained in:
+24
-1
@@ -31,9 +31,32 @@
|
|||||||
"@typescript-eslint/no-unsafe-call": "warn",
|
"@typescript-eslint/no-unsafe-call": "warn",
|
||||||
"@typescript-eslint/no-unsafe-return": "warn",
|
"@typescript-eslint/no-unsafe-return": "warn",
|
||||||
"@typescript-eslint/no-unsafe-argument": "warn",
|
"@typescript-eslint/no-unsafe-argument": "warn",
|
||||||
|
"@typescript-eslint/no-unsafe-function-type": "error",
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||||
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
|
"@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": [
|
"ignorePatterns": [
|
||||||
"node_modules/",
|
"node_modules/",
|
||||||
|
|||||||
+33
-33
@@ -1,20 +1,20 @@
|
|||||||
import { TimerManager } from './Utils/Timers/TimerManager';
|
import {TimerManager} from "./Utils/Timers/TimerManager";
|
||||||
import { ITimer } from './Utils/Timers/ITimer';
|
import {ITimer} from "./Utils/Timers/ITimer";
|
||||||
import { Timer } from './Utils/Timers/Timer';
|
import {Timer} from "./Utils/Timers/Timer";
|
||||||
import { Time } from './Utils/Time';
|
import {Time} from "./Utils/Time";
|
||||||
import { PerformanceMonitor } from './Utils/PerformanceMonitor';
|
import {PerformanceMonitor} from "./Utils/PerformanceMonitor";
|
||||||
import { PoolManager } from './Utils/Pool/PoolManager';
|
import {PoolManager} from "./Utils/Pool/PoolManager";
|
||||||
import { DebugManager } from './Utils/Debug';
|
import {DebugManager} from "./Utils/Debug";
|
||||||
import { ICoreConfig, IECSDebugConfig } from './Types';
|
import {ICoreConfig, IECSDebugConfig} from "./Types";
|
||||||
import { createLogger } from './Utils/Logger';
|
import {createLogger} from "./Utils/Logger";
|
||||||
import { SceneManager } from './ECS/SceneManager';
|
import {SceneManager} from "./ECS/SceneManager";
|
||||||
import { IScene } from './ECS/IScene';
|
import {IScene} from "./ECS/IScene";
|
||||||
import { ServiceContainer } from './Core/ServiceContainer';
|
import {ServiceContainer} from "./Core/ServiceContainer";
|
||||||
import { PluginManager } from './Core/PluginManager';
|
import {PluginManager} from "./Core/PluginManager";
|
||||||
import { IPlugin } from './Core/Plugin';
|
import {IPlugin} from "./Core/Plugin";
|
||||||
import { WorldManager } from './ECS/WorldManager';
|
import {WorldManager} from "./ECS/WorldManager";
|
||||||
import { DebugConfigService } from './Utils/Debug/DebugConfigService';
|
import {DebugConfigService} from "./Utils/Debug/DebugConfigService";
|
||||||
import { createInstance } from './Core/DI/Decorators';
|
import {createInstance} from "./Core/DI/Decorators";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 游戏引擎核心类
|
* 游戏引擎核心类
|
||||||
@@ -67,7 +67,7 @@ export class Core {
|
|||||||
/**
|
/**
|
||||||
* Core专用日志器
|
* Core专用日志器
|
||||||
*/
|
*/
|
||||||
private static _logger = createLogger('Core');
|
private static _logger = createLogger("Core");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实体系统启用状态
|
* 实体系统启用状态
|
||||||
@@ -246,7 +246,7 @@ export class Core {
|
|||||||
*/
|
*/
|
||||||
public static get services(): ServiceContainer {
|
public static get services(): ServiceContainer {
|
||||||
if (!this._instance) {
|
if (!this._instance) {
|
||||||
throw new Error('Core实例未创建,请先调用Core.create()');
|
throw new Error("Core实例未创建,请先调用Core.create()");
|
||||||
}
|
}
|
||||||
return this._instance._serviceContainer;
|
return this._instance._serviceContainer;
|
||||||
}
|
}
|
||||||
@@ -270,7 +270,7 @@ export class Core {
|
|||||||
*/
|
*/
|
||||||
public static get worldManager(): WorldManager {
|
public static get worldManager(): WorldManager {
|
||||||
if (!this._instance) {
|
if (!this._instance) {
|
||||||
throw new Error('Core实例未创建,请先调用Core.create()');
|
throw new Error("Core实例未创建,请先调用Core.create()");
|
||||||
}
|
}
|
||||||
return this._instance._worldManager;
|
return this._instance._worldManager;
|
||||||
}
|
}
|
||||||
@@ -302,12 +302,12 @@ export class Core {
|
|||||||
public static create(config: ICoreConfig | boolean = true): Core {
|
public static create(config: ICoreConfig | boolean = true): Core {
|
||||||
if (this._instance == null) {
|
if (this._instance == null) {
|
||||||
// 向后兼容:如果传入boolean,转换为配置对象
|
// 向后兼容:如果传入boolean,转换为配置对象
|
||||||
const coreConfig: ICoreConfig = typeof config === 'boolean'
|
const coreConfig: ICoreConfig = typeof config === "boolean"
|
||||||
? {debug: config, enableEntitySystems: true}
|
? {debug: config, enableEntitySystems: true}
|
||||||
: config;
|
: config;
|
||||||
this._instance = new Core(coreConfig);
|
this._instance = new Core(coreConfig);
|
||||||
} else {
|
} else {
|
||||||
this._logger.warn('Core实例已创建,返回现有实例');
|
this._logger.warn("Core实例已创建,返回现有实例");
|
||||||
}
|
}
|
||||||
return this._instance;
|
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> {
|
public static schedule<TContext = unknown>(timeInSeconds: number, repeats: boolean = false, context?: TContext, onTime?: (timer: ITimer<TContext>) => void): Timer<TContext> {
|
||||||
if (!this._instance) {
|
if (!this._instance) {
|
||||||
throw new Error('Core实例未创建,请先调用Core.create()');
|
throw new Error("Core实例未创建,请先调用Core.create()");
|
||||||
}
|
}
|
||||||
if (!onTime) {
|
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);
|
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> {
|
public static async installPlugin(plugin: IPlugin): Promise<void> {
|
||||||
if (!this._instance) {
|
if (!this._instance) {
|
||||||
throw new Error('Core实例未创建,请先调用Core.create()');
|
throw new Error("Core实例未创建,请先调用Core.create()");
|
||||||
}
|
}
|
||||||
|
|
||||||
await this._instance._pluginManager.install(plugin);
|
await this._instance._pluginManager.install(plugin);
|
||||||
@@ -568,7 +568,7 @@ export class Core {
|
|||||||
*/
|
*/
|
||||||
public static async uninstallPlugin(name: string): Promise<void> {
|
public static async uninstallPlugin(name: string): Promise<void> {
|
||||||
if (!this._instance) {
|
if (!this._instance) {
|
||||||
throw new Error('Core实例未创建,请先调用Core.create()');
|
throw new Error("Core实例未创建,请先调用Core.create()");
|
||||||
}
|
}
|
||||||
|
|
||||||
await this._instance._pluginManager.uninstall(name);
|
await this._instance._pluginManager.uninstall(name);
|
||||||
@@ -624,7 +624,7 @@ export class Core {
|
|||||||
*/
|
*/
|
||||||
protected initialize() {
|
protected initialize() {
|
||||||
// 核心系统初始化
|
// 核心系统初始化
|
||||||
Core._logger.info('Core initialized', {
|
Core._logger.info("Core initialized", {
|
||||||
debug: this.debug,
|
debug: this.debug,
|
||||||
entitySystemsEnabled: Core.entitySystemsEnabled,
|
entitySystemsEnabled: Core.entitySystemsEnabled,
|
||||||
debugEnabled: this._config.debugConfig?.enabled || false
|
debugEnabled: this._config.debugConfig?.enabled || false
|
||||||
@@ -640,20 +640,20 @@ export class Core {
|
|||||||
if (Core.paused) return;
|
if (Core.paused) return;
|
||||||
|
|
||||||
// 开始性能监控
|
// 开始性能监控
|
||||||
const frameStartTime = this._performanceMonitor.startMonitoring('Core.update');
|
const frameStartTime = this._performanceMonitor.startMonitoring("Core.update");
|
||||||
|
|
||||||
// 更新时间系统
|
// 更新时间系统
|
||||||
Time.update(deltaTime);
|
Time.update(deltaTime);
|
||||||
|
|
||||||
// 更新FPS监控(如果性能监控器支持)
|
// 更新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);
|
this._performanceMonitor.updateFPS(Time.deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新所有可更新的服务
|
// 更新所有可更新的服务
|
||||||
const servicesStartTime = this._performanceMonitor.startMonitoring('Services.update');
|
const servicesStartTime = this._performanceMonitor.startMonitoring("Services.update");
|
||||||
this._serviceContainer.updateAll(deltaTime);
|
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();
|
this._poolManager.update();
|
||||||
@@ -665,7 +665,7 @@ export class Core {
|
|||||||
this._worldManager.updateAll();
|
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();
|
this._instance._serviceContainer.clear();
|
||||||
|
|
||||||
Core._logger.info('Core destroyed');
|
Core._logger.info("Core destroyed");
|
||||||
|
|
||||||
// 清空实例引用,允许重新创建Core实例
|
// 清空实例引用,允许重新创建Core实例
|
||||||
this._instance = null;
|
this._instance = null;
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
* 提供 @Injectable、@Inject 和 @Updatable 装饰器,用于标记可注入的类和依赖注入点
|
* 提供 @Injectable、@Inject 和 @Updatable 装饰器,用于标记可注入的类和依赖注入点
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { ServiceContainer } from '../ServiceContainer';
|
import type {ServiceContainer} from "../ServiceContainer";
|
||||||
import type { IService, ServiceType } from '../ServiceContainer';
|
import type {IService, ServiceType} from "../ServiceContainer";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 依赖注入元数据存储
|
* 依赖注入元数据存储
|
||||||
@@ -76,8 +76,8 @@ export interface UpdatableMetadata {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function Injectable(): ClassDecorator {
|
export function Injectable(): ClassDecorator {
|
||||||
return function (target: Function): void {
|
return function (target: Constructor): void {
|
||||||
const existing = injectableMetadata.get(target as Constructor);
|
const existing = injectableMetadata.get(target);
|
||||||
|
|
||||||
injectableMetadata.set(target as Constructor, {
|
injectableMetadata.set(target as Constructor, {
|
||||||
injectable: true,
|
injectable: true,
|
||||||
@@ -117,13 +117,13 @@ export function Injectable(): ClassDecorator {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export function Updatable(priority: number = 0): ClassDecorator {
|
export function Updatable(priority: number = 0): ClassDecorator {
|
||||||
return function (target: Function): void {
|
return function (target: Constructor): void {
|
||||||
// 验证类原型上是否有update方法
|
// 验证类原型上是否有update方法
|
||||||
const prototype = (target as Constructor & { prototype: { update?: unknown } }).prototype;
|
const prototype = (target as Constructor & { prototype: { update?: unknown } }).prototype;
|
||||||
if (!prototype || typeof prototype.update !== 'function') {
|
if (!prototype || typeof prototype.update !== "function") {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`@Updatable() decorator requires class ${target.name} to implement IUpdatable interface with update() method. ` +
|
`@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) {
|
if (serviceType) {
|
||||||
// 如果有显式的@Inject标记,使用标记的类型
|
// 如果有显式的@Inject标记,使用标记的类型
|
||||||
if (typeof serviceType === 'string' || typeof serviceType === 'symbol') {
|
if (typeof serviceType === "string" || typeof serviceType === "symbol") {
|
||||||
// 字符串或Symbol类型的服务标识
|
// 字符串或Symbol类型的服务标识
|
||||||
throw new Error(
|
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}`
|
`Please use class types for ${constructor.name} parameter ${i}`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -338,7 +338,7 @@ export function registerInjectable<T extends IService>(
|
|||||||
if (!isInjectable(serviceType)) {
|
if (!isInjectable(serviceType)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`${serviceType.name} is not marked as @Injectable(). ` +
|
`${serviceType.name} is not marked as @Injectable(). ` +
|
||||||
`Please add @Injectable() decorator to the class.`
|
"Please add @Injectable() decorator to the class."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ export {
|
|||||||
createInstance,
|
createInstance,
|
||||||
injectProperties,
|
injectProperties,
|
||||||
registerInjectable
|
registerInjectable
|
||||||
} from './Decorators';
|
} from "./Decorators";
|
||||||
|
|
||||||
export type { InjectableMetadata, UpdatableMetadata } from './Decorators';
|
export type {InjectableMetadata, UpdatableMetadata} from "./Decorators";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Core } from '../Core';
|
import type {Core} from "../Core";
|
||||||
import type { ServiceContainer } from './ServiceContainer';
|
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"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { IPlugin, IPluginMetadata, PluginState } from './Plugin';
|
import {IPlugin, IPluginMetadata, PluginState} from "./Plugin";
|
||||||
import type { IService } from './ServiceContainer';
|
import type {IService} from "./ServiceContainer";
|
||||||
import type { Core } from '../Core';
|
import type {Core} from "../Core";
|
||||||
import type { ServiceContainer } from './ServiceContainer';
|
import type {ServiceContainer} from "./ServiceContainer";
|
||||||
import { createLogger } from '../Utils/Logger';
|
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 {
|
public initialize(core: Core, services: ServiceContainer): void {
|
||||||
this._core = core;
|
this._core = core;
|
||||||
this._services = services;
|
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> {
|
public async install(plugin: IPlugin): Promise<void> {
|
||||||
if (!this._core || !this._services) {
|
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) {
|
if (missingDeps.length > 0) {
|
||||||
throw new Error(
|
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) {
|
if (dependents.length > 0) {
|
||||||
throw new Error(
|
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._core = null;
|
||||||
this._services = null;
|
this._services = null;
|
||||||
|
|
||||||
logger.info('PluginManager disposed');
|
logger.info("PluginManager disposed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createLogger } from '../Utils/Logger';
|
import {createLogger} from "../Utils/Logger";
|
||||||
import { isUpdatable as checkUpdatable, getUpdatableMetadata } from './DI';
|
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"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -240,7 +240,7 @@ export class ServiceContainer {
|
|||||||
|
|
||||||
// 检测循环依赖
|
// 检测循环依赖
|
||||||
if (this._resolving.has(type as ServiceType<IService>)) {
|
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}`);
|
throw new Error(`Circular dependency detected: ${chain} -> ${type.name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +337,7 @@ export class ServiceContainer {
|
|||||||
// 如果有单例实例,调用 dispose
|
// 如果有单例实例,调用 dispose
|
||||||
if (registration.instance) {
|
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) {
|
if (index !== -1) {
|
||||||
this._updatableServices.splice(index, 1);
|
this._updatableServices.splice(index, 1);
|
||||||
}
|
}
|
||||||
@@ -363,7 +363,7 @@ export class ServiceContainer {
|
|||||||
|
|
||||||
this._services.clear();
|
this._services.clear();
|
||||||
this._updatableServices = [];
|
this._updatableServices = [];
|
||||||
logger.debug('Cleared all services');
|
logger.debug("Cleared all services");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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。
|
* 用于为每个组件分配唯一的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给组件。
|
* 自动分配唯一ID给组件。
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
this.id = Component._idGenerator++;
|
this.id = Component._nextId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
import { ComponentType, ComponentRegistry } from './ComponentStorage';
|
import {ComponentType, ComponentRegistry} from "./ComponentStorage";
|
||||||
import {BitMask64Data, BitMask64Utils} from "../Utils";
|
import {BitMask64Data, BitMask64Utils} from "../Utils";
|
||||||
import {BitMaskHashMap} from "../Utils/BitMaskHashMap";
|
import {BitMaskHashMap} from "../Utils/BitMaskHashMap";
|
||||||
|
|
||||||
@@ -126,12 +126,12 @@ export class ArchetypeSystem {
|
|||||||
* @param operation 查询操作类型:'AND'(包含所有)或 'OR'(包含任意)
|
* @param operation 查询操作类型:'AND'(包含所有)或 'OR'(包含任意)
|
||||||
* @returns 匹配的原型列表及实体总数
|
* @returns 匹配的原型列表及实体总数
|
||||||
*/
|
*/
|
||||||
public queryArchetypes(componentTypes: ComponentType[], operation: 'AND' | 'OR' = 'AND'): ArchetypeQueryResult {
|
public queryArchetypes(componentTypes: ComponentType[], operation: "AND" | "OR" = "AND"): ArchetypeQueryResult {
|
||||||
|
|
||||||
const matchingArchetypes: Archetype[] = [];
|
const matchingArchetypes: Archetype[] = [];
|
||||||
let totalEntities = 0;
|
let totalEntities = 0;
|
||||||
|
|
||||||
if (operation === 'AND') {
|
if (operation === "AND") {
|
||||||
if (componentTypes.length === 0) {
|
if (componentTypes.length === 0) {
|
||||||
for (const archetype of this._allArchetypes) {
|
for (const archetype of this._allArchetypes) {
|
||||||
matchingArchetypes.push(archetype);
|
matchingArchetypes.push(archetype);
|
||||||
@@ -247,7 +247,7 @@ export class ArchetypeSystem {
|
|||||||
*/
|
*/
|
||||||
private updateAllArchetypeArrays(): void {
|
private updateAllArchetypeArrays(): void {
|
||||||
this._allArchetypes = [];
|
this._allArchetypes = [];
|
||||||
for (let archetype of this._archetypes.values()) {
|
for (const archetype of this._archetypes.values()) {
|
||||||
this._allArchetypes.push(archetype);
|
this._allArchetypes.push(archetype);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,7 +258,7 @@ export class ArchetypeSystem {
|
|||||||
private getEntityComponentTypes(entity: Entity): ComponentType[] {
|
private getEntityComponentTypes(entity: Entity): ComponentType[] {
|
||||||
let componentTypes = this._entityComponentTypesCache.get(entity);
|
let componentTypes = this._entityComponentTypesCache.get(entity);
|
||||||
if (!componentTypes) {
|
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);
|
this._entityComponentTypesCache.set(entity, componentTypes);
|
||||||
}
|
}
|
||||||
return componentTypes;
|
return componentTypes;
|
||||||
@@ -269,7 +269,7 @@ export class ArchetypeSystem {
|
|||||||
* 使用ComponentRegistry确保与Entity.componentMask使用相同的bitIndex
|
* 使用ComponentRegistry确保与Entity.componentMask使用相同的bitIndex
|
||||||
*/
|
*/
|
||||||
private generateArchetypeId(componentTypes: ComponentType[]): ArchetypeId {
|
private generateArchetypeId(componentTypes: ComponentType[]): ArchetypeId {
|
||||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
for (const type of componentTypes) {
|
for (const type of componentTypes) {
|
||||||
if (!ComponentRegistry.isRegistered(type)) {
|
if (!ComponentRegistry.isRegistered(type)) {
|
||||||
ComponentRegistry.register(type);
|
ComponentRegistry.register(type);
|
||||||
|
|||||||
@@ -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 {
|
acquireComponent<T extends Component>(componentName: string): T | null {
|
||||||
const pool = this.pools.get(componentName);
|
const pool = this.pools.get(componentName);
|
||||||
|
|
||||||
this.trackUsage(componentName, 'create');
|
this.trackUsage(componentName, "create");
|
||||||
|
|
||||||
return pool ? (pool.acquire() as T) : null;
|
return pool ? (pool.acquire() as T) : null;
|
||||||
}
|
}
|
||||||
@@ -194,7 +194,7 @@ export class ComponentPoolManager {
|
|||||||
releaseComponent<T extends Component>(componentName: string, component: T): void {
|
releaseComponent<T extends Component>(componentName: string, component: T): void {
|
||||||
const pool = this.pools.get(componentName);
|
const pool = this.pools.get(componentName);
|
||||||
|
|
||||||
this.trackUsage(componentName, 'release');
|
this.trackUsage(componentName, "release");
|
||||||
|
|
||||||
if (pool) {
|
if (pool) {
|
||||||
pool.release(component);
|
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);
|
let tracker = this.usageTracker.get(componentName);
|
||||||
|
|
||||||
if (!tracker) {
|
if (!tracker) {
|
||||||
@@ -216,7 +216,7 @@ export class ComponentPoolManager {
|
|||||||
this.usageTracker.set(componentName, tracker);
|
this.usageTracker.set(componentName, tracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action === 'create') {
|
if (action === "create") {
|
||||||
tracker.createCount++;
|
tracker.createCount++;
|
||||||
} else {
|
} else {
|
||||||
tracker.releaseCount++;
|
tracker.releaseCount++;
|
||||||
@@ -289,12 +289,12 @@ export class ComponentPoolManager {
|
|||||||
*/
|
*/
|
||||||
getGlobalStats(): Array<{
|
getGlobalStats(): Array<{
|
||||||
componentName: string;
|
componentName: string;
|
||||||
poolStats: ReturnType<ComponentPool<Component>['getStats']>;
|
poolStats: ReturnType<ComponentPool<Component>["getStats"]>;
|
||||||
usage: ComponentUsageTracker | undefined;
|
usage: ComponentUsageTracker | undefined;
|
||||||
}> {
|
}> {
|
||||||
const stats: Array<{
|
const stats: Array<{
|
||||||
componentName: string;
|
componentName: string;
|
||||||
poolStats: ReturnType<ComponentPool<Component>['getStats']>;
|
poolStats: ReturnType<ComponentPool<Component>["getStats"]>;
|
||||||
usage: ComponentUsageTracker | undefined;
|
usage: ComponentUsageTracker | undefined;
|
||||||
}> = [];
|
}> = [];
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import { Component } from '../Component';
|
import {Component} from "../Component";
|
||||||
import { BitMask64Utils, BitMask64Data } from '../Utils/BigIntCompatibility';
|
import {BitMask64Utils, BitMask64Data} from "../Utils/BigIntCompatibility";
|
||||||
import { SoAStorage, SupportedTypedArray } from './SoAStorage';
|
import {SoAStorage, SupportedTypedArray} from "./SoAStorage";
|
||||||
import { createLogger } from '../../Utils/Logger';
|
import {createLogger} from "../../Utils/Logger";
|
||||||
import { getComponentTypeName } from '../Decorators';
|
import {getComponentTypeName} from "../Decorators";
|
||||||
import { ComponentRegistry, ComponentType } from './ComponentStorage/ComponentRegistry';
|
import {ComponentRegistry, ComponentType} from "./ComponentStorage/ComponentRegistry";
|
||||||
|
|
||||||
// 导出核心类型
|
// 导出核心类型
|
||||||
export {ComponentRegistry, ComponentType};
|
export {ComponentRegistry, ComponentType};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 高性能组件存储器
|
* 高性能组件存储器
|
||||||
*/
|
*/
|
||||||
@@ -172,7 +171,7 @@ export class ComponentStorage<T extends Component> {
|
|||||||
* 管理所有组件类型的存储器
|
* 管理所有组件类型的存储器
|
||||||
*/
|
*/
|
||||||
export class ComponentStorageManager {
|
export class ComponentStorageManager {
|
||||||
private static readonly _logger = createLogger('ComponentStorage');
|
private static readonly _logger = createLogger("ComponentStorage");
|
||||||
private storages = new Map<Function, ComponentStorage<Component> | SoAStorage<Component>>();
|
private storages = new Map<Function, ComponentStorage<Component> | SoAStorage<Component>>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -342,7 +341,7 @@ export class ComponentStorageManager {
|
|||||||
* @returns 组件位掩码
|
* @returns 组件位掩码
|
||||||
*/
|
*/
|
||||||
public getComponentMask(entityId: number): BitMask64Data {
|
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()) {
|
for (const [componentType, storage] of this.storages.entries()) {
|
||||||
if (storage.hasComponent(entityId)) {
|
if (storage.hasComponent(entityId)) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Component } from '../../Component';
|
import {Component} from "../../Component";
|
||||||
import { BitMask64Utils, BitMask64Data } from '../../Utils/BigIntCompatibility';
|
import {BitMask64Utils, BitMask64Data} from "../../Utils/BigIntCompatibility";
|
||||||
import { createLogger } from '../../../Utils/Logger';
|
import {createLogger} from "../../../Utils/Logger";
|
||||||
import { getComponentTypeName } from '../../Decorators';
|
import {getComponentTypeName} from "../../Decorators";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件类型定义
|
* 组件类型定义
|
||||||
@@ -13,10 +13,10 @@ export type ComponentType<T extends Component = Component> = new (...args: any[]
|
|||||||
* 管理组件类型的位掩码分配
|
* 管理组件类型的位掩码分配
|
||||||
*/
|
*/
|
||||||
export class ComponentRegistry {
|
export class ComponentRegistry {
|
||||||
protected static readonly _logger = createLogger('ComponentStorage');
|
protected static readonly _logger = createLogger("ComponentStorage");
|
||||||
private static componentTypes = new Map<Function, number>();
|
private static componentTypes = new Map<ComponentType, number>();
|
||||||
private static bitIndexToType = new Map<number, Function>();
|
private static bitIndexToType = new Map<number, ComponentType>();
|
||||||
private static componentNameToType = new Map<string, Function>();
|
private static componentNameToType = new Map<string, ComponentType>();
|
||||||
private static componentNameToId = new Map<string, number>();
|
private static componentNameToId = new Map<string, number>();
|
||||||
private static maskCache = new Map<string, BitMask64Data>();
|
private static maskCache = new Map<string, BitMask64Data>();
|
||||||
private static nextBitIndex = 0;
|
private static nextBitIndex = 0;
|
||||||
@@ -175,13 +175,13 @@ export class ComponentRegistry {
|
|||||||
*/
|
*/
|
||||||
public static createComponentMask(componentNames: string[]): BitMask64Data {
|
public static createComponentMask(componentNames: string[]): BitMask64Data {
|
||||||
const sortedNames = [...componentNames].sort();
|
const sortedNames = [...componentNames].sort();
|
||||||
const cacheKey = `multi:${sortedNames.join(',')}`;
|
const cacheKey = `multi:${sortedNames.join(",")}`;
|
||||||
|
|
||||||
if (this.maskCache.has(cacheKey)) {
|
if (this.maskCache.has(cacheKey)) {
|
||||||
return this.maskCache.get(cacheKey)!;
|
return this.maskCache.get(cacheKey)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
for (const name of componentNames) {
|
for (const name of componentNames) {
|
||||||
const componentId = this.getComponentId(name);
|
const componentId = this.getComponentId(name);
|
||||||
if (componentId !== undefined) {
|
if (componentId !== undefined) {
|
||||||
|
|||||||
@@ -8,25 +8,25 @@ import {
|
|||||||
ISystemEventData,
|
ISystemEventData,
|
||||||
ISceneEventData,
|
ISceneEventData,
|
||||||
IPerformanceEventData
|
IPerformanceEventData
|
||||||
} from '../../Types';
|
} from "../../Types";
|
||||||
import { createLogger } from '../../Utils/Logger';
|
import {createLogger} from "../../Utils/Logger";
|
||||||
import {
|
import {
|
||||||
TypeSafeEventSystem,
|
TypeSafeEventSystem,
|
||||||
EventListenerConfig,
|
EventListenerConfig,
|
||||||
EventStats
|
EventStats
|
||||||
} from './EventSystem';
|
} from "./EventSystem";
|
||||||
import {
|
import {
|
||||||
ECSEventType,
|
ECSEventType,
|
||||||
EventPriority,
|
EventPriority,
|
||||||
EventTypeValidator
|
EventTypeValidator
|
||||||
} from '../CoreEvents';
|
} from "../CoreEvents";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增强的事件总线实现
|
* 增强的事件总线实现
|
||||||
* 基于TypeSafeEventSystem,提供类型安全的事件发布订阅机制
|
* 基于TypeSafeEventSystem,提供类型安全的事件发布订阅机制
|
||||||
*/
|
*/
|
||||||
export class EventBus implements IEventBus {
|
export class EventBus implements IEventBus {
|
||||||
private static readonly _logger = createLogger('EventBus');
|
private static readonly _logger = createLogger("EventBus");
|
||||||
private eventSystem: TypeSafeEventSystem;
|
private eventSystem: TypeSafeEventSystem;
|
||||||
private eventIdCounter = 0;
|
private eventIdCounter = 0;
|
||||||
private isDebugMode = false;
|
private isDebugMode = false;
|
||||||
@@ -187,7 +187,7 @@ export class EventBus implements IEventBus {
|
|||||||
*/
|
*/
|
||||||
public clear(): void {
|
public clear(): void {
|
||||||
if (this.isDebugMode) {
|
if (this.isDebugMode) {
|
||||||
EventBus._logger.info('清空所有监听器');
|
EventBus._logger.info("清空所有监听器");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.eventSystem.clear();
|
this.eventSystem.clear();
|
||||||
@@ -399,7 +399,7 @@ export class EventBus implements IEventBus {
|
|||||||
return {
|
return {
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
eventId: `${eventType}_${++this.eventIdCounter}`,
|
eventId: `${eventType}_${++this.eventIdCounter}`,
|
||||||
source: 'EventBus'
|
source: "EventBus"
|
||||||
} as T & IEventData;
|
} as T & IEventData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,7 +413,7 @@ export class EventBus implements IEventBus {
|
|||||||
enhanced.eventId = `${eventType}_${++this.eventIdCounter}`;
|
enhanced.eventId = `${eventType}_${++this.eventIdCounter}`;
|
||||||
}
|
}
|
||||||
if (!enhanced.source) {
|
if (!enhanced.source) {
|
||||||
enhanced.source = 'EventBus';
|
enhanced.source = "EventBus";
|
||||||
}
|
}
|
||||||
|
|
||||||
return enhanced;
|
return enhanced;
|
||||||
@@ -466,4 +466,3 @@ export class GlobalEventBus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createLogger } from '../../Utils/Logger';
|
import {createLogger} from "../../Utils/Logger";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事件处理器函数类型
|
* 事件处理器函数类型
|
||||||
@@ -68,7 +68,7 @@ export interface EventBatchConfig {
|
|||||||
* 支持同步/异步事件、优先级、批处理等功能
|
* 支持同步/异步事件、优先级、批处理等功能
|
||||||
*/
|
*/
|
||||||
export class TypeSafeEventSystem {
|
export class TypeSafeEventSystem {
|
||||||
private static readonly _logger = createLogger('EventSystem');
|
private static readonly _logger = createLogger("EventSystem");
|
||||||
private listeners = new Map<string, InternalEventListener[]>();
|
private listeners = new Map<string, InternalEventListener[]>();
|
||||||
private stats = new Map<string, EventStats>();
|
private stats = new Map<string, EventStats>();
|
||||||
private batchQueue = new Map<string, any[]>();
|
private batchQueue = new Map<string, any[]>();
|
||||||
@@ -133,7 +133,7 @@ export class TypeSafeEventSystem {
|
|||||||
const listeners = this.listeners.get(eventType);
|
const listeners = this.listeners.get(eventType);
|
||||||
if (!listeners) return false;
|
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;
|
if (index === -1) return false;
|
||||||
|
|
||||||
listeners.splice(index, 1);
|
listeners.splice(index, 1);
|
||||||
@@ -340,7 +340,7 @@ export class TypeSafeEventSystem {
|
|||||||
// 检查监听器数量限制
|
// 检查监听器数量限制
|
||||||
if (listeners.length >= this.maxListeners) {
|
if (listeners.length >= this.maxListeners) {
|
||||||
TypeSafeEventSystem._logger.warn(`事件类型 ${eventType} 的监听器数量超过最大限制 (${this.maxListeners})`);
|
TypeSafeEventSystem._logger.warn(`事件类型 ${eventType} 的监听器数量超过最大限制 (${this.maxListeners})`);
|
||||||
return '';
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
const listenerId = `listener_${this.nextListenerId++}`;
|
const listenerId = `listener_${this.nextListenerId++}`;
|
||||||
@@ -379,8 +379,8 @@ export class TypeSafeEventSystem {
|
|||||||
const sortedListeners = this.sortListenersByPriority(listeners);
|
const sortedListeners = this.sortListenersByPriority(listeners);
|
||||||
|
|
||||||
// 分离同步和异步监听器
|
// 分离同步和异步监听器
|
||||||
const syncListeners = sortedListeners.filter(l => !l.config.async);
|
const syncListeners = sortedListeners.filter((l) => !l.config.async);
|
||||||
const asyncListeners = sortedListeners.filter(l => l.config.async);
|
const asyncListeners = sortedListeners.filter((l) => l.config.async);
|
||||||
|
|
||||||
// 执行同步监听器
|
// 执行同步监听器
|
||||||
for (const listener of syncListeners) {
|
for (const listener of syncListeners) {
|
||||||
@@ -447,7 +447,7 @@ export class TypeSafeEventSystem {
|
|||||||
if (!listeners) return;
|
if (!listeners) return;
|
||||||
|
|
||||||
for (const id of listenerIds) {
|
for (const id of listenerIds) {
|
||||||
const index = listeners.findIndex(l => l.id === id);
|
const index = listeners.findIndex((l) => l.id === id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
listeners.splice(index, 1);
|
listeners.splice(index, 1);
|
||||||
}
|
}
|
||||||
@@ -578,4 +578,3 @@ export class TypeSafeEventSystem {
|
|||||||
*/
|
*/
|
||||||
export const GlobalEventSystem = new TypeSafeEventSystem();
|
export const GlobalEventSystem = new TypeSafeEventSystem();
|
||||||
|
|
||||||
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
export { EventBus, GlobalEventBus } from '../EventBus';
|
export {EventBus, GlobalEventBus} from "../EventBus";
|
||||||
export { TypeSafeEventSystem, EventListenerConfig, EventStats } from '../EventSystem';
|
export {TypeSafeEventSystem, EventListenerConfig, EventStats} from "../EventSystem";
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ export {
|
|||||||
createECSAPI,
|
createECSAPI,
|
||||||
initializeECS,
|
initializeECS,
|
||||||
ECS
|
ECS
|
||||||
} from './FluentAPI/index';
|
} from "./FluentAPI/index";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Component } from '../../Component';
|
import {Component} from "../../Component";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件构建器 - 提供流式API创建组件
|
* 组件构建器 - 提供流式API创建组件
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { Entity } from '../../Entity';
|
import {Entity} from "../../Entity";
|
||||||
import { Component } from '../../Component';
|
import {Component} from "../../Component";
|
||||||
import { IScene } from '../../IScene';
|
import {IScene} from "../../IScene";
|
||||||
import { ComponentType } from '../ComponentStorage';
|
import {ComponentType} from "../ComponentStorage";
|
||||||
import { QuerySystem, QueryBuilder } from '../QuerySystem';
|
import {QuerySystem, QueryBuilder} from "../QuerySystem";
|
||||||
import { TypeSafeEventSystem } from '../EventSystem';
|
import {TypeSafeEventSystem} from "../EventSystem";
|
||||||
import { EntityBuilder } from './EntityBuilder';
|
import {EntityBuilder} from "./EntityBuilder";
|
||||||
import { SceneBuilder } from './SceneBuilder';
|
import {SceneBuilder} from "./SceneBuilder";
|
||||||
import { ComponentBuilder } from './ComponentBuilder';
|
import {ComponentBuilder} from "./ComponentBuilder";
|
||||||
import { EntityBatchOperator } from './EntityBatchOperator';
|
import {EntityBatchOperator} from "./EntityBatchOperator";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ECS流式API主入口
|
* ECS流式API主入口
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Entity } from '../../Entity';
|
import {Entity} from "../../Entity";
|
||||||
import { Component } from '../../Component';
|
import {Component} from "../../Component";
|
||||||
import { ComponentType } from '../ComponentStorage';
|
import {ComponentType} from "../ComponentStorage";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实体批量操作器
|
* 实体批量操作器
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Entity } from '../../Entity';
|
import {Entity} from "../../Entity";
|
||||||
import { Component } from '../../Component';
|
import {Component} from "../../Component";
|
||||||
import { IScene } from '../../IScene';
|
import {IScene} from "../../IScene";
|
||||||
import { ComponentType, ComponentStorageManager } from '../ComponentStorage';
|
import {ComponentType, ComponentStorageManager} from "../ComponentStorage";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实体构建器 - 提供流式API创建和配置实体
|
* 实体构建器 - 提供流式API创建和配置实体
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Entity } from '../../Entity';
|
import {Entity} from "../../Entity";
|
||||||
import { Scene } from '../../Scene';
|
import {Scene} from "../../Scene";
|
||||||
import { EntitySystem } from '../../Systems/EntitySystem';
|
import {EntitySystem} from "../../Systems/EntitySystem";
|
||||||
import { EntityBuilder } from './EntityBuilder';
|
import {EntityBuilder} from "./EntityBuilder";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 场景构建器 - 提供流式API创建和配置场景
|
* 场景构建器 - 提供流式API创建和配置场景
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export { EntityBuilder } from './EntityBuilder';
|
export {EntityBuilder} from "./EntityBuilder";
|
||||||
export { SceneBuilder } from './SceneBuilder';
|
export {SceneBuilder} from "./SceneBuilder";
|
||||||
export { ComponentBuilder } from './ComponentBuilder';
|
export {ComponentBuilder} from "./ComponentBuilder";
|
||||||
export { EntityBatchOperator } from './EntityBatchOperator';
|
export {EntityBatchOperator} from "./EntityBatchOperator";
|
||||||
export { ECSFluentAPI, createECSAPI, initializeECS, ECS } from './ECSFluentAPI';
|
export {ECSFluentAPI, createECSAPI, initializeECS, ECS} from "./ECSFluentAPI";
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* 提供完整的TypeScript类型推断,在编译时确保类型安全
|
* 提供完整的TypeScript类型推断,在编译时确保类型安全
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Entity } from '../../Entity';
|
import type {Entity} from "../../Entity";
|
||||||
import type { ComponentConstructor } from '../../../Types/TypeHelpers';
|
import type {ComponentConstructor} from "../../../Types/TypeHelpers";
|
||||||
import { Matcher, type QueryCondition } from '../../Utils/Matcher';
|
import {Matcher, type QueryCondition} from "../../Utils/Matcher";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 类型安全的查询结果
|
* 类型安全的查询结果
|
||||||
|
|||||||
@@ -1,3 +1,2 @@
|
|||||||
export { QuerySystem } from '../QuerySystem';
|
export {QuerySystem} from "../QuerySystem";
|
||||||
export { ECSFluentAPI, createECSAPI } from '../FluentAPI';
|
export {ECSFluentAPI, createECSAPI} from "../FluentAPI";
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
import { Component } from '../Component';
|
import {Component} from "../Component";
|
||||||
import { ComponentRegistry, ComponentType } from './ComponentStorage';
|
import {ComponentRegistry, ComponentType} from "./ComponentStorage";
|
||||||
import { BitMask64Utils, BitMask64Data } from '../Utils/BigIntCompatibility';
|
import {BitMask64Utils, BitMask64Data} from "../Utils/BigIntCompatibility";
|
||||||
import { createLogger } from '../../Utils/Logger';
|
import {createLogger} from "../../Utils/Logger";
|
||||||
import { getComponentTypeName } from '../Decorators';
|
import {getComponentTypeName} from "../Decorators";
|
||||||
import { Archetype, ArchetypeSystem } from './ArchetypeSystem';
|
import {Archetype, ArchetypeSystem} from "./ArchetypeSystem";
|
||||||
import { ReactiveQuery, ReactiveQueryConfig } from './ReactiveQuery';
|
import {ReactiveQuery, ReactiveQueryConfig} from "./ReactiveQuery";
|
||||||
import { QueryCondition, QueryConditionType, QueryResult } from './QueryTypes';
|
import {QueryCondition, QueryConditionType, QueryResult} from "./QueryTypes";
|
||||||
|
|
||||||
export {QueryCondition, QueryConditionType, QueryResult};
|
export {QueryCondition, QueryConditionType, QueryResult};
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ interface QueryCacheEntry {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export class QuerySystem {
|
export class QuerySystem {
|
||||||
private _logger = createLogger('QuerySystem');
|
private _logger = createLogger("QuerySystem");
|
||||||
private entities: Entity[] = [];
|
private entities: Entity[] = [];
|
||||||
private entityIndex: EntityIndex;
|
private entityIndex: EntityIndex;
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ export class QuerySystem {
|
|||||||
if (entities.length === 0) return;
|
if (entities.length === 0) return;
|
||||||
|
|
||||||
// 使用Set来快速检查重复
|
// 使用Set来快速检查重复
|
||||||
const existingIds = new Set(this.entities.map(e => e.id));
|
const existingIds = new Set(this.entities.map((e) => e.id));
|
||||||
let addedCount = 0;
|
let addedCount = 0;
|
||||||
|
|
||||||
for (const entity of entities) {
|
for (const entity of entities) {
|
||||||
@@ -550,7 +550,7 @@ export class QuerySystem {
|
|||||||
const startTime = performance.now();
|
const startTime = performance.now();
|
||||||
this.queryStats.totalQueries++;
|
this.queryStats.totalQueries++;
|
||||||
|
|
||||||
const cacheKey = this.generateCacheKey('component', [componentType]);
|
const cacheKey = this.generateCacheKey("component", [componentType]);
|
||||||
|
|
||||||
// 检查缓存
|
// 检查缓存
|
||||||
const cached = this.getFromCache(cacheKey);
|
const cached = this.getFromCache(cacheKey);
|
||||||
@@ -627,7 +627,7 @@ export class QuerySystem {
|
|||||||
// 如果还是太满,移除最少使用的条目
|
// 如果还是太满,移除最少使用的条目
|
||||||
if (this.queryCache.size >= this.cacheMaxSize) {
|
if (this.queryCache.size >= this.cacheMaxSize) {
|
||||||
let minHitCount = Infinity;
|
let minHitCount = Infinity;
|
||||||
let oldestKey = '';
|
let oldestKey = "";
|
||||||
let oldestTimestamp = Infinity;
|
let oldestTimestamp = Infinity;
|
||||||
|
|
||||||
// 单次遍历找到最少使用或最旧的条目
|
// 单次遍历找到最少使用或最旧的条目
|
||||||
@@ -679,10 +679,10 @@ export class QuerySystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 多组件查询:使用排序后的类型名称创建键
|
// 多组件查询:使用排序后的类型名称创建键
|
||||||
const sortKey = componentTypes.map(t => {
|
const sortKey = componentTypes.map((t) => {
|
||||||
const name = getComponentTypeName(t);
|
const name = getComponentTypeName(t);
|
||||||
return name;
|
return name;
|
||||||
}).sort().join(',');
|
}).sort().join(",");
|
||||||
|
|
||||||
const fullKey = `${prefix}:${sortKey}`;
|
const fullKey = `${prefix}:${sortKey}`;
|
||||||
|
|
||||||
@@ -729,7 +729,7 @@ export class QuerySystem {
|
|||||||
config?: ReactiveQueryConfig
|
config?: ReactiveQueryConfig
|
||||||
): ReactiveQuery {
|
): ReactiveQuery {
|
||||||
if (!componentTypes || componentTypes.length === 0) {
|
if (!componentTypes || componentTypes.length === 0) {
|
||||||
throw new Error('组件类型列表不能为空');
|
throw new Error("组件类型列表不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
const mask = this.createComponentMask(componentTypes);
|
const mask = this.createComponentMask(componentTypes);
|
||||||
@@ -747,7 +747,7 @@ export class QuerySystem {
|
|||||||
);
|
);
|
||||||
query.initializeWith(initialEntities);
|
query.initializeWith(initialEntities);
|
||||||
|
|
||||||
const cacheKey = this.generateCacheKey('all', componentTypes);
|
const cacheKey = this.generateCacheKey("all", componentTypes);
|
||||||
this._reactiveQueries.set(cacheKey, query);
|
this._reactiveQueries.set(cacheKey, query);
|
||||||
|
|
||||||
for (const type of componentTypes) {
|
for (const type of componentTypes) {
|
||||||
@@ -810,9 +810,9 @@ export class QuerySystem {
|
|||||||
*/
|
*/
|
||||||
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
|
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
|
||||||
// 生成缓存键
|
// 生成缓存键
|
||||||
const cacheKey = componentTypes.map(t => {
|
const cacheKey = componentTypes.map((t) => {
|
||||||
return getComponentTypeName(t);
|
return getComponentTypeName(t);
|
||||||
}).sort().join(',');
|
}).sort().join(",");
|
||||||
|
|
||||||
// 检查缓存
|
// 检查缓存
|
||||||
const cached = this.componentMaskCache.get(cacheKey);
|
const cached = this.componentMaskCache.get(cacheKey);
|
||||||
@@ -821,7 +821,7 @@ export class QuerySystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 使用ComponentRegistry而不是ComponentTypeManager,确保bitIndex一致
|
// 使用ComponentRegistry而不是ComponentTypeManager,确保bitIndex一致
|
||||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
for (const type of componentTypes) {
|
for (const type of componentTypes) {
|
||||||
// 确保组件已注册
|
// 确保组件已注册
|
||||||
if (!ComponentRegistry.isRegistered(type)) {
|
if (!ComponentRegistry.isRegistered(type)) {
|
||||||
@@ -843,11 +843,31 @@ export class QuerySystem {
|
|||||||
return this._version;
|
return this._version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有实体
|
||||||
|
*
|
||||||
|
* 返回场景中的所有实体,不进行任何过滤。
|
||||||
|
*
|
||||||
|
* @returns 所有实体的只读数组
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* const allEntities = scene.querySystem.queryAllEntities();
|
||||||
|
* console.log(`场景中共有 ${allEntities.length} 个实体`);
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
public queryAllEntities(): readonly Entity[] {
|
||||||
|
return this.entities;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有实体
|
* 获取所有实体
|
||||||
|
*
|
||||||
|
* @deprecated 使用 queryAllEntities() 代替,以保持命名一致性
|
||||||
|
* @see {@link queryAllEntities}
|
||||||
*/
|
*/
|
||||||
public getAllEntities(): readonly Entity[] {
|
public getAllEntities(): readonly Entity[] {
|
||||||
return this.entities;
|
return this.queryAllEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -892,19 +912,19 @@ export class QuerySystem {
|
|||||||
queryStats: {
|
queryStats: {
|
||||||
...this.queryStats,
|
...this.queryStats,
|
||||||
cacheHitRate: this.queryStats.totalQueries > 0 ?
|
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: {
|
optimizationStats: {
|
||||||
archetypeSystem: this.archetypeSystem.getAllArchetypes().map(a => ({
|
archetypeSystem: this.archetypeSystem.getAllArchetypes().map((a) => ({
|
||||||
id: a.id,
|
id: a.id,
|
||||||
componentTypes: a.componentTypes.map(t => getComponentTypeName(t)),
|
componentTypes: a.componentTypes.map((t) => getComponentTypeName(t)),
|
||||||
entityCount: a.entities.size
|
entityCount: a.entities.size
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
cacheStats: {
|
cacheStats: {
|
||||||
size: this._reactiveQueries.size,
|
size: this._reactiveQueries.size,
|
||||||
hitRate: this.queryStats.totalQueries > 0 ?
|
hitRate: this.queryStats.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[] {
|
): Entity[] {
|
||||||
switch (queryType) {
|
switch (queryType) {
|
||||||
case QueryConditionType.ALL: {
|
case QueryConditionType.ALL: {
|
||||||
const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, 'AND');
|
const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, "AND");
|
||||||
const entities: Entity[] = [];
|
const entities: Entity[] = [];
|
||||||
for (const archetype of archetypeResult.archetypes) {
|
for (const archetype of archetypeResult.archetypes) {
|
||||||
for (const entity of archetype.entities) {
|
for (const entity of archetype.entities) {
|
||||||
@@ -1012,7 +1032,7 @@ export class QuerySystem {
|
|||||||
return entities;
|
return entities;
|
||||||
}
|
}
|
||||||
case QueryConditionType.ANY: {
|
case QueryConditionType.ANY: {
|
||||||
const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, 'OR');
|
const archetypeResult = this.archetypeSystem.queryArchetypes(componentTypes, "OR");
|
||||||
const entities: Entity[] = [];
|
const entities: Entity[] = [];
|
||||||
for (const archetype of archetypeResult.archetypes) {
|
for (const archetype of archetypeResult.archetypes) {
|
||||||
for (const entity of archetype.entities) {
|
for (const entity of archetype.entities) {
|
||||||
@@ -1023,7 +1043,7 @@ export class QuerySystem {
|
|||||||
}
|
}
|
||||||
case QueryConditionType.NONE: {
|
case QueryConditionType.NONE: {
|
||||||
const mask = this.createComponentMask(componentTypes);
|
const mask = this.createComponentMask(componentTypes);
|
||||||
return this.entities.filter(entity =>
|
return this.entities.filter((entity) =>
|
||||||
BitMask64Utils.hasNone(entity.componentMask, mask)
|
BitMask64Utils.hasNone(entity.componentMask, mask)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1152,7 +1172,7 @@ export class QuerySystem {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export class QueryBuilder {
|
export class QueryBuilder {
|
||||||
private _logger = createLogger('QueryBuilder');
|
private _logger = createLogger("QueryBuilder");
|
||||||
private conditions: QueryCondition[] = [];
|
private conditions: QueryCondition[] = [];
|
||||||
private querySystem: QuerySystem;
|
private querySystem: QuerySystem;
|
||||||
|
|
||||||
@@ -1241,7 +1261,7 @@ export class QueryBuilder {
|
|||||||
* 创建组件掩码
|
* 创建组件掩码
|
||||||
*/
|
*/
|
||||||
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
|
private createComponentMask(componentTypes: ComponentType[]): BitMask64Data {
|
||||||
let mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const mask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
for (const type of componentTypes) {
|
for (const type of componentTypes) {
|
||||||
try {
|
try {
|
||||||
const bitMask = ComponentRegistry.getBitMask(type);
|
const bitMask = ComponentRegistry.getBitMask(type);
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { ComponentType } from './ComponentStorage';
|
import {ComponentType} from "./ComponentStorage";
|
||||||
import { BitMask64Data } from '../Utils/BigIntCompatibility';
|
import {BitMask64Data} from "../Utils/BigIntCompatibility";
|
||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询条件类型
|
* 查询条件类型
|
||||||
*/
|
*/
|
||||||
export enum QueryConditionType {
|
export enum QueryConditionType {
|
||||||
/** 必须包含所有指定组件 */
|
/** 必须包含所有指定组件 */
|
||||||
ALL = 'all',
|
ALL = "all",
|
||||||
/** 必须包含任意一个指定组件 */
|
/** 必须包含任意一个指定组件 */
|
||||||
ANY = 'any',
|
ANY = "any",
|
||||||
/** 不能包含任何指定组件 */
|
/** 不能包含任何指定组件 */
|
||||||
NONE = 'none'
|
NONE = "none"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
import { QueryCondition, QueryConditionType } from './QueryTypes';
|
import {QueryCondition, QueryConditionType} from "./QueryTypes";
|
||||||
import { BitMask64Utils } from '../Utils/BigIntCompatibility';
|
import {BitMask64Utils} from "../Utils/BigIntCompatibility";
|
||||||
import { createLogger } from '../../Utils/Logger';
|
import {createLogger} from "../../Utils/Logger";
|
||||||
|
|
||||||
const logger = createLogger('ReactiveQuery');
|
const logger = createLogger("ReactiveQuery");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 响应式查询变化类型
|
* 响应式查询变化类型
|
||||||
*/
|
*/
|
||||||
export enum ReactiveQueryChangeType {
|
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 {
|
private generateQueryId(): string {
|
||||||
const typeStr = this._condition.type;
|
const typeStr = this._condition.type;
|
||||||
const componentsStr = this._condition.componentTypes
|
const componentsStr = this._condition.componentTypes
|
||||||
.map(t => t.name)
|
.map((t) => t.name)
|
||||||
.sort()
|
.sort()
|
||||||
.join(',');
|
.join(",");
|
||||||
return `${typeStr}:${componentsStr}`;
|
return `${typeStr}:${componentsStr}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,8 +153,8 @@ export class ReactiveQuery {
|
|||||||
throw new Error(`Cannot subscribe to disposed ReactiveQuery ${this._id}`);
|
throw new Error(`Cannot subscribe to disposed ReactiveQuery ${this._id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof listener !== 'function') {
|
if (typeof listener !== "function") {
|
||||||
throw new TypeError('Listener must be a function');
|
throw new TypeError("Listener must be a function");
|
||||||
}
|
}
|
||||||
|
|
||||||
this._listeners.push(listener);
|
this._listeners.push(listener);
|
||||||
@@ -239,7 +239,7 @@ export class ReactiveQuery {
|
|||||||
|
|
||||||
// 通知监听器
|
// 通知监听器
|
||||||
if (this._config.enableBatchMode) {
|
if (this._config.enableBatchMode) {
|
||||||
this.addToBatch('added', entity);
|
this.addToBatch("added", entity);
|
||||||
} else {
|
} else {
|
||||||
this.notifyListeners({
|
this.notifyListeners({
|
||||||
type: ReactiveQueryChangeType.ADDED,
|
type: ReactiveQueryChangeType.ADDED,
|
||||||
@@ -276,7 +276,7 @@ export class ReactiveQuery {
|
|||||||
|
|
||||||
// 通知监听器
|
// 通知监听器
|
||||||
if (this._config.enableBatchMode) {
|
if (this._config.enableBatchMode) {
|
||||||
this.addToBatch('removed', entity);
|
this.addToBatch("removed", entity);
|
||||||
} else {
|
} else {
|
||||||
this.notifyListeners({
|
this.notifyListeners({
|
||||||
type: ReactiveQueryChangeType.REMOVED,
|
type: ReactiveQueryChangeType.REMOVED,
|
||||||
@@ -337,8 +337,8 @@ export class ReactiveQuery {
|
|||||||
/**
|
/**
|
||||||
* 添加到批量变化缓存
|
* 添加到批量变化缓存
|
||||||
*/
|
*/
|
||||||
private addToBatch(type: 'added' | 'removed', entity: Entity): void {
|
private addToBatch(type: "added" | "removed", entity: Entity): void {
|
||||||
if (type === 'added') {
|
if (type === "added") {
|
||||||
this._batchChanges.added.push(entity);
|
this._batchChanges.added.push(entity);
|
||||||
} else {
|
} else {
|
||||||
this._batchChanges.removed.push(entity);
|
this._batchChanges.removed.push(entity);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component } from '../Component';
|
import {Component} from "../Component";
|
||||||
import type { Entity } from '../Entity';
|
import type {Entity} from "../Entity";
|
||||||
import type { IScene } from '../IScene';
|
import type {IScene} from "../IScene";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WeakRef 接口定义
|
* WeakRef 接口定义
|
||||||
@@ -45,9 +45,9 @@ interface IWeakRefConstructor {
|
|||||||
* 优先使用原生 WeakRef,不支持时降级到 Polyfill
|
* 优先使用原生 WeakRef,不支持时降级到 Polyfill
|
||||||
*/
|
*/
|
||||||
const WeakRefImpl: IWeakRefConstructor = (
|
const WeakRefImpl: IWeakRefConstructor = (
|
||||||
(typeof globalThis !== 'undefined' && (globalThis as any).WeakRef) ||
|
(typeof globalThis !== "undefined" && (globalThis as any).WeakRef) ||
|
||||||
(typeof global !== 'undefined' && (global as any).WeakRef) ||
|
(typeof global !== "undefined" && (global as any).WeakRef) ||
|
||||||
(typeof window !== 'undefined' && (window as any).WeakRef) ||
|
(typeof window !== "undefined" && (window as any).WeakRef) ||
|
||||||
WeakRefPolyfill
|
WeakRefPolyfill
|
||||||
) as IWeakRefConstructor;
|
) as IWeakRefConstructor;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Component } from '../Component';
|
import {Component} from "../Component";
|
||||||
import { ComponentType } from './ComponentStorage';
|
import {ComponentType} from "./ComponentStorage";
|
||||||
import { createLogger } from '../../Utils/Logger';
|
import {createLogger} from "../../Utils/Logger";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 启用SoA优化装饰器
|
* 启用SoA优化装饰器
|
||||||
@@ -222,12 +222,12 @@ export class TypeInference {
|
|||||||
} = {}): string {
|
} = {}): string {
|
||||||
const type = typeof value;
|
const type = typeof value;
|
||||||
|
|
||||||
if (type === 'boolean') {
|
if (type === "boolean") {
|
||||||
return 'uint8'; // 布尔值使用最小的无符号整数
|
return "uint8"; // 布尔值使用最小的无符号整数
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type !== 'number') {
|
if (type !== "number") {
|
||||||
return 'float32'; // 非数值类型默认使用Float32
|
return "float32"; // 非数值类型默认使用Float32
|
||||||
}
|
}
|
||||||
|
|
||||||
const {minValue, maxValue, precision, signed} = options;
|
const {minValue, maxValue, precision, signed} = options;
|
||||||
@@ -236,9 +236,9 @@ export class TypeInference {
|
|||||||
if (precision === true) {
|
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)) {
|
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 (needsSigned) {
|
||||||
// 有符号整数
|
// 有符号整数
|
||||||
if (actualMin >= -128 && actualMax <= 127) {
|
if (actualMin >= -128 && actualMax <= 127) {
|
||||||
return 'int8';
|
return "int8";
|
||||||
} else if (actualMin >= -32768 && actualMax <= 32767) {
|
} else if (actualMin >= -32768 && actualMax <= 32767) {
|
||||||
return 'int16';
|
return "int16";
|
||||||
} else if (actualMin >= -2147483648 && actualMax <= 2147483647) {
|
} else if (actualMin >= -2147483648 && actualMax <= 2147483647) {
|
||||||
return 'int32';
|
return "int32";
|
||||||
} else {
|
} else {
|
||||||
return 'float64'; // 超出int32范围,使用双精度浮点
|
return "float64"; // 超出int32范围,使用双精度浮点
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 无符号整数
|
// 无符号整数
|
||||||
if (actualMax <= 255) {
|
if (actualMax <= 255) {
|
||||||
return 'uint8';
|
return "uint8";
|
||||||
} else if (actualMax <= 65535) {
|
} else if (actualMax <= 65535) {
|
||||||
return 'uint16';
|
return "uint16";
|
||||||
} else if (actualMax <= 4294967295) {
|
} else if (actualMax <= 4294967295) {
|
||||||
return 'uint32';
|
return "uint32";
|
||||||
} else {
|
} else {
|
||||||
return 'float64'; // 超出uint32范围,使用双精度浮点
|
return "float64"; // 超出uint32范围,使用双精度浮点
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认情况:检查是否为小数
|
// 默认情况:检查是否为小数
|
||||||
if (!Number.isInteger(value)) {
|
if (!Number.isInteger(value)) {
|
||||||
return 'float32';
|
return "float32";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 整数值,但没有指定范围,根据值的大小选择
|
// 整数值,但没有指定范围,根据值的大小选择
|
||||||
if (value >= 0 && value <= 255) {
|
if (value >= 0 && value <= 255) {
|
||||||
return 'uint8';
|
return "uint8";
|
||||||
} else if (value >= -128 && value <= 127) {
|
} else if (value >= -128 && value <= 127) {
|
||||||
return 'int8';
|
return "int8";
|
||||||
} else if (value >= 0 && value <= 65535) {
|
} else if (value >= 0 && value <= 65535) {
|
||||||
return 'uint16';
|
return "uint16";
|
||||||
} else if (value >= -32768 && value <= 32767) {
|
} else if (value >= -32768 && value <= 32767) {
|
||||||
return 'int16';
|
return "int16";
|
||||||
} else if (value >= 0 && value <= 4294967295) {
|
} else if (value >= 0 && value <= 4294967295) {
|
||||||
return 'uint32';
|
return "uint32";
|
||||||
} else if (value >= -2147483648 && value <= 2147483647) {
|
} else if (value >= -2147483648 && value <= 2147483647) {
|
||||||
return 'int32';
|
return "int32";
|
||||||
} else {
|
} 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 {
|
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) {
|
switch (typeName) {
|
||||||
case 'float32': return Float32Array;
|
case "float32": return Float32Array;
|
||||||
case 'float64': return Float64Array;
|
case "float64": return Float64Array;
|
||||||
case 'int32': return Int32Array;
|
case "int32": return Int32Array;
|
||||||
case 'uint32': return Uint32Array;
|
case "uint32": return Uint32Array;
|
||||||
case 'int16': return Int16Array;
|
case "int16": return Int16Array;
|
||||||
case 'uint16': return Uint16Array;
|
case "uint16": return Uint16Array;
|
||||||
case 'int8': return Int8Array;
|
case "int8": return Int8Array;
|
||||||
case 'uint8': return Uint8Array;
|
case "uint8": return Uint8Array;
|
||||||
case 'uint8clamped': return Uint8ClampedArray;
|
case "uint8clamped": return Uint8ClampedArray;
|
||||||
default: return Float32Array;
|
default: return Float32Array;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,7 +334,7 @@ export type SupportedTypedArray =
|
|||||||
* 使用Structure of Arrays存储模式,在大规模批量操作时提供优异性能
|
* 使用Structure of Arrays存储模式,在大规模批量操作时提供优异性能
|
||||||
*/
|
*/
|
||||||
export class SoAStorage<T extends Component> {
|
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 fields = new Map<string, SupportedTypedArray>();
|
||||||
private stringFields = new Map<string, string[]>(); // 专门存储字符串
|
private stringFields = new Map<string, string[]>(); // 专门存储字符串
|
||||||
private serializedFields = new Map<string, string[]>(); // 序列化存储Map/Set/Array
|
private serializedFields = new Map<string, string[]>(); // 序列化存储Map/Set/Array
|
||||||
@@ -370,11 +370,11 @@ export class SoAStorage<T extends Component> {
|
|||||||
// const deepCopyFields = (componentType as any).__deepCopyFields || new Set(); // 未使用,但保留供future使用
|
// const deepCopyFields = (componentType as any).__deepCopyFields || new Set(); // 未使用,但保留供future使用
|
||||||
|
|
||||||
for (const key in instance) {
|
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 value = (instance as any)[key];
|
||||||
const type = typeof value;
|
const type = typeof value;
|
||||||
|
|
||||||
if (type === 'number') {
|
if (type === "number") {
|
||||||
if (highPrecisionFields.has(key)) {
|
if (highPrecisionFields.has(key)) {
|
||||||
// 标记为高精度,作为复杂对象处理
|
// 标记为高精度,作为复杂对象处理
|
||||||
// 不添加到fields,会在updateComponentAtIndex中自动添加到complexFields
|
// 不添加到fields,会在updateComponentAtIndex中自动添加到complexFields
|
||||||
@@ -416,7 +416,7 @@ export class SoAStorage<T extends Component> {
|
|||||||
// 默认使用Float32Array
|
// 默认使用Float32Array
|
||||||
this.fields.set(key, new Float32Array(this._capacity));
|
this.fields.set(key, new Float32Array(this._capacity));
|
||||||
}
|
}
|
||||||
} else if (type === 'boolean') {
|
} else if (type === "boolean") {
|
||||||
// 布尔值默认使用Uint8Array存储为0/1(更节省内存)
|
// 布尔值默认使用Uint8Array存储为0/1(更节省内存)
|
||||||
if (uint8Fields.has(key) || (!float32Fields.has(key) && !float64Fields.has(key))) {
|
if (uint8Fields.has(key) || (!float32Fields.has(key) && !float64Fields.has(key))) {
|
||||||
this.fields.set(key, new Uint8Array(this._capacity));
|
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));
|
this.fields.set(key, new Float32Array(this._capacity));
|
||||||
}
|
}
|
||||||
} else if (type === 'string') {
|
} else if (type === "string") {
|
||||||
// 字符串专门处理
|
// 字符串专门处理
|
||||||
this.stringFields.set(key, new Array(this._capacity));
|
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)) {
|
if (serializeMapFields.has(key) || serializeSetFields.has(key) || serializeArrayFields.has(key)) {
|
||||||
// 序列化存储
|
// 序列化存储
|
||||||
@@ -473,11 +473,11 @@ export class SoAStorage<T extends Component> {
|
|||||||
|
|
||||||
// 处理所有字段
|
// 处理所有字段
|
||||||
for (const key in component) {
|
for (const key in component) {
|
||||||
if (component.hasOwnProperty(key) && key !== 'id') {
|
if (Object.prototype.hasOwnProperty.call(component, key) && key !== "id") {
|
||||||
const value = (component as any)[key];
|
const value = (component as any)[key];
|
||||||
const type = typeof value;
|
const type = typeof value;
|
||||||
|
|
||||||
if (type === 'number') {
|
if (type === "number") {
|
||||||
if (highPrecisionFields.has(key) || !this.fields.has(key)) {
|
if (highPrecisionFields.has(key) || !this.fields.has(key)) {
|
||||||
// 标记为高精度或未在TypedArray中的数值作为复杂对象存储
|
// 标记为高精度或未在TypedArray中的数值作为复杂对象存储
|
||||||
complexFieldMap.set(key, value);
|
complexFieldMap.set(key, value);
|
||||||
@@ -486,7 +486,7 @@ export class SoAStorage<T extends Component> {
|
|||||||
const array = this.fields.get(key)!;
|
const array = this.fields.get(key)!;
|
||||||
array[index] = value;
|
array[index] = value;
|
||||||
}
|
}
|
||||||
} else if (type === 'boolean' && this.fields.has(key)) {
|
} else if (type === "boolean" && this.fields.has(key)) {
|
||||||
// 布尔值存储到TypedArray
|
// 布尔值存储到TypedArray
|
||||||
const array = this.fields.get(key)!;
|
const array = this.fields.get(key)!;
|
||||||
array[index] = value ? 1 : 0;
|
array[index] = value ? 1 : 0;
|
||||||
@@ -536,7 +536,7 @@ export class SoAStorage<T extends Component> {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
SoAStorage._logger.warn(`SoA序列化字段 ${key} 失败:`, error);
|
SoAStorage._logger.warn(`SoA序列化字段 ${key} 失败:`, error);
|
||||||
return '{}';
|
return "{}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,7 +569,7 @@ export class SoAStorage<T extends Component> {
|
|||||||
* 深拷贝对象
|
* 深拷贝对象
|
||||||
*/
|
*/
|
||||||
private deepClone(obj: any): any {
|
private deepClone(obj: any): any {
|
||||||
if (obj === null || typeof obj !== 'object') {
|
if (obj === null || typeof obj !== "object") {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,7 +578,7 @@ export class SoAStorage<T extends Component> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof Array) {
|
if (obj instanceof Array) {
|
||||||
return obj.map(item => this.deepClone(item));
|
return obj.map((item) => this.deepClone(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof Map) {
|
if (obj instanceof Map) {
|
||||||
@@ -600,7 +600,7 @@ export class SoAStorage<T extends Component> {
|
|||||||
// 普通对象
|
// 普通对象
|
||||||
const cloned: any = {};
|
const cloned: any = {};
|
||||||
for (const key in obj) {
|
for (const key in obj) {
|
||||||
if (obj.hasOwnProperty(key)) {
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||||
cloned[key] = this.deepClone(obj[key]);
|
cloned[key] = this.deepClone(obj[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -624,7 +624,7 @@ export class SoAStorage<T extends Component> {
|
|||||||
const value = array[index];
|
const value = array[index];
|
||||||
const fieldType = this.getFieldType(fieldName);
|
const fieldType = this.getFieldType(fieldName);
|
||||||
|
|
||||||
if (fieldType === 'boolean') {
|
if (fieldType === "boolean") {
|
||||||
component[fieldName] = value === 1;
|
component[fieldName] = value === 1;
|
||||||
} else {
|
} else {
|
||||||
component[fieldName] = value;
|
component[fieldName] = value;
|
||||||
@@ -854,35 +854,35 @@ export class SoAStorage<T extends Component> {
|
|||||||
|
|
||||||
if (array instanceof Float32Array) {
|
if (array instanceof Float32Array) {
|
||||||
bytesPerElement = 4;
|
bytesPerElement = 4;
|
||||||
typeName = 'float32';
|
typeName = "float32";
|
||||||
} else if (array instanceof Float64Array) {
|
} else if (array instanceof Float64Array) {
|
||||||
bytesPerElement = 8;
|
bytesPerElement = 8;
|
||||||
typeName = 'float64';
|
typeName = "float64";
|
||||||
} else if (array instanceof Int32Array) {
|
} else if (array instanceof Int32Array) {
|
||||||
bytesPerElement = 4;
|
bytesPerElement = 4;
|
||||||
typeName = 'int32';
|
typeName = "int32";
|
||||||
} else if (array instanceof Uint32Array) {
|
} else if (array instanceof Uint32Array) {
|
||||||
bytesPerElement = 4;
|
bytesPerElement = 4;
|
||||||
typeName = 'uint32';
|
typeName = "uint32";
|
||||||
} else if (array instanceof Int16Array) {
|
} else if (array instanceof Int16Array) {
|
||||||
bytesPerElement = 2;
|
bytesPerElement = 2;
|
||||||
typeName = 'int16';
|
typeName = "int16";
|
||||||
} else if (array instanceof Uint16Array) {
|
} else if (array instanceof Uint16Array) {
|
||||||
bytesPerElement = 2;
|
bytesPerElement = 2;
|
||||||
typeName = 'uint16';
|
typeName = "uint16";
|
||||||
} else if (array instanceof Int8Array) {
|
} else if (array instanceof Int8Array) {
|
||||||
bytesPerElement = 1;
|
bytesPerElement = 1;
|
||||||
typeName = 'int8';
|
typeName = "int8";
|
||||||
} else if (array instanceof Uint8Array) {
|
} else if (array instanceof Uint8Array) {
|
||||||
bytesPerElement = 1;
|
bytesPerElement = 1;
|
||||||
typeName = 'uint8';
|
typeName = "uint8";
|
||||||
} else if (array instanceof Uint8ClampedArray) {
|
} else if (array instanceof Uint8ClampedArray) {
|
||||||
bytesPerElement = 1;
|
bytesPerElement = 1;
|
||||||
typeName = 'uint8clamped';
|
typeName = "uint8clamped";
|
||||||
} else {
|
} else {
|
||||||
// 默认回退
|
// 默认回退
|
||||||
bytesPerElement = 4;
|
bytesPerElement = 4;
|
||||||
typeName = 'unknown';
|
typeName = "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
const memory = array.length * bytesPerElement;
|
const memory = array.length * bytesPerElement;
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export { ComponentPool, ComponentPoolManager } from '../ComponentPool';
|
export {ComponentPool, ComponentPoolManager} from "../ComponentPool";
|
||||||
export { ComponentStorage, ComponentRegistry } from '../ComponentStorage';
|
export {ComponentStorage, ComponentRegistry} from "../ComponentStorage";
|
||||||
export { EnableSoA, HighPrecision, Float64, Float32, Int32, SerializeMap, SoAStorage } from '../SoAStorage';
|
export {EnableSoA, HighPrecision, Float64, Float32, Int32, SerializeMap, SoAStorage} from "../SoAStorage";
|
||||||
|
|||||||
@@ -46,4 +46,4 @@ export {
|
|||||||
|
|
||||||
// 类型定义
|
// 类型定义
|
||||||
SupportedTypedArray
|
SupportedTypedArray
|
||||||
} from './SoAStorage';
|
} from "./SoAStorage";
|
||||||
|
|||||||
@@ -6,75 +6,75 @@
|
|||||||
*/
|
*/
|
||||||
export enum ECSEventType {
|
export enum ECSEventType {
|
||||||
// 实体相关事件
|
// 实体相关事件
|
||||||
ENTITY_CREATED = 'entity:created',
|
ENTITY_CREATED = "entity:created",
|
||||||
ENTITY_DESTROYED = 'entity:destroyed',
|
ENTITY_DESTROYED = "entity:destroyed",
|
||||||
ENTITY_ENABLED = 'entity:enabled',
|
ENTITY_ENABLED = "entity:enabled",
|
||||||
ENTITY_DISABLED = 'entity:disabled',
|
ENTITY_DISABLED = "entity:disabled",
|
||||||
ENTITY_TAG_ADDED = 'entity:tag:added',
|
ENTITY_TAG_ADDED = "entity:tag:added",
|
||||||
ENTITY_TAG_REMOVED = 'entity:tag:removed',
|
ENTITY_TAG_REMOVED = "entity:tag:removed",
|
||||||
ENTITY_NAME_CHANGED = 'entity:name:changed',
|
ENTITY_NAME_CHANGED = "entity:name:changed",
|
||||||
|
|
||||||
// 组件相关事件
|
// 组件相关事件
|
||||||
COMPONENT_ADDED = 'component:added',
|
COMPONENT_ADDED = "component:added",
|
||||||
COMPONENT_REMOVED = 'component:removed',
|
COMPONENT_REMOVED = "component:removed",
|
||||||
COMPONENT_MODIFIED = 'component:modified',
|
COMPONENT_MODIFIED = "component:modified",
|
||||||
COMPONENT_ENABLED = 'component:enabled',
|
COMPONENT_ENABLED = "component:enabled",
|
||||||
COMPONENT_DISABLED = 'component:disabled',
|
COMPONENT_DISABLED = "component:disabled",
|
||||||
|
|
||||||
// 系统相关事件
|
// 系统相关事件
|
||||||
SYSTEM_ADDED = 'system:added',
|
SYSTEM_ADDED = "system:added",
|
||||||
SYSTEM_REMOVED = 'system:removed',
|
SYSTEM_REMOVED = "system:removed",
|
||||||
SYSTEM_ENABLED = 'system:enabled',
|
SYSTEM_ENABLED = "system:enabled",
|
||||||
SYSTEM_DISABLED = 'system:disabled',
|
SYSTEM_DISABLED = "system:disabled",
|
||||||
SYSTEM_PROCESSING_START = 'system:processing:start',
|
SYSTEM_PROCESSING_START = "system:processing:start",
|
||||||
SYSTEM_PROCESSING_END = 'system:processing:end',
|
SYSTEM_PROCESSING_END = "system:processing:end",
|
||||||
SYSTEM_ERROR = 'system:error',
|
SYSTEM_ERROR = "system:error",
|
||||||
|
|
||||||
// 场景相关事件
|
// 场景相关事件
|
||||||
SCENE_CREATED = 'scene:created',
|
SCENE_CREATED = "scene:created",
|
||||||
SCENE_DESTROYED = 'scene:destroyed',
|
SCENE_DESTROYED = "scene:destroyed",
|
||||||
SCENE_ACTIVATED = 'scene:activated',
|
SCENE_ACTIVATED = "scene:activated",
|
||||||
SCENE_DEACTIVATED = 'scene:deactivated',
|
SCENE_DEACTIVATED = "scene:deactivated",
|
||||||
SCENE_PAUSED = 'scene:paused',
|
SCENE_PAUSED = "scene:paused",
|
||||||
SCENE_RESUMED = 'scene:resumed',
|
SCENE_RESUMED = "scene:resumed",
|
||||||
|
|
||||||
// 查询相关事件
|
// 查询相关事件
|
||||||
QUERY_EXECUTED = 'query:executed',
|
QUERY_EXECUTED = "query:executed",
|
||||||
QUERY_CACHE_HIT = 'query:cache:hit',
|
QUERY_CACHE_HIT = "query:cache:hit",
|
||||||
QUERY_CACHE_MISS = 'query:cache:miss',
|
QUERY_CACHE_MISS = "query:cache:miss",
|
||||||
QUERY_OPTIMIZED = 'query:optimized',
|
QUERY_OPTIMIZED = "query:optimized",
|
||||||
|
|
||||||
// 性能相关事件
|
// 性能相关事件
|
||||||
PERFORMANCE_WARNING = 'performance:warning',
|
PERFORMANCE_WARNING = "performance:warning",
|
||||||
PERFORMANCE_CRITICAL = 'performance:critical',
|
PERFORMANCE_CRITICAL = "performance:critical",
|
||||||
MEMORY_USAGE_HIGH = 'memory:usage:high',
|
MEMORY_USAGE_HIGH = "memory:usage:high",
|
||||||
FRAME_RATE_DROP = 'frame:rate:drop',
|
FRAME_RATE_DROP = "frame:rate:drop",
|
||||||
|
|
||||||
// 索引相关事件
|
// 索引相关事件
|
||||||
INDEX_CREATED = 'index:created',
|
INDEX_CREATED = "index:created",
|
||||||
INDEX_UPDATED = 'index:updated',
|
INDEX_UPDATED = "index:updated",
|
||||||
INDEX_OPTIMIZED = 'index:optimized',
|
INDEX_OPTIMIZED = "index:optimized",
|
||||||
|
|
||||||
// Archetype相关事件
|
// Archetype相关事件
|
||||||
ARCHETYPE_CREATED = 'archetype:created',
|
ARCHETYPE_CREATED = "archetype:created",
|
||||||
ARCHETYPE_ENTITY_ADDED = 'archetype:entity:added',
|
ARCHETYPE_ENTITY_ADDED = "archetype:entity:added",
|
||||||
ARCHETYPE_ENTITY_REMOVED = 'archetype:entity:removed',
|
ARCHETYPE_ENTITY_REMOVED = "archetype:entity:removed",
|
||||||
|
|
||||||
// 脏标记相关事件
|
// 脏标记相关事件
|
||||||
DIRTY_MARK_ADDED = 'dirty:mark:added',
|
DIRTY_MARK_ADDED = "dirty:mark:added",
|
||||||
DIRTY_BATCH_PROCESSED = 'dirty:batch:processed',
|
DIRTY_BATCH_PROCESSED = "dirty:batch:processed",
|
||||||
|
|
||||||
// 错误和警告事件
|
// 错误和警告事件
|
||||||
ERROR_OCCURRED = 'error:occurred',
|
ERROR_OCCURRED = "error:occurred",
|
||||||
WARNING_ISSUED = 'warning:issued',
|
WARNING_ISSUED = "warning:issued",
|
||||||
|
|
||||||
// 生命周期事件
|
// 生命周期事件
|
||||||
FRAMEWORK_INITIALIZED = 'framework:initialized',
|
FRAMEWORK_INITIALIZED = "framework:initialized",
|
||||||
FRAMEWORK_SHUTDOWN = 'framework:shutdown',
|
FRAMEWORK_SHUTDOWN = "framework:shutdown",
|
||||||
|
|
||||||
// 调试相关事件
|
// 调试相关事件
|
||||||
DEBUG_INFO = 'debug:info',
|
DEBUG_INFO = "debug:info",
|
||||||
DEBUG_STATS_UPDATED = 'debug:stats:updated'
|
DEBUG_STATS_UPDATED = "debug:stats:updated"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import type { Entity } from '../Entity';
|
import type {Entity} from "../Entity";
|
||||||
import type { Component } from '../Component';
|
import type {Component} from "../Component";
|
||||||
import { getSceneByEntityId } from '../Core/ReferenceTracker';
|
import {getSceneByEntityId} from "../Core/ReferenceTracker";
|
||||||
import { createLogger } from '../../Utils/Logger';
|
import {createLogger} from "../../Utils/Logger";
|
||||||
|
|
||||||
const logger = createLogger('EntityRefDecorator');
|
const logger = createLogger("EntityRefDecorator");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EntityRef元数据的Symbol键
|
* EntityRef元数据的Symbol键
|
||||||
*/
|
*/
|
||||||
export const ENTITY_REF_METADATA = Symbol('EntityRefMetadata');
|
export const ENTITY_REF_METADATA = Symbol("EntityRefMetadata");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EntityRef值存储的Symbol键
|
* EntityRef值存储的Symbol键
|
||||||
*/
|
*/
|
||||||
const ENTITY_REF_VALUES = Symbol('EntityRefValues');
|
const ENTITY_REF_VALUES = Symbol("EntityRefValues");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EntityRef元数据
|
* EntityRef元数据
|
||||||
@@ -66,7 +66,7 @@ export function EntityRef(): PropertyDecorator {
|
|||||||
constructor[ENTITY_REF_METADATA] = metadata;
|
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);
|
metadata.properties.add(propKeyString);
|
||||||
|
|
||||||
Object.defineProperty(target, propertyKey, {
|
Object.defineProperty(target, propertyKey, {
|
||||||
@@ -97,7 +97,7 @@ export function EntityRef(): PropertyDecorator {
|
|||||||
|
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
if (newValue.scene !== scene) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ export function getEntityRefMetadata(component: any): EntityRefMetadata | null {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const constructor = typeof component === 'function'
|
const constructor = typeof component === "function"
|
||||||
? component
|
? component
|
||||||
: component.constructor;
|
: component.constructor;
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import type {Component} from '../Component';
|
import type {Component} from "../Component";
|
||||||
import type {EntitySystem} from '../Systems';
|
import type {EntitySystem} from "../Systems";
|
||||||
import {ComponentType} from "../../Types";
|
import {ComponentType} from "../../Types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 存储组件类型名称的Symbol键
|
* 存储组件类型名称的Symbol键
|
||||||
*/
|
*/
|
||||||
export const COMPONENT_TYPE_NAME = Symbol('ComponentTypeName');
|
export const COMPONENT_TYPE_NAME = Symbol("ComponentTypeName");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 存储系统类型名称的Symbol键
|
* 存储系统类型名称的Symbol键
|
||||||
*/
|
*/
|
||||||
export const SYSTEM_TYPE_NAME = Symbol('SystemTypeName');
|
export const SYSTEM_TYPE_NAME = Symbol("SystemTypeName");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件类型装饰器
|
* 组件类型装饰器
|
||||||
@@ -28,8 +28,8 @@ export const SYSTEM_TYPE_NAME = Symbol('SystemTypeName');
|
|||||||
*/
|
*/
|
||||||
export function ECSComponent(typeName: string) {
|
export function ECSComponent(typeName: string) {
|
||||||
return function <T extends new (...args: any[]) => Component>(target: T): T {
|
return function <T extends new (...args: any[]) => Component>(target: T): T {
|
||||||
if (!typeName || typeof typeName !== 'string') {
|
if (!typeName || typeof typeName !== "string") {
|
||||||
throw new Error('ECSComponent装饰器必须提供有效的类型名称');
|
throw new Error("ECSComponent装饰器必须提供有效的类型名称");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在构造函数上存储类型名称
|
// 在构造函数上存储类型名称
|
||||||
@@ -82,8 +82,8 @@ export interface SystemMetadata {
|
|||||||
*/
|
*/
|
||||||
export function ECSSystem(typeName: string, metadata?: SystemMetadata) {
|
export function ECSSystem(typeName: string, metadata?: SystemMetadata) {
|
||||||
return function <T extends new (...args: any[]) => EntitySystem>(target: T): T {
|
return function <T extends new (...args: any[]) => EntitySystem>(target: T): T {
|
||||||
if (!typeName || typeof typeName !== 'string') {
|
if (!typeName || typeof typeName !== "string") {
|
||||||
throw new Error('ECSSystem装饰器必须提供有效的类型名称');
|
throw new Error("ECSSystem装饰器必须提供有效的类型名称");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在构造函数上存储类型名称
|
// 在构造函数上存储类型名称
|
||||||
@@ -121,7 +121,7 @@ export function getComponentTypeName(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 回退到constructor.name
|
// 回退到constructor.name
|
||||||
return componentType.name || 'UnknownComponent';
|
return componentType.name || "UnknownComponent";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,7 +140,7 @@ export function getSystemTypeName<T extends EntitySystem>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 回退到constructor.name
|
// 回退到constructor.name
|
||||||
return systemType.name || 'UnknownSystem';
|
return systemType.name || "UnknownSystem";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,15 +8,15 @@ export {
|
|||||||
getSystemMetadata,
|
getSystemMetadata,
|
||||||
COMPONENT_TYPE_NAME,
|
COMPONENT_TYPE_NAME,
|
||||||
SYSTEM_TYPE_NAME
|
SYSTEM_TYPE_NAME
|
||||||
} from './TypeDecorators';
|
} from "./TypeDecorators";
|
||||||
|
|
||||||
export type { SystemMetadata } from './TypeDecorators';
|
export type {SystemMetadata} from "./TypeDecorators";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
EntityRef,
|
EntityRef,
|
||||||
getEntityRefMetadata,
|
getEntityRefMetadata,
|
||||||
hasEntityRef,
|
hasEntityRef,
|
||||||
ENTITY_REF_METADATA
|
ENTITY_REF_METADATA
|
||||||
} from './EntityRefDecorator';
|
} from "./EntityRefDecorator";
|
||||||
|
|
||||||
export type { EntityRefMetadata } from './EntityRefDecorator';
|
export type {EntityRefMetadata} from "./EntityRefDecorator";
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Component } from './Component';
|
import {Component} from "./Component";
|
||||||
import { ComponentRegistry, ComponentType } from './Core/ComponentStorage';
|
import {ComponentRegistry, ComponentType} from "./Core/ComponentStorage";
|
||||||
import { EventBus } from './Core/EventBus';
|
import {EventBus} from "./Core/EventBus";
|
||||||
import { BitMask64Utils, BitMask64Data } from './Utils/BigIntCompatibility';
|
import {BitMask64Utils, BitMask64Data} from "./Utils/BigIntCompatibility";
|
||||||
import { createLogger } from '../Utils/Logger';
|
import {createLogger} from "../Utils/Logger";
|
||||||
import { getComponentInstanceTypeName, getComponentTypeName } from './Decorators';
|
import {getComponentInstanceTypeName, getComponentTypeName} from "./Decorators";
|
||||||
import type { IScene } from './IScene';
|
import type {IScene} from "./IScene";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实体比较器
|
* 实体比较器
|
||||||
@@ -28,7 +28,6 @@ export class EntityComparer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 游戏实体类
|
* 游戏实体类
|
||||||
*
|
*
|
||||||
@@ -59,7 +58,7 @@ export class Entity {
|
|||||||
/**
|
/**
|
||||||
* Entity专用日志器
|
* Entity专用日志器
|
||||||
*/
|
*/
|
||||||
private static _logger = createLogger('Entity');
|
private static _logger = createLogger("Entity");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实体比较器实例
|
* 实体比较器实例
|
||||||
@@ -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
|
* @returns 如果实体已被销毁则返回true
|
||||||
*/
|
*/
|
||||||
public get isDestroyed(): boolean {
|
public get isDestroyed(): boolean {
|
||||||
return this._isDestroyed;
|
return this._destroyed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -394,11 +402,11 @@ export class Entity {
|
|||||||
const componentType = component.constructor as ComponentType<T>;
|
const componentType = component.constructor as ComponentType<T>;
|
||||||
|
|
||||||
if (!this.scene) {
|
if (!this.scene) {
|
||||||
throw new Error(`Entity must be added to Scene before adding components. Use scene.createEntity() instead of new Entity()`);
|
throw new Error("Entity must be added to Scene before adding components. Use scene.createEntity() instead of new Entity()");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.scene.componentStorageManager) {
|
if (!this.scene.componentStorageManager) {
|
||||||
throw new Error(`Scene does not have componentStorageManager`);
|
throw new Error("Scene does not have componentStorageManager");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasComponent(componentType)) {
|
if (this.hasComponent(componentType)) {
|
||||||
@@ -418,7 +426,7 @@ export class Entity {
|
|||||||
if (Entity.eventBus) {
|
if (Entity.eventBus) {
|
||||||
Entity.eventBus.emitComponentAdded({
|
Entity.eventBus.emitComponentAdded({
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
source: 'Entity',
|
source: "Entity",
|
||||||
entityId: this.id,
|
entityId: this.id,
|
||||||
entityName: this.name,
|
entityName: this.name,
|
||||||
entityTag: this.tag?.toString(),
|
entityTag: this.tag?.toString(),
|
||||||
@@ -465,8 +473,6 @@ export class Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查实体是否拥有指定类型的组件
|
* 检查实体是否拥有指定类型的组件
|
||||||
*
|
*
|
||||||
@@ -555,7 +561,7 @@ export class Entity {
|
|||||||
if (Entity.eventBus) {
|
if (Entity.eventBus) {
|
||||||
Entity.eventBus.emitComponentRemoved({
|
Entity.eventBus.emitComponentRemoved({
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
source: 'Entity',
|
source: "Entity",
|
||||||
entityId: this.id,
|
entityId: this.id,
|
||||||
entityName: this.name,
|
entityName: this.name,
|
||||||
entityTag: this.tag?.toString(),
|
entityTag: this.tag?.toString(),
|
||||||
@@ -646,7 +652,6 @@ export class Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有指定类型的组件
|
* 获取所有指定类型的组件
|
||||||
*
|
*
|
||||||
@@ -877,13 +882,13 @@ export class Entity {
|
|||||||
*/
|
*/
|
||||||
private onActiveChanged(): void {
|
private onActiveChanged(): void {
|
||||||
for (const component of this.components) {
|
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();
|
(component as any).onActiveChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.scene && this.scene.eventSystem) {
|
if (this.scene && this.scene.eventSystem) {
|
||||||
this.scene.eventSystem.emitSync('entity:activeChanged', {
|
this.scene.eventSystem.emitSync("entity:activeChanged", {
|
||||||
entity: this,
|
entity: this,
|
||||||
active: this._active,
|
active: this._active,
|
||||||
activeInHierarchy: this.activeInHierarchy
|
activeInHierarchy: this.activeInHierarchy
|
||||||
@@ -898,11 +903,11 @@ export class Entity {
|
|||||||
* 移除所有组件、子实体并标记为已销毁
|
* 移除所有组件、子实体并标记为已销毁
|
||||||
*/
|
*/
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
if (this._isDestroyed) {
|
if (this._destroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._isDestroyed = true;
|
this._destroyed = true;
|
||||||
|
|
||||||
if (this.scene && this.scene.referenceTracker) {
|
if (this.scene && this.scene.referenceTracker) {
|
||||||
this.scene.referenceTracker.clearReferencesTo(this.id);
|
this.scene.referenceTracker.clearReferencesTo(this.id);
|
||||||
@@ -949,7 +954,7 @@ export class Entity {
|
|||||||
collectChildren(this);
|
collectChildren(this);
|
||||||
|
|
||||||
for (const entity of toDestroy) {
|
for (const entity of toDestroy) {
|
||||||
entity._isDestroyed = true;
|
entity.setDestroyed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const entity of toDestroy) {
|
for (const entity of toDestroy) {
|
||||||
@@ -1014,13 +1019,13 @@ export class Entity {
|
|||||||
enabled: this._enabled,
|
enabled: this._enabled,
|
||||||
active: this._active,
|
active: this._active,
|
||||||
activeInHierarchy: this.activeInHierarchy,
|
activeInHierarchy: this.activeInHierarchy,
|
||||||
destroyed: this._isDestroyed,
|
destroyed: this._destroyed,
|
||||||
componentCount: this.components.length,
|
componentCount: this.components.length,
|
||||||
componentTypes: this.components.map(c => getComponentInstanceTypeName(c)),
|
componentTypes: this.components.map((c) => getComponentInstanceTypeName(c)),
|
||||||
componentMask: BitMask64Utils.toString(this._componentMask, 2), // 二进制表示
|
componentMask: BitMask64Utils.toString(this._componentMask, 2), // 二进制表示
|
||||||
parentId: this._parent?.id || null,
|
parentId: this._parent?.id || null,
|
||||||
childCount: this._children.length,
|
childCount: this._children.length,
|
||||||
childIds: this._children.map(c => c.id),
|
childIds: this._children.map((c) => c.id),
|
||||||
depth: this.getDepth(),
|
depth: this.getDepth(),
|
||||||
cacheBuilt: this._componentCache !== null
|
cacheBuilt: this._componentCache !== null
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { Entity } from './Entity';
|
import {Entity} from "./Entity";
|
||||||
import { EntityList } from './Utils/EntityList';
|
import {EntityList} from "./Utils/EntityList";
|
||||||
import { IdentifierPool } from './Utils/IdentifierPool';
|
import {IdentifierPool} from "./Utils/IdentifierPool";
|
||||||
import { EntitySystem } from './Systems/EntitySystem';
|
import {EntitySystem} from "./Systems/EntitySystem";
|
||||||
import { ComponentStorageManager } from './Core/ComponentStorage';
|
import {ComponentStorageManager} from "./Core/ComponentStorage";
|
||||||
import { QuerySystem } from './Core/QuerySystem';
|
import {QuerySystem} from "./Core/QuerySystem";
|
||||||
import { TypeSafeEventSystem } from './Core/EventSystem';
|
import {TypeSafeEventSystem} from "./Core/EventSystem";
|
||||||
import type { ReferenceTracker } from './Core/ReferenceTracker';
|
import type {ReferenceTracker} from "./Core/ReferenceTracker";
|
||||||
import type { ServiceContainer, ServiceType } from '../Core/ServiceContainer';
|
import type {ServiceContainer, ServiceType} from "../Core/ServiceContainer";
|
||||||
import type { TypedQueryBuilder } from './Core/Query/TypedQuery';
|
import type {TypedQueryBuilder} from "./Core/Query/TypedQuery";
|
||||||
import type { SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer';
|
import type {SceneSerializationOptions, SceneDeserializationOptions} from "./Serialization/SceneSerializer";
|
||||||
import type { IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer';
|
import type {IncrementalSnapshot, IncrementalSerializationOptions} from "./Serialization/IncrementalSerializer";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 场景接口定义
|
* 场景接口定义
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
import { Entity } from './Entity';
|
import {Entity} from "./Entity";
|
||||||
import { EntityList } from './Utils/EntityList';
|
import {EntityList} from "./Utils/EntityList";
|
||||||
import { IdentifierPool } from './Utils/IdentifierPool';
|
import {IdentifierPool} from "./Utils/IdentifierPool";
|
||||||
import { EntitySystem } from './Systems/EntitySystem';
|
import {EntitySystem} from "./Systems/EntitySystem";
|
||||||
import { ComponentStorageManager, ComponentRegistry } from './Core/ComponentStorage';
|
import {ComponentStorageManager, ComponentRegistry} from "./Core/ComponentStorage";
|
||||||
import { QuerySystem } from './Core/QuerySystem';
|
import {QuerySystem} from "./Core/QuerySystem";
|
||||||
import { TypeSafeEventSystem } from './Core/EventSystem';
|
import {TypeSafeEventSystem} from "./Core/EventSystem";
|
||||||
import { EventBus } from './Core/EventBus';
|
import {EventBus} from "./Core/EventBus";
|
||||||
import { ReferenceTracker } from './Core/ReferenceTracker';
|
import {ReferenceTracker} from "./Core/ReferenceTracker";
|
||||||
import { IScene, ISceneConfig } from './IScene';
|
import {IScene, ISceneConfig} from "./IScene";
|
||||||
import {getComponentInstanceTypeName, getSystemInstanceTypeName, getSystemMetadata} from "./Decorators";
|
import {getComponentInstanceTypeName, getSystemInstanceTypeName, getSystemMetadata} from "./Decorators";
|
||||||
import { TypedQueryBuilder } from './Core/Query/TypedQuery';
|
import {TypedQueryBuilder} from "./Core/Query/TypedQuery";
|
||||||
import { SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions } from './Serialization/SceneSerializer';
|
import {SceneSerializer, SceneSerializationOptions, SceneDeserializationOptions} from "./Serialization/SceneSerializer";
|
||||||
import { IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions } from './Serialization/IncrementalSerializer';
|
import {IncrementalSerializer, IncrementalSnapshot, IncrementalSerializationOptions} from "./Serialization/IncrementalSerializer";
|
||||||
import { ComponentPoolManager } from './Core/ComponentPool';
|
import {ComponentPoolManager} from "./Core/ComponentPool";
|
||||||
import { PerformanceMonitor } from '../Utils/PerformanceMonitor';
|
import {PerformanceMonitor} from "../Utils/PerformanceMonitor";
|
||||||
import { ServiceContainer, type ServiceType } from '../Core/ServiceContainer';
|
import {ServiceContainer, type ServiceType} from "../Core/ServiceContainer";
|
||||||
import { createInstance, isInjectable, injectProperties } from '../Core/DI';
|
import {createInstance, isInjectable, injectProperties} from "../Core/DI";
|
||||||
import { createLogger } from '../Utils/Logger';
|
import {createLogger} from "../Utils/Logger";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 游戏场景默认实现类
|
* 游戏场景默认实现类
|
||||||
@@ -207,7 +207,7 @@ export class Scene implements IScene {
|
|||||||
this.eventSystem = new TypeSafeEventSystem();
|
this.eventSystem = new TypeSafeEventSystem();
|
||||||
this.referenceTracker = new ReferenceTracker();
|
this.referenceTracker = new ReferenceTracker();
|
||||||
this._services = new ServiceContainer();
|
this._services = new ServiceContainer();
|
||||||
this.logger = createLogger('Scene');
|
this.logger = createLogger("Scene");
|
||||||
|
|
||||||
if (config?.name) {
|
if (config?.name) {
|
||||||
this.name = config.name;
|
this.name = config.name;
|
||||||
@@ -219,7 +219,7 @@ export class Scene implements IScene {
|
|||||||
|
|
||||||
if (Entity.eventBus) {
|
if (Entity.eventBus) {
|
||||||
Entity.eventBus.onComponentAdded((data: unknown) => {
|
Entity.eventBus.onComponentAdded((data: unknown) => {
|
||||||
this.eventSystem.emitSync('component:added', data);
|
this.eventSystem.emitSync("component:added", data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -338,9 +338,9 @@ export class Scene implements IScene {
|
|||||||
* @param name 实体名称
|
* @param name 实体名称
|
||||||
*/
|
*/
|
||||||
public createEntity(name: string) {
|
public createEntity(name: string) {
|
||||||
let entity = new Entity(name, this.identifierPool.checkOut());
|
const entity = new Entity(name, this.identifierPool.checkOut());
|
||||||
|
|
||||||
this.eventSystem.emitSync('entity:created', { entityName: name, entity, scene: this });
|
this.eventSystem.emitSync("entity:created", {entityName: name, entity, scene: this});
|
||||||
|
|
||||||
return this.addEntity(entity);
|
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;
|
return entity;
|
||||||
}
|
}
|
||||||
@@ -403,7 +403,7 @@ export class Scene implements IScene {
|
|||||||
this.querySystem.addEntitiesUnchecked(entities);
|
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;
|
return entities;
|
||||||
}
|
}
|
||||||
@@ -416,7 +416,7 @@ export class Scene implements IScene {
|
|||||||
if (entities.length === 0) return;
|
if (entities.length === 0) return;
|
||||||
|
|
||||||
for (const entity of entities) {
|
for (const entity of entities) {
|
||||||
entity._isDestroyed = true;
|
entity.setDestroyed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const entity of entities) {
|
for (const entity of entities) {
|
||||||
@@ -583,7 +583,7 @@ export class Scene implements IScene {
|
|||||||
let system: T;
|
let system: T;
|
||||||
let constructor: any;
|
let constructor: any;
|
||||||
|
|
||||||
if (typeof systemTypeOrInstance === 'function') {
|
if (typeof systemTypeOrInstance === "function") {
|
||||||
constructor = systemTypeOrInstance;
|
constructor = systemTypeOrInstance;
|
||||||
|
|
||||||
if (this._services.isRegistered(constructor)) {
|
if (this._services.isRegistered(constructor)) {
|
||||||
@@ -609,7 +609,7 @@ export class Scene implements IScene {
|
|||||||
} else {
|
} else {
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`Attempting to register a different instance of ${constructor.name}, ` +
|
`Attempting to register a different instance of ${constructor.name}, ` +
|
||||||
`but type is already registered. Returning existing instance.`
|
"but type is already registered. Returning existing instance."
|
||||||
);
|
);
|
||||||
return existingSystem as T;
|
return existingSystem as T;
|
||||||
}
|
}
|
||||||
@@ -786,13 +786,13 @@ export class Scene implements IScene {
|
|||||||
entityCount: this.entities.count,
|
entityCount: this.entities.count,
|
||||||
processorCount: systems.length,
|
processorCount: systems.length,
|
||||||
isRunning: this._didSceneBegin,
|
isRunning: this._didSceneBegin,
|
||||||
entities: this.entities.buffer.map(entity => ({
|
entities: this.entities.buffer.map((entity) => ({
|
||||||
name: entity.name,
|
name: entity.name,
|
||||||
id: entity.id,
|
id: entity.id,
|
||||||
componentCount: entity.components.length,
|
componentCount: entity.components.length,
|
||||||
componentTypes: entity.components.map(c => getComponentInstanceTypeName(c))
|
componentTypes: entity.components.map((c) => getComponentInstanceTypeName(c))
|
||||||
})),
|
})),
|
||||||
processors: systems.map(processor => ({
|
processors: systems.map((processor) => ({
|
||||||
name: getSystemInstanceTypeName(processor),
|
name: getSystemInstanceTypeName(processor),
|
||||||
updateOrder: processor.updateOrder,
|
updateOrder: processor.updateOrder,
|
||||||
entityCount: (processor as any)._entities?.length || 0
|
entityCount: (processor as any)._entities?.length || 0
|
||||||
@@ -907,7 +907,7 @@ export class Scene implements IScene {
|
|||||||
*/
|
*/
|
||||||
public serializeIncremental(options?: IncrementalSerializationOptions): IncrementalSnapshot {
|
public serializeIncremental(options?: IncrementalSerializationOptions): IncrementalSnapshot {
|
||||||
if (!this._incrementalBaseSnapshot) {
|
if (!this._incrementalBaseSnapshot) {
|
||||||
throw new Error('必须先调用 createIncrementalSnapshot() 创建基础快照');
|
throw new Error("必须先调用 createIncrementalSnapshot() 创建基础快照");
|
||||||
}
|
}
|
||||||
|
|
||||||
return IncrementalSerializer.computeIncremental(
|
return IncrementalSerializer.computeIncremental(
|
||||||
@@ -941,7 +941,7 @@ export class Scene implements IScene {
|
|||||||
incremental: IncrementalSnapshot | string | Uint8Array,
|
incremental: IncrementalSnapshot | string | Uint8Array,
|
||||||
componentRegistry?: Map<string, any>
|
componentRegistry?: Map<string, any>
|
||||||
): void {
|
): void {
|
||||||
const isSerializedData = typeof incremental === 'string' ||
|
const isSerializedData = typeof incremental === "string" ||
|
||||||
incremental instanceof Uint8Array;
|
incremental instanceof Uint8Array;
|
||||||
|
|
||||||
const snapshot = isSerializedData
|
const snapshot = isSerializedData
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { IScene } from './IScene';
|
import {IScene} from "./IScene";
|
||||||
import { ECSFluentAPI, createECSAPI } from './Core/FluentAPI';
|
import {ECSFluentAPI, createECSAPI} from "./Core/FluentAPI";
|
||||||
import { Time } from '../Utils/Time';
|
import {Time} from "../Utils/Time";
|
||||||
import { createLogger } from '../Utils/Logger';
|
import {createLogger} from "../Utils/Logger";
|
||||||
import type { IService } from '../Core/ServiceContainer';
|
import type {IService} from "../Core/ServiceContainer";
|
||||||
import { World } from './World';
|
import {World} from "./World";
|
||||||
import { PerformanceMonitor } from '../Utils/PerformanceMonitor';
|
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
|
* 默认场景ID
|
||||||
*/
|
*/
|
||||||
private static readonly DEFAULT_SCENE_ID = '__main__';
|
private static readonly DEFAULT_SCENE_ID = "__main__";
|
||||||
|
|
||||||
constructor(performanceMonitor?: PerformanceMonitor) {
|
constructor(performanceMonitor?: PerformanceMonitor) {
|
||||||
this._defaultWorld = new World({ name: '__default__' });
|
this._defaultWorld = new World({name: "__default__"});
|
||||||
this._defaultWorld.start();
|
this._defaultWorld.start();
|
||||||
this._performanceMonitor = performanceMonitor || null;
|
this._performanceMonitor = performanceMonitor || null;
|
||||||
}
|
}
|
||||||
@@ -238,13 +238,13 @@ export class SceneManager implements IService {
|
|||||||
* 通常在应用程序关闭时调用。
|
* 通常在应用程序关闭时调用。
|
||||||
*/
|
*/
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
this._logger.info('SceneManager destroying');
|
this._logger.info("SceneManager destroying");
|
||||||
|
|
||||||
this._defaultWorld.destroy();
|
this._defaultWorld.destroy();
|
||||||
this._nextScene = null;
|
this._nextScene = null;
|
||||||
this._ecsAPI = null;
|
this._ecsAPI = null;
|
||||||
|
|
||||||
this._logger.info('SceneManager destroyed');
|
this._logger.info("SceneManager destroyed");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
* 负责组件的序列化和反序列化操作
|
* 负责组件的序列化和反序列化操作
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component } from '../Component';
|
import {Component} from "../Component";
|
||||||
import { ComponentType } from '../Core/ComponentStorage';
|
import {ComponentType} from "../Core/ComponentStorage";
|
||||||
import { getComponentTypeName } from '../Decorators';
|
import {getComponentTypeName} from "../Decorators";
|
||||||
import {
|
import {
|
||||||
getSerializationMetadata
|
getSerializationMetadata
|
||||||
} from './SerializationDecorators';
|
} from "./SerializationDecorators";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 可序列化的值类型
|
* 可序列化的值类型
|
||||||
@@ -22,9 +22,9 @@ export type SerializableValue =
|
|||||||
| undefined
|
| undefined
|
||||||
| SerializableValue[]
|
| SerializableValue[]
|
||||||
| { [key: string]: SerializableValue }
|
| { [key: string]: SerializableValue }
|
||||||
| { __type: 'Date'; value: string }
|
| { __type: "Date"; value: string }
|
||||||
| { __type: 'Map'; value: Array<[SerializableValue, SerializableValue]> }
|
| { __type: "Map"; value: Array<[SerializableValue, SerializableValue]> }
|
||||||
| { __type: 'Set'; value: SerializableValue[] };
|
| { __type: "Set"; value: SerializableValue[] };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化后的组件数据
|
* 序列化后的组件数据
|
||||||
@@ -70,7 +70,7 @@ export class ComponentSerializer {
|
|||||||
|
|
||||||
// 序列化标记的字段
|
// 序列化标记的字段
|
||||||
for (const [fieldName, options] of metadata.fields) {
|
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];
|
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) {
|
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 key = options.alias || fieldKey;
|
||||||
const serializedValue = serializedData.data[key];
|
const serializedValue = serializedData.data[key];
|
||||||
|
|
||||||
@@ -198,27 +198,27 @@ export class ComponentSerializer {
|
|||||||
|
|
||||||
// 基本类型
|
// 基本类型
|
||||||
const type = typeof value;
|
const type = typeof value;
|
||||||
if (type === 'string' || type === 'number' || type === 'boolean') {
|
if (type === "string" || type === "number" || type === "boolean") {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 日期
|
// 日期
|
||||||
if (value instanceof Date) {
|
if (value instanceof Date) {
|
||||||
return {
|
return {
|
||||||
__type: 'Date',
|
__type: "Date",
|
||||||
value: value.toISOString()
|
value: value.toISOString()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数组
|
// 数组
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return value.map(item => this.serializeValue(item));
|
return value.map((item) => this.serializeValue(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map (如果没有使用@SerializeMap装饰器)
|
// Map (如果没有使用@SerializeMap装饰器)
|
||||||
if (value instanceof Map) {
|
if (value instanceof Map) {
|
||||||
return {
|
return {
|
||||||
__type: 'Map',
|
__type: "Map",
|
||||||
value: Array.from(value.entries())
|
value: Array.from(value.entries())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -226,13 +226,13 @@ export class ComponentSerializer {
|
|||||||
// Set
|
// Set
|
||||||
if (value instanceof Set) {
|
if (value instanceof Set) {
|
||||||
return {
|
return {
|
||||||
__type: 'Set',
|
__type: "Set",
|
||||||
value: Array.from(value)
|
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 result: Record<string, SerializableValue> = {};
|
||||||
const obj = value as Record<string, SerializableValue>;
|
const obj = value as Record<string, SerializableValue>;
|
||||||
for (const key in obj) {
|
for (const key in obj) {
|
||||||
@@ -257,30 +257,30 @@ export class ComponentSerializer {
|
|||||||
|
|
||||||
// 基本类型直接返回
|
// 基本类型直接返回
|
||||||
const type = typeof value;
|
const type = typeof value;
|
||||||
if (type === 'string' || type === 'number' || type === 'boolean') {
|
if (type === "string" || type === "number" || type === "boolean") {
|
||||||
return value;
|
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 };
|
const typedValue = value as { __type: string; value: SerializableValue };
|
||||||
switch (typedValue.__type) {
|
switch (typedValue.__type) {
|
||||||
case 'Date':
|
case "Date":
|
||||||
return { __type: 'Date', value: typeof typedValue.value === 'string' ? typedValue.value : String(typedValue.value) };
|
return {__type: "Date", value: typeof typedValue.value === "string" ? typedValue.value : String(typedValue.value)};
|
||||||
case 'Map':
|
case "Map":
|
||||||
return { __type: 'Map', value: typedValue.value as Array<[SerializableValue, SerializableValue]> };
|
return {__type: "Map", value: typedValue.value as Array<[SerializableValue, SerializableValue]>};
|
||||||
case 'Set':
|
case "Set":
|
||||||
return { __type: 'Set', value: typedValue.value as SerializableValue[] };
|
return {__type: "Set", value: typedValue.value as SerializableValue[]};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数组
|
// 数组
|
||||||
if (Array.isArray(value)) {
|
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 result: Record<string, SerializableValue> = {};
|
||||||
const obj = value as Record<string, SerializableValue>;
|
const obj = value as Record<string, SerializableValue>;
|
||||||
for (const key in obj) {
|
for (const key in obj) {
|
||||||
@@ -325,7 +325,7 @@ export class ComponentSerializer {
|
|||||||
|
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
return {
|
return {
|
||||||
type: 'unknown',
|
type: "unknown",
|
||||||
version: 0,
|
version: 0,
|
||||||
fields: [],
|
fields: [],
|
||||||
ignoredFields: [],
|
ignoredFields: [],
|
||||||
@@ -333,18 +333,18 @@ export class ComponentSerializer {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const componentType = typeof component === 'function'
|
const componentType = typeof component === "function"
|
||||||
? component
|
? component
|
||||||
: (component.constructor as ComponentType);
|
: (component.constructor as ComponentType);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: metadata.options.typeId || getComponentTypeName(componentType),
|
type: metadata.options.typeId || getComponentTypeName(componentType),
|
||||||
version: metadata.options.version,
|
version: metadata.options.version,
|
||||||
fields: Array.from(metadata.fields.keys()).map(k =>
|
fields: Array.from(metadata.fields.keys()).map((k) =>
|
||||||
typeof k === 'symbol' ? k.toString() : k
|
typeof k === "symbol" ? k.toString() : k
|
||||||
),
|
),
|
||||||
ignoredFields: Array.from(metadata.ignoredFields).map(k =>
|
ignoredFields: Array.from(metadata.ignoredFields).map((k) =>
|
||||||
typeof k === 'symbol' ? k.toString() : k
|
typeof k === "symbol" ? k.toString() : k
|
||||||
),
|
),
|
||||||
isSerializable: true
|
isSerializable: true
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
* 负责实体的序列化和反序列化操作
|
* 负责实体的序列化和反序列化操作
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
import { ComponentType } from '../Core/ComponentStorage';
|
import {ComponentType} from "../Core/ComponentStorage";
|
||||||
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
|
import {ComponentSerializer, SerializedComponent} from "./ComponentSerializer";
|
||||||
import { IScene } from '../IScene';
|
import {IScene} from "../IScene";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化后的实体数据
|
* 序列化后的实体数据
|
||||||
|
|||||||
@@ -5,31 +5,31 @@
|
|||||||
* 适用于网络同步、大场景存档、时间回溯等场景
|
* 适用于网络同步、大场景存档、时间回溯等场景
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { IScene } from '../IScene';
|
import type {IScene} from "../IScene";
|
||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
|
import {ComponentSerializer, SerializedComponent} from "./ComponentSerializer";
|
||||||
import { SerializedEntity } from './EntitySerializer';
|
import {SerializedEntity} from "./EntitySerializer";
|
||||||
import { ComponentType } from '../Core/ComponentStorage';
|
import {ComponentType} from "../Core/ComponentStorage";
|
||||||
import { BinarySerializer } from '../../Utils/BinarySerializer';
|
import {BinarySerializer} from "../../Utils/BinarySerializer";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 变更操作类型
|
* 变更操作类型
|
||||||
*/
|
*/
|
||||||
export enum ChangeOperation {
|
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";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增量序列化选项
|
* 增量序列化选项
|
||||||
@@ -511,7 +511,7 @@ export class IncrementalSerializer {
|
|||||||
private static applyEntityAdded(scene: IScene, change: EntityChange): void {
|
private static applyEntityAdded(scene: IScene, change: EntityChange): void {
|
||||||
if (!change.entityData) return;
|
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.tag = change.entityData.tag || 0;
|
||||||
entity.active = change.entityData.active ?? true;
|
entity.active = change.entityData.active ?? true;
|
||||||
entity.enabled = change.entityData.enabled ?? true;
|
entity.enabled = change.entityData.enabled ?? true;
|
||||||
@@ -632,12 +632,12 @@ export class IncrementalSerializer {
|
|||||||
options?: { format?: IncrementalSerializationFormat; pretty?: boolean }
|
options?: { format?: IncrementalSerializationFormat; pretty?: boolean }
|
||||||
): string | Uint8Array {
|
): string | Uint8Array {
|
||||||
const opts = {
|
const opts = {
|
||||||
format: 'json' as IncrementalSerializationFormat,
|
format: "json" as IncrementalSerializationFormat,
|
||||||
pretty: false,
|
pretty: false,
|
||||||
...options
|
...options
|
||||||
};
|
};
|
||||||
|
|
||||||
if (opts.format === 'binary') {
|
if (opts.format === "binary") {
|
||||||
return BinarySerializer.encode(incremental);
|
return BinarySerializer.encode(incremental);
|
||||||
} else {
|
} else {
|
||||||
return opts.pretty
|
return opts.pretty
|
||||||
@@ -662,7 +662,7 @@ export class IncrementalSerializer {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
public static deserializeIncremental(data: string | Uint8Array): IncrementalSnapshot {
|
public static deserializeIncremental(data: string | Uint8Array): IncrementalSnapshot {
|
||||||
if (typeof data === 'string') {
|
if (typeof data === "string") {
|
||||||
return JSON.parse(data);
|
return JSON.parse(data);
|
||||||
} else {
|
} else {
|
||||||
return BinarySerializer.decode(data) as IncrementalSnapshot;
|
return BinarySerializer.decode(data) as IncrementalSnapshot;
|
||||||
@@ -696,22 +696,22 @@ export class IncrementalSerializer {
|
|||||||
componentChanges: incremental.componentChanges.length,
|
componentChanges: incremental.componentChanges.length,
|
||||||
sceneDataChanges: incremental.sceneDataChanges.length,
|
sceneDataChanges: incremental.sceneDataChanges.length,
|
||||||
addedEntities: incremental.entityChanges.filter(
|
addedEntities: incremental.entityChanges.filter(
|
||||||
c => c.operation === ChangeOperation.EntityAdded
|
(c) => c.operation === ChangeOperation.EntityAdded
|
||||||
).length,
|
).length,
|
||||||
removedEntities: incremental.entityChanges.filter(
|
removedEntities: incremental.entityChanges.filter(
|
||||||
c => c.operation === ChangeOperation.EntityRemoved
|
(c) => c.operation === ChangeOperation.EntityRemoved
|
||||||
).length,
|
).length,
|
||||||
updatedEntities: incremental.entityChanges.filter(
|
updatedEntities: incremental.entityChanges.filter(
|
||||||
c => c.operation === ChangeOperation.EntityUpdated
|
(c) => c.operation === ChangeOperation.EntityUpdated
|
||||||
).length,
|
).length,
|
||||||
addedComponents: incremental.componentChanges.filter(
|
addedComponents: incremental.componentChanges.filter(
|
||||||
c => c.operation === ChangeOperation.ComponentAdded
|
(c) => c.operation === ChangeOperation.ComponentAdded
|
||||||
).length,
|
).length,
|
||||||
removedComponents: incremental.componentChanges.filter(
|
removedComponents: incremental.componentChanges.filter(
|
||||||
c => c.operation === ChangeOperation.ComponentRemoved
|
(c) => c.operation === ChangeOperation.ComponentRemoved
|
||||||
).length,
|
).length,
|
||||||
updatedComponents: incremental.componentChanges.filter(
|
updatedComponents: incremental.componentChanges.filter(
|
||||||
c => c.operation === ChangeOperation.ComponentUpdated
|
(c) => c.operation === ChangeOperation.ComponentUpdated
|
||||||
).length
|
).length
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,23 +4,23 @@
|
|||||||
* 负责整个场景的序列化和反序列化,包括实体、组件等
|
* 负责整个场景的序列化和反序列化,包括实体、组件等
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { IScene } from '../IScene';
|
import type {IScene} from "../IScene";
|
||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
import { ComponentType, ComponentRegistry } from '../Core/ComponentStorage';
|
import {ComponentType, ComponentRegistry} from "../Core/ComponentStorage";
|
||||||
import { EntitySerializer, SerializedEntity } from './EntitySerializer';
|
import {EntitySerializer, SerializedEntity} from "./EntitySerializer";
|
||||||
import { getComponentTypeName } from '../Decorators';
|
import {getComponentTypeName} from "../Decorators";
|
||||||
import { getSerializationMetadata } from './SerializationDecorators';
|
import {getSerializationMetadata} from "./SerializationDecorators";
|
||||||
import { BinarySerializer } from '../../Utils/BinarySerializer';
|
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 {
|
public static serialize(scene: IScene, options?: SceneSerializationOptions): string | Uint8Array {
|
||||||
const opts: SceneSerializationOptions = {
|
const opts: SceneSerializationOptions = {
|
||||||
systems: false,
|
systems: false,
|
||||||
format: 'json',
|
format: "json",
|
||||||
pretty: true,
|
pretty: true,
|
||||||
includeMetadata: true,
|
includeMetadata: true,
|
||||||
...options
|
...options
|
||||||
@@ -199,7 +199,7 @@ export class SceneSerializer {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.format === 'json') {
|
if (opts.format === "json") {
|
||||||
return opts.pretty
|
return opts.pretty
|
||||||
? JSON.stringify(serializedScene, null, 2)
|
? JSON.stringify(serializedScene, null, 2)
|
||||||
: JSON.stringify(serializedScene);
|
: JSON.stringify(serializedScene);
|
||||||
@@ -221,14 +221,14 @@ export class SceneSerializer {
|
|||||||
options?: SceneDeserializationOptions
|
options?: SceneDeserializationOptions
|
||||||
): void {
|
): void {
|
||||||
const opts: SceneDeserializationOptions = {
|
const opts: SceneDeserializationOptions = {
|
||||||
strategy: 'replace',
|
strategy: "replace",
|
||||||
preserveIds: false,
|
preserveIds: false,
|
||||||
...options
|
...options
|
||||||
};
|
};
|
||||||
|
|
||||||
let serializedScene: SerializedScene;
|
let serializedScene: SerializedScene;
|
||||||
try {
|
try {
|
||||||
if (typeof saveData === 'string') {
|
if (typeof saveData === "string") {
|
||||||
serializedScene = JSON.parse(saveData);
|
serializedScene = JSON.parse(saveData);
|
||||||
} else {
|
} else {
|
||||||
serializedScene = BinarySerializer.decode(saveData) as SerializedScene;
|
serializedScene = BinarySerializer.decode(saveData) as SerializedScene;
|
||||||
@@ -250,7 +250,7 @@ export class SceneSerializer {
|
|||||||
const componentRegistry = opts.componentRegistry || this.getGlobalComponentRegistry();
|
const componentRegistry = opts.componentRegistry || this.getGlobalComponentRegistry();
|
||||||
|
|
||||||
// 根据策略处理场景
|
// 根据策略处理场景
|
||||||
if (opts.strategy === 'replace') {
|
if (opts.strategy === "replace") {
|
||||||
// 清空场景
|
// 清空场景
|
||||||
scene.destroyAllEntities();
|
scene.destroyAllEntities();
|
||||||
}
|
}
|
||||||
@@ -342,35 +342,35 @@ export class SceneSerializer {
|
|||||||
|
|
||||||
// 基本类型
|
// 基本类型
|
||||||
const type = typeof value;
|
const type = typeof value;
|
||||||
if (type === 'string' || type === 'number' || type === 'boolean') {
|
if (type === "string" || type === "number" || type === "boolean") {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Date
|
// Date
|
||||||
if (value instanceof Date) {
|
if (value instanceof Date) {
|
||||||
return { __type: 'Date', value: value.toISOString() };
|
return {__type: "Date", value: value.toISOString()};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map
|
// Map
|
||||||
if (value instanceof Map) {
|
if (value instanceof Map) {
|
||||||
return { __type: 'Map', value: Array.from(value.entries()) };
|
return {__type: "Map", value: Array.from(value.entries())};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set
|
// Set
|
||||||
if (value instanceof Set) {
|
if (value instanceof Set) {
|
||||||
return { __type: 'Set', value: Array.from(value) };
|
return {__type: "Set", value: Array.from(value)};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数组
|
// 数组
|
||||||
if (Array.isArray(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> = {};
|
const result: Record<string, any> = {};
|
||||||
for (const key in value) {
|
for (const key in value) {
|
||||||
if (value.hasOwnProperty(key)) {
|
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
||||||
result[key] = this.serializeValue(value[key]);
|
result[key] = this.serializeValue(value[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -391,32 +391,32 @@ export class SceneSerializer {
|
|||||||
|
|
||||||
// 基本类型
|
// 基本类型
|
||||||
const type = typeof value;
|
const type = typeof value;
|
||||||
if (type === 'string' || type === 'number' || type === 'boolean') {
|
if (type === "string" || type === "number" || type === "boolean") {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理特殊类型标记
|
// 处理特殊类型标记
|
||||||
if (type === 'object' && value.__type) {
|
if (type === "object" && value.__type) {
|
||||||
switch (value.__type) {
|
switch (value.__type) {
|
||||||
case 'Date':
|
case "Date":
|
||||||
return new Date(value.value);
|
return new Date(value.value);
|
||||||
case 'Map':
|
case "Map":
|
||||||
return new Map(value.value);
|
return new Map(value.value);
|
||||||
case 'Set':
|
case "Set":
|
||||||
return new Set(value.value);
|
return new Set(value.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数组
|
// 数组
|
||||||
if (Array.isArray(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> = {};
|
const result: Record<string, any> = {};
|
||||||
for (const key in value) {
|
for (const key in value) {
|
||||||
if (value.hasOwnProperty(key)) {
|
if (Object.prototype.hasOwnProperty.call(value, key)) {
|
||||||
result[key] = this.deserializeValue(value[key]);
|
result[key] = this.deserializeValue(value[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -437,8 +437,8 @@ export class SceneSerializer {
|
|||||||
const componentTypeSet = new Set(options.components);
|
const componentTypeSet = new Set(options.components);
|
||||||
|
|
||||||
// 只返回拥有指定组件的实体
|
// 只返回拥有指定组件的实体
|
||||||
return entities.filter(entity => {
|
return entities.filter((entity) => {
|
||||||
return Array.from(entity.components).some(component =>
|
return Array.from(entity.components).some((component) =>
|
||||||
componentTypeSet.has(component.constructor as ComponentType)
|
componentTypeSet.has(component.constructor as ComponentType)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -499,15 +499,15 @@ export class SceneSerializer {
|
|||||||
const data = JSON.parse(saveData);
|
const data = JSON.parse(saveData);
|
||||||
|
|
||||||
if (!data.version) {
|
if (!data.version) {
|
||||||
errors.push('Missing version field');
|
errors.push("Missing version field");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.entities || !Array.isArray(data.entities)) {
|
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)) {
|
if (!data.componentTypeRegistry || !Array.isArray(data.componentTypeRegistry)) {
|
||||||
errors.push('Missing or invalid componentTypeRegistry field');
|
errors.push("Missing or invalid componentTypeRegistry field");
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -4,14 +4,14 @@
|
|||||||
* 提供组件级别的序列化支持,包括字段级装饰器和类级装饰器
|
* 提供组件级别的序列化支持,包括字段级装饰器和类级装饰器
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Component } from '../Component';
|
import {Component} from "../Component";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 序列化元数据的Symbol键
|
* 序列化元数据的Symbol键
|
||||||
*/
|
*/
|
||||||
export const SERIALIZABLE_METADATA = Symbol('SerializableMetadata');
|
export const SERIALIZABLE_METADATA = Symbol("SerializableMetadata");
|
||||||
export const SERIALIZE_FIELD = Symbol('SerializeField');
|
export const SERIALIZE_FIELD = Symbol("SerializeField");
|
||||||
export const SERIALIZE_OPTIONS = Symbol('SerializeOptions');
|
export const SERIALIZE_OPTIONS = Symbol("SerializeOptions");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 可序列化配置选项
|
* 可序列化配置选项
|
||||||
@@ -76,8 +76,8 @@ export interface SerializationMetadata {
|
|||||||
*/
|
*/
|
||||||
export function Serializable(options: SerializableOptions) {
|
export function Serializable(options: SerializableOptions) {
|
||||||
return function <T extends new (...args: any[]) => Component>(target: T): T {
|
return function <T extends new (...args: any[]) => Component>(target: T): T {
|
||||||
if (!options || typeof options.version !== 'number') {
|
if (!options || typeof options.version !== "number") {
|
||||||
throw new Error('Serializable装饰器必须提供有效的版本号');
|
throw new Error("Serializable装饰器必须提供有效的版本号");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化或获取现有元数据
|
// 初始化或获取现有元数据
|
||||||
@@ -236,7 +236,7 @@ export function getSerializationMetadata(componentClass: any): SerializationMeta
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 如果是实例,获取其构造函数
|
// 如果是实例,获取其构造函数
|
||||||
const constructor = typeof componentClass === 'function'
|
const constructor = typeof componentClass === "function"
|
||||||
? componentClass
|
? componentClass
|
||||||
: componentClass.constructor;
|
: componentClass.constructor;
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
* 提供组件和场景数据的版本迁移支持
|
* 提供组件和场景数据的版本迁移支持
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { SerializedComponent } from './ComponentSerializer';
|
import {SerializedComponent} from "./ComponentSerializer";
|
||||||
import { SerializedScene } from './SceneSerializer';
|
import {SerializedScene} from "./SceneSerializer";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件迁移函数
|
* 组件迁移函数
|
||||||
@@ -127,7 +127,7 @@ export class VersionMigrationManager {
|
|||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
let migratedData = { ...component };
|
const migratedData = {...component};
|
||||||
let version = currentVersion;
|
let version = currentVersion;
|
||||||
|
|
||||||
// 执行迁移链
|
// 执行迁移链
|
||||||
@@ -193,12 +193,12 @@ export class VersionMigrationManager {
|
|||||||
private static migrateSceneComponents(scene: SerializedScene): SerializedScene {
|
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,
|
...entity,
|
||||||
components: entity.components.map(component => {
|
components: entity.components.map((component) => {
|
||||||
// 查找组件的目标版本
|
// 查找组件的目标版本
|
||||||
const typeInfo = scene.componentTypeRegistry.find(
|
const typeInfo = scene.componentTypeRegistry.find(
|
||||||
t => t.typeName === component.type
|
(t) => t.typeName === component.type
|
||||||
);
|
);
|
||||||
|
|
||||||
if (typeInfo && typeInfo.version !== component.version) {
|
if (typeInfo && typeInfo.version !== component.version) {
|
||||||
@@ -220,10 +220,10 @@ export class VersionMigrationManager {
|
|||||||
entities: any[],
|
entities: any[],
|
||||||
typeRegistry: Array<{ typeName: string; version: number }>
|
typeRegistry: Array<{ typeName: string; version: number }>
|
||||||
): any[] {
|
): any[] {
|
||||||
return entities.map(entity => ({
|
return entities.map((entity) => ({
|
||||||
...entity,
|
...entity,
|
||||||
components: entity.components.map((component: SerializedComponent) => {
|
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) {
|
if (typeInfo && typeInfo.version !== component.version) {
|
||||||
return this.migrateComponent(component, typeInfo.version);
|
return this.migrateComponent(component, typeInfo.version);
|
||||||
|
|||||||
@@ -16,24 +16,24 @@ export {
|
|||||||
SERIALIZABLE_METADATA,
|
SERIALIZABLE_METADATA,
|
||||||
SERIALIZE_FIELD,
|
SERIALIZE_FIELD,
|
||||||
SERIALIZE_OPTIONS
|
SERIALIZE_OPTIONS
|
||||||
} from './SerializationDecorators';
|
} from "./SerializationDecorators";
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
SerializableOptions,
|
SerializableOptions,
|
||||||
FieldSerializeOptions,
|
FieldSerializeOptions,
|
||||||
SerializationMetadata
|
SerializationMetadata
|
||||||
} from './SerializationDecorators';
|
} from "./SerializationDecorators";
|
||||||
|
|
||||||
// 组件序列化器
|
// 组件序列化器
|
||||||
export { ComponentSerializer } from './ComponentSerializer';
|
export {ComponentSerializer} from "./ComponentSerializer";
|
||||||
export type { SerializedComponent } from './ComponentSerializer';
|
export type {SerializedComponent} from "./ComponentSerializer";
|
||||||
|
|
||||||
// 实体序列化器
|
// 实体序列化器
|
||||||
export { EntitySerializer } from './EntitySerializer';
|
export {EntitySerializer} from "./EntitySerializer";
|
||||||
export type { SerializedEntity } from './EntitySerializer';
|
export type {SerializedEntity} from "./EntitySerializer";
|
||||||
|
|
||||||
// 场景序列化器
|
// 场景序列化器
|
||||||
export { SceneSerializer } from './SceneSerializer';
|
export {SceneSerializer} from "./SceneSerializer";
|
||||||
export type {
|
export type {
|
||||||
SerializedScene,
|
SerializedScene,
|
||||||
SerializationFormat,
|
SerializationFormat,
|
||||||
@@ -41,17 +41,17 @@ export type {
|
|||||||
MigrationFunction,
|
MigrationFunction,
|
||||||
SceneSerializationOptions,
|
SceneSerializationOptions,
|
||||||
SceneDeserializationOptions
|
SceneDeserializationOptions
|
||||||
} from './SceneSerializer';
|
} from "./SceneSerializer";
|
||||||
|
|
||||||
// 版本迁移
|
// 版本迁移
|
||||||
export { VersionMigrationManager, MigrationBuilder } from './VersionMigration';
|
export {VersionMigrationManager, MigrationBuilder} from "./VersionMigration";
|
||||||
export type {
|
export type {
|
||||||
ComponentMigrationFunction,
|
ComponentMigrationFunction,
|
||||||
SceneMigrationFunction
|
SceneMigrationFunction
|
||||||
} from './VersionMigration';
|
} from "./VersionMigration";
|
||||||
|
|
||||||
// 增量序列化
|
// 增量序列化
|
||||||
export { IncrementalSerializer, ChangeOperation } from './IncrementalSerializer';
|
export {IncrementalSerializer, ChangeOperation} from "./IncrementalSerializer";
|
||||||
export type {
|
export type {
|
||||||
IncrementalSnapshot,
|
IncrementalSnapshot,
|
||||||
IncrementalSerializationOptions,
|
IncrementalSerializationOptions,
|
||||||
@@ -59,4 +59,4 @@ export type {
|
|||||||
EntityChange,
|
EntityChange,
|
||||||
ComponentChange,
|
ComponentChange,
|
||||||
SceneDataChange
|
SceneDataChange
|
||||||
} from './IncrementalSerializer';
|
} from "./IncrementalSerializer";
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
import { PerformanceMonitor } from '../../Utils/PerformanceMonitor';
|
import {PerformanceMonitor} from "../../Utils/PerformanceMonitor";
|
||||||
import { Matcher, type QueryCondition } from '../Utils/Matcher';
|
import {Matcher, type QueryCondition} from "../Utils/Matcher";
|
||||||
import type { Scene } from '../Scene';
|
import type {Scene} from "../Scene";
|
||||||
import type { ISystemBase } from '../../Types';
|
import type {ISystemBase} from "../../Types";
|
||||||
import type { QuerySystem } from '../Core/QuerySystem';
|
import type {QuerySystem} from "../Core/QuerySystem";
|
||||||
import { getSystemInstanceTypeName } from '../Decorators';
|
import {getSystemInstanceTypeName} from "../Decorators";
|
||||||
import { createLogger } from '../../Utils/Logger';
|
import {createLogger} from "../../Utils/Logger";
|
||||||
import type { EventListenerConfig, TypeSafeEventSystem, EventHandler } from '../Core/EventSystem';
|
import type {EventListenerConfig, TypeSafeEventSystem, EventHandler} from "../Core/EventSystem";
|
||||||
import type { ComponentConstructor, ComponentInstance } from '../../Types/TypeHelpers';
|
import type {ComponentConstructor, ComponentInstance} from "../../Types/TypeHelpers";
|
||||||
import type { IService } from '../../Core/ServiceContainer';
|
import type {IService} from "../../Core/ServiceContainer";
|
||||||
|
import type {ComponentType} from "../Core/ComponentStorage";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事件监听器记录
|
* 事件监听器记录
|
||||||
@@ -259,8 +260,11 @@ export abstract class EntitySystem<
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清除实体缓存(内部使用)
|
* 清除实体缓存
|
||||||
* 当Scene中的实体发生变化时调用
|
*
|
||||||
|
* 当 Scene 中的实体发生变化时调用,使系统的实体缓存失效。
|
||||||
|
*
|
||||||
|
* @internal 框架内部使用,不应在外部代码中直接调用
|
||||||
*/
|
*/
|
||||||
public clearEntityCache(): void {
|
public clearEntityCache(): void {
|
||||||
this._entityCache.invalidate();
|
this._entityCache.invalidate();
|
||||||
@@ -299,7 +303,7 @@ export abstract class EntitySystem<
|
|||||||
|
|
||||||
// 空条件返回所有实体
|
// 空条件返回所有实体
|
||||||
if (this._matcher.isEmpty()) {
|
if (this._matcher.isEmpty()) {
|
||||||
currentEntities = querySystem.getAllEntities();
|
currentEntities = querySystem.queryAllEntities();
|
||||||
} else if (this.isSingleCondition(condition)) {
|
} else if (this.isSingleCondition(condition)) {
|
||||||
// 单一条件优化查询
|
// 单一条件优化查询
|
||||||
currentEntities = this.executeSingleConditionQuery(condition, querySystem);
|
currentEntities = this.executeSingleConditionQuery(condition, querySystem);
|
||||||
@@ -403,7 +407,7 @@ export abstract class EntitySystem<
|
|||||||
// 6. 应用none条件 (差集)
|
// 6. 应用none条件 (差集)
|
||||||
if (condition.none.length > 0) {
|
if (condition.none.length > 0) {
|
||||||
if (!resultIds) {
|
if (!resultIds) {
|
||||||
resultIds = this.extractEntityIds(querySystem.getAllEntities());
|
resultIds = this.extractEntityIds(querySystem.queryAllEntities());
|
||||||
}
|
}
|
||||||
|
|
||||||
const noneResult = querySystem.queryAny(...condition.none);
|
const noneResult = querySystem.queryAny(...condition.none);
|
||||||
@@ -411,16 +415,23 @@ export abstract class EntitySystem<
|
|||||||
resultIds = this.differenceIdSets(resultIds, noneIds);
|
resultIds = this.differenceIdSets(resultIds, noneIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultIds ? this.idSetToEntityArray(resultIds, querySystem.getAllEntities()) : [];
|
return resultIds ? this.idSetToEntityArray(resultIds, querySystem.queryAllEntities()) : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提取实体ID集合
|
* 提取实体ID集合
|
||||||
|
*
|
||||||
|
* 使用位运算 | 0 强制转换为 32 位整数,帮助 JavaScript 引擎的 JIT 编译器
|
||||||
|
* 进行整数优化,在大规模实体集合操作时可以提供微小的性能提升。
|
||||||
|
*
|
||||||
|
* @param entities 实体数组
|
||||||
|
* @returns 包含所有实体ID的集合
|
||||||
*/
|
*/
|
||||||
private extractEntityIds(entities: readonly Entity[]): Set<number> {
|
private extractEntityIds(entities: readonly Entity[]): Set<number> {
|
||||||
const len = entities.length;
|
const len = entities.length;
|
||||||
const idSet = new Set<number>();
|
const idSet = new Set<number>();
|
||||||
|
|
||||||
|
// 使用位运算 | 0 进行整数优化(JIT 友好)
|
||||||
for (let i = 0; i < len; i = (i + 1) | 0) {
|
for (let i = 0; i < len; i = (i + 1) | 0) {
|
||||||
idSet.add(entities[i]!.id | 0);
|
idSet.add(entities[i]!.id | 0);
|
||||||
}
|
}
|
||||||
@@ -482,6 +493,12 @@ export abstract class EntitySystem<
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 重建实体ID映射
|
* 重建实体ID映射
|
||||||
|
*
|
||||||
|
* 重新构建从实体ID到实体引用的映射表。使用位运算优化性能。
|
||||||
|
*
|
||||||
|
* @param allEntities 所有实体的数组
|
||||||
|
* @param version QuerySystem 的版本号,用于缓存失效判断
|
||||||
|
* @returns 重建后的实体ID映射表
|
||||||
*/
|
*/
|
||||||
private rebuildEntityIdMap(allEntities: readonly Entity[], version: number): Map<number, Entity> {
|
private rebuildEntityIdMap(allEntities: readonly Entity[], version: number): Map<number, Entity> {
|
||||||
let entityMap = this._entityIdMap;
|
let entityMap = this._entityIdMap;
|
||||||
@@ -493,6 +510,7 @@ export abstract class EntitySystem<
|
|||||||
}
|
}
|
||||||
|
|
||||||
const len = allEntities.length;
|
const len = allEntities.length;
|
||||||
|
// 使用位运算 | 0 进行整数优化(JIT 友好)
|
||||||
for (let i = 0; i < len; i = (i + 1) | 0) {
|
for (let i = 0; i < len; i = (i + 1) | 0) {
|
||||||
const entity = allEntities[i]!;
|
const entity = allEntities[i]!;
|
||||||
entityMap.set(entity.id | 0, entity);
|
entityMap.set(entity.id | 0, entity);
|
||||||
@@ -506,6 +524,12 @@ export abstract class EntitySystem<
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 从ID集合构建Entity数组
|
* 从ID集合构建Entity数组
|
||||||
|
*
|
||||||
|
* 将实体ID集合转换为实体引用数组。跳过无效的实体ID(已被删除的实体)。
|
||||||
|
*
|
||||||
|
* @param idSet 实体ID集合
|
||||||
|
* @param allEntities 所有实体的数组(用于构建映射表)
|
||||||
|
* @returns 实体引用数组
|
||||||
*/
|
*/
|
||||||
private idSetToEntityArray(idSet: Set<number>, allEntities: readonly Entity[]): readonly Entity[] {
|
private idSetToEntityArray(idSet: Set<number>, allEntities: readonly Entity[]): readonly Entity[] {
|
||||||
const entityMap = this.getEntityIdMap(allEntities);
|
const entityMap = this.getEntityIdMap(allEntities);
|
||||||
@@ -518,10 +542,12 @@ export abstract class EntitySystem<
|
|||||||
const entity = entityMap.get(id);
|
const entity = entityMap.get(id);
|
||||||
if (entity !== undefined) {
|
if (entity !== undefined) {
|
||||||
result[index] = entity;
|
result[index] = entity;
|
||||||
|
// 使用位运算 | 0 进行整数优化(JIT 友好)
|
||||||
index = (index + 1) | 0;
|
index = (index + 1) | 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果有无效ID,调整数组长度
|
||||||
if (index < size) {
|
if (index < size) {
|
||||||
result.length = index;
|
result.length = index;
|
||||||
}
|
}
|
||||||
@@ -673,7 +699,7 @@ export abstract class EntitySystem<
|
|||||||
public toString(): string {
|
public toString(): string {
|
||||||
const entityCount = this.entities.length;
|
const entityCount = this.entities.length;
|
||||||
const perfData = this.getPerformanceData();
|
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}`;
|
return `${this._systemName}[${entityCount} entities]${perfInfo}`;
|
||||||
}
|
}
|
||||||
@@ -803,7 +829,7 @@ export abstract class EntitySystem<
|
|||||||
handler: EventHandler<T>
|
handler: EventHandler<T>
|
||||||
): void {
|
): void {
|
||||||
const listenerIndex = this._eventListeners.findIndex(
|
const listenerIndex = this._eventListeners.findIndex(
|
||||||
listener => listener.eventType === eventType && listener.handler === handler
|
(listener) => listener.eventType === eventType && listener.handler === handler
|
||||||
);
|
);
|
||||||
|
|
||||||
if (listenerIndex >= 0) {
|
if (listenerIndex >= 0) {
|
||||||
@@ -891,7 +917,7 @@ export abstract class EntitySystem<
|
|||||||
entity: Entity,
|
entity: Entity,
|
||||||
componentType: T
|
componentType: T
|
||||||
): ComponentInstance<T> {
|
): ComponentInstance<T> {
|
||||||
const component = entity.getComponent(componentType as any);
|
const component = entity.getComponent(componentType as ComponentType);
|
||||||
if (!component) {
|
if (!component) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Component ${componentType.name} not found on entity ${entity.name} in ${this.systemName}`
|
`Component ${componentType.name} not found on entity ${entity.name} in ${this.systemName}`
|
||||||
@@ -929,7 +955,7 @@ export abstract class EntitySystem<
|
|||||||
): { [K in keyof T]: ComponentInstance<T[K]> } {
|
): { [K in keyof T]: ComponentInstance<T[K]> } {
|
||||||
return components.map((type) =>
|
return components.map((type) =>
|
||||||
this.requireComponent(entity, type)
|
this.requireComponent(entity, type)
|
||||||
) as any;
|
) as { [K in keyof T]: ComponentInstance<T[K]> };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { EntitySystem } from './EntitySystem';
|
import {EntitySystem} from "./EntitySystem";
|
||||||
import { Matcher } from '../Utils/Matcher';
|
import {Matcher} from "../Utils/Matcher";
|
||||||
import { Time } from '../../Utils/Time';
|
import {Time} from "../../Utils/Time";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 间隔系统抽象类
|
* 间隔系统抽象类
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { EntitySystem } from './EntitySystem';
|
import {EntitySystem} from "./EntitySystem";
|
||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
import { Matcher } from '../Utils/Matcher';
|
import {Matcher} from "../Utils/Matcher";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 被动实体系统
|
* 被动实体系统
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { EntitySystem } from './EntitySystem';
|
import {EntitySystem} from "./EntitySystem";
|
||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
import { Matcher } from '../Utils/Matcher';
|
import {Matcher} from "../Utils/Matcher";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理系统抽象类
|
* 处理系统抽象类
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
import { EntitySystem } from './EntitySystem';
|
import {EntitySystem} from "./EntitySystem";
|
||||||
import { Matcher } from '../Utils/Matcher';
|
import {Matcher} from "../Utils/Matcher";
|
||||||
import { Time } from '../../Utils/Time';
|
import {Time} from "../../Utils/Time";
|
||||||
import { PlatformManager } from '../../Platform/PlatformManager';
|
import {PlatformManager} from "../../Platform/PlatformManager";
|
||||||
import type { IPlatformAdapter, PlatformWorker } from '../../Platform/IPlatformAdapter';
|
import type {IPlatformAdapter, PlatformWorker} from "../../Platform/IPlatformAdapter";
|
||||||
import { getSystemInstanceTypeName } from '../Decorators';
|
import {getSystemInstanceTypeName} from "../Decorators";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Worker处理函数类型
|
* Worker处理函数类型
|
||||||
@@ -188,7 +188,7 @@ export type SharedArrayBufferProcessFunction = (
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem {
|
export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem {
|
||||||
protected config: Required<Omit<WorkerSystemConfig, 'systemConfig' | 'entitiesPerWorker'>> & {
|
protected config: Required<Omit<WorkerSystemConfig, "systemConfig" | "entitiesPerWorker">> & {
|
||||||
systemConfig?: any;
|
systemConfig?: any;
|
||||||
entitiesPerWorker?: number;
|
entitiesPerWorker?: number;
|
||||||
};
|
};
|
||||||
@@ -305,7 +305,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
// 在WorkerEntitySystem中处理平台相关逻辑
|
// 在WorkerEntitySystem中处理平台相关逻辑
|
||||||
const workers: PlatformWorker[] = [];
|
const workers: PlatformWorker[] = [];
|
||||||
const platformConfig = this.platformAdapter.getPlatformConfig();
|
const platformConfig = this.platformAdapter.getPlatformConfig();
|
||||||
const fullScript = (platformConfig.workerScriptPrefix || '') + script;
|
const fullScript = (platformConfig.workerScriptPrefix || "") + script;
|
||||||
|
|
||||||
for (let i = 0; i < this.config.workerCount; i++) {
|
for (let i = 0; i < this.config.workerCount; i++) {
|
||||||
try {
|
try {
|
||||||
@@ -336,7 +336,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
// 提取函数体部分(去掉方法签名)
|
// 提取函数体部分(去掉方法签名)
|
||||||
const functionBodyMatch = methodStr.match(/\{([\s\S]*)\}/);
|
const functionBodyMatch = methodStr.match(/\{([\s\S]*)\}/);
|
||||||
if (!functionBodyMatch) {
|
if (!functionBodyMatch) {
|
||||||
throw new Error('无法解析workerProcess方法');
|
throw new Error("无法解析workerProcess方法");
|
||||||
}
|
}
|
||||||
|
|
||||||
const functionBody = functionBodyMatch[1];
|
const functionBody = functionBodyMatch[1];
|
||||||
@@ -344,13 +344,13 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
|
|
||||||
// 获取SharedArrayBuffer处理函数的字符串
|
// 获取SharedArrayBuffer处理函数的字符串
|
||||||
const sharedProcessMethod = this.getSharedArrayBufferProcessFunction?.() || null;
|
const sharedProcessMethod = this.getSharedArrayBufferProcessFunction?.() || null;
|
||||||
let sharedProcessFunctionBody = '';
|
let sharedProcessFunctionBody = "";
|
||||||
|
|
||||||
if (sharedProcessMethod) {
|
if (sharedProcessMethod) {
|
||||||
const sharedMethodStr = sharedProcessMethod.toString();
|
const sharedMethodStr = sharedProcessMethod.toString();
|
||||||
const sharedFunctionBodyMatch = sharedMethodStr.match(/\{([\s\S]*)\}/);
|
const sharedFunctionBodyMatch = sharedMethodStr.match(/\{([\s\S]*)\}/);
|
||||||
if (sharedFunctionBodyMatch) {
|
if (sharedFunctionBodyMatch) {
|
||||||
sharedProcessFunctionBody = sharedFunctionBodyMatch[1] ?? '';
|
sharedProcessFunctionBody = sharedFunctionBodyMatch[1] ?? "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,7 +414,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
${sharedProcessFunctionBody}
|
${sharedProcessFunctionBody}
|
||||||
};
|
};
|
||||||
userProcessFunction(sharedFloatArray, startIndex, endIndex, deltaTime, systemConfig);
|
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> {
|
private async processWithSharedArrayBuffer(entities: readonly Entity[]): Promise<void> {
|
||||||
if (!this.sharedFloatArray) {
|
if (!this.sharedFloatArray) {
|
||||||
throw new Error('SharedArrayBuffer not initialized');
|
throw new Error("SharedArrayBuffer not initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 将实体数据写入SharedArrayBuffer
|
// 1. 将实体数据写入SharedArrayBuffer
|
||||||
@@ -494,7 +494,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
const deltaTime = Time.deltaTime;
|
const deltaTime = Time.deltaTime;
|
||||||
|
|
||||||
// 3. Worker执行阶段
|
// 3. Worker执行阶段
|
||||||
const promises = batches.map(batch =>
|
const promises = batches.map((batch) =>
|
||||||
this.workerPool!.execute({
|
this.workerPool!.execute({
|
||||||
entities: batch,
|
entities: batch,
|
||||||
deltaTime,
|
deltaTime,
|
||||||
@@ -525,7 +525,7 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
*/
|
*/
|
||||||
private processSynchronously(entities: readonly Entity[]): void {
|
private processSynchronously(entities: readonly Entity[]): void {
|
||||||
// 1. 数据提取阶段
|
// 1. 数据提取阶段
|
||||||
const entityData = entities.map(entity => this.extractEntityData(entity));
|
const entityData = entities.map((entity) => this.extractEntityData(entity));
|
||||||
|
|
||||||
// 2. 主线程处理阶段
|
// 2. 主线程处理阶段
|
||||||
const deltaTime = Time.deltaTime;
|
const deltaTime = Time.deltaTime;
|
||||||
@@ -533,8 +533,8 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
|
|
||||||
// 3. 结果应用阶段
|
// 3. 结果应用阶段
|
||||||
// 处理Promise返回值
|
// 处理Promise返回值
|
||||||
if (results && typeof (results as any).then === 'function') {
|
if (results && typeof (results as any).then === "function") {
|
||||||
(results as Promise<TEntityData[]>).then(finalResults => {
|
(results as Promise<TEntityData[]>).then((finalResults) => {
|
||||||
entities.forEach((entity, index) => {
|
entities.forEach((entity, index) => {
|
||||||
this.applyResult(entity, finalResults[index]!);
|
this.applyResult(entity, finalResults[index]!);
|
||||||
});
|
});
|
||||||
@@ -812,15 +812,15 @@ export abstract class WorkerEntitySystem<TEntityData = any> extends EntitySystem
|
|||||||
isProcessing: boolean;
|
isProcessing: boolean;
|
||||||
sharedArrayBufferSupported: boolean;
|
sharedArrayBufferSupported: boolean;
|
||||||
sharedArrayBufferEnabled: boolean;
|
sharedArrayBufferEnabled: boolean;
|
||||||
currentMode: 'shared-buffer' | 'worker' | 'sync';
|
currentMode: "shared-buffer" | "worker" | "sync";
|
||||||
} {
|
} {
|
||||||
let currentMode: 'shared-buffer' | 'worker' | 'sync' = 'sync';
|
let currentMode: "shared-buffer" | "worker" | "sync" = "sync";
|
||||||
|
|
||||||
if (this.config.enableWorker && this.workerPool) {
|
if (this.config.enableWorker && this.workerPool) {
|
||||||
if (this.config.useSharedArrayBuffer && this.sharedFloatArray && this.isSharedArrayBufferSupported()) {
|
if (this.config.useSharedArrayBuffer && this.sharedFloatArray && this.isSharedArrayBufferSupported()) {
|
||||||
currentMode = 'shared-buffer';
|
currentMode = "shared-buffer";
|
||||||
} else {
|
} else {
|
||||||
currentMode = 'worker';
|
currentMode = "worker";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -890,7 +890,7 @@ class PlatformWorkerPool {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const task = {
|
const task = {
|
||||||
id: `shared-task-${++this.taskCounter}`,
|
id: `shared-task-${++this.taskCounter}`,
|
||||||
data: { ...data, type: 'shared' },
|
data: {...data, type: "shared"},
|
||||||
resolve: () => resolve(), // SharedArrayBuffer不需要返回数据
|
resolve: () => resolve(), // SharedArrayBuffer不需要返回数据
|
||||||
reject
|
reject
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
// ECS系统导出
|
// ECS系统导出
|
||||||
export { EntitySystem } from './EntitySystem';
|
export {EntitySystem} from "./EntitySystem";
|
||||||
export { ProcessingSystem } from './ProcessingSystem';
|
export {ProcessingSystem} from "./ProcessingSystem";
|
||||||
export { PassiveSystem } from './PassiveSystem';
|
export {PassiveSystem} from "./PassiveSystem";
|
||||||
export { IntervalSystem } from './IntervalSystem';
|
export {IntervalSystem} from "./IntervalSystem";
|
||||||
export { WorkerEntitySystem } from './WorkerEntitySystem';
|
export {WorkerEntitySystem} from "./WorkerEntitySystem";
|
||||||
|
|
||||||
// Worker系统相关类型导出
|
// Worker系统相关类型导出
|
||||||
export type {
|
export type {
|
||||||
WorkerProcessFunction,
|
WorkerProcessFunction,
|
||||||
WorkerSystemConfig,
|
WorkerSystemConfig,
|
||||||
SharedArrayBufferProcessFunction
|
SharedArrayBufferProcessFunction
|
||||||
} from './WorkerEntitySystem';
|
} from "./WorkerEntitySystem";
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
* 提供类型安全的组件操作工具函数,无需修改Entity类
|
* 提供类型安全的组件操作工具函数,无需修改Entity类
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Entity } from './Entity';
|
import {Entity} from "./Entity";
|
||||||
import type { Component } from './Component';
|
import type {Component} from "./Component";
|
||||||
import type { ComponentType } from './Core/ComponentStorage';
|
import type {ComponentType} from "./Core/ComponentStorage";
|
||||||
import type { ComponentConstructor, ComponentInstance } from '../Types/TypeHelpers';
|
import type {ComponentConstructor, ComponentInstance} from "../Types/TypeHelpers";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取组件,如果不存在则抛出错误
|
* 获取组件,如果不存在则抛出错误
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export class BitMask64Utils {
|
|||||||
return maskSegments.some((seg, index) => {
|
return maskSegments.some((seg, index) => {
|
||||||
const bitsSeg = bitsSegments[index];
|
const bitsSeg = bitsSegments[index];
|
||||||
return bitsSeg && ((seg[SegmentPart.LOW] & bitsSeg[SegmentPart.LOW]) !== 0 || (seg[SegmentPart.HIGH] & bitsSeg[SegmentPart.HIGH]) !== 0);
|
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;
|
return baseIsZero;
|
||||||
}
|
}
|
||||||
// 额外检查扩展区域是否都为0
|
// 额外检查扩展区域是否都为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
|
* @returns 如果两个掩码完全相等则返回true
|
||||||
*/
|
*/
|
||||||
public static equals(a: BitMask64Data, b: BitMask64Data): boolean {
|
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比较结果
|
// base不相等,或ab都没有扩展区域位,直接返回base比较结果
|
||||||
if(!baseEquals || (!a.segments && !b.segments)) return baseEquals;
|
if(!baseEquals || (!a.segments && !b.segments)) return baseEquals;
|
||||||
// 不能假设a,b的segments都存在或长度相同.
|
// 不能假设a,b的segments都存在或长度相同.
|
||||||
@@ -355,7 +355,7 @@ export class BitMask64Utils {
|
|||||||
if(!source.segments || source.segments.length == 0) return;
|
if(!source.segments || source.segments.length == 0) return;
|
||||||
// 没有拓展段,则直接复制数组
|
// 没有拓展段,则直接复制数组
|
||||||
if(!target.segments){
|
if(!target.segments){
|
||||||
target.segments = source.segments.map(seg => [...seg]);
|
target.segments = source.segments.map((seg) => [...seg]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// source有扩展段,target扩展段不足,则补充长度
|
// source有扩展段,target扩展段不足,则补充长度
|
||||||
@@ -382,7 +382,7 @@ export class BitMask64Utils {
|
|||||||
public static clone(mask: BitMask64Data): BitMask64Data {
|
public static clone(mask: BitMask64Data): BitMask64Data {
|
||||||
return {
|
return {
|
||||||
base: mask.base.slice() as BitMask64Segment,
|
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 {
|
public static toString(mask: BitMask64Data, radix: 2 | 16 = 2, printHead: boolean = false): string {
|
||||||
if(radix != 2 && radix != 16) radix = 2;
|
if(radix != 2 && radix != 16) radix = 2;
|
||||||
const totalLength = mask.segments?.length ?? 0;
|
const totalLength = mask.segments?.length ?? 0;
|
||||||
let result: string = '';
|
let result: string = "";
|
||||||
if(printHead){
|
if(printHead){
|
||||||
let paddingLength = 0;
|
let paddingLength = 0;
|
||||||
if(radix === 2){
|
if(radix === 2){
|
||||||
@@ -405,38 +405,38 @@ export class BitMask64Utils {
|
|||||||
paddingLength = 16 + 2 + 1;
|
paddingLength = 16 + 2 + 1;
|
||||||
}
|
}
|
||||||
for (let i = 0; i <= totalLength; i++) {
|
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 += title.toString().padEnd(paddingLength);
|
||||||
}
|
}
|
||||||
result += '\n';
|
result += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = -1; i < totalLength; i++) {
|
for (let i = -1; i < totalLength; i++) {
|
||||||
let segResult = '';
|
let segResult = "";
|
||||||
const bitMaskData = i == -1 ? mask.base : mask.segments![i]!;
|
const bitMaskData = i == -1 ? mask.base : mask.segments![i]!;
|
||||||
let hi = bitMaskData[SegmentPart.HIGH];
|
const hi = bitMaskData[SegmentPart.HIGH];
|
||||||
let lo = bitMaskData[SegmentPart.LOW];
|
const lo = bitMaskData[SegmentPart.LOW];
|
||||||
if(radix == 2){
|
if(radix == 2){
|
||||||
const hiBits = hi.toString(2).padStart(32, '0');
|
const hiBits = hi.toString(2).padStart(32, "0");
|
||||||
const loBits = lo.toString(2).padStart(32, '0');
|
const loBits = lo.toString(2).padStart(32, "0");
|
||||||
segResult = hiBits + '_' + loBits; //高低位之间使用_隔离
|
segResult = hiBits + "_" + loBits; //高低位之间使用_隔离
|
||||||
}else{
|
}else{
|
||||||
let hiBits = hi ? hi.toString(16).toUpperCase() : '';
|
let hiBits = hi ? hi.toString(16).toUpperCase() : "";
|
||||||
if(printHead){
|
if(printHead){
|
||||||
// 存在标头,则输出高位之前需要补齐位数
|
// 存在标头,则输出高位之前需要补齐位数
|
||||||
hiBits = hiBits.padStart(8, '0');
|
hiBits = hiBits.padStart(8, "0");
|
||||||
}
|
}
|
||||||
let loBits = lo.toString(16).toUpperCase();
|
let loBits = lo.toString(16).toUpperCase();
|
||||||
if(hiBits){
|
if(hiBits){
|
||||||
// 存在高位 则输出低位之前需要补齐位数
|
// 存在高位 则输出低位之前需要补齐位数
|
||||||
loBits = loBits.padStart(8, '0');
|
loBits = loBits.padStart(8, "0");
|
||||||
}
|
}
|
||||||
segResult = '0x' + hiBits + loBits;
|
segResult = "0x" + hiBits + loBits;
|
||||||
}
|
}
|
||||||
if(i === -1)
|
if(i === -1)
|
||||||
result += segResult;
|
result += segResult;
|
||||||
else
|
else
|
||||||
result += ' ' + segResult; // 不同段之间使用空格隔离
|
result += " " + segResult; // 不同段之间使用空格隔离
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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对象、数字或字符串
|
* @param initialValue 初始值,可以是BitMask64Data对象、数字或字符串
|
||||||
*/
|
*/
|
||||||
constructor(initialValue?: BitMask64Data | number | string) {
|
constructor(initialValue?: BitMask64Data | number | string) {
|
||||||
if (initialValue && typeof initialValue === 'object') {
|
if (initialValue && typeof initialValue === "object") {
|
||||||
this._value = BitMask64Utils.clone(initialValue);
|
this._value = BitMask64Utils.clone(initialValue);
|
||||||
} else if (typeof initialValue === 'number') {
|
} else if (typeof initialValue === "number") {
|
||||||
this._value = BitMask64Utils.fromNumber(initialValue);
|
this._value = BitMask64Utils.fromNumber(initialValue);
|
||||||
} else if (typeof initialValue === 'string') {
|
} else if (typeof initialValue === "string") {
|
||||||
const num = parseInt(initialValue, 10);
|
const num = parseInt(initialValue, 10);
|
||||||
this._value = BitMask64Utils.fromNumber(num);
|
this._value = BitMask64Utils.fromNumber(num);
|
||||||
} else {
|
} else {
|
||||||
@@ -33,7 +33,7 @@ export class Bits {
|
|||||||
*/
|
*/
|
||||||
public set(index: number): void {
|
public set(index: number): void {
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
throw new Error('Bit index cannot be negative');
|
throw new Error("Bit index cannot be negative");
|
||||||
}
|
}
|
||||||
|
|
||||||
BitMask64Utils.setBit(this._value, index);
|
BitMask64Utils.setBit(this._value, index);
|
||||||
@@ -46,7 +46,7 @@ export class Bits {
|
|||||||
*/
|
*/
|
||||||
public clear(index: number): void {
|
public clear(index: number): void {
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
throw new Error('Bit index cannot be negative');
|
throw new Error("Bit index cannot be negative");
|
||||||
}
|
}
|
||||||
|
|
||||||
BitMask64Utils.clearBit(this._value, index);
|
BitMask64Utils.clearBit(this._value, index);
|
||||||
@@ -207,9 +207,9 @@ export class Bits {
|
|||||||
* @param value 新值,可以是BitMask64Data对象、数字或字符串
|
* @param value 新值,可以是BitMask64Data对象、数字或字符串
|
||||||
*/
|
*/
|
||||||
public setValue(value: BitMask64Data | number | string): void {
|
public setValue(value: BitMask64Data | number | string): void {
|
||||||
if (typeof value === 'object') {
|
if (typeof value === "object") {
|
||||||
BitMask64Utils.copy(value, this._value);
|
BitMask64Utils.copy(value, this._value);
|
||||||
} else if (typeof value === 'number') {
|
} else if (typeof value === "number") {
|
||||||
this._value = BitMask64Utils.fromNumber(value);
|
this._value = BitMask64Utils.fromNumber(value);
|
||||||
} else {
|
} else {
|
||||||
const num = parseInt(value, 10);
|
const num = parseInt(value, 10);
|
||||||
@@ -228,7 +228,7 @@ export class Bits {
|
|||||||
bits.push(i.toString());
|
bits.push(i.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return `Bits[${bits.join(', ')}]`;
|
return `Bits[${bits.join(", ")}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -240,11 +240,11 @@ export class Bits {
|
|||||||
if(maxBits == 0){
|
if(maxBits == 0){
|
||||||
maxBits = 64 + (this._value.segments ? this._value.segments.length * 64 : 0);
|
maxBits = 64 + (this._value.segments ? this._value.segments.length * 64 : 0);
|
||||||
}
|
}
|
||||||
let result = '';
|
let result = "";
|
||||||
for (let i = maxBits - 1; i >= 0; i--) {
|
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) {
|
if (i % 8 === 0 && i > 0) {
|
||||||
result += ' ';
|
result += " ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -264,7 +264,7 @@ export class Bits {
|
|||||||
* @returns 新的位集合对象
|
* @returns 新的位集合对象
|
||||||
*/
|
*/
|
||||||
public static fromBinaryString(binaryString: string): Bits {
|
public static fromBinaryString(binaryString: string): Bits {
|
||||||
const cleanString = binaryString.replace(/\s/g, '');
|
const cleanString = binaryString.replace(/\s/g, "");
|
||||||
let data: BitMask64Data;
|
let data: BitMask64Data;
|
||||||
if (cleanString.length <= 32) {
|
if (cleanString.length <= 32) {
|
||||||
const num = parseInt(cleanString, 2);
|
const num = parseInt(cleanString, 2);
|
||||||
@@ -285,7 +285,7 @@ export class Bits {
|
|||||||
* @returns 新的位集合对象
|
* @returns 新的位集合对象
|
||||||
*/
|
*/
|
||||||
public static fromHexString(hexString: string): Bits {
|
public static fromHexString(hexString: string): Bits {
|
||||||
const cleanString = hexString.replace(/^0x/i, '');
|
const cleanString = hexString.replace(/^0x/i, "");
|
||||||
let data: BitMask64Data;
|
let data: BitMask64Data;
|
||||||
if (cleanString.length <= 8) {
|
if (cleanString.length <= 8) {
|
||||||
const num = parseInt(cleanString, 16);
|
const num = parseInt(cleanString, 16);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
import { ComponentType, ComponentRegistry } from '../Core/ComponentStorage';
|
import {ComponentType, ComponentRegistry} from "../Core/ComponentStorage";
|
||||||
import { BitMask64Utils, BitMask64Data } from './BigIntCompatibility';
|
import {BitMask64Utils, BitMask64Data} from "./BigIntCompatibility";
|
||||||
import { SparseSet } from './SparseSet';
|
import {SparseSet} from "./SparseSet";
|
||||||
import { Pool } from '../../Utils/Pool/Pool';
|
import {Pool} from "../../Utils/Pool/Pool";
|
||||||
import { IPoolable } from '../../Utils/Pool/IPoolable';
|
import {IPoolable} from "../../Utils/Pool/IPoolable";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 可池化的实体集合
|
* 可池化的实体集合
|
||||||
@@ -77,7 +77,7 @@ export class ComponentSparseSet {
|
|||||||
this.removeEntity(entity);
|
this.removeEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
let componentMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const componentMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
const entityComponents = new Set<ComponentType>();
|
const entityComponents = new Set<ComponentType>();
|
||||||
|
|
||||||
// 分析实体组件并构建位掩码
|
// 分析实体组件并构建位掩码
|
||||||
@@ -169,7 +169,7 @@ export class ComponentSparseSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 构建目标位掩码
|
// 构建目标位掩码
|
||||||
let targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
for (const componentType of componentTypes) {
|
for (const componentType of componentTypes) {
|
||||||
if (!ComponentRegistry.isRegistered(componentType)) {
|
if (!ComponentRegistry.isRegistered(componentType)) {
|
||||||
return new Set<Entity>(); // 未注册的组件类型,结果为空
|
return new Set<Entity>(); // 未注册的组件类型,结果为空
|
||||||
@@ -209,7 +209,7 @@ export class ComponentSparseSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 构建目标位掩码
|
// 构建目标位掩码
|
||||||
let targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
const targetMask = BitMask64Utils.clone(BitMask64Utils.ZERO);
|
||||||
for (const componentType of componentTypes) {
|
for (const componentType of componentTypes) {
|
||||||
if (ComponentRegistry.isRegistered(componentType)) {
|
if (ComponentRegistry.isRegistered(componentType)) {
|
||||||
const bitMask = ComponentRegistry.getBitMask(componentType);
|
const bitMask = ComponentRegistry.getBitMask(componentType);
|
||||||
@@ -272,14 +272,26 @@ export class ComponentSparseSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有实体
|
* 查询所有实体
|
||||||
|
*
|
||||||
|
* 返回拥有此组件的所有实体。
|
||||||
*
|
*
|
||||||
* @returns 所有实体的数组
|
* @returns 所有实体的数组
|
||||||
*/
|
*/
|
||||||
public getAllEntities(): Entity[] {
|
public queryAllEntities(): Entity[] {
|
||||||
return this._entities.toArray();
|
return this._entities.toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有实体
|
||||||
|
*
|
||||||
|
* @deprecated 使用 queryAllEntities() 代替,以保持命名一致性
|
||||||
|
* @see {@link queryAllEntities}
|
||||||
|
*/
|
||||||
|
public getAllEntities(): Entity[] {
|
||||||
|
return this.queryAllEntities();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取实体数量
|
* 获取实体数量
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Entity } from '../Entity';
|
import {Entity} from "../Entity";
|
||||||
import { Component } from '../Component';
|
import {Component} from "../Component";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 高性能实体列表管理器
|
* 高性能实体列表管理器
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { EntitySystem } from '../Systems/EntitySystem';
|
import {EntitySystem} from "../Systems/EntitySystem";
|
||||||
import { createLogger } from '../../Utils/Logger';
|
import {createLogger} from "../../Utils/Logger";
|
||||||
import { getSystemInstanceTypeName } from '../Decorators';
|
import {getSystemInstanceTypeName} from "../Decorators";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实体处理器列表管理器
|
* 实体处理器列表管理器
|
||||||
* 管理场景中的所有实体系统
|
* 管理场景中的所有实体系统
|
||||||
*/
|
*/
|
||||||
export class EntityProcessorList {
|
export class EntityProcessorList {
|
||||||
private static readonly _logger = createLogger('EntityProcessorList');
|
private static readonly _logger = createLogger("EntityProcessorList");
|
||||||
private _processors: EntitySystem[] = [];
|
private _processors: EntitySystem[] = [];
|
||||||
private _isDirty = false;
|
private _isDirty = false;
|
||||||
|
|
||||||
|
|||||||
@@ -117,8 +117,8 @@ export class IdentifierPool {
|
|||||||
if (this._nextAvailableIndex > IdentifierPool.MAX_INDEX) {
|
if (this._nextAvailableIndex > IdentifierPool.MAX_INDEX) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`实体索引已达到框架设计限制 (${IdentifierPool.MAX_INDEX})。` +
|
`实体索引已达到框架设计限制 (${IdentifierPool.MAX_INDEX})。` +
|
||||||
`这意味着您已经分配了超过65535个不同的实体索引。` +
|
"这意味着您已经分配了超过65535个不同的实体索引。" +
|
||||||
`这是16位索引设计的限制,考虑优化实体回收策略或升级到64位ID设计。`
|
"这是16位索引设计的限制,考虑优化实体回收策略或升级到64位ID设计。"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ export class IdentifierPool {
|
|||||||
|
|
||||||
// 检查是否已经在待回收队列中
|
// 检查是否已经在待回收队列中
|
||||||
const alreadyPending = this._pendingRecycle.some(
|
const alreadyPending = this._pendingRecycle.some(
|
||||||
item => item.index === index && item.generation === generation
|
(item) => item.index === index && item.generation === generation
|
||||||
);
|
);
|
||||||
|
|
||||||
if (alreadyPending) {
|
if (alreadyPending) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ComponentType } from '../Core/ComponentStorage';
|
import {ComponentType} from "../Core/ComponentStorage";
|
||||||
import { getComponentTypeName } from '../Decorators';
|
import {getComponentTypeName} from "../Decorators";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询条件类型
|
* 查询条件类型
|
||||||
@@ -267,15 +267,15 @@ export class Matcher {
|
|||||||
const parts: string[] = [];
|
const parts: string[] = [];
|
||||||
|
|
||||||
if (this.condition.all.length > 0) {
|
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) {
|
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) {
|
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) {
|
if (this.condition.tag !== undefined) {
|
||||||
@@ -290,7 +290,7 @@ export class Matcher {
|
|||||||
parts.push(`component(${getComponentTypeName(this.condition.component)})`);
|
parts.push(`component(${getComponentTypeName(this.condition.component)})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return `Matcher[${parts.join(' & ')}]`;
|
return `Matcher[${parts.join(" & ")}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
// ECS工具类导出
|
// ECS工具类导出
|
||||||
export { EntityList } from './EntityList';
|
export {EntityList} from "./EntityList";
|
||||||
export { EntityProcessorList } from './EntityProcessorList';
|
export {EntityProcessorList} from "./EntityProcessorList";
|
||||||
export { IdentifierPool } from './IdentifierPool';
|
export {IdentifierPool} from "./IdentifierPool";
|
||||||
export { Matcher } from './Matcher';
|
export {Matcher} from "./Matcher";
|
||||||
export { Bits } from './Bits';
|
export {Bits} from "./Bits";
|
||||||
export { BitMask64Utils, BitMask64Data } from './BigIntCompatibility';
|
export {BitMask64Utils, BitMask64Data} from "./BigIntCompatibility";
|
||||||
export { SparseSet } from './SparseSet';
|
export {SparseSet} from "./SparseSet";
|
||||||
export { ComponentSparseSet } from './ComponentSparseSet';
|
export {ComponentSparseSet} from "./ComponentSparseSet";
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { IScene } from './IScene';
|
import {IScene} from "./IScene";
|
||||||
import { Scene } from './Scene';
|
import {Scene} from "./Scene";
|
||||||
import { createLogger } from '../Utils/Logger';
|
import {createLogger} from "../Utils/Logger";
|
||||||
|
|
||||||
const logger = createLogger('World');
|
const logger = createLogger("World");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局系统接口
|
* 全局系统接口
|
||||||
@@ -93,7 +93,7 @@ export class World {
|
|||||||
|
|
||||||
constructor(config: IWorldConfig = {}) {
|
constructor(config: IWorldConfig = {}) {
|
||||||
this._config = {
|
this._config = {
|
||||||
name: 'World',
|
name: "World",
|
||||||
debug: false,
|
debug: false,
|
||||||
maxScenes: 10,
|
maxScenes: 10,
|
||||||
autoCleanup: true,
|
autoCleanup: true,
|
||||||
@@ -122,10 +122,10 @@ export class World {
|
|||||||
const scene = sceneInstance || (new Scene() as unknown as T);
|
const scene = sceneInstance || (new Scene() as unknown as T);
|
||||||
|
|
||||||
// 设置Scene的标识
|
// 设置Scene的标识
|
||||||
if ('id' in scene) {
|
if ("id" in scene) {
|
||||||
(scene as any).id = sceneId;
|
(scene as any).id = sceneId;
|
||||||
}
|
}
|
||||||
if ('name' in scene && !scene.name) {
|
if ("name" in scene && !scene.name) {
|
||||||
scene.name = sceneId;
|
scene.name = sceneId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +408,7 @@ export class World {
|
|||||||
globalSystemCount: this._globalSystems.length,
|
globalSystemCount: this._globalSystems.length,
|
||||||
createdAt: this._createdAt,
|
createdAt: this._createdAt,
|
||||||
config: {...this._config},
|
config: {...this._config},
|
||||||
scenes: Array.from(this._scenes.keys()).map(sceneId => ({
|
scenes: Array.from(this._scenes.keys()).map((sceneId) => ({
|
||||||
id: sceneId,
|
id: sceneId,
|
||||||
isActive: this._activeScenes.has(sceneId),
|
isActive: this._activeScenes.has(sceneId),
|
||||||
name: this._scenes.get(sceneId)?.name || sceneId
|
name: this._scenes.get(sceneId)?.name || sceneId
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { World, IWorldConfig } from './World';
|
import {World, IWorldConfig} from "./World";
|
||||||
import { createLogger } from '../Utils/Logger';
|
import {createLogger} from "../Utils/Logger";
|
||||||
import type { IService } from '../Core/ServiceContainer';
|
import type {IService} from "../Core/ServiceContainer";
|
||||||
|
|
||||||
const logger = createLogger('WorldManager');
|
const logger = createLogger("WorldManager");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WorldManager配置接口
|
* WorldManager配置接口
|
||||||
@@ -81,7 +81,7 @@ export class WorldManager implements IService {
|
|||||||
// 默认启动运行状态
|
// 默认启动运行状态
|
||||||
this._isRunning = true;
|
this._isRunning = true;
|
||||||
|
|
||||||
logger.info('WorldManager已初始化', {
|
logger.info("WorldManager已初始化", {
|
||||||
maxWorlds: this._config.maxWorlds,
|
maxWorlds: this._config.maxWorlds,
|
||||||
autoCleanup: this._config.autoCleanup,
|
autoCleanup: this._config.autoCleanup,
|
||||||
cleanupInterval: this._config.cleanupInterval
|
cleanupInterval: this._config.cleanupInterval
|
||||||
@@ -96,8 +96,8 @@ export class WorldManager implements IService {
|
|||||||
* 创建新World
|
* 创建新World
|
||||||
*/
|
*/
|
||||||
public createWorld(worldId: string, config?: IWorldConfig): World {
|
public createWorld(worldId: string, config?: IWorldConfig): World {
|
||||||
if (!worldId || typeof worldId !== 'string' || worldId.trim() === '') {
|
if (!worldId || typeof worldId !== "string" || worldId.trim() === "") {
|
||||||
throw new Error('World ID不能为空');
|
throw new Error("World ID不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._worlds.has(worldId)) {
|
if (this._worlds.has(worldId)) {
|
||||||
@@ -247,7 +247,7 @@ export class WorldManager implements IService {
|
|||||||
this.setWorldActive(worldId, true);
|
this.setWorldActive(worldId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info('启动所有World');
|
logger.info("启动所有World");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -260,7 +260,7 @@ export class WorldManager implements IService {
|
|||||||
this.setWorldActive(worldId, false);
|
this.setWorldActive(worldId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info('停止所有World');
|
logger.info("停止所有World");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -367,7 +367,7 @@ export class WorldManager implements IService {
|
|||||||
* 销毁WorldManager
|
* 销毁WorldManager
|
||||||
*/
|
*/
|
||||||
public destroy(): void {
|
public destroy(): void {
|
||||||
logger.info('正在销毁WorldManager...');
|
logger.info("正在销毁WorldManager...");
|
||||||
|
|
||||||
// 停止清理定时器
|
// 停止清理定时器
|
||||||
this.stopCleanupTimer();
|
this.stopCleanupTimer();
|
||||||
@@ -385,7 +385,7 @@ export class WorldManager implements IService {
|
|||||||
this._activeWorlds.clear();
|
this._activeWorlds.clear();
|
||||||
this._isRunning = false;
|
this._isRunning = false;
|
||||||
|
|
||||||
logger.info('WorldManager已销毁');
|
logger.info("WorldManager已销毁");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -420,7 +420,7 @@ export class WorldManager implements IService {
|
|||||||
if (this._cleanupTimer) {
|
if (this._cleanupTimer) {
|
||||||
clearInterval(this._cleanupTimer);
|
clearInterval(this._cleanupTimer);
|
||||||
this._cleanupTimer = null;
|
this._cleanupTimer = null;
|
||||||
logger.debug('停止World清理定时器');
|
logger.debug("停止World清理定时器");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,7 +444,7 @@ export class WorldManager implements IService {
|
|||||||
|
|
||||||
// 检查是否所有Scene都是空的
|
// 检查是否所有Scene都是空的
|
||||||
const allScenes = world.getAllScenes();
|
const allScenes = world.getAllScenes();
|
||||||
const hasEntities = allScenes.some(scene =>
|
const hasEntities = allScenes.some((scene) =>
|
||||||
scene.entities && scene.entities.count > 0
|
scene.entities && scene.entities.count > 0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
export { Entity } from './Entity';
|
export {Entity} from "./Entity";
|
||||||
export { Component } from './Component';
|
export {Component} from "./Component";
|
||||||
export { ECSEventType, EventPriority, EVENT_TYPES, EventTypeValidator } from './CoreEvents';
|
export {ECSEventType, EventPriority, EVENT_TYPES, EventTypeValidator} from "./CoreEvents";
|
||||||
export * from './Systems';
|
export * from "./Systems";
|
||||||
export * from './Utils';
|
export * from "./Utils";
|
||||||
export * from './Decorators';
|
export * from "./Decorators";
|
||||||
export { Scene } from './Scene';
|
export {Scene} from "./Scene";
|
||||||
export { IScene, ISceneFactory, ISceneConfig } from './IScene';
|
export {IScene, ISceneFactory, ISceneConfig} from "./IScene";
|
||||||
export { SceneManager } from './SceneManager';
|
export {SceneManager} from "./SceneManager";
|
||||||
export { World, IWorldConfig } from './World';
|
export {World, IWorldConfig} from "./World";
|
||||||
export { WorldManager, IWorldManagerConfig } from './WorldManager';
|
export {WorldManager, IWorldManagerConfig} from "./WorldManager";
|
||||||
export * from './Core/Events';
|
export * from "./Core/Events";
|
||||||
export * from './Core/Query';
|
export * from "./Core/Query";
|
||||||
export * from './Core/Storage';
|
export * from "./Core/Storage";
|
||||||
export * from './Core/StorageDecorators';
|
export * from "./Core/StorageDecorators";
|
||||||
export * from './Serialization';
|
export * from "./Serialization";
|
||||||
export { ReferenceTracker, getSceneByEntityId } from './Core/ReferenceTracker';
|
export {ReferenceTracker, getSceneByEntityId} from "./Core/ReferenceTracker";
|
||||||
export type { EntityRefRecord } from './Core/ReferenceTracker';
|
export type {EntityRefRecord} from "./Core/ReferenceTracker";
|
||||||
export { ReactiveQuery, ReactiveQueryChangeType } from './Core/ReactiveQuery';
|
export {ReactiveQuery, ReactiveQueryChangeType} from "./Core/ReactiveQuery";
|
||||||
export type { ReactiveQueryChange, ReactiveQueryListener, ReactiveQueryConfig } from './Core/ReactiveQuery';
|
export type {ReactiveQueryChange, ReactiveQueryListener, ReactiveQueryConfig} from "./Core/ReactiveQuery";
|
||||||
|
|||||||
@@ -64,12 +64,12 @@ export interface WorkerCreationOptions {
|
|||||||
/**
|
/**
|
||||||
* Worker类型
|
* Worker类型
|
||||||
*/
|
*/
|
||||||
type?: 'classic' | 'module';
|
type?: "classic" | "module";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 凭据模式
|
* 凭据模式
|
||||||
*/
|
*/
|
||||||
credentials?: 'omit' | 'same-origin' | 'include';
|
credentials?: "omit" | "same-origin" | "include";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Worker名称(用于调试)
|
* Worker名称(用于调试)
|
||||||
@@ -104,7 +104,7 @@ export interface PlatformWorker {
|
|||||||
/**
|
/**
|
||||||
* Worker状态
|
* 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";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否确定检测结果
|
* 是否确定检测结果
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { PlatformDetectionResult } from './IPlatformAdapter';
|
import type {PlatformDetectionResult} from "./IPlatformAdapter";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 平台检测器
|
* 平台检测器
|
||||||
@@ -10,89 +10,89 @@ export class PlatformDetector {
|
|||||||
*/
|
*/
|
||||||
public static detect(): PlatformDetectionResult {
|
public static detect(): PlatformDetectionResult {
|
||||||
const features: string[] = [];
|
const features: string[] = [];
|
||||||
let platform: PlatformDetectionResult['platform'] = 'unknown';
|
let platform: PlatformDetectionResult["platform"] = "unknown";
|
||||||
let confident = false;
|
let confident = false;
|
||||||
let adapterClass: string | undefined;
|
let adapterClass: string | undefined;
|
||||||
|
|
||||||
// 检查全局对象和API
|
// 检查全局对象和API
|
||||||
if (typeof globalThis !== 'undefined') {
|
if (typeof globalThis !== "undefined") {
|
||||||
features.push('globalThis');
|
features.push("globalThis");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== "undefined") {
|
||||||
features.push('window');
|
features.push("window");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof self !== 'undefined') {
|
if (typeof self !== "undefined") {
|
||||||
features.push('self');
|
features.push("self");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测Node.js环境(优先级最高,因为Node.js可能包含全局对象模拟)
|
// 检测Node.js环境(优先级最高,因为Node.js可能包含全局对象模拟)
|
||||||
if (this.isNodeJS()) {
|
if (this.isNodeJS()) {
|
||||||
platform = 'nodejs';
|
platform = "nodejs";
|
||||||
confident = true;
|
confident = true;
|
||||||
adapterClass = 'NodeAdapter';
|
adapterClass = "NodeAdapter";
|
||||||
features.push('nodejs', 'process', 'require');
|
features.push("nodejs", "process", "require");
|
||||||
}
|
}
|
||||||
// 检测微信小游戏环境
|
// 检测微信小游戏环境
|
||||||
else if (this.isWeChatMiniGame()) {
|
else if (this.isWeChatMiniGame()) {
|
||||||
platform = 'wechat-minigame';
|
platform = "wechat-minigame";
|
||||||
confident = true;
|
confident = true;
|
||||||
adapterClass = 'WeChatMiniGameAdapter';
|
adapterClass = "WeChatMiniGameAdapter";
|
||||||
features.push('wx', 'wechat-minigame');
|
features.push("wx", "wechat-minigame");
|
||||||
}
|
}
|
||||||
// 检测字节跳动小游戏环境
|
// 检测字节跳动小游戏环境
|
||||||
else if (this.isByteDanceMiniGame()) {
|
else if (this.isByteDanceMiniGame()) {
|
||||||
platform = 'bytedance-minigame';
|
platform = "bytedance-minigame";
|
||||||
confident = true;
|
confident = true;
|
||||||
adapterClass = 'ByteDanceMiniGameAdapter';
|
adapterClass = "ByteDanceMiniGameAdapter";
|
||||||
features.push('tt', 'bytedance-minigame');
|
features.push("tt", "bytedance-minigame");
|
||||||
}
|
}
|
||||||
// 检测支付宝小游戏环境
|
// 检测支付宝小游戏环境
|
||||||
else if (this.isAlipayMiniGame()) {
|
else if (this.isAlipayMiniGame()) {
|
||||||
platform = 'alipay-minigame';
|
platform = "alipay-minigame";
|
||||||
confident = true;
|
confident = true;
|
||||||
adapterClass = 'AlipayMiniGameAdapter';
|
adapterClass = "AlipayMiniGameAdapter";
|
||||||
features.push('my', 'alipay-minigame');
|
features.push("my", "alipay-minigame");
|
||||||
}
|
}
|
||||||
// 检测百度小游戏环境
|
// 检测百度小游戏环境
|
||||||
else if (this.isBaiduMiniGame()) {
|
else if (this.isBaiduMiniGame()) {
|
||||||
platform = 'baidu-minigame';
|
platform = "baidu-minigame";
|
||||||
confident = true;
|
confident = true;
|
||||||
adapterClass = 'BaiduMiniGameAdapter';
|
adapterClass = "BaiduMiniGameAdapter";
|
||||||
features.push('swan', 'baidu-minigame');
|
features.push("swan", "baidu-minigame");
|
||||||
}
|
}
|
||||||
// 检测浏览器环境
|
// 检测浏览器环境
|
||||||
else if (this.isBrowser()) {
|
else if (this.isBrowser()) {
|
||||||
platform = 'browser';
|
platform = "browser";
|
||||||
confident = true;
|
confident = true;
|
||||||
adapterClass = 'BrowserAdapter';
|
adapterClass = "BrowserAdapter";
|
||||||
features.push('browser');
|
features.push("browser");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加功能检测特征
|
// 添加功能检测特征
|
||||||
if (typeof Worker !== 'undefined') {
|
if (typeof Worker !== "undefined") {
|
||||||
features.push('Worker');
|
features.push("Worker");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof SharedArrayBuffer !== 'undefined') {
|
if (typeof SharedArrayBuffer !== "undefined") {
|
||||||
features.push('SharedArrayBuffer');
|
features.push("SharedArrayBuffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof navigator !== 'undefined' && navigator.hardwareConcurrency) {
|
if (typeof navigator !== "undefined" && navigator.hardwareConcurrency) {
|
||||||
features.push('hardwareConcurrency');
|
features.push("hardwareConcurrency");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof performance !== 'undefined' && typeof performance.now === 'function') {
|
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
||||||
features.push('performance.now');
|
features.push("performance.now");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof Blob !== 'undefined') {
|
if (typeof Blob !== "undefined") {
|
||||||
features.push('Blob');
|
features.push("Blob");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function') {
|
if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
|
||||||
features.push('URL.createObjectURL');
|
features.push("URL.createObjectURL");
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -108,7 +108,7 @@ export class PlatformDetector {
|
|||||||
*/
|
*/
|
||||||
private static isWeChatMiniGame(): boolean {
|
private static isWeChatMiniGame(): boolean {
|
||||||
// 检查wx全局对象
|
// 检查wx全局对象
|
||||||
if (typeof (globalThis as any).wx !== 'undefined') {
|
if (typeof (globalThis as any).wx !== "undefined") {
|
||||||
const wx = (globalThis as any).wx;
|
const wx = (globalThis as any).wx;
|
||||||
// 检查微信小游戏特有的API
|
// 检查微信小游戏特有的API
|
||||||
return !!(wx.getSystemInfo && wx.createCanvas && wx.createImage);
|
return !!(wx.getSystemInfo && wx.createCanvas && wx.createImage);
|
||||||
@@ -121,7 +121,7 @@ export class PlatformDetector {
|
|||||||
*/
|
*/
|
||||||
private static isByteDanceMiniGame(): boolean {
|
private static isByteDanceMiniGame(): boolean {
|
||||||
// 检查tt全局对象
|
// 检查tt全局对象
|
||||||
if (typeof (globalThis as any).tt !== 'undefined') {
|
if (typeof (globalThis as any).tt !== "undefined") {
|
||||||
const tt = (globalThis as any).tt;
|
const tt = (globalThis as any).tt;
|
||||||
// 检查字节跳动小游戏特有的API
|
// 检查字节跳动小游戏特有的API
|
||||||
return !!(tt.getSystemInfo && tt.createCanvas && tt.createImage);
|
return !!(tt.getSystemInfo && tt.createCanvas && tt.createImage);
|
||||||
@@ -136,15 +136,15 @@ export class PlatformDetector {
|
|||||||
try {
|
try {
|
||||||
// 检查Node.js特有的全局对象和模块
|
// 检查Node.js特有的全局对象和模块
|
||||||
return !!(
|
return !!(
|
||||||
typeof process !== 'undefined' &&
|
typeof process !== "undefined" &&
|
||||||
process.versions &&
|
process.versions &&
|
||||||
process.versions.node &&
|
process.versions.node &&
|
||||||
typeof require !== 'undefined' &&
|
typeof require !== "undefined" &&
|
||||||
typeof module !== 'undefined' &&
|
typeof module !== "undefined" &&
|
||||||
typeof exports !== 'undefined' &&
|
typeof exports !== "undefined" &&
|
||||||
// 确保不是在浏览器环境中的Node.js模拟
|
// 确保不是在浏览器环境中的Node.js模拟
|
||||||
typeof window === 'undefined' &&
|
typeof window === "undefined" &&
|
||||||
typeof document === 'undefined'
|
typeof document === "undefined"
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
@@ -156,7 +156,7 @@ export class PlatformDetector {
|
|||||||
*/
|
*/
|
||||||
private static isAlipayMiniGame(): boolean {
|
private static isAlipayMiniGame(): boolean {
|
||||||
// 检查my全局对象
|
// 检查my全局对象
|
||||||
if (typeof (globalThis as any).my !== 'undefined') {
|
if (typeof (globalThis as any).my !== "undefined") {
|
||||||
const my = (globalThis as any).my;
|
const my = (globalThis as any).my;
|
||||||
// 检查支付宝小游戏特有的API
|
// 检查支付宝小游戏特有的API
|
||||||
return !!(my.getSystemInfo && my.createCanvas);
|
return !!(my.getSystemInfo && my.createCanvas);
|
||||||
@@ -169,7 +169,7 @@ export class PlatformDetector {
|
|||||||
*/
|
*/
|
||||||
private static isBaiduMiniGame(): boolean {
|
private static isBaiduMiniGame(): boolean {
|
||||||
// 检查swan全局对象
|
// 检查swan全局对象
|
||||||
if (typeof (globalThis as any).swan !== 'undefined') {
|
if (typeof (globalThis as any).swan !== "undefined") {
|
||||||
const swan = (globalThis as any).swan;
|
const swan = (globalThis as any).swan;
|
||||||
// 检查百度小游戏特有的API
|
// 检查百度小游戏特有的API
|
||||||
return !!(swan.getSystemInfo && swan.createCanvas);
|
return !!(swan.getSystemInfo && swan.createCanvas);
|
||||||
@@ -182,9 +182,9 @@ export class PlatformDetector {
|
|||||||
*/
|
*/
|
||||||
private static isBrowser(): boolean {
|
private static isBrowser(): boolean {
|
||||||
// 检查浏览器特有的对象和API
|
// 检查浏览器特有的对象和API
|
||||||
return typeof window !== 'undefined' &&
|
return typeof window !== "undefined" &&
|
||||||
typeof document !== 'undefined' &&
|
typeof document !== "undefined" &&
|
||||||
typeof navigator !== 'undefined' &&
|
typeof navigator !== "undefined" &&
|
||||||
window.location !== undefined;
|
window.location !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,42 +195,42 @@ export class PlatformDetector {
|
|||||||
const info: Record<string, any> = {};
|
const info: Record<string, any> = {};
|
||||||
|
|
||||||
// 基础检测
|
// 基础检测
|
||||||
info['userAgent'] = typeof navigator !== 'undefined' ? navigator.userAgent : 'unknown';
|
info["userAgent"] = typeof navigator !== "undefined" ? navigator.userAgent : "unknown";
|
||||||
info['platform'] = typeof navigator !== 'undefined' ? navigator.platform : 'unknown';
|
info["platform"] = typeof navigator !== "undefined" ? navigator.platform : "unknown";
|
||||||
|
|
||||||
// 全局对象检测
|
// 全局对象检测
|
||||||
info['globalObjects'] = {
|
info["globalObjects"] = {
|
||||||
window: typeof window !== 'undefined',
|
window: typeof window !== "undefined",
|
||||||
document: typeof document !== 'undefined',
|
document: typeof document !== "undefined",
|
||||||
navigator: typeof navigator !== 'undefined',
|
navigator: typeof navigator !== "undefined",
|
||||||
wx: typeof (globalThis as any).wx !== 'undefined',
|
wx: typeof (globalThis as any).wx !== "undefined",
|
||||||
tt: typeof (globalThis as any).tt !== 'undefined',
|
tt: typeof (globalThis as any).tt !== "undefined",
|
||||||
my: typeof (globalThis as any).my !== 'undefined',
|
my: typeof (globalThis as any).my !== "undefined",
|
||||||
swan: typeof (globalThis as any).swan !== 'undefined'
|
swan: typeof (globalThis as any).swan !== "undefined"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Worker相关检测
|
// Worker相关检测
|
||||||
info['workerSupport'] = {
|
info["workerSupport"] = {
|
||||||
Worker: typeof Worker !== 'undefined',
|
Worker: typeof Worker !== "undefined",
|
||||||
SharedWorker: typeof SharedWorker !== 'undefined',
|
SharedWorker: typeof SharedWorker !== "undefined",
|
||||||
ServiceWorker: typeof navigator !== 'undefined' && 'serviceWorker' in navigator,
|
ServiceWorker: typeof navigator !== "undefined" && "serviceWorker" in navigator,
|
||||||
SharedArrayBuffer: typeof SharedArrayBuffer !== 'undefined',
|
SharedArrayBuffer: typeof SharedArrayBuffer !== "undefined",
|
||||||
crossOriginIsolated: typeof self !== 'undefined' ? self.crossOriginIsolated : false
|
crossOriginIsolated: typeof self !== "undefined" ? self.crossOriginIsolated : false
|
||||||
};
|
};
|
||||||
|
|
||||||
// 性能相关检测
|
// 性能相关检测
|
||||||
info['performance'] = {
|
info["performance"] = {
|
||||||
performanceNow: typeof performance !== 'undefined' && typeof performance.now === 'function',
|
performanceNow: typeof performance !== "undefined" && typeof performance.now === "function",
|
||||||
hardwareConcurrency: typeof navigator !== 'undefined' ? navigator.hardwareConcurrency : undefined
|
hardwareConcurrency: typeof navigator !== "undefined" ? navigator.hardwareConcurrency : undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
// 其他API检测
|
// 其他API检测
|
||||||
info['apiSupport'] = {
|
info["apiSupport"] = {
|
||||||
Blob: typeof Blob !== 'undefined',
|
Blob: typeof Blob !== "undefined",
|
||||||
URL: typeof URL !== 'undefined',
|
URL: typeof URL !== "undefined",
|
||||||
createObjectURL: typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function',
|
createObjectURL: typeof URL !== "undefined" && typeof URL.createObjectURL === "function",
|
||||||
ArrayBuffer: typeof ArrayBuffer !== 'undefined',
|
ArrayBuffer: typeof ArrayBuffer !== "undefined",
|
||||||
TypedArrays: typeof Float32Array !== 'undefined'
|
TypedArrays: typeof Float32Array !== "undefined"
|
||||||
};
|
};
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { IPlatformAdapter } from './IPlatformAdapter';
|
import type {IPlatformAdapter} from "./IPlatformAdapter";
|
||||||
import { createLogger, type ILogger } from '../Utils/Logger';
|
import {createLogger, type ILogger} from "../Utils/Logger";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 平台管理器
|
* 平台管理器
|
||||||
@@ -11,7 +11,7 @@ export class PlatformManager {
|
|||||||
private readonly logger: ILogger;
|
private readonly logger: ILogger;
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
this.logger = createLogger('PlatformManager');
|
this.logger = createLogger("PlatformManager");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,7 +29,7 @@ export class PlatformManager {
|
|||||||
*/
|
*/
|
||||||
public getAdapter(): IPlatformAdapter {
|
public getAdapter(): IPlatformAdapter {
|
||||||
if (!this.adapter) {
|
if (!this.adapter) {
|
||||||
throw new Error('平台适配器未注册,请调用 registerAdapter() 注册适配器');
|
throw new Error("平台适配器未注册,请调用 registerAdapter() 注册适配器");
|
||||||
}
|
}
|
||||||
return this.adapter;
|
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;
|
if (!this.adapter) return false;
|
||||||
|
|
||||||
const config = this.adapter.getPlatformConfig();
|
const config = this.adapter.getPlatformConfig();
|
||||||
|
|
||||||
switch (feature) {
|
switch (feature) {
|
||||||
case 'worker':
|
case "worker":
|
||||||
return this.adapter.isWorkerSupported();
|
return this.adapter.isWorkerSupported();
|
||||||
case 'shared-array-buffer':
|
case "shared-array-buffer":
|
||||||
return this.adapter.isSharedArrayBufferSupported();
|
return this.adapter.isSharedArrayBufferSupported();
|
||||||
case 'transferable-objects':
|
case "transferable-objects":
|
||||||
return config.supportsTransferableObjects;
|
return config.supportsTransferableObjects;
|
||||||
case 'module-worker':
|
case "module-worker":
|
||||||
return config.supportsModuleWorker;
|
return config.supportsModuleWorker;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@@ -123,11 +123,11 @@ export class PlatformManager {
|
|||||||
*/
|
*/
|
||||||
public async getFullPlatformConfig(): Promise<any> {
|
public async getFullPlatformConfig(): Promise<any> {
|
||||||
if (!this.adapter) {
|
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 await this.adapter.getPlatformConfigAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,17 +9,17 @@ export type {
|
|||||||
WorkerCreationOptions,
|
WorkerCreationOptions,
|
||||||
PlatformConfig,
|
PlatformConfig,
|
||||||
PlatformDetectionResult
|
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 {PlatformManager} from "./PlatformManager";
|
||||||
import type { IPlatformAdapter } from './IPlatformAdapter';
|
import type {IPlatformAdapter} from "./IPlatformAdapter";
|
||||||
|
|
||||||
// 便利函数
|
// 便利函数
|
||||||
export function registerPlatformAdapter(adapter: IPlatformAdapter) {
|
export function registerPlatformAdapter(adapter: IPlatformAdapter) {
|
||||||
@@ -38,7 +38,7 @@ export function getFullPlatformConfig() {
|
|||||||
return PlatformManager.getInstance().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);
|
return PlatformManager.getInstance().supportsFeature(feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import type { Core } from '../Core';
|
import type {Core} from "../Core";
|
||||||
import type { ServiceContainer } from '../Core/ServiceContainer';
|
import type {ServiceContainer} from "../Core/ServiceContainer";
|
||||||
import { IPlugin } from '../Core/Plugin';
|
import {IPlugin} from "../Core/Plugin";
|
||||||
import { createLogger } from '../Utils/Logger';
|
import {createLogger} from "../Utils/Logger";
|
||||||
import type { IScene } from '../ECS/IScene';
|
import type {IScene} from "../ECS/IScene";
|
||||||
import type { Entity } from '../ECS/Entity';
|
import type {Entity} from "../ECS/Entity";
|
||||||
import type { EntitySystem } from '../ECS/Systems/EntitySystem';
|
import type {EntitySystem} from "../ECS/Systems/EntitySystem";
|
||||||
import { WorldManager } from '../ECS/WorldManager';
|
import {WorldManager} from "../ECS/WorldManager";
|
||||||
import { Injectable } from '../Core/DI/Decorators';
|
import {Injectable} from "../Core/DI/Decorators";
|
||||||
import type { IService } from '../Core/ServiceContainer';
|
import type {IService} from "../Core/ServiceContainer";
|
||||||
|
|
||||||
const logger = createLogger('DebugPlugin');
|
const logger = createLogger("DebugPlugin");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ECS 调试插件统计信息
|
* ECS 调试插件统计信息
|
||||||
@@ -91,8 +91,8 @@ export interface ComponentDebugInfo {
|
|||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DebugPlugin implements IPlugin, IService {
|
export class DebugPlugin implements IPlugin, IService {
|
||||||
readonly name = '@esengine/debug-plugin';
|
readonly name = "@esengine/debug-plugin";
|
||||||
readonly version = '1.0.0';
|
readonly version = "1.0.0";
|
||||||
|
|
||||||
private worldManager: WorldManager | null = null;
|
private worldManager: WorldManager | null = null;
|
||||||
private updateInterval: number;
|
private updateInterval: number;
|
||||||
@@ -115,7 +115,7 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
async install(_core: Core, services: ServiceContainer): Promise<void> {
|
async install(_core: Core, services: ServiceContainer): Promise<void> {
|
||||||
this.worldManager = services.resolve(WorldManager);
|
this.worldManager = services.resolve(WorldManager);
|
||||||
|
|
||||||
logger.info('ECS Debug Plugin installed');
|
logger.info("ECS Debug Plugin installed");
|
||||||
|
|
||||||
if (this.autoStart) {
|
if (this.autoStart) {
|
||||||
this.start();
|
this.start();
|
||||||
@@ -129,7 +129,7 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
this.stop();
|
this.stop();
|
||||||
this.worldManager = null;
|
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 {
|
public start(): void {
|
||||||
if (this.updateTimer) {
|
if (this.updateTimer) {
|
||||||
logger.warn('Debug monitoring already started');
|
logger.warn("Debug monitoring already started");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info('Starting debug monitoring');
|
logger.info("Starting debug monitoring");
|
||||||
|
|
||||||
this.updateTimer = setInterval(() => {
|
this.updateTimer = setInterval(() => {
|
||||||
this.logStats();
|
this.logStats();
|
||||||
@@ -163,7 +163,7 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
if (this.updateTimer) {
|
if (this.updateTimer) {
|
||||||
clearInterval(this.updateTimer);
|
clearInterval(this.updateTimer);
|
||||||
this.updateTimer = null;
|
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 {
|
public getStats(): ECSDebugStats {
|
||||||
if (!this.worldManager) {
|
if (!this.worldManager) {
|
||||||
throw new Error('Plugin not installed');
|
throw new Error("Plugin not installed");
|
||||||
}
|
}
|
||||||
|
|
||||||
const scenes: SceneDebugInfo[] = [];
|
const scenes: SceneDebugInfo[] = [];
|
||||||
@@ -208,8 +208,8 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
return {
|
return {
|
||||||
name: scene.name,
|
name: scene.name,
|
||||||
entityCount: entities.length,
|
entityCount: entities.length,
|
||||||
systems: systems.map(sys => this.getSystemInfo(sys)),
|
systems: systems.map((sys) => this.getSystemInfo(sys)),
|
||||||
entities: entities.map(entity => this.getEntityInfo(entity))
|
entities: entities.map((entity) => this.getEntityInfo(entity))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,7 +246,7 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
enabled: entity.enabled,
|
enabled: entity.enabled,
|
||||||
tag: entity.tag,
|
tag: entity.tag,
|
||||||
componentCount: components.length,
|
componentCount: components.length,
|
||||||
components: components.map(comp => this.getComponentInfo(comp))
|
components: components.map((comp) => this.getComponentInfo(comp))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,9 +258,9 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
const data: any = {};
|
const data: any = {};
|
||||||
|
|
||||||
for (const key of Object.keys(component)) {
|
for (const key of Object.keys(component)) {
|
||||||
if (!key.startsWith('_')) {
|
if (!key.startsWith("_")) {
|
||||||
const value = component[key];
|
const value = component[key];
|
||||||
if (typeof value !== 'function') {
|
if (typeof value !== "function") {
|
||||||
data[key] = value;
|
data[key] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,7 +281,7 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
hasComponent?: string;
|
hasComponent?: string;
|
||||||
}): EntityDebugInfo[] {
|
}): EntityDebugInfo[] {
|
||||||
if (!this.worldManager) {
|
if (!this.worldManager) {
|
||||||
throw new Error('Plugin not installed');
|
throw new Error("Plugin not installed");
|
||||||
}
|
}
|
||||||
|
|
||||||
const results: EntityDebugInfo[] = [];
|
const results: EntityDebugInfo[] = [];
|
||||||
@@ -304,7 +304,7 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
|
|
||||||
if (filter.hasComponent) {
|
if (filter.hasComponent) {
|
||||||
const hasComp = entity.components.some(
|
const hasComp = entity.components.some(
|
||||||
c => c.constructor.name === filter.hasComponent
|
(c) => c.constructor.name === filter.hasComponent
|
||||||
);
|
);
|
||||||
if (!hasComp) {
|
if (!hasComp) {
|
||||||
continue;
|
continue;
|
||||||
@@ -325,7 +325,7 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
private logStats(): void {
|
private logStats(): void {
|
||||||
const stats = this.getStats();
|
const stats = this.getStats();
|
||||||
|
|
||||||
logger.info('=== ECS Debug Stats ===');
|
logger.info("=== ECS Debug Stats ===");
|
||||||
logger.info(`Total Entities: ${stats.totalEntities}`);
|
logger.info(`Total Entities: ${stats.totalEntities}`);
|
||||||
logger.info(`Total Systems: ${stats.totalSystems}`);
|
logger.info(`Total Systems: ${stats.totalSystems}`);
|
||||||
logger.info(`Scenes: ${stats.scenes.length}`);
|
logger.info(`Scenes: ${stats.scenes.length}`);
|
||||||
@@ -338,14 +338,14 @@ export class DebugPlugin implements IPlugin, IService {
|
|||||||
for (const system of scene.systems) {
|
for (const system of scene.systems) {
|
||||||
const perfStr = system.performance
|
const perfStr = system.performance
|
||||||
? ` | Avg: ${system.performance.avgExecutionTime.toFixed(2)}ms, Max: ${system.performance.maxExecutionTime.toFixed(2)}ms`
|
? ` | Avg: ${system.performance.avgExecutionTime.toFixed(2)}ms, Max: ${system.performance.maxExecutionTime.toFixed(2)}ms`
|
||||||
: '';
|
: "";
|
||||||
logger.info(
|
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 @@
|
|||||||
export * from './DebugPlugin';
|
export * from "./DebugPlugin";
|
||||||
|
|||||||
@@ -16,5 +16,5 @@ export interface IUpdatable {
|
|||||||
* 检查对象是否实现了IUpdatable接口
|
* 检查对象是否实现了IUpdatable接口
|
||||||
*/
|
*/
|
||||||
export function isUpdatable(obj: any): obj is IUpdatable {
|
export function isUpdatable(obj: any): obj is IUpdatable {
|
||||||
return obj && typeof obj.update === 'function';
|
return obj && typeof obj.update === "function";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
* 提供高级类型推断和类型安全的工具类型
|
* 提供高级类型推断和类型安全的工具类型
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { IComponent } from './index';
|
import type {IComponent} from "./index";
|
||||||
import { Component } from '../ECS/Component';
|
import {Component} from "../ECS/Component";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件类型提取器
|
* 组件类型提取器
|
||||||
@@ -240,7 +240,7 @@ export interface TypedQueryCondition<
|
|||||||
export function isComponentType<T extends IComponent>(
|
export function isComponentType<T extends IComponent>(
|
||||||
value: any
|
value: any
|
||||||
): value is ComponentConstructor<T> {
|
): value is ComponentConstructor<T> {
|
||||||
return typeof value === 'function' && value.prototype instanceof Component;
|
return typeof value === "function" && value.prototype instanceof Component;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
* 框架核心类型定义
|
* 框架核心类型定义
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { IWorldManagerConfig } from '../ECS';
|
import type {IWorldManagerConfig} from "../ECS";
|
||||||
|
|
||||||
// 导出TypeScript类型增强工具
|
// 导出TypeScript类型增强工具
|
||||||
export * from './TypeHelpers';
|
export * from "./TypeHelpers";
|
||||||
export * from './IUpdatable';
|
export * from "./IUpdatable";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件接口
|
* 组件接口
|
||||||
|
|||||||
@@ -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 {IComponentDebugData} from "../../Types";
|
||||||
import { ComponentPoolManager } from '../../ECS/Core/ComponentPool';
|
import {ComponentPoolManager} from "../../ECS/Core/ComponentPool";
|
||||||
import { getComponentInstanceTypeName } from '../../ECS/Decorators';
|
import {getComponentInstanceTypeName} from "../../ECS/Decorators";
|
||||||
import { IScene } from '../../ECS/IScene';
|
import {IScene} from "../../ECS/IScene";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 组件数据收集器
|
* 组件数据收集器
|
||||||
@@ -47,8 +47,8 @@ export class ComponentDataCollector {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 获取池利用率信息
|
// 获取池利用率信息
|
||||||
let poolUtilizations = new Map<string, number>();
|
const poolUtilizations = new Map<string, number>();
|
||||||
let poolSizes = new Map<string, number>();
|
const poolSizes = new Map<string, number>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const poolManager = ComponentPoolManager.getInstance();
|
const poolManager = ComponentPoolManager.getInstance();
|
||||||
@@ -122,13 +122,13 @@ export class ComponentDataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private calculateQuickObjectSize(obj: any): number {
|
private calculateQuickObjectSize(obj: any): number {
|
||||||
if (!obj || typeof obj !== 'object') return 8;
|
if (!obj || typeof obj !== "object") return 8;
|
||||||
|
|
||||||
let size = 32;
|
let size = 32;
|
||||||
const visited = new WeakSet();
|
const visited = new WeakSet();
|
||||||
|
|
||||||
const calculate = (item: any, depth: number = 0): number => {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
visited.add(item);
|
visited.add(item);
|
||||||
@@ -139,18 +139,18 @@ export class ComponentDataCollector {
|
|||||||
const keys = Object.keys(item);
|
const keys = Object.keys(item);
|
||||||
for (let i = 0; i < Math.min(keys.length, 20); i++) {
|
for (let i = 0; i < Math.min(keys.length, 20); i++) {
|
||||||
const key = keys[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];
|
const value = item[key];
|
||||||
itemSize += key.length * 2;
|
itemSize += key.length * 2;
|
||||||
|
|
||||||
if (typeof value === 'string') {
|
if (typeof value === "string") {
|
||||||
itemSize += Math.min(value.length * 2, 200);
|
itemSize += Math.min(value.length * 2, 200);
|
||||||
} else if (typeof value === 'number') {
|
} else if (typeof value === "number") {
|
||||||
itemSize += 8;
|
itemSize += 8;
|
||||||
} else if (typeof value === 'boolean') {
|
} else if (typeof value === "boolean") {
|
||||||
itemSize += 4;
|
itemSize += 4;
|
||||||
} else if (typeof value === 'object' && value !== null) {
|
} else if (typeof value === "object" && value !== null) {
|
||||||
itemSize += calculate(value, depth + 1);
|
itemSize += calculate(value, depth + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,16 +206,16 @@ export class ComponentDataCollector {
|
|||||||
const type = typeof obj;
|
const type = typeof obj;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'boolean':
|
case "boolean":
|
||||||
size = 4;
|
size = 4;
|
||||||
break;
|
break;
|
||||||
case 'number':
|
case "number":
|
||||||
size = 8;
|
size = 8;
|
||||||
break;
|
break;
|
||||||
case 'string':
|
case "string":
|
||||||
size = 24 + Math.min(obj.length * 2, 1000);
|
size = 24 + Math.min(obj.length * 2, 1000);
|
||||||
break;
|
break;
|
||||||
case 'object':
|
case "object":
|
||||||
visited.add(obj);
|
visited.add(obj);
|
||||||
|
|
||||||
if (Array.isArray(obj)) {
|
if (Array.isArray(obj)) {
|
||||||
@@ -235,12 +235,12 @@ export class ComponentDataCollector {
|
|||||||
const key = ownKeys[i];
|
const key = ownKeys[i];
|
||||||
if (!key) continue;
|
if (!key) continue;
|
||||||
|
|
||||||
if (key === 'constructor' ||
|
if (key === "constructor" ||
|
||||||
key === '__proto__' ||
|
key === "__proto__" ||
|
||||||
key === 'entity' ||
|
key === "entity" ||
|
||||||
key === '_entity' ||
|
key === "_entity" ||
|
||||||
key.startsWith('_cc_') ||
|
key.startsWith("_cc_") ||
|
||||||
key.startsWith('__')) {
|
key.startsWith("__")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { IECSDebugConfig } from '../../Types';
|
import {IECSDebugConfig} from "../../Types";
|
||||||
import { Injectable } from '../../Core/DI/Decorators';
|
import {Injectable} from "../../Core/DI/Decorators";
|
||||||
import type { IService } from '../../Core/ServiceContainer';
|
import type {IService} from "../../Core/ServiceContainer";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调试配置服务
|
* 调试配置服务
|
||||||
@@ -14,7 +14,7 @@ export class DebugConfigService implements IService {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this._config = {
|
this._config = {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
websocketUrl: '',
|
websocketUrl: "",
|
||||||
debugFrameRate: 30,
|
debugFrameRate: 30,
|
||||||
autoReconnect: true,
|
autoReconnect: true,
|
||||||
channels: {
|
channels: {
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { IECSDebugConfig, IECSDebugData } from '../../Types';
|
import {IECSDebugConfig, IECSDebugData} from "../../Types";
|
||||||
import { EntityDataCollector } from './EntityDataCollector';
|
import {EntityDataCollector} from "./EntityDataCollector";
|
||||||
import { SystemDataCollector } from './SystemDataCollector';
|
import {SystemDataCollector} from "./SystemDataCollector";
|
||||||
import { PerformanceDataCollector } from './PerformanceDataCollector';
|
import {PerformanceDataCollector} from "./PerformanceDataCollector";
|
||||||
import { ComponentDataCollector } from './ComponentDataCollector';
|
import {ComponentDataCollector} from "./ComponentDataCollector";
|
||||||
import { SceneDataCollector } from './SceneDataCollector';
|
import {SceneDataCollector} from "./SceneDataCollector";
|
||||||
import { WebSocketManager } from './WebSocketManager';
|
import {WebSocketManager} from "./WebSocketManager";
|
||||||
import { Component } from '../../ECS/Component';
|
import {Component} from "../../ECS/Component";
|
||||||
import { ComponentPoolManager } from '../../ECS/Core/ComponentPool';
|
import {ComponentPoolManager} from "../../ECS/Core/ComponentPool";
|
||||||
import { Pool } from '../../Utils/Pool';
|
import {Pool} from "../../Utils/Pool";
|
||||||
import { getComponentInstanceTypeName, getSystemInstanceTypeName } from '../../ECS/Decorators';
|
import {getComponentInstanceTypeName, getSystemInstanceTypeName} from "../../ECS/Decorators";
|
||||||
import type { IService } from '../../Core/ServiceContainer';
|
import type {IService} from "../../Core/ServiceContainer";
|
||||||
import type { IUpdatable } from '../../Types/IUpdatable';
|
import type {IUpdatable} from "../../Types/IUpdatable";
|
||||||
import { SceneManager } from '../../ECS/SceneManager';
|
import {SceneManager} from "../../ECS/SceneManager";
|
||||||
import { PerformanceMonitor } from '../PerformanceMonitor';
|
import {PerformanceMonitor} from "../PerformanceMonitor";
|
||||||
import { Injectable, Inject, Updatable } from '../../Core/DI/Decorators';
|
import {Injectable, Inject, Updatable} from "../../Core/DI/Decorators";
|
||||||
import { DebugConfigService } from './DebugConfigService';
|
import {DebugConfigService} from "./DebugConfigService";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调试管理器
|
* 调试管理器
|
||||||
@@ -106,27 +106,27 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
*/
|
*/
|
||||||
private interceptConsole(): void {
|
private interceptConsole(): void {
|
||||||
console.log = (...args: unknown[]) => {
|
console.log = (...args: unknown[]) => {
|
||||||
this.sendLog('info', this.formatLogMessage(args));
|
this.sendLog("info", this.formatLogMessage(args));
|
||||||
this.originalConsole.log(...args);
|
this.originalConsole.log(...args);
|
||||||
};
|
};
|
||||||
|
|
||||||
console.debug = (...args: unknown[]) => {
|
console.debug = (...args: unknown[]) => {
|
||||||
this.sendLog('debug', this.formatLogMessage(args));
|
this.sendLog("debug", this.formatLogMessage(args));
|
||||||
this.originalConsole.debug(...args);
|
this.originalConsole.debug(...args);
|
||||||
};
|
};
|
||||||
|
|
||||||
console.info = (...args: unknown[]) => {
|
console.info = (...args: unknown[]) => {
|
||||||
this.sendLog('info', this.formatLogMessage(args));
|
this.sendLog("info", this.formatLogMessage(args));
|
||||||
this.originalConsole.info(...args);
|
this.originalConsole.info(...args);
|
||||||
};
|
};
|
||||||
|
|
||||||
console.warn = (...args: unknown[]) => {
|
console.warn = (...args: unknown[]) => {
|
||||||
this.sendLog('warn', this.formatLogMessage(args));
|
this.sendLog("warn", this.formatLogMessage(args));
|
||||||
this.originalConsole.warn(...args);
|
this.originalConsole.warn(...args);
|
||||||
};
|
};
|
||||||
|
|
||||||
console.error = (...args: unknown[]) => {
|
console.error = (...args: unknown[]) => {
|
||||||
this.sendLog('error', this.formatLogMessage(args));
|
this.sendLog("error", this.formatLogMessage(args));
|
||||||
this.originalConsole.error(...args);
|
this.originalConsole.error(...args);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -135,12 +135,12 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
* 格式化日志消息
|
* 格式化日志消息
|
||||||
*/
|
*/
|
||||||
private formatLogMessage(args: unknown[]): string {
|
private formatLogMessage(args: unknown[]): string {
|
||||||
return args.map(arg => {
|
return args.map((arg) => {
|
||||||
if (typeof arg === 'string') return arg;
|
if (typeof arg === "string") return arg;
|
||||||
if (arg instanceof Error) return `${arg.name}: ${arg.message}`;
|
if (arg instanceof Error) return `${arg.name}: ${arg.message}`;
|
||||||
if (arg === null) return 'null';
|
if (arg === null) return "null";
|
||||||
if (arg === undefined) return 'undefined';
|
if (arg === undefined) return "undefined";
|
||||||
if (typeof arg === 'object') {
|
if (typeof arg === "object") {
|
||||||
try {
|
try {
|
||||||
return this.safeStringify(arg, 6);
|
return this.safeStringify(arg, 6);
|
||||||
} catch {
|
} catch {
|
||||||
@@ -148,7 +148,7 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return String(arg);
|
return String(arg);
|
||||||
}).join(' ');
|
}).join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,20 +160,20 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
const stringify = (value: any, depth: number): any => {
|
const stringify = (value: any, depth: number): any => {
|
||||||
if (value === null) return null;
|
if (value === null) return null;
|
||||||
if (value === undefined) return undefined;
|
if (value === undefined) return undefined;
|
||||||
if (typeof value !== 'object') return value;
|
if (typeof value !== "object") return value;
|
||||||
|
|
||||||
if (depth >= maxDepth) {
|
if (depth >= maxDepth) {
|
||||||
return '[Max Depth Reached]';
|
return "[Max Depth Reached]";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (seen.has(value)) {
|
if (seen.has(value)) {
|
||||||
return '[Circular]';
|
return "[Circular]";
|
||||||
}
|
}
|
||||||
|
|
||||||
seen.add(value);
|
seen.add(value);
|
||||||
|
|
||||||
if (Array.isArray(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);
|
seen.delete(value);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -201,7 +201,7 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'log',
|
type: "log",
|
||||||
data: {
|
data: {
|
||||||
level,
|
level,
|
||||||
message,
|
message,
|
||||||
@@ -263,35 +263,35 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
private handleMessage(message: any): void {
|
private handleMessage(message: any): void {
|
||||||
try {
|
try {
|
||||||
switch (message.type) {
|
switch (message.type) {
|
||||||
case 'capture_memory_snapshot':
|
case "capture_memory_snapshot":
|
||||||
this.handleMemorySnapshotRequest();
|
this.handleMemorySnapshotRequest();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'config_update':
|
case "config_update":
|
||||||
if (message.config) {
|
if (message.config) {
|
||||||
this.updateConfig({...this.config, ...message.config});
|
this.updateConfig({...this.config, ...message.config});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'expand_lazy_object':
|
case "expand_lazy_object":
|
||||||
this.handleExpandLazyObjectRequest(message);
|
this.handleExpandLazyObjectRequest(message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'get_component_properties':
|
case "get_component_properties":
|
||||||
this.handleGetComponentPropertiesRequest(message);
|
this.handleGetComponentPropertiesRequest(message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'get_raw_entity_list':
|
case "get_raw_entity_list":
|
||||||
this.handleGetRawEntityListRequest(message);
|
this.handleGetRawEntityListRequest(message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'get_entity_details':
|
case "get_entity_details":
|
||||||
this.handleGetEntityDetailsRequest(message);
|
this.handleGetEntityDetailsRequest(message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'ping':
|
case "ping":
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'pong',
|
type: "pong",
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@@ -304,7 +304,7 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
// console.error('[ECS Debug] 处理消息失败:', error);
|
// console.error('[ECS Debug] 处理消息失败:', error);
|
||||||
if (message.requestId) {
|
if (message.requestId) {
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'error_response',
|
type: "error_response",
|
||||||
requestId: message.requestId,
|
requestId: message.requestId,
|
||||||
error: error instanceof Error ? error.message : String(error)
|
error: error instanceof Error ? error.message : String(error)
|
||||||
});
|
});
|
||||||
@@ -321,9 +321,9 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
|
|
||||||
if (entityId === undefined || componentIndex === undefined || !propertyPath) {
|
if (entityId === undefined || componentIndex === undefined || !propertyPath) {
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'expand_lazy_object_response',
|
type: "expand_lazy_object_response",
|
||||||
requestId,
|
requestId,
|
||||||
error: '缺少必要参数'
|
error: "缺少必要参数"
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -332,13 +332,13 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
const expandedData = this.entityCollector.expandLazyObject(entityId, componentIndex, propertyPath, scene);
|
const expandedData = this.entityCollector.expandLazyObject(entityId, componentIndex, propertyPath, scene);
|
||||||
|
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'expand_lazy_object_response',
|
type: "expand_lazy_object_response",
|
||||||
requestId,
|
requestId,
|
||||||
data: expandedData
|
data: expandedData
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'expand_lazy_object_response',
|
type: "expand_lazy_object_response",
|
||||||
requestId: message.requestId,
|
requestId: message.requestId,
|
||||||
error: error instanceof Error ? error.message : String(error)
|
error: error instanceof Error ? error.message : String(error)
|
||||||
});
|
});
|
||||||
@@ -354,9 +354,9 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
|
|
||||||
if (entityId === undefined || componentIndex === undefined) {
|
if (entityId === undefined || componentIndex === undefined) {
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'get_component_properties_response',
|
type: "get_component_properties_response",
|
||||||
requestId,
|
requestId,
|
||||||
error: '缺少必要参数'
|
error: "缺少必要参数"
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -365,13 +365,13 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
const properties = this.entityCollector.getComponentProperties(entityId, componentIndex, scene);
|
const properties = this.entityCollector.getComponentProperties(entityId, componentIndex, scene);
|
||||||
|
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'get_component_properties_response',
|
type: "get_component_properties_response",
|
||||||
requestId,
|
requestId,
|
||||||
data: properties
|
data: properties
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'get_component_properties_response',
|
type: "get_component_properties_response",
|
||||||
requestId: message.requestId,
|
requestId: message.requestId,
|
||||||
error: error instanceof Error ? error.message : String(error)
|
error: error instanceof Error ? error.message : String(error)
|
||||||
});
|
});
|
||||||
@@ -389,13 +389,13 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
const rawEntityList = this.entityCollector.getRawEntityList(scene);
|
const rawEntityList = this.entityCollector.getRawEntityList(scene);
|
||||||
|
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'get_raw_entity_list_response',
|
type: "get_raw_entity_list_response",
|
||||||
requestId,
|
requestId,
|
||||||
data: rawEntityList
|
data: rawEntityList
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'get_raw_entity_list_response',
|
type: "get_raw_entity_list_response",
|
||||||
requestId: message.requestId,
|
requestId: message.requestId,
|
||||||
error: error instanceof Error ? error.message : String(error)
|
error: error instanceof Error ? error.message : String(error)
|
||||||
});
|
});
|
||||||
@@ -411,9 +411,9 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
|
|
||||||
if (entityId === undefined) {
|
if (entityId === undefined) {
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'get_entity_details_response',
|
type: "get_entity_details_response",
|
||||||
requestId,
|
requestId,
|
||||||
error: '缺少实体ID参数'
|
error: "缺少实体ID参数"
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -422,13 +422,13 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
const entityDetails = this.entityCollector.getEntityDetails(entityId, scene);
|
const entityDetails = this.entityCollector.getEntityDetails(entityId, scene);
|
||||||
|
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'get_entity_details_response',
|
type: "get_entity_details_response",
|
||||||
requestId,
|
requestId,
|
||||||
data: entityDetails
|
data: entityDetails
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'get_entity_details_response',
|
type: "get_entity_details_response",
|
||||||
requestId: message.requestId,
|
requestId: message.requestId,
|
||||||
error: error instanceof Error ? error.message : String(error)
|
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 {
|
try {
|
||||||
const memorySnapshot = this.captureMemorySnapshot();
|
const memorySnapshot = this.captureMemorySnapshot();
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'memory_snapshot_response',
|
type: "memory_snapshot_response",
|
||||||
data: memorySnapshot
|
data: memorySnapshot
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.webSocketManager.send({
|
this.webSocketManager.send({
|
||||||
type: 'memory_snapshot_error',
|
type: "memory_snapshot_error",
|
||||||
error: error instanceof Error ? error.message : '内存快照捕获失败'
|
error: error instanceof Error ? error.message : "内存快照捕获失败"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -479,7 +476,7 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
timestamp,
|
timestamp,
|
||||||
version: '2.0',
|
version: "2.0",
|
||||||
summary: {
|
summary: {
|
||||||
totalEntities: entityData.totalEntities,
|
totalEntities: entityData.totalEntities,
|
||||||
totalMemoryUsage: baseMemoryInfo.usedMemory,
|
totalMemoryUsage: baseMemoryInfo.usedMemory,
|
||||||
@@ -575,7 +572,6 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 收集组件内存统计(仅用于内存快照)
|
* 收集组件内存统计(仅用于内存快照)
|
||||||
*/
|
*/
|
||||||
@@ -720,7 +716,7 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private calculateQuickSystemSize(system: unknown): number {
|
private calculateQuickSystemSize(system: unknown): number {
|
||||||
if (!system || typeof system !== 'object') return 64;
|
if (!system || typeof system !== "object") return 64;
|
||||||
|
|
||||||
let size = 128;
|
let size = 128;
|
||||||
|
|
||||||
@@ -728,20 +724,20 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
const keys = Object.keys(system);
|
const keys = Object.keys(system);
|
||||||
for (let i = 0; i < Math.min(keys.length, 15); i++) {
|
for (let i = 0; i < Math.min(keys.length, 15); i++) {
|
||||||
const key = keys[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];
|
const value = (system as Record<string, unknown>)[key];
|
||||||
size += key.length * 2;
|
size += key.length * 2;
|
||||||
|
|
||||||
if (typeof value === 'string') {
|
if (typeof value === "string") {
|
||||||
size += Math.min(value.length * 2, 100);
|
size += Math.min(value.length * 2, 100);
|
||||||
} else if (typeof value === 'number') {
|
} else if (typeof value === "number") {
|
||||||
size += 8;
|
size += 8;
|
||||||
} else if (typeof value === 'boolean') {
|
} else if (typeof value === "boolean") {
|
||||||
size += 4;
|
size += 4;
|
||||||
} else if (Array.isArray(value)) {
|
} else if (Array.isArray(value)) {
|
||||||
size += 40 + Math.min(value.length * 8, 200);
|
size += 40 + Math.min(value.length * 8, 200);
|
||||||
} else if (typeof value === 'object' && value !== null) {
|
} else if (typeof value === "object" && value !== null) {
|
||||||
size += 64;
|
size += 64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -883,10 +879,10 @@ export class DebugManager implements IService, IUpdatable {
|
|||||||
|
|
||||||
const debugData: IECSDebugData = {
|
const debugData: IECSDebugData = {
|
||||||
timestamp: currentTime,
|
timestamp: currentTime,
|
||||||
frameworkVersion: '1.0.0', // 可以从package.json读取
|
frameworkVersion: "1.0.0", // 可以从package.json读取
|
||||||
isRunning: this.isRunning,
|
isRunning: this.isRunning,
|
||||||
frameworkLoaded: true,
|
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 debugData = this.getDebugData();
|
||||||
// 包装成调试面板期望的消息格式
|
// 包装成调试面板期望的消息格式
|
||||||
const message = {
|
const message = {
|
||||||
type: 'debug_data',
|
type: "debug_data",
|
||||||
data: debugData
|
data: debugData
|
||||||
};
|
};
|
||||||
this.webSocketManager.send(message);
|
this.webSocketManager.send(message);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { IEntityDebugData } from '../../Types';
|
import {IEntityDebugData} from "../../Types";
|
||||||
import { Entity } from '../../ECS/Entity';
|
import {Entity} from "../../ECS/Entity";
|
||||||
import { Component } from '../../ECS/Component';
|
import {Component} from "../../ECS/Component";
|
||||||
import { getComponentInstanceTypeName } from '../../ECS/Decorators';
|
import {getComponentInstanceTypeName} from "../../ECS/Decorators";
|
||||||
import { IScene } from '../../ECS/IScene';
|
import {IScene} from "../../ECS/IScene";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实体数据收集器
|
* 实体数据收集器
|
||||||
@@ -129,7 +129,7 @@ export class EntityDataCollector {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
error: `获取实体详情失败: ${error instanceof Error ? error.message : String(error)}`,
|
error: `获取实体详情失败: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
scene: '获取失败',
|
scene: "获取失败",
|
||||||
components: [],
|
components: [],
|
||||||
componentCount: 0,
|
componentCount: 0,
|
||||||
componentTypes: []
|
componentTypes: []
|
||||||
@@ -138,26 +138,26 @@ export class EntityDataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getSceneInfo(scene: any): { name: string; type: string } {
|
private getSceneInfo(scene: any): { name: string; type: string } {
|
||||||
let sceneName = '当前场景';
|
let sceneName = "当前场景";
|
||||||
let sceneType = 'Scene';
|
let sceneType = "Scene";
|
||||||
|
|
||||||
try {
|
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();
|
sceneName = scene.name.trim();
|
||||||
} else if (scene.constructor && scene.constructor.name) {
|
} else if (scene.constructor && scene.constructor.name) {
|
||||||
sceneName = scene.constructor.name;
|
sceneName = scene.constructor.name;
|
||||||
sceneType = 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();
|
sceneName = scene._name.trim();
|
||||||
} else {
|
} else {
|
||||||
const sceneClassName = Object.getPrototypeOf(scene)?.constructor?.name;
|
const sceneClassName = Object.getPrototypeOf(scene)?.constructor?.name;
|
||||||
if (sceneClassName && sceneClassName !== 'Object') {
|
if (sceneClassName && sceneClassName !== "Object") {
|
||||||
sceneName = sceneClassName;
|
sceneName = sceneClassName;
|
||||||
sceneType = sceneClassName;
|
sceneType = sceneClassName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
sceneName = '场景名获取失败';
|
sceneName = "场景名获取失败";
|
||||||
}
|
}
|
||||||
|
|
||||||
return {name: sceneName, type: sceneType};
|
return {name: sceneName, type: sceneType};
|
||||||
@@ -213,7 +213,7 @@ export class EntityDataCollector {
|
|||||||
distribution: Array<{ signature: string; count: number; memory: number }>;
|
distribution: Array<{ signature: string; count: number; memory: number }>;
|
||||||
topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>;
|
topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>;
|
||||||
} {
|
} {
|
||||||
if (scene && scene.archetypeSystem && typeof scene.archetypeSystem.getAllArchetypes === 'function') {
|
if (scene && scene.archetypeSystem && typeof scene.archetypeSystem.getAllArchetypes === "function") {
|
||||||
return this.extractArchetypeStatistics(scene.archetypeSystem);
|
return this.extractArchetypeStatistics(scene.archetypeSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +230,7 @@ export class EntityDataCollector {
|
|||||||
if (entityContainer && entityContainer.entities) {
|
if (entityContainer && entityContainer.entities) {
|
||||||
entityContainer.entities.forEach((entity: any) => {
|
entityContainer.entities.forEach((entity: any) => {
|
||||||
const componentTypes = entity.components?.map((comp: any) => getComponentInstanceTypeName(comp)) || [];
|
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);
|
const existing = distribution.get(signature);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
@@ -271,7 +271,7 @@ export class EntityDataCollector {
|
|||||||
distribution: Array<{ signature: string; count: number; memory: number }>;
|
distribution: Array<{ signature: string; count: number; memory: number }>;
|
||||||
topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>;
|
topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }>;
|
||||||
} {
|
} {
|
||||||
if (scene && scene.archetypeSystem && typeof scene.archetypeSystem.getAllArchetypes === 'function') {
|
if (scene && scene.archetypeSystem && typeof scene.archetypeSystem.getAllArchetypes === "function") {
|
||||||
return this.extractArchetypeStatisticsWithMemory(scene.archetypeSystem);
|
return this.extractArchetypeStatisticsWithMemory(scene.archetypeSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +292,7 @@ export class EntityDataCollector {
|
|||||||
const topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }> = [];
|
const topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }> = [];
|
||||||
|
|
||||||
archetypes.forEach((archetype: any) => {
|
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;
|
const entityCount = archetype.entities?.length || 0;
|
||||||
|
|
||||||
distribution.push({
|
distribution.push({
|
||||||
@@ -329,7 +329,7 @@ export class EntityDataCollector {
|
|||||||
const topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }> = [];
|
const topEntities: Array<{ id: string; name: string; componentCount: number; memory: number }> = [];
|
||||||
|
|
||||||
archetypes.forEach((archetype: any) => {
|
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;
|
const entityCount = archetype.entities?.length || 0;
|
||||||
|
|
||||||
let actualMemory = 0;
|
let actualMemory = 0;
|
||||||
@@ -369,14 +369,13 @@ export class EntityDataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private getArchetypeDistributionWithMemory(entityContainer: any): Array<{ signature: string; count: number; memory: number }> {
|
private getArchetypeDistributionWithMemory(entityContainer: any): Array<{ signature: string; count: number; memory: number }> {
|
||||||
const distribution = new Map<string, { count: number; memory: number; componentTypes: string[] }>();
|
const distribution = new Map<string, { count: number; memory: number; componentTypes: string[] }>();
|
||||||
|
|
||||||
if (entityContainer && entityContainer.entities) {
|
if (entityContainer && entityContainer.entities) {
|
||||||
entityContainer.entities.forEach((entity: any) => {
|
entityContainer.entities.forEach((entity: any) => {
|
||||||
const componentTypes = entity.components?.map((comp: any) => getComponentInstanceTypeName(comp)) || [];
|
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);
|
const existing = distribution.get(signature);
|
||||||
let memory = this.estimateEntityMemoryUsage(entity);
|
let memory = this.estimateEntityMemoryUsage(entity);
|
||||||
@@ -437,7 +436,7 @@ export class EntityDataCollector {
|
|||||||
private calculateFallbackEntityStats(entityList: any): any {
|
private calculateFallbackEntityStats(entityList: any): any {
|
||||||
const allEntities = entityList.buffer || [];
|
const allEntities = entityList.buffer || [];
|
||||||
const activeEntities = allEntities.filter((entity: any) =>
|
const activeEntities = allEntities.filter((entity: any) =>
|
||||||
entity.enabled && !entity._isDestroyed
|
entity.enabled && !entity.isDestroyed
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -454,14 +453,14 @@ export class EntityDataCollector {
|
|||||||
try {
|
try {
|
||||||
let totalSize = 0;
|
let totalSize = 0;
|
||||||
|
|
||||||
const entitySize = this.calculateObjectSize(entity, ['components', 'children', 'parent']);
|
const entitySize = this.calculateObjectSize(entity, ["components", "children", "parent"]);
|
||||||
if (!isNaN(entitySize) && entitySize > 0) {
|
if (!isNaN(entitySize) && entitySize > 0) {
|
||||||
totalSize += entitySize;
|
totalSize += entitySize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity.components && Array.isArray(entity.components)) {
|
if (entity.components && Array.isArray(entity.components)) {
|
||||||
entity.components.forEach((component: any) => {
|
entity.components.forEach((component: any) => {
|
||||||
const componentSize = this.calculateObjectSize(component, ['entity']);
|
const componentSize = this.calculateObjectSize(component, ["entity"]);
|
||||||
if (!isNaN(componentSize) && componentSize > 0) {
|
if (!isNaN(componentSize) && componentSize > 0) {
|
||||||
totalSize += componentSize;
|
totalSize += componentSize;
|
||||||
}
|
}
|
||||||
@@ -475,13 +474,13 @@ export class EntityDataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public calculateObjectSize(obj: any, excludeKeys: string[] = []): number {
|
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 visited = new WeakSet();
|
||||||
const maxDepth = 2;
|
const maxDepth = 2;
|
||||||
|
|
||||||
const calculate = (item: any, depth: number = 0): number => {
|
const calculate = (item: any, depth: number = 0): number => {
|
||||||
if (!item || typeof item !== 'object' || depth >= maxDepth) {
|
if (!item || typeof item !== "object" || depth >= maxDepth) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,25 +496,25 @@ export class EntityDataCollector {
|
|||||||
for (let i = 0; i < maxKeys; i++) {
|
for (let i = 0; i < maxKeys; i++) {
|
||||||
const key = keys[i];
|
const key = keys[i];
|
||||||
if (!key || excludeKeys.includes(key) ||
|
if (!key || excludeKeys.includes(key) ||
|
||||||
key === 'constructor' ||
|
key === "constructor" ||
|
||||||
key === '__proto__' ||
|
key === "__proto__" ||
|
||||||
key.startsWith('_cc_') ||
|
key.startsWith("_cc_") ||
|
||||||
key.startsWith('__')) {
|
key.startsWith("__")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = item[key];
|
const value = item[key];
|
||||||
itemSize += key.length * 2;
|
itemSize += key.length * 2;
|
||||||
|
|
||||||
if (typeof value === 'string') {
|
if (typeof value === "string") {
|
||||||
itemSize += Math.min(value.length * 2, 200);
|
itemSize += Math.min(value.length * 2, 200);
|
||||||
} else if (typeof value === 'number') {
|
} else if (typeof value === "number") {
|
||||||
itemSize += 8;
|
itemSize += 8;
|
||||||
} else if (typeof value === 'boolean') {
|
} else if (typeof value === "boolean") {
|
||||||
itemSize += 4;
|
itemSize += 4;
|
||||||
} else if (Array.isArray(value)) {
|
} else if (Array.isArray(value)) {
|
||||||
itemSize += 40 + Math.min(value.length * 8, 160);
|
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);
|
itemSize += calculate(value, depth + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -596,7 +595,7 @@ export class EntityDataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 优先使用Entity的getDebugInfo方法
|
// 优先使用Entity的getDebugInfo方法
|
||||||
if (typeof entity.getDebugInfo === 'function') {
|
if (typeof entity.getDebugInfo === "function") {
|
||||||
const debugInfo = entity.getDebugInfo();
|
const debugInfo = entity.getDebugInfo();
|
||||||
node = {
|
node = {
|
||||||
...node,
|
...node,
|
||||||
@@ -671,7 +670,7 @@ export class EntityDataCollector {
|
|||||||
sceneType: sceneInfo.type,
|
sceneType: sceneInfo.type,
|
||||||
componentCount: entity.components.length,
|
componentCount: entity.components.length,
|
||||||
componentTypes: entity.components.map((component: Component) => getComponentInstanceTypeName(component)),
|
componentTypes: entity.components.map((component: Component) => getComponentInstanceTypeName(component)),
|
||||||
componentMask: entity.componentMask?.toString() || '0',
|
componentMask: entity.componentMask?.toString() || "0",
|
||||||
parentId: entity.parent?.id || null,
|
parentId: entity.parent?.id || null,
|
||||||
childCount: entity.children?.length || 0,
|
childCount: entity.children?.length || 0,
|
||||||
childIds: entity.children.map((child: Entity) => child.id) || [],
|
childIds: entity.children.map((child: Entity) => child.id) || [],
|
||||||
@@ -694,8 +693,8 @@ export class EntityDataCollector {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const propertyKeys = Object.keys(component);
|
const propertyKeys = Object.keys(component);
|
||||||
propertyKeys.forEach(propertyKey => {
|
propertyKeys.forEach((propertyKey) => {
|
||||||
if (!propertyKey.startsWith('_') && propertyKey !== 'entity' && propertyKey !== 'constructor') {
|
if (!propertyKey.startsWith("_") && propertyKey !== "entity" && propertyKey !== "constructor") {
|
||||||
const propertyValue = (component as any)[propertyKey];
|
const propertyValue = (component as any)[propertyKey];
|
||||||
if (propertyValue !== undefined && propertyValue !== null) {
|
if (propertyValue !== undefined && propertyValue !== null) {
|
||||||
properties[propertyKey] = this.formatPropertyValue(propertyValue);
|
properties[propertyKey] = this.formatPropertyValue(propertyValue);
|
||||||
@@ -705,12 +704,12 @@ export class EntityDataCollector {
|
|||||||
|
|
||||||
// 如果没有找到任何属性,添加一些调试信息
|
// 如果没有找到任何属性,添加一些调试信息
|
||||||
if (Object.keys(properties).length === 0) {
|
if (Object.keys(properties).length === 0) {
|
||||||
properties['_info'] = '该组件没有公开属性';
|
properties["_info"] = "该组件没有公开属性";
|
||||||
properties['_componentId'] = getComponentInstanceTypeName(component);
|
properties["_componentId"] = getComponentInstanceTypeName(component);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
properties['_error'] = '属性提取失败';
|
properties["_error"] = "属性提取失败";
|
||||||
properties['_componentId'] = getComponentInstanceTypeName(component);
|
properties["_componentId"] = getComponentInstanceTypeName(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -740,8 +739,8 @@ export class EntityDataCollector {
|
|||||||
const properties: Record<string, any> = {};
|
const properties: Record<string, any> = {};
|
||||||
|
|
||||||
const propertyKeys = Object.keys(component);
|
const propertyKeys = Object.keys(component);
|
||||||
propertyKeys.forEach(propertyKey => {
|
propertyKeys.forEach((propertyKey) => {
|
||||||
if (!propertyKey.startsWith('_') && propertyKey !== 'entity') {
|
if (!propertyKey.startsWith("_") && propertyKey !== "entity") {
|
||||||
const propertyValue = (component as any)[propertyKey];
|
const propertyValue = (component as any)[propertyKey];
|
||||||
if (propertyValue !== undefined && propertyValue !== null) {
|
if (propertyValue !== undefined && propertyValue !== null) {
|
||||||
properties[propertyKey] = this.formatPropertyValue(propertyValue);
|
properties[propertyKey] = this.formatPropertyValue(propertyValue);
|
||||||
@@ -751,7 +750,7 @@ export class EntityDataCollector {
|
|||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { _error: '属性提取失败' };
|
return {_error: "属性提取失败"};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -763,8 +762,8 @@ export class EntityDataCollector {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof value !== 'object') {
|
if (typeof value !== "object") {
|
||||||
if (typeof value === 'string' && value.length > 200) {
|
if (typeof value === "string" && value.length > 200) {
|
||||||
return `[长字符串: ${value.length}字符] ${value.substring(0, 100)}...`;
|
return `[长字符串: ${value.length}字符] ${value.substring(0, 100)}...`;
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
@@ -786,7 +785,7 @@ export class EntityDataCollector {
|
|||||||
if (obj.length === 0) return [];
|
if (obj.length === 0) return [];
|
||||||
|
|
||||||
if (obj.length > 10) {
|
if (obj.length > 10) {
|
||||||
const sample = obj.slice(0, 3).map(item => this.formatPropertyValue(item, 1));
|
const sample = obj.slice(0, 3).map((item) => this.formatPropertyValue(item, 1));
|
||||||
return {
|
return {
|
||||||
_isLazyArray: true,
|
_isLazyArray: true,
|
||||||
_arrayLength: obj.length,
|
_arrayLength: obj.length,
|
||||||
@@ -795,7 +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);
|
const keys = Object.keys(obj);
|
||||||
@@ -813,7 +812,7 @@ export class EntityDataCollector {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key.startsWith('_') || key.startsWith('$') || typeof obj[key] === 'function') {
|
if (key.startsWith("_") || key.startsWith("$") || typeof obj[key] === "function") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -840,7 +839,7 @@ export class EntityDataCollector {
|
|||||||
*/
|
*/
|
||||||
private createLazyLoadPlaceholder(obj: any): any {
|
private createLazyLoadPlaceholder(obj: any): any {
|
||||||
try {
|
try {
|
||||||
const typeName = obj.constructor?.name || 'Object';
|
const typeName = obj.constructor?.name || "Object";
|
||||||
const summary = this.getObjectSummary(obj, typeName);
|
const summary = this.getObjectSummary(obj, typeName);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -852,7 +851,7 @@ export class EntityDataCollector {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
_isLazyObject: true,
|
_isLazyObject: true,
|
||||||
_typeName: 'Unknown',
|
_typeName: "Unknown",
|
||||||
_summary: `无法分析的对象: ${error instanceof Error ? error.message : String(error)}`,
|
_summary: `无法分析的对象: ${error instanceof Error ? error.message : String(error)}`,
|
||||||
_objectId: Math.random().toString(36).substr(2, 9)
|
_objectId: Math.random().toString(36).substr(2, 9)
|
||||||
};
|
};
|
||||||
@@ -864,28 +863,28 @@ export class EntityDataCollector {
|
|||||||
*/
|
*/
|
||||||
private getObjectSummary(obj: any, typeName: string): string {
|
private getObjectSummary(obj: any, typeName: string): string {
|
||||||
try {
|
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) {
|
if (obj.x !== undefined && obj.y !== undefined) {
|
||||||
const z = obj.z !== undefined ? obj.z : '';
|
const z = obj.z !== undefined ? obj.z : "";
|
||||||
return `${typeName}(${obj.x}, ${obj.y}${z ? ', ' + 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) {
|
if (obj.r !== undefined && obj.g !== undefined && obj.b !== undefined) {
|
||||||
const a = obj.a !== undefined ? obj.a : 1;
|
const a = obj.a !== undefined ? obj.a : 1;
|
||||||
return `${typeName}(${obj.r}, ${obj.g}, ${obj.b}, ${a})`;
|
return `${typeName}(${obj.r}, ${obj.g}, ${obj.b}, ${a})`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeName.toLowerCase().includes('node')) {
|
if (typeName.toLowerCase().includes("node")) {
|
||||||
const name = obj.name || obj._name || '未命名';
|
const name = obj.name || obj._name || "未命名";
|
||||||
return `${typeName}: ${name}`;
|
return `${typeName}: ${name}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeName.toLowerCase().includes('component')) {
|
if (typeName.toLowerCase().includes("component")) {
|
||||||
const nodeName = obj.node?.name || obj.node?._name || '';
|
const nodeName = obj.node?.name || obj.node?._name || "";
|
||||||
return `${typeName}${nodeName ? ` on ${nodeName}` : ''}`;
|
return `${typeName}${nodeName ? ` on ${nodeName}` : ""}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys = Object.keys(obj);
|
const keys = Object.keys(obj);
|
||||||
@@ -956,16 +955,16 @@ export class EntityDataCollector {
|
|||||||
private getObjectByPath(root: any, path: string): any {
|
private getObjectByPath(root: any, path: string): any {
|
||||||
if (!path) return root;
|
if (!path) return root;
|
||||||
|
|
||||||
const parts = path.split('.');
|
const parts = path.split(".");
|
||||||
let current = root;
|
let current = root;
|
||||||
|
|
||||||
for (const part of parts) {
|
for (const part of parts) {
|
||||||
if (current === null || current === undefined) return null;
|
if (current === null || current === undefined) return null;
|
||||||
|
|
||||||
// 处理数组索引
|
// 处理数组索引
|
||||||
if (part.includes('[') && part.includes(']')) {
|
if (part.includes("[") && part.includes("]")) {
|
||||||
const arrayName = part.substring(0, part.indexOf('['));
|
const arrayName = part.substring(0, part.indexOf("["));
|
||||||
const index = parseInt(part.substring(part.indexOf('[') + 1, part.indexOf(']')));
|
const index = parseInt(part.substring(part.indexOf("[") + 1, part.indexOf("]")));
|
||||||
|
|
||||||
if (arrayName) {
|
if (arrayName) {
|
||||||
current = current[arrayName];
|
current = current[arrayName];
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { IPerformanceDebugData } from '../../Types';
|
import {IPerformanceDebugData} from "../../Types";
|
||||||
import { Time } from '../Time';
|
import {Time} from "../Time";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 性能数据收集器
|
* 性能数据收集器
|
||||||
@@ -34,7 +34,7 @@ export class PerformanceDataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 计算ECS执行时间统计
|
// 计算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 averageECSTime = history.length > 0 ? history.reduce((a, b) => a + b, 0) / history.length : ecsExecutionTimeMs;
|
||||||
const minECSTime = history.length > 0 ? Math.min(...history) : ecsExecutionTimeMs;
|
const minECSTime = history.length > 0 ? Math.min(...history) : ecsExecutionTimeMs;
|
||||||
const maxECSTime = history.length > 0 ? Math.max(...history) : ecsExecutionTimeMs;
|
const maxECSTime = history.length > 0 ? Math.max(...history) : ecsExecutionTimeMs;
|
||||||
@@ -100,7 +100,7 @@ export class PerformanceDataCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 计算各系统占ECS总时间的百分比
|
// 计算各系统占ECS总时间的百分比
|
||||||
systemBreakdown.forEach(system => {
|
systemBreakdown.forEach((system) => {
|
||||||
system.percentage = totalTime > 0 ? (system.executionTime / totalTime * 100) : 0;
|
system.percentage = totalTime > 0 ? (system.executionTime / totalTime * 100) : 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -202,7 +202,7 @@ export class PerformanceDataCollector {
|
|||||||
private updateGCCount(): number {
|
private updateGCCount(): number {
|
||||||
try {
|
try {
|
||||||
// 尝试使用PerformanceObserver来检测GC
|
// 尝试使用PerformanceObserver来检测GC
|
||||||
if (typeof PerformanceObserver !== 'undefined') {
|
if (typeof PerformanceObserver !== "undefined") {
|
||||||
// 这是一个简化的GC检测方法
|
// 这是一个简化的GC检测方法
|
||||||
// 实际的GC检测需要更复杂的逻辑
|
// 实际的GC检测需要更复杂的逻辑
|
||||||
return this.gcCollections;
|
return this.gcCollections;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ISceneDebugData } from '../../Types';
|
import {ISceneDebugData} from "../../Types";
|
||||||
import { IScene } from '../../ECS/IScene';
|
import {IScene} from "../../ECS/IScene";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 场景数据收集器
|
* 场景数据收集器
|
||||||
@@ -14,7 +14,7 @@ export class SceneDataCollector {
|
|||||||
public collectSceneData(scene?: IScene | null): ISceneDebugData {
|
public collectSceneData(scene?: IScene | null): ISceneDebugData {
|
||||||
if (!scene) {
|
if (!scene) {
|
||||||
return {
|
return {
|
||||||
currentSceneName: 'No Scene',
|
currentSceneName: "No Scene",
|
||||||
isInitialized: false,
|
isInitialized: false,
|
||||||
sceneRunTime: 0,
|
sceneRunTime: 0,
|
||||||
sceneEntityCount: 0,
|
sceneEntityCount: 0,
|
||||||
@@ -31,7 +31,7 @@ export class SceneDataCollector {
|
|||||||
const entityProcessors = (scene as any).entityProcessors;
|
const entityProcessors = (scene as any).entityProcessors;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
currentSceneName: (scene as any).name || 'Unnamed Scene',
|
currentSceneName: (scene as any).name || "Unnamed Scene",
|
||||||
isInitialized: (scene as any)._didSceneBegin || false,
|
isInitialized: (scene as any)._didSceneBegin || false,
|
||||||
sceneRunTime: runTime,
|
sceneRunTime: runTime,
|
||||||
sceneEntityCount: entityList?.buffer?.length || 0,
|
sceneEntityCount: entityList?.buffer?.length || 0,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ISystemDebugData } from '../../Types';
|
import {ISystemDebugData} from "../../Types";
|
||||||
import { getSystemInstanceTypeName } from '../../ECS/Decorators';
|
import {getSystemInstanceTypeName} from "../../ECS/Decorators";
|
||||||
import { IScene } from '../../ECS/IScene';
|
import {IScene} from "../../ECS/IScene";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统数据收集器
|
* 系统数据收集器
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export class WebSocketManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const message = typeof data === 'string' ? data : JSON.stringify(data);
|
const message = typeof data === "string" ? data : JSON.stringify(data);
|
||||||
this.ws.send(message);
|
this.ws.send(message);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ export class WebSocketManager {
|
|||||||
this.reconnectAttempts++;
|
this.reconnectAttempts++;
|
||||||
|
|
||||||
this.reconnectTimer = setTimeout(() => {
|
this.reconnectTimer = setTimeout(() => {
|
||||||
this.connect().catch(_error => {
|
this.connect().catch((_error) => {
|
||||||
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
||||||
this.scheduleReconnect();
|
this.scheduleReconnect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
export { EntityDataCollector } from './EntityDataCollector';
|
export {EntityDataCollector} from "./EntityDataCollector";
|
||||||
export { SystemDataCollector } from './SystemDataCollector';
|
export {SystemDataCollector} from "./SystemDataCollector";
|
||||||
export { PerformanceDataCollector } from './PerformanceDataCollector';
|
export {PerformanceDataCollector} from "./PerformanceDataCollector";
|
||||||
export { ComponentDataCollector } from './ComponentDataCollector';
|
export {ComponentDataCollector} from "./ComponentDataCollector";
|
||||||
export { SceneDataCollector } from './SceneDataCollector';
|
export {SceneDataCollector} from "./SceneDataCollector";
|
||||||
export { WebSocketManager } from './WebSocketManager';
|
export {WebSocketManager} from "./WebSocketManager";
|
||||||
export { DebugManager } from './DebugManager';
|
export {DebugManager} from "./DebugManager";
|
||||||
export { DebugConfigService } from './DebugConfigService';
|
export {DebugConfigService} from "./DebugConfigService";
|
||||||
|
|||||||
@@ -47,9 +47,9 @@ export class Emitter<T, TContext = unknown> {
|
|||||||
* @param handler 事件函数
|
* @param handler 事件函数
|
||||||
*/
|
*/
|
||||||
public removeObserver(eventType: T, handler: Function) {
|
public removeObserver(eventType: T, handler: Function) {
|
||||||
let messageData = this._messageTable.get(eventType);
|
const messageData = this._messageTable.get(eventType);
|
||||||
if (messageData) {
|
if (messageData) {
|
||||||
let index = messageData.findIndex(data => data.func == handler);
|
const index = messageData.findIndex((data) => data.func == handler);
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
messageData.splice(index, 1);
|
messageData.splice(index, 1);
|
||||||
}
|
}
|
||||||
@@ -61,9 +61,9 @@ export class Emitter<T, TContext = unknown> {
|
|||||||
* @param data 事件数据
|
* @param data 事件数据
|
||||||
*/
|
*/
|
||||||
public emit<TData = unknown>(eventType: T, ...data: TData[]) {
|
public emit<TData = unknown>(eventType: T, ...data: TData[]) {
|
||||||
let list = this._messageTable.get(eventType);
|
const list = this._messageTable.get(eventType);
|
||||||
if (list) {
|
if (list) {
|
||||||
for (let observer of list) {
|
for (const observer of list) {
|
||||||
observer.func.call(observer.context, ...data);
|
observer.func.call(observer.context, ...data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,8 +75,8 @@ export class Emitter<T, TContext = unknown> {
|
|||||||
* @param handler 事件函数
|
* @param handler 事件函数
|
||||||
*/
|
*/
|
||||||
public hasObserver(eventType: T, handler: Function): boolean {
|
public hasObserver(eventType: T, handler: Function): boolean {
|
||||||
let list = this._messageTable.get(eventType);
|
const list = this._messageTable.get(eventType);
|
||||||
return list ? list.some(observer => observer.func === handler) : false;
|
return list ? list.some((observer) => observer.func === handler) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// 扩展工具类导出
|
// 扩展工具类导出
|
||||||
export { TypeUtils } from './TypeUtils';
|
export {TypeUtils} from "./TypeUtils";
|
||||||
export { NumberExtension } from './NumberExtension';
|
export {NumberExtension} from "./NumberExtension";
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export class ConsoleLogger implements ILogger {
|
|||||||
this._config = {
|
this._config = {
|
||||||
level: LogLevel.Info,
|
level: LogLevel.Info,
|
||||||
enableTimestamp: true,
|
enableTimestamp: true,
|
||||||
enableColors: typeof window === 'undefined',
|
enableColors: typeof window === "undefined",
|
||||||
...config
|
...config
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,27 +15,27 @@ export enum LogLevel {
|
|||||||
*/
|
*/
|
||||||
export const Colors = {
|
export const Colors = {
|
||||||
// 基础颜色
|
// 基础颜色
|
||||||
BLACK: '\x1b[30m',
|
BLACK: "\x1b[30m",
|
||||||
RED: '\x1b[31m',
|
RED: "\x1b[31m",
|
||||||
GREEN: '\x1b[32m',
|
GREEN: "\x1b[32m",
|
||||||
YELLOW: '\x1b[33m',
|
YELLOW: "\x1b[33m",
|
||||||
BLUE: '\x1b[34m',
|
BLUE: "\x1b[34m",
|
||||||
MAGENTA: '\x1b[35m',
|
MAGENTA: "\x1b[35m",
|
||||||
CYAN: '\x1b[36m',
|
CYAN: "\x1b[36m",
|
||||||
WHITE: '\x1b[37m',
|
WHITE: "\x1b[37m",
|
||||||
|
|
||||||
// 亮色版本
|
// 亮色版本
|
||||||
BRIGHT_BLACK: '\x1b[90m',
|
BRIGHT_BLACK: "\x1b[90m",
|
||||||
BRIGHT_RED: '\x1b[91m',
|
BRIGHT_RED: "\x1b[91m",
|
||||||
BRIGHT_GREEN: '\x1b[92m',
|
BRIGHT_GREEN: "\x1b[92m",
|
||||||
BRIGHT_YELLOW: '\x1b[93m',
|
BRIGHT_YELLOW: "\x1b[93m",
|
||||||
BRIGHT_BLUE: '\x1b[94m',
|
BRIGHT_BLUE: "\x1b[94m",
|
||||||
BRIGHT_MAGENTA: '\x1b[95m',
|
BRIGHT_MAGENTA: "\x1b[95m",
|
||||||
BRIGHT_CYAN: '\x1b[96m',
|
BRIGHT_CYAN: "\x1b[96m",
|
||||||
BRIGHT_WHITE: '\x1b[97m',
|
BRIGHT_WHITE: "\x1b[97m",
|
||||||
|
|
||||||
// 特殊
|
// 特殊
|
||||||
RESET: '\x1b[0m',
|
RESET: "\x1b[0m",
|
||||||
BOLD: '\x1b[1m',
|
BOLD: "\x1b[1m",
|
||||||
UNDERLINE: '\x1b[4m'
|
UNDERLINE: "\x1b[4m"
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -136,8 +136,8 @@ export class LoggerManager {
|
|||||||
public setLoggerFactory(factory: (name?: string) => ILogger): void {
|
public setLoggerFactory(factory: (name?: string) => ILogger): void {
|
||||||
if (this._defaultLogger || this._loggers.size > 0) {
|
if (this._defaultLogger || this._loggers.size > 0) {
|
||||||
console.warn(
|
console.warn(
|
||||||
'[LoggerManager] setLoggerFactory 应该在导入 ECS 模块之前调用。' +
|
"[LoggerManager] setLoggerFactory 应该在导入 ECS 模块之前调用。" +
|
||||||
'已创建的 logger 引用不会被更新。'
|
"已创建的 logger 引用不会被更新。"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export * from './ConsoleLogger';
|
export * from "./ConsoleLogger";
|
||||||
export * from './Constants';
|
export * from "./Constants";
|
||||||
export * from './LoggerManager';
|
export * from "./LoggerManager";
|
||||||
export * from './Types';
|
export * from "./Types";
|
||||||
|
|||||||
@@ -46,12 +46,12 @@ export interface PerformanceStats {
|
|||||||
* 性能警告类型
|
* 性能警告类型
|
||||||
*/
|
*/
|
||||||
export enum PerformanceWarningType {
|
export enum PerformanceWarningType {
|
||||||
HIGH_EXECUTION_TIME = 'high_execution_time',
|
HIGH_EXECUTION_TIME = "high_execution_time",
|
||||||
HIGH_MEMORY_USAGE = 'high_memory_usage',
|
HIGH_MEMORY_USAGE = "high_memory_usage",
|
||||||
HIGH_CPU_USAGE = 'high_cpu_usage',
|
HIGH_CPU_USAGE = "high_cpu_usage",
|
||||||
FREQUENT_GC = 'frequent_gc',
|
FREQUENT_GC = "frequent_gc",
|
||||||
LOW_FPS = 'low_fps',
|
LOW_FPS = "low_fps",
|
||||||
HIGH_ENTITY_COUNT = 'high_entity_count'
|
HIGH_ENTITY_COUNT = "high_entity_count"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,7 +61,7 @@ export interface PerformanceWarning {
|
|||||||
type: PerformanceWarningType;
|
type: PerformanceWarningType;
|
||||||
systemName: string;
|
systemName: string;
|
||||||
message: string;
|
message: string;
|
||||||
severity: 'low' | 'medium' | 'high' | 'critical';
|
severity: "low" | "medium" | "high" | "critical";
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
value: number;
|
value: number;
|
||||||
threshold: number;
|
threshold: number;
|
||||||
@@ -99,7 +99,7 @@ export interface PerformanceThresholds {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
import type { IService } from '../Core/ServiceContainer';
|
import type {IService} from "../Core/ServiceContainer";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 高性能监控器
|
* 高性能监控器
|
||||||
@@ -310,7 +310,7 @@ export class PerformanceMonitor implements IService {
|
|||||||
lines.push(`Total Frame Time: ${totalCurrentTime.toFixed(2)}ms`);
|
lines.push(`Total Frame Time: ${totalCurrentTime.toFixed(2)}ms`);
|
||||||
lines.push(`Systems Count: ${this._systemData.size}`);
|
lines.push(`Systems Count: ${this._systemData.size}`);
|
||||||
|
|
||||||
return lines.join('\n');
|
return lines.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { IPoolable, PoolStats } from './IPoolable';
|
import {IPoolable, PoolStats} from "./IPoolable";
|
||||||
|
|
||||||
|
type Constructor<T = unknown> = new (...args: unknown[]) => T;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 高性能通用对象池
|
* 高性能通用对象池
|
||||||
* 支持任意类型的对象池化,包含详细的统计信息
|
* 支持任意类型的对象池化,包含详细的统计信息
|
||||||
*/
|
*/
|
||||||
export class Pool<T extends IPoolable> {
|
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 _objects: T[] = [];
|
||||||
private _createFn: () => T;
|
private _createFn: () => T;
|
||||||
@@ -197,7 +199,7 @@ export class Pool<T extends IPoolable> {
|
|||||||
* 获取所有已注册的池类型
|
* 获取所有已注册的池类型
|
||||||
* @returns 所有池类型的数组
|
* @returns 所有池类型的数组
|
||||||
*/
|
*/
|
||||||
public static getAllPoolTypes(): Function[] {
|
public static getAllPoolTypes(): Constructor[] {
|
||||||
return Array.from(this._pools.keys());
|
return Array.from(this._pools.keys());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,11 +243,11 @@ export class Pool<T extends IPoolable> {
|
|||||||
*/
|
*/
|
||||||
public static getGlobalStatsString(): string {
|
public static getGlobalStatsString(): string {
|
||||||
const stats = this.getAllPoolStats();
|
const stats = this.getAllPoolStats();
|
||||||
const lines: string[] = ['=== Object Pool Global Statistics ===', ''];
|
const lines: string[] = ["=== Object Pool Global Statistics ===", ""];
|
||||||
|
|
||||||
if (Object.keys(stats).length === 0) {
|
if (Object.keys(stats).length === 0) {
|
||||||
lines.push('No pools registered');
|
lines.push("No pools registered");
|
||||||
return lines.join('\n');
|
return lines.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [typeName, stat] of Object.entries(stats)) {
|
for (const [typeName, stat] of Object.entries(stats)) {
|
||||||
@@ -255,10 +257,10 @@ export class Pool<T extends IPoolable> {
|
|||||||
lines.push(` Total Created: ${stat.totalCreated}`);
|
lines.push(` Total Created: ${stat.totalCreated}`);
|
||||||
lines.push(` Total Obtained: ${stat.totalObtained}`);
|
lines.push(` Total Obtained: ${stat.totalObtained}`);
|
||||||
lines.push(` Memory: ${(stat.estimatedMemoryUsage / 1024).toFixed(1)} KB`);
|
lines.push(` Memory: ${(stat.estimatedMemoryUsage / 1024).toFixed(1)} KB`);
|
||||||
lines.push('');
|
lines.push("");
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines.join('\n');
|
return lines.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { IPoolable, PoolStats } from './IPoolable';
|
import {IPoolable, PoolStats} from "./IPoolable";
|
||||||
import { Pool } from './Pool';
|
import {Pool} from "./Pool";
|
||||||
import type { IService } from '../../Core/ServiceContainer';
|
import type {IService} from "../../Core/ServiceContainer";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 池管理器
|
* 池管理器
|
||||||
@@ -173,18 +173,18 @@ export class PoolManager implements IService {
|
|||||||
* @returns 格式化字符串
|
* @returns 格式化字符串
|
||||||
*/
|
*/
|
||||||
public getStatsString(): string {
|
public getStatsString(): string {
|
||||||
const lines: string[] = ['=== Pool Manager Statistics ===', ''];
|
const lines: string[] = ["=== Pool Manager Statistics ===", ""];
|
||||||
|
|
||||||
if (this.pools.size === 0) {
|
if (this.pools.size === 0) {
|
||||||
lines.push('No pools registered');
|
lines.push("No pools registered");
|
||||||
return lines.join('\n');
|
return lines.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalStats = this.getGlobalStats();
|
const globalStats = this.getGlobalStats();
|
||||||
lines.push(`Total Pools: ${this.pools.size}`);
|
lines.push(`Total Pools: ${this.pools.size}`);
|
||||||
lines.push(`Global Hit Rate: ${(globalStats.hitRate * 100).toFixed(1)}%`);
|
lines.push(`Global Hit Rate: ${(globalStats.hitRate * 100).toFixed(1)}%`);
|
||||||
lines.push(`Global Memory Usage: ${(globalStats.estimatedMemoryUsage / 1024).toFixed(1)} KB`);
|
lines.push(`Global Memory Usage: ${(globalStats.estimatedMemoryUsage / 1024).toFixed(1)} KB`);
|
||||||
lines.push('');
|
lines.push("");
|
||||||
|
|
||||||
for (const [name, pool] of this.pools) {
|
for (const [name, pool] of this.pools) {
|
||||||
const stats = pool.getStats();
|
const stats = pool.getStats();
|
||||||
@@ -192,10 +192,10 @@ export class PoolManager implements IService {
|
|||||||
lines.push(` Size: ${stats.size}/${stats.maxSize}`);
|
lines.push(` Size: ${stats.size}/${stats.maxSize}`);
|
||||||
lines.push(` Hit Rate: ${(stats.hitRate * 100).toFixed(1)}%`);
|
lines.push(` Hit Rate: ${(stats.hitRate * 100).toFixed(1)}%`);
|
||||||
lines.push(` Memory: ${(stats.estimatedMemoryUsage / 1024).toFixed(1)} KB`);
|
lines.push(` Memory: ${(stats.estimatedMemoryUsage / 1024).toFixed(1)} KB`);
|
||||||
lines.push('');
|
lines.push("");
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines.join('\n');
|
return lines.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export * from './IPoolable';
|
export * from "./IPoolable";
|
||||||
export * from './Pool';
|
export * from "./Pool";
|
||||||
export * from './PoolManager';
|
export * from "./PoolManager";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ITimer } from './ITimer';
|
import {ITimer} from "./ITimer";
|
||||||
import { Time } from '../Time';
|
import {Time} from "../Time";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 私有类隐藏ITimer的实现
|
* 私有类隐藏ITimer的实现
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Timer } from './Timer';
|
import {Timer} from "./Timer";
|
||||||
import { ITimer } from './ITimer';
|
import {ITimer} from "./ITimer";
|
||||||
import type { IService } from '../../Core/ServiceContainer';
|
import type {IService} from "../../Core/ServiceContainer";
|
||||||
import type { IUpdatable } from '../../Types/IUpdatable';
|
import type {IUpdatable} from "../../Types/IUpdatable";
|
||||||
import { Updatable } from '../../Core/DI';
|
import {Updatable} from "../../Core/DI";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 定时器管理器
|
* 定时器管理器
|
||||||
@@ -30,7 +30,7 @@ export class TimerManager implements IService, IUpdatable {
|
|||||||
* @param onTime
|
* @param onTime
|
||||||
*/
|
*/
|
||||||
public schedule<TContext = unknown>(timeInSeconds: number, repeats: boolean, context: TContext, onTime: (timer: ITimer<TContext>)=>void): Timer<TContext> {
|
public schedule<TContext = unknown>(timeInSeconds: number, repeats: boolean, context: TContext, onTime: (timer: ITimer<TContext>)=>void): Timer<TContext> {
|
||||||
let timer = new Timer<TContext>();
|
const timer = new Timer<TContext>();
|
||||||
timer.initialize(timeInSeconds, repeats, context, onTime);
|
timer.initialize(timeInSeconds, repeats, context, onTime);
|
||||||
this._timers.push(timer as Timer<unknown>);
|
this._timers.push(timer as Timer<unknown>);
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
export * from './Extensions';
|
export * from "./Extensions";
|
||||||
export * from './Pool';
|
export * from "./Pool";
|
||||||
export * from './Emitter';
|
export * from "./Emitter";
|
||||||
export * from './GlobalManager';
|
export * from "./GlobalManager";
|
||||||
export * from './PerformanceMonitor';
|
export * from "./PerformanceMonitor";
|
||||||
export { Time } from './Time';
|
export {Time} from "./Time";
|
||||||
export * from './Debug';
|
export * from "./Debug";
|
||||||
export * from './Logger';
|
export * from "./Logger";
|
||||||
export * from './BinarySerializer';
|
export * from "./BinarySerializer";
|
||||||
|
|||||||
+24
-24
@@ -4,17 +4,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// 核心模块
|
// 核心模块
|
||||||
export { Core } from './Core';
|
export {Core} from "./Core";
|
||||||
export { ServiceContainer, ServiceLifetime } from './Core/ServiceContainer';
|
export {ServiceContainer, ServiceLifetime} from "./Core/ServiceContainer";
|
||||||
export type { IService, ServiceType } from './Core/ServiceContainer';
|
export type {IService, ServiceType} from "./Core/ServiceContainer";
|
||||||
|
|
||||||
// 插件系统
|
// 插件系统
|
||||||
export { PluginManager } from './Core/PluginManager';
|
export {PluginManager} from "./Core/PluginManager";
|
||||||
export { PluginState } from './Core/Plugin';
|
export {PluginState} from "./Core/Plugin";
|
||||||
export type { IPlugin, IPluginMetadata } from './Core/Plugin';
|
export type {IPlugin, IPluginMetadata} from "./Core/Plugin";
|
||||||
|
|
||||||
// 内置插件
|
// 内置插件
|
||||||
export * from './Plugins';
|
export * from "./Plugins";
|
||||||
|
|
||||||
// 依赖注入
|
// 依赖注入
|
||||||
export {
|
export {
|
||||||
@@ -25,15 +25,15 @@ export {
|
|||||||
createInstance,
|
createInstance,
|
||||||
isUpdatable,
|
isUpdatable,
|
||||||
getUpdatableMetadata
|
getUpdatableMetadata
|
||||||
} from './Core/DI';
|
} from "./Core/DI";
|
||||||
export type { InjectableMetadata, UpdatableMetadata } from './Core/DI';
|
export type {InjectableMetadata, UpdatableMetadata} from "./Core/DI";
|
||||||
|
|
||||||
// 核心管理器
|
// 核心管理器
|
||||||
export { Emitter, FuncPack } from './Utils/Emitter';
|
export {Emitter, FuncPack} from "./Utils/Emitter";
|
||||||
export { GlobalManager } from './Utils/GlobalManager';
|
export {GlobalManager} from "./Utils/GlobalManager";
|
||||||
export { TimerManager } from './Utils/Timers/TimerManager';
|
export {TimerManager} from "./Utils/Timers/TimerManager";
|
||||||
export { ITimer } from './Utils/Timers/ITimer';
|
export {ITimer} from "./Utils/Timers/ITimer";
|
||||||
export { Timer } from './Utils/Timers/Timer';
|
export {Timer} from "./Utils/Timers/Timer";
|
||||||
|
|
||||||
// 日志系统
|
// 日志系统
|
||||||
export {
|
export {
|
||||||
@@ -43,25 +43,25 @@ export {
|
|||||||
createLogger,
|
createLogger,
|
||||||
setGlobalLogLevel,
|
setGlobalLogLevel,
|
||||||
LogLevel
|
LogLevel
|
||||||
} from './Utils/Logger';
|
} from "./Utils/Logger";
|
||||||
export type { ILogger, LoggerConfig } from './Utils/Logger';
|
export type {ILogger, LoggerConfig} from "./Utils/Logger";
|
||||||
|
|
||||||
// ECS核心组件
|
// ECS核心组件
|
||||||
export * from './ECS';
|
export * from "./ECS";
|
||||||
|
|
||||||
// TypeScript类型增强API
|
// TypeScript类型增强API
|
||||||
export * from './ECS/TypedEntity';
|
export * from "./ECS/TypedEntity";
|
||||||
export * from './ECS/Core/Query/TypedQuery';
|
export * from "./ECS/Core/Query/TypedQuery";
|
||||||
|
|
||||||
// 事件系统
|
// 事件系统
|
||||||
export { ECSEventType, EventPriority, EVENT_TYPES, EventTypeValidator } from './ECS/CoreEvents';
|
export {ECSEventType, EventPriority, EVENT_TYPES, EventTypeValidator} from "./ECS/CoreEvents";
|
||||||
|
|
||||||
// 工具类和类型定义
|
// 工具类和类型定义
|
||||||
export * from './Utils';
|
export * from "./Utils";
|
||||||
export * from './Types';
|
export * from "./Types";
|
||||||
|
|
||||||
// 显式导出ComponentPool类(解决与Types中ComponentPool接口的命名冲突)
|
// 显式导出ComponentPool类(解决与Types中ComponentPool接口的命名冲突)
|
||||||
export { ComponentPool, ComponentPoolManager } from './ECS/Core/Storage';
|
export {ComponentPool, ComponentPoolManager} from "./ECS/Core/Storage";
|
||||||
|
|
||||||
// 平台适配
|
// 平台适配
|
||||||
export * from './Platform';
|
export * from "./Platform";
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ describe('Component - 组件基类测试', () => {
|
|||||||
let scene: Scene;
|
let scene: Scene;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
Component._idGenerator = 0;
|
|
||||||
component = new TestComponent();
|
component = new TestComponent();
|
||||||
scene = new Scene();
|
scene = new Scene();
|
||||||
entity = scene.createEntity('TestEntity');
|
entity = scene.createEntity('TestEntity');
|
||||||
@@ -51,7 +50,7 @@ describe('Component - 组件基类测试', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('组件ID应该递增分配', () => {
|
test('组件ID应该递增分配', () => {
|
||||||
const startId = Component._idGenerator;
|
const startId = Component.nextComponentId;
|
||||||
const component1 = new TestComponent();
|
const component1 = new TestComponent();
|
||||||
const component2 = new TestComponent();
|
const component2 = new TestComponent();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user