更新network库及core库优化
This commit is contained in:
@@ -7,6 +7,7 @@ import { PerformanceMonitor } from './Utils/PerformanceMonitor';
|
||||
import { PoolManager } from './Utils/Pool/PoolManager';
|
||||
import { ECSFluentAPI, createECSAPI } from './ECS/Core/FluentAPI';
|
||||
import { Scene } from './ECS/Scene';
|
||||
import { IScene } from './ECS/IScene';
|
||||
import { DebugManager } from './Utils/Debug';
|
||||
import { ICoreConfig, IECSDebugConfig } from './Types';
|
||||
import { BigIntFactory, EnvironmentInfo } from './ECS/Utils/BigIntCompatibility';
|
||||
@@ -75,7 +76,7 @@ export class Core {
|
||||
*
|
||||
* 存储下一帧要切换到的场景实例。
|
||||
*/
|
||||
public _nextScene: Scene | null = null;
|
||||
public _nextScene: IScene | null = null;
|
||||
|
||||
/**
|
||||
* 全局管理器集合
|
||||
@@ -115,7 +116,7 @@ export class Core {
|
||||
/**
|
||||
* 当前活动场景
|
||||
*/
|
||||
public _scene?: Scene;
|
||||
public _scene?: IScene;
|
||||
|
||||
/**
|
||||
* 调试管理器
|
||||
@@ -197,7 +198,7 @@ export class Core {
|
||||
*
|
||||
* @returns 当前场景实例,如果没有则返回null
|
||||
*/
|
||||
public static get scene(): Scene | null {
|
||||
public static get scene(): IScene | null {
|
||||
if (!this._instance)
|
||||
return null;
|
||||
return this._instance._scene || null;
|
||||
@@ -209,24 +210,41 @@ export class Core {
|
||||
* 如果当前没有场景,会立即切换;否则会在下一帧切换。
|
||||
*
|
||||
* @param value - 要设置的场景实例
|
||||
* @throws {Error} 当场景为空时抛出错误
|
||||
*/
|
||||
public static set scene(value: Scene | null) {
|
||||
public static set scene(value: IScene | null) {
|
||||
if (!value) return;
|
||||
|
||||
if (!value) {
|
||||
throw new Error("场景不能为空");
|
||||
}
|
||||
|
||||
if (this._instance._scene == null) {
|
||||
this._instance._scene = value;
|
||||
this._instance.onSceneChanged();
|
||||
this._instance._scene.begin();
|
||||
this._instance.setSceneInternal(value);
|
||||
} else {
|
||||
this._instance._nextScene = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型安全的场景设置方法
|
||||
*
|
||||
* @param scene - 要设置的场景实例
|
||||
* @returns 设置的场景实例
|
||||
*/
|
||||
public static setScene<T extends IScene>(scene: T): T {
|
||||
if (this._instance._scene == null) {
|
||||
this._instance.setSceneInternal(scene);
|
||||
} else {
|
||||
this._instance._nextScene = scene;
|
||||
}
|
||||
return scene;
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型安全的场景获取方法
|
||||
*
|
||||
* @returns 当前场景实例
|
||||
*/
|
||||
public static getScene<T extends IScene>(): T | null {
|
||||
return this._instance?._scene as T || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Core实例
|
||||
*
|
||||
@@ -327,8 +345,11 @@ export class Core {
|
||||
* @param onTime - 定时器触发时的回调函数
|
||||
* @returns 创建的定时器实例
|
||||
*/
|
||||
public static schedule<TContext = unknown>(timeInSeconds: number, repeats: boolean = false, context: TContext = null as any, onTime: (timer: ITimer<TContext>) => void): Timer<TContext> {
|
||||
return this._instance._timerManager.schedule(timeInSeconds, repeats, context, onTime);
|
||||
public static schedule<TContext = unknown>(timeInSeconds: number, repeats: boolean = false, context?: TContext, onTime?: (timer: ITimer<TContext>) => void): Timer<TContext> {
|
||||
if (!onTime) {
|
||||
throw new Error('onTime callback is required');
|
||||
}
|
||||
return this._instance._timerManager.schedule(timeInSeconds, repeats, context as TContext, onTime);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -383,7 +404,7 @@ export class Core {
|
||||
*
|
||||
* @returns 当前调试数据,如果调试未启用则返回null
|
||||
*/
|
||||
public static getDebugData(): any {
|
||||
public static getDebugData(): unknown {
|
||||
if (!this._instance?._debugManager) {
|
||||
return null;
|
||||
}
|
||||
@@ -418,6 +439,17 @@ export class Core {
|
||||
return this._instance?._environmentInfo.supportsBigInt || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部场景设置方法
|
||||
*
|
||||
* @param scene - 要设置的场景实例
|
||||
*/
|
||||
private setSceneInternal(scene: IScene): void {
|
||||
this._scene = scene;
|
||||
this.onSceneChanged();
|
||||
this._scene.begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景切换回调
|
||||
*
|
||||
@@ -427,14 +459,27 @@ export class Core {
|
||||
Time.sceneChanged();
|
||||
|
||||
// 初始化ECS API(如果场景支持)
|
||||
if (this._scene && typeof (this._scene as any).querySystem !== 'undefined') {
|
||||
const scene = this._scene as any;
|
||||
this._ecsAPI = createECSAPI(scene, scene.querySystem, scene.eventSystem);
|
||||
if (this._scene && this._scene.querySystem && this._scene.eventSystem) {
|
||||
this._ecsAPI = createECSAPI(this._scene, this._scene.querySystem, this._scene.eventSystem);
|
||||
}
|
||||
|
||||
// 通知调试管理器场景已变更
|
||||
// 延迟调试管理器通知,避免在场景初始化过程中干扰属性
|
||||
if (this._debugManager) {
|
||||
this._debugManager.onSceneChanged();
|
||||
// 使用 requestAnimationFrame 确保在场景完全初始化后再收集数据
|
||||
if (typeof requestAnimationFrame !== 'undefined') {
|
||||
requestAnimationFrame(() => {
|
||||
if (this._debugManager) {
|
||||
this._debugManager.onSceneChanged();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 兜底:使用 setTimeout
|
||||
setTimeout(() => {
|
||||
if (this._debugManager) {
|
||||
this._debugManager.onSceneChanged();
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,8 +525,8 @@ export class Core {
|
||||
Time.update(deltaTime);
|
||||
|
||||
// 更新FPS监控(如果性能监控器支持)
|
||||
if (typeof (this._performanceMonitor as any).updateFPS === 'function') {
|
||||
(this._performanceMonitor as any).updateFPS(Time.deltaTime);
|
||||
if ('updateFPS' in this._performanceMonitor && typeof this._performanceMonitor.updateFPS === 'function') {
|
||||
this._performanceMonitor.updateFPS(Time.deltaTime);
|
||||
}
|
||||
|
||||
// 更新全局管理器
|
||||
@@ -510,7 +555,7 @@ export class Core {
|
||||
if (this._scene != null && this._scene.update) {
|
||||
const sceneStartTime = this._performanceMonitor.startMonitoring('Scene.update');
|
||||
this._scene.update();
|
||||
const entityCount = (this._scene as any).entities?.count || 0;
|
||||
const entityCount = this._scene.entities?.count || 0;
|
||||
this._performanceMonitor.endMonitoring('Scene.update', sceneStartTime, entityCount);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Entity } from '../../Entity';
|
||||
import { Component } from '../../Component';
|
||||
import { Scene } from '../../Scene';
|
||||
import { IScene } from '../../IScene';
|
||||
import { ComponentType } from '../ComponentStorage';
|
||||
import { QuerySystem, QueryBuilder } from '../QuerySystem';
|
||||
import { TypeSafeEventSystem } from '../EventSystem';
|
||||
@@ -14,11 +14,11 @@ import { EntityBatchOperator } from './EntityBatchOperator';
|
||||
* 提供统一的流式接口
|
||||
*/
|
||||
export class ECSFluentAPI {
|
||||
private scene: Scene;
|
||||
private scene: IScene;
|
||||
private querySystem: QuerySystem;
|
||||
private eventSystem: TypeSafeEventSystem;
|
||||
|
||||
constructor(scene: Scene, querySystem: QuerySystem, eventSystem: TypeSafeEventSystem) {
|
||||
constructor(scene: IScene, querySystem: QuerySystem, eventSystem: TypeSafeEventSystem) {
|
||||
this.scene = scene;
|
||||
this.querySystem = querySystem;
|
||||
this.eventSystem = eventSystem;
|
||||
@@ -86,7 +86,7 @@ export class ECSFluentAPI {
|
||||
* @returns 实体或null
|
||||
*/
|
||||
public findByName(name: string): Entity | null {
|
||||
return this.scene.getEntityByName(name);
|
||||
return this.scene.findEntity(name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +95,7 @@ export class ECSFluentAPI {
|
||||
* @returns 实体数组
|
||||
*/
|
||||
public findByTag(tag: number): Entity[] {
|
||||
return this.scene.getEntitiesByTag(tag);
|
||||
return this.scene.findEntitiesByTag(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,16 +161,16 @@ export class ECSFluentAPI {
|
||||
public getStats(): {
|
||||
entityCount: number;
|
||||
systemCount: number;
|
||||
componentStats: Map<string, any>;
|
||||
componentStats: Map<string, unknown>;
|
||||
queryStats: unknown;
|
||||
eventStats: Map<string, any>;
|
||||
eventStats: Map<string, unknown>;
|
||||
} {
|
||||
return {
|
||||
entityCount: this.scene.entities.count,
|
||||
systemCount: this.scene.systems.length,
|
||||
componentStats: this.scene.componentStorageManager.getAllStats(),
|
||||
queryStats: this.querySystem.getStats(),
|
||||
eventStats: this.eventSystem.getStats() as Map<string, any>
|
||||
eventStats: this.eventSystem.getStats() as Map<string, unknown>
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -183,7 +183,7 @@ export class ECSFluentAPI {
|
||||
* @returns ECS流式API实例
|
||||
*/
|
||||
export function createECSAPI(
|
||||
scene: Scene,
|
||||
scene: IScene,
|
||||
querySystem: QuerySystem,
|
||||
eventSystem: TypeSafeEventSystem
|
||||
): ECSFluentAPI {
|
||||
@@ -202,7 +202,7 @@ export let ECS: ECSFluentAPI;
|
||||
* @param eventSystem 事件系统
|
||||
*/
|
||||
export function initializeECS(
|
||||
scene: Scene,
|
||||
scene: IScene,
|
||||
querySystem: QuerySystem,
|
||||
eventSystem: TypeSafeEventSystem
|
||||
): void {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Entity } from '../../Entity';
|
||||
import { Component } from '../../Component';
|
||||
import { Scene } from '../../Scene';
|
||||
import { IScene } from '../../IScene';
|
||||
import { ComponentType, ComponentStorageManager } from '../ComponentStorage';
|
||||
|
||||
/**
|
||||
@@ -8,10 +8,10 @@ import { ComponentType, ComponentStorageManager } from '../ComponentStorage';
|
||||
*/
|
||||
export class EntityBuilder {
|
||||
private entity: Entity;
|
||||
private scene: Scene;
|
||||
private scene: IScene;
|
||||
private storageManager: ComponentStorageManager;
|
||||
|
||||
constructor(scene: Scene, storageManager: ComponentStorageManager) {
|
||||
constructor(scene: IScene, storageManager: ComponentStorageManager) {
|
||||
this.scene = scene;
|
||||
this.storageManager = storageManager;
|
||||
this.entity = new Entity("", scene.identifierPool.checkOut());
|
||||
|
||||
158
packages/core/src/ECS/IScene.ts
Normal file
158
packages/core/src/ECS/IScene.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
import { Entity } from './Entity';
|
||||
import { EntityList } from './Utils/EntityList';
|
||||
import { EntityProcessorList } from './Utils/EntityProcessorList';
|
||||
import { IdentifierPool } from './Utils/IdentifierPool';
|
||||
import { EntitySystem } from './Systems/EntitySystem';
|
||||
import { ComponentStorageManager } from './Core/ComponentStorage';
|
||||
import { QuerySystem } from './Core/QuerySystem';
|
||||
import { TypeSafeEventSystem } from './Core/EventSystem';
|
||||
|
||||
/**
|
||||
* 场景接口定义
|
||||
*
|
||||
* 定义场景应该实现的核心功能和属性,使用接口而非继承提供更灵活的实现方式。
|
||||
*/
|
||||
export interface IScene {
|
||||
/**
|
||||
* 场景名称
|
||||
*/
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* 场景中的实体集合
|
||||
*/
|
||||
readonly entities: EntityList;
|
||||
|
||||
/**
|
||||
* 实体系统处理器集合
|
||||
*/
|
||||
readonly entityProcessors: EntityProcessorList;
|
||||
|
||||
/**
|
||||
* 标识符池
|
||||
*/
|
||||
readonly identifierPool: IdentifierPool;
|
||||
|
||||
/**
|
||||
* 组件存储管理器
|
||||
*/
|
||||
readonly componentStorageManager: ComponentStorageManager;
|
||||
|
||||
/**
|
||||
* 查询系统
|
||||
*/
|
||||
readonly querySystem: QuerySystem;
|
||||
|
||||
/**
|
||||
* 事件系统
|
||||
*/
|
||||
readonly eventSystem: TypeSafeEventSystem;
|
||||
|
||||
/**
|
||||
* 获取系统列表
|
||||
*/
|
||||
readonly systems: EntitySystem[];
|
||||
|
||||
/**
|
||||
* 初始化场景
|
||||
*/
|
||||
initialize(): void;
|
||||
|
||||
/**
|
||||
* 场景开始运行时的回调
|
||||
*/
|
||||
onStart(): void;
|
||||
|
||||
/**
|
||||
* 场景卸载时的回调
|
||||
*/
|
||||
unload(): void;
|
||||
|
||||
/**
|
||||
* 开始场景
|
||||
*/
|
||||
begin(): void;
|
||||
|
||||
/**
|
||||
* 结束场景
|
||||
*/
|
||||
end(): void;
|
||||
|
||||
/**
|
||||
* 更新场景
|
||||
*/
|
||||
update(): void;
|
||||
|
||||
/**
|
||||
* 创建实体
|
||||
*/
|
||||
createEntity(name: string): Entity;
|
||||
|
||||
/**
|
||||
* 添加实体
|
||||
*/
|
||||
addEntity(entity: Entity, deferCacheClear?: boolean): Entity;
|
||||
|
||||
/**
|
||||
* 批量创建实体
|
||||
*/
|
||||
createEntities(count: number, namePrefix?: string): Entity[];
|
||||
|
||||
/**
|
||||
* 销毁所有实体
|
||||
*/
|
||||
destroyAllEntities(): void;
|
||||
|
||||
/**
|
||||
* 查找实体
|
||||
*/
|
||||
findEntity(name: string): Entity | null;
|
||||
|
||||
/**
|
||||
* 根据标签查找实体
|
||||
*/
|
||||
findEntitiesByTag(tag: number): Entity[];
|
||||
|
||||
/**
|
||||
* 添加实体处理器
|
||||
*/
|
||||
addEntityProcessor(processor: EntitySystem): EntitySystem;
|
||||
|
||||
/**
|
||||
* 移除实体处理器
|
||||
*/
|
||||
removeEntityProcessor(processor: EntitySystem): void;
|
||||
|
||||
/**
|
||||
* 获取实体处理器
|
||||
*/
|
||||
getEntityProcessor<T extends EntitySystem>(type: new (...args: any[]) => T): T | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景工厂接口
|
||||
*/
|
||||
export interface ISceneFactory<T extends IScene> {
|
||||
/**
|
||||
* 创建场景实例
|
||||
*/
|
||||
createScene(): T;
|
||||
}
|
||||
|
||||
/**
|
||||
* 场景配置接口
|
||||
*/
|
||||
export interface ISceneConfig {
|
||||
/**
|
||||
* 场景名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 是否自动开始
|
||||
*/
|
||||
autoStart?: boolean;
|
||||
/**
|
||||
* 调试配置
|
||||
*/
|
||||
debug?: boolean;
|
||||
}
|
||||
@@ -7,27 +7,36 @@ import { ComponentStorageManager } from './Core/ComponentStorage';
|
||||
import { QuerySystem } from './Core/QuerySystem';
|
||||
import { TypeSafeEventSystem } from './Core/EventSystem';
|
||||
import { EventBus } from './Core/EventBus';
|
||||
import { IScene, ISceneConfig } from './IScene';
|
||||
|
||||
/**
|
||||
* 游戏场景类
|
||||
* 游戏场景默认实现类
|
||||
*
|
||||
* 管理游戏场景中的所有实体和系统,提供场景生命周期管理。
|
||||
* 场景是游戏世界的容器,负责协调实体和系统的运行。
|
||||
* 实现IScene接口,提供场景的基础功能。
|
||||
* 推荐使用组合而非继承的方式来构建自定义场景。
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // 推荐的组合方式
|
||||
* class GameScene implements IScene {
|
||||
* private scene = new Scene();
|
||||
*
|
||||
* public initialize(): void {
|
||||
* this.scene.initialize();
|
||||
* // 自定义初始化逻辑
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // 仍然支持继承方式
|
||||
* class GameScene extends Scene {
|
||||
* public initialize(): void {
|
||||
* // 创建游戏实体
|
||||
* const player = this.createEntity("Player");
|
||||
*
|
||||
* // 添加系统
|
||||
* this.addEntityProcessor(new MovementSystem());
|
||||
* super.initialize();
|
||||
* // 自定义逻辑
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export class Scene {
|
||||
export class Scene implements IScene {
|
||||
/**
|
||||
* 场景名称
|
||||
*
|
||||
@@ -89,10 +98,15 @@ export class Scene {
|
||||
return this.entityProcessors.processors;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否已完成基础初始化
|
||||
*/
|
||||
private _isBaseInitialized = false;
|
||||
|
||||
/**
|
||||
* 创建场景实例
|
||||
*/
|
||||
constructor() {
|
||||
constructor(config?: ISceneConfig) {
|
||||
this.entities = new EntityList(this);
|
||||
this.entityProcessors = new EntityProcessorList();
|
||||
this.identifierPool = new IdentifierPool();
|
||||
@@ -100,17 +114,30 @@ export class Scene {
|
||||
this.querySystem = new QuerySystem();
|
||||
this.eventSystem = new TypeSafeEventSystem();
|
||||
|
||||
// 应用配置
|
||||
if (config?.name) {
|
||||
this.name = config.name;
|
||||
}
|
||||
|
||||
if (!Entity.eventBus) {
|
||||
Entity.eventBus = new EventBus(false);
|
||||
}
|
||||
|
||||
if (Entity.eventBus) {
|
||||
Entity.eventBus.onComponentAdded((data: any) => {
|
||||
Entity.eventBus.onComponentAdded((data: unknown) => {
|
||||
this.eventSystem.emitSync('component:added', data);
|
||||
});
|
||||
}
|
||||
|
||||
// 标记基础初始化完成
|
||||
this._isBaseInitialized = true;
|
||||
|
||||
// 立即调用初始化,但确保在基础设施就绪后
|
||||
this.initialize();
|
||||
|
||||
if (config?.autoStart) {
|
||||
this.begin();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ export { ECSEventType, EventPriority, EVENT_TYPES, EventTypeValidator } from './
|
||||
export * from './Systems';
|
||||
export * from './Utils';
|
||||
export { Scene } from './Scene';
|
||||
export { IScene, ISceneFactory, ISceneConfig } from './IScene';
|
||||
export { EntityManager, EntityQueryBuilder } from './Core/EntityManager';
|
||||
export * from './Core/Events';
|
||||
export * from './Core/Query';
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ComponentDataCollector } from './ComponentDataCollector';
|
||||
import { SceneDataCollector } from './SceneDataCollector';
|
||||
import { WebSocketManager } from './WebSocketManager';
|
||||
import { Core } from '../../Core';
|
||||
import { Component } from '../../ECS/Component';
|
||||
|
||||
/**
|
||||
* 调试管理器
|
||||
@@ -181,7 +182,7 @@ export class DebugManager {
|
||||
private handleExpandLazyObjectRequest(message: any): void {
|
||||
try {
|
||||
const { entityId, componentIndex, propertyPath, requestId } = message;
|
||||
|
||||
|
||||
if (entityId === undefined || componentIndex === undefined || !propertyPath) {
|
||||
this.webSocketManager.send({
|
||||
type: 'expand_lazy_object_response',
|
||||
@@ -192,7 +193,7 @@ export class DebugManager {
|
||||
}
|
||||
|
||||
const expandedData = this.entityCollector.expandLazyObject(entityId, componentIndex, propertyPath);
|
||||
|
||||
|
||||
this.webSocketManager.send({
|
||||
type: 'expand_lazy_object_response',
|
||||
requestId,
|
||||
@@ -213,7 +214,7 @@ export class DebugManager {
|
||||
private handleGetComponentPropertiesRequest(message: any): void {
|
||||
try {
|
||||
const { entityId, componentIndex, requestId } = message;
|
||||
|
||||
|
||||
if (entityId === undefined || componentIndex === undefined) {
|
||||
this.webSocketManager.send({
|
||||
type: 'get_component_properties_response',
|
||||
@@ -224,7 +225,7 @@ export class DebugManager {
|
||||
}
|
||||
|
||||
const properties = this.entityCollector.getComponentProperties(entityId, componentIndex);
|
||||
|
||||
|
||||
this.webSocketManager.send({
|
||||
type: 'get_component_properties_response',
|
||||
requestId,
|
||||
@@ -245,9 +246,9 @@ export class DebugManager {
|
||||
private handleGetRawEntityListRequest(message: any): void {
|
||||
try {
|
||||
const { requestId } = message;
|
||||
|
||||
|
||||
const rawEntityList = this.entityCollector.getRawEntityList();
|
||||
|
||||
|
||||
this.webSocketManager.send({
|
||||
type: 'get_raw_entity_list_response',
|
||||
requestId,
|
||||
@@ -268,7 +269,7 @@ export class DebugManager {
|
||||
private handleGetEntityDetailsRequest(message: any): void {
|
||||
try {
|
||||
const { entityId, requestId } = message;
|
||||
|
||||
|
||||
if (entityId === undefined) {
|
||||
this.webSocketManager.send({
|
||||
type: 'get_entity_details_response',
|
||||
@@ -279,7 +280,7 @@ export class DebugManager {
|
||||
}
|
||||
|
||||
const entityDetails = this.entityCollector.getEntityDetails(entityId);
|
||||
|
||||
|
||||
this.webSocketManager.send({
|
||||
type: 'get_entity_details_response',
|
||||
requestId,
|
||||
@@ -327,7 +328,8 @@ export class DebugManager {
|
||||
|
||||
// 收集其他内存统计
|
||||
const baseMemoryInfo = this.collectBaseMemoryInfo();
|
||||
const componentMemoryStats = this.collectComponentMemoryStats((Core.scene as any)?.entities);
|
||||
const scene = Core.scene;
|
||||
const componentMemoryStats = scene?.entities ? this.collectComponentMemoryStats(scene.entities) : { totalMemory: 0, componentTypes: 0, totalInstances: 0, breakdown: [] };
|
||||
const systemMemoryStats = this.collectSystemMemoryStats();
|
||||
const poolMemoryStats = this.collectPoolMemoryStats();
|
||||
const performanceStats = this.collectPerformanceStats();
|
||||
@@ -366,18 +368,44 @@ export class DebugManager {
|
||||
/**
|
||||
* 收集基础内存信息
|
||||
*/
|
||||
private collectBaseMemoryInfo(): any {
|
||||
const memoryInfo: any = {
|
||||
private collectBaseMemoryInfo(): {
|
||||
totalMemory: number;
|
||||
usedMemory: number;
|
||||
freeMemory: number;
|
||||
gcCollections: number;
|
||||
heapInfo: {
|
||||
totalJSHeapSize: number;
|
||||
usedJSHeapSize: number;
|
||||
jsHeapSizeLimit: number;
|
||||
} | null;
|
||||
detailedMemory?: unknown;
|
||||
} {
|
||||
const memoryInfo = {
|
||||
totalMemory: 0,
|
||||
usedMemory: 0,
|
||||
freeMemory: 0,
|
||||
gcCollections: 0,
|
||||
heapInfo: null
|
||||
heapInfo: null as {
|
||||
totalJSHeapSize: number;
|
||||
usedJSHeapSize: number;
|
||||
jsHeapSizeLimit: number;
|
||||
} | null,
|
||||
detailedMemory: undefined as unknown
|
||||
};
|
||||
|
||||
try {
|
||||
if ((performance as any).memory) {
|
||||
const perfMemory = (performance as any).memory;
|
||||
// 类型安全的performance memory访问
|
||||
const performanceWithMemory = performance as Performance & {
|
||||
memory?: {
|
||||
jsHeapSizeLimit?: number;
|
||||
usedJSHeapSize?: number;
|
||||
totalJSHeapSize?: number;
|
||||
};
|
||||
measureUserAgentSpecificMemory?: () => Promise<unknown>;
|
||||
};
|
||||
|
||||
if (performanceWithMemory.memory) {
|
||||
const perfMemory = performanceWithMemory.memory;
|
||||
memoryInfo.totalMemory = perfMemory.jsHeapSizeLimit || 512 * 1024 * 1024;
|
||||
memoryInfo.usedMemory = perfMemory.usedJSHeapSize || 0;
|
||||
memoryInfo.freeMemory = memoryInfo.totalMemory - memoryInfo.usedMemory;
|
||||
@@ -392,9 +420,8 @@ export class DebugManager {
|
||||
}
|
||||
|
||||
// 尝试获取GC信息
|
||||
if ((performance as any).measureUserAgentSpecificMemory) {
|
||||
// 这是一个实验性API,可能不可用
|
||||
(performance as any).measureUserAgentSpecificMemory().then((result: any) => {
|
||||
if (performanceWithMemory.measureUserAgentSpecificMemory) {
|
||||
performanceWithMemory.measureUserAgentSpecificMemory().then((result: unknown) => {
|
||||
memoryInfo.detailedMemory = result;
|
||||
}).catch(() => {
|
||||
// 忽略错误
|
||||
@@ -412,8 +439,24 @@ export class DebugManager {
|
||||
/**
|
||||
* 收集组件内存统计(仅用于内存快照)
|
||||
*/
|
||||
private collectComponentMemoryStats(entityList: any): any {
|
||||
const componentStats = new Map<string, { count: number; totalMemory: number; instances: any[] }>();
|
||||
private collectComponentMemoryStats(entityList: { buffer: Array<{ id: number; name?: string; destroyed?: boolean; components?: Component[] }> }): {
|
||||
totalMemory: number;
|
||||
componentTypes: number;
|
||||
totalInstances: number;
|
||||
breakdown: Array<{
|
||||
typeName: string;
|
||||
instanceCount: number;
|
||||
totalMemory: number;
|
||||
averageMemory: number;
|
||||
percentage: number;
|
||||
largestInstances: Array<{
|
||||
entityId: number;
|
||||
entityName: string;
|
||||
memory: number;
|
||||
}>;
|
||||
}>;
|
||||
} {
|
||||
const componentStats = new Map<string, { count: number; totalMemory: number; instances: Array<{ entityId: number; entityName: string; memory: number }> }>();
|
||||
let totalComponentMemory = 0;
|
||||
|
||||
// 首先统计组件类型和数量
|
||||
@@ -434,12 +477,12 @@ export class DebugManager {
|
||||
totalComponentMemory += totalMemoryForType;
|
||||
|
||||
// 收集该类型组件的实例信息(用于显示最大的几个实例)
|
||||
const instances: any[] = [];
|
||||
const instances: Array<{ entityId: number; entityName: string; memory: number }> = [];
|
||||
let instanceCount = 0;
|
||||
|
||||
|
||||
for (const entity of entityList.buffer) {
|
||||
if (!entity || entity.destroyed || !entity.components) continue;
|
||||
|
||||
|
||||
for (const component of entity.components) {
|
||||
if (component.constructor.name === typeName) {
|
||||
instances.push({
|
||||
@@ -448,7 +491,7 @@ export class DebugManager {
|
||||
memory: detailedMemoryPerInstance // 使用统一的详细计算结果
|
||||
});
|
||||
instanceCount++;
|
||||
|
||||
|
||||
// 限制收集的实例数量,避免过多数据
|
||||
if (instanceCount >= 100) break;
|
||||
}
|
||||
@@ -480,19 +523,33 @@ export class DebugManager {
|
||||
};
|
||||
}
|
||||
|
||||
private collectSystemMemoryStats(): any {
|
||||
private collectSystemMemoryStats(): {
|
||||
totalMemory: number;
|
||||
systemCount: number;
|
||||
breakdown: Array<{
|
||||
name: string;
|
||||
memory: number;
|
||||
enabled: boolean;
|
||||
updateOrder: number;
|
||||
}>;
|
||||
} {
|
||||
const scene = Core.scene;
|
||||
let totalSystemMemory = 0;
|
||||
const systemBreakdown: any[] = [];
|
||||
const systemBreakdown: Array<{
|
||||
name: string;
|
||||
memory: number;
|
||||
enabled: boolean;
|
||||
updateOrder: number;
|
||||
}> = [];
|
||||
|
||||
try {
|
||||
const entityProcessors = (scene as any).entityProcessors;
|
||||
const entityProcessors = scene?.entityProcessors;
|
||||
if (entityProcessors && entityProcessors.processors) {
|
||||
const systemTypeMemoryCache = new Map<string, number>();
|
||||
|
||||
|
||||
for (const system of entityProcessors.processors) {
|
||||
const systemTypeName = system.constructor.name;
|
||||
|
||||
|
||||
let systemMemory: number;
|
||||
if (systemTypeMemoryCache.has(systemTypeName)) {
|
||||
systemMemory = systemTypeMemoryCache.get(systemTypeName)!;
|
||||
@@ -500,7 +557,7 @@ export class DebugManager {
|
||||
systemMemory = this.calculateQuickSystemSize(system);
|
||||
systemTypeMemoryCache.set(systemTypeName, systemMemory);
|
||||
}
|
||||
|
||||
|
||||
totalSystemMemory += systemMemory;
|
||||
|
||||
systemBreakdown.push({
|
||||
@@ -522,20 +579,20 @@ export class DebugManager {
|
||||
};
|
||||
}
|
||||
|
||||
private calculateQuickSystemSize(system: any): number {
|
||||
private calculateQuickSystemSize(system: unknown): number {
|
||||
if (!system || typeof system !== 'object') return 64;
|
||||
|
||||
|
||||
let size = 128;
|
||||
|
||||
|
||||
try {
|
||||
const keys = Object.keys(system);
|
||||
for (let i = 0; i < Math.min(keys.length, 15); i++) {
|
||||
const key = keys[i];
|
||||
if (key === 'entities' || key === 'scene' || key === 'constructor') continue;
|
||||
|
||||
const value = system[key];
|
||||
|
||||
const value = (system as Record<string, unknown>)[key];
|
||||
size += key.length * 2;
|
||||
|
||||
|
||||
if (typeof value === 'string') {
|
||||
size += Math.min(value.length * 2, 100);
|
||||
} else if (typeof value === 'number') {
|
||||
@@ -551,16 +608,34 @@ export class DebugManager {
|
||||
} catch (error) {
|
||||
return 128;
|
||||
}
|
||||
|
||||
|
||||
return Math.max(size, 64);
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集对象池内存统计
|
||||
*/
|
||||
private collectPoolMemoryStats(): any {
|
||||
private collectPoolMemoryStats(): {
|
||||
totalMemory: number;
|
||||
poolCount: number;
|
||||
breakdown: Array<{
|
||||
typeName: string;
|
||||
maxSize: number;
|
||||
currentSize: number;
|
||||
estimatedMemory: number;
|
||||
utilization: number;
|
||||
hitRate?: number;
|
||||
}>;
|
||||
} {
|
||||
let totalPoolMemory = 0;
|
||||
const poolBreakdown: any[] = [];
|
||||
const poolBreakdown: Array<{
|
||||
typeName: string;
|
||||
maxSize: number;
|
||||
currentSize: number;
|
||||
estimatedMemory: number;
|
||||
utilization: number;
|
||||
hitRate?: number;
|
||||
}> = [];
|
||||
|
||||
try {
|
||||
// 尝试获取组件池统计
|
||||
@@ -569,7 +644,7 @@ export class DebugManager {
|
||||
const poolStats = poolManager.getPoolStats();
|
||||
|
||||
for (const [typeName, stats] of poolStats.entries()) {
|
||||
const poolData = stats as any; // 类型断言
|
||||
const poolData = stats as { maxSize: number; currentSize?: number };
|
||||
const poolMemory = poolData.maxSize * 32; // 估算每个对象32字节
|
||||
totalPoolMemory += poolMemory;
|
||||
|
||||
@@ -591,7 +666,12 @@ export class DebugManager {
|
||||
const poolStats = Pool.getStats();
|
||||
|
||||
for (const [typeName, stats] of Object.entries(poolStats)) {
|
||||
const poolData = stats as any; // 类型断言
|
||||
const poolData = stats as {
|
||||
maxSize: number;
|
||||
size: number;
|
||||
estimatedMemoryUsage: number;
|
||||
hitRate: number;
|
||||
};
|
||||
totalPoolMemory += poolData.estimatedMemoryUsage;
|
||||
poolBreakdown.push({
|
||||
typeName: `Pool_${typeName}`,
|
||||
@@ -616,9 +696,21 @@ export class DebugManager {
|
||||
/**
|
||||
* 收集性能统计信息
|
||||
*/
|
||||
private collectPerformanceStats(): any {
|
||||
private collectPerformanceStats(): {
|
||||
enabled: boolean;
|
||||
systemCount?: number;
|
||||
warnings?: unknown[];
|
||||
topSystems?: Array<{
|
||||
name: string;
|
||||
averageTime: number;
|
||||
maxTime: number;
|
||||
samples: number;
|
||||
}>;
|
||||
error?: string;
|
||||
} {
|
||||
try {
|
||||
const performanceMonitor = (Core.Instance as any)._performanceMonitor;
|
||||
const coreInstance = Core.Instance as Core & { _performanceMonitor?: unknown };
|
||||
const performanceMonitor = coreInstance._performanceMonitor;
|
||||
if (!performanceMonitor) {
|
||||
return { enabled: false };
|
||||
}
|
||||
@@ -626,35 +718,25 @@ export class DebugManager {
|
||||
const stats = performanceMonitor.getAllSystemStats();
|
||||
const warnings = performanceMonitor.getPerformanceWarnings();
|
||||
|
||||
return {
|
||||
enabled: performanceMonitor.enabled,
|
||||
return {
|
||||
enabled: (performanceMonitor as { enabled?: boolean }).enabled ?? false,
|
||||
systemCount: stats.size,
|
||||
warnings: warnings.slice(0, 10), // 最多10个警告
|
||||
topSystems: Array.from(stats.entries() as any).map((entry: any) => {
|
||||
const [name, stat] = entry;
|
||||
topSystems: Array.from(stats.entries()).map((entry) => {
|
||||
const [name, stat] = entry as [string, { averageTime: number; maxTime: number; executionCount: number }];
|
||||
return {
|
||||
name,
|
||||
averageTime: stat.averageTime,
|
||||
maxTime: stat.maxTime,
|
||||
samples: stat.executionCount
|
||||
};
|
||||
}).sort((a: any, b: any) => b.averageTime - a.averageTime).slice(0, 5)
|
||||
}).sort((a, b) => b.averageTime - a.averageTime).slice(0, 5)
|
||||
};
|
||||
} catch (error: any) {
|
||||
return { enabled: false, error: error.message };
|
||||
} catch (error: unknown) {
|
||||
return { enabled: false, error: error instanceof Error ? error.message : String(error) };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内存大小分类
|
||||
*/
|
||||
private getMemorySizeCategory(memoryBytes: number): string {
|
||||
if (memoryBytes < 1024) return '< 1KB';
|
||||
if (memoryBytes < 10 * 1024) return '1-10KB';
|
||||
if (memoryBytes < 100 * 1024) return '10-100KB';
|
||||
if (memoryBytes < 1024 * 1024) return '100KB-1MB';
|
||||
return '> 1MB';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取调试数据
|
||||
@@ -677,12 +759,14 @@ export class DebugManager {
|
||||
}
|
||||
|
||||
if (this.config.channels.systems) {
|
||||
const performanceMonitor = (Core.Instance as any)._performanceMonitor;
|
||||
const coreInstance = Core.Instance as Core & { _performanceMonitor?: unknown };
|
||||
const performanceMonitor = coreInstance._performanceMonitor;
|
||||
debugData.systems = this.systemCollector.collectSystemData(performanceMonitor);
|
||||
}
|
||||
|
||||
if (this.config.channels.performance) {
|
||||
const performanceMonitor = (Core.Instance as any)._performanceMonitor;
|
||||
const coreInstance = Core.Instance as Core & { _performanceMonitor?: unknown };
|
||||
const performanceMonitor = coreInstance._performanceMonitor;
|
||||
debugData.performance = this.performanceCollector.collectPerformanceData(performanceMonitor);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user