新增cocos-debug-profiler

This commit is contained in:
YHH
2025-06-17 00:32:16 +08:00
parent 103f773286
commit 1b5363611d
46 changed files with 6757 additions and 37 deletions

View File

@@ -6,6 +6,8 @@ import { PerformanceMonitor } from './Utils/PerformanceMonitor';
import { PoolManager } from './Utils/Pool';
import { ECSFluentAPI, createECSAPI } from './ECS/Core/FluentAPI';
import { Scene } from './ECS/Scene';
import { DebugReporter } from './Utils/DebugReporter';
import { ICoreConfig, IECSDebugConfig } from './Types';
/**
* 游戏引擎核心类
@@ -107,27 +109,56 @@ export class Core {
*/
public _scene?: Scene;
/**
* 调试报告器
*
* 负责收集和发送调试数据。
*/
public _debugReporter?: DebugReporter;
/**
* Core配置
*/
private _config: ICoreConfig;
/**
* 创建核心实例
*
* @param debug - 是否启用调试模式默认为true
* @param enableEntitySystems - 是否启用实体系统默认为true
* @param config - Core配置对象
*/
private constructor(debug: boolean = true, enableEntitySystems: boolean = true) {
private constructor(config: ICoreConfig = {}) {
Core._instance = this;
// 保存配置
this._config = {
debug: true,
enableEntitySystems: true,
...config
};
// 初始化管理器
this._timerManager = new TimerManager();
Core.registerGlobalManager(this._timerManager);
// 初始化性能监控器
this._performanceMonitor = PerformanceMonitor.instance;
// 在调试模式下启用性能监控
if (this._config.debug) {
this._performanceMonitor.enable();
}
// 初始化对象池管理器
this._poolManager = PoolManager.getInstance();
Core.entitySystemsEnabled = enableEntitySystems;
this.debug = debug;
Core.entitySystemsEnabled = this._config.enableEntitySystems || true;
this.debug = this._config.debug || true;
// 初始化调试报告器
if (this._config.debugConfig?.enabled) {
this._debugReporter = new DebugReporter(this, this._config.debugConfig);
}
this.initialize();
}
@@ -180,12 +211,16 @@ export class Core {
*
* 如果实例已存在,则返回现有实例。
*
* @param debug - 是否为调试模式默认为true
* @param config - Core配置也可以直接传入boolean表示debug模式向后兼容
* @returns Core实例
*/
public static create(debug: boolean = true): Core {
public static create(config: ICoreConfig | boolean = true): Core {
if (this._instance == null) {
this._instance = new Core(debug);
// 向后兼容如果传入boolean转换为配置对象
const coreConfig: ICoreConfig = typeof config === 'boolean'
? { debug: config, enableEntitySystems: true }
: config;
this._instance = new Core(coreConfig);
}
return this._instance;
}
@@ -284,6 +319,66 @@ export class Core {
return this._instance?._ecsAPI || null;
}
/**
* 启用调试功能
*
* @param config 调试配置
*/
public static enableDebug(config: IECSDebugConfig): void {
if (!this._instance) {
console.warn("Core实例未创建请先调用Core.create()");
return;
}
if (this._instance._debugReporter) {
this._instance._debugReporter.updateConfig(config);
} else {
this._instance._debugReporter = new DebugReporter(this._instance, config);
}
// 更新Core配置
this._instance._config.debugConfig = config;
}
/**
* 禁用调试功能
*/
public static disableDebug(): void {
if (!this._instance) return;
if (this._instance._debugReporter) {
this._instance._debugReporter.stop();
this._instance._debugReporter = undefined;
}
// 更新Core配置
if (this._instance._config.debugConfig) {
this._instance._config.debugConfig.enabled = false;
}
}
/**
* 获取调试数据
*
* @returns 当前调试数据如果调试未启用则返回null
*/
public static getDebugData(): any {
if (!this._instance?._debugReporter) {
return null;
}
return this._instance._debugReporter.getDebugData();
}
/**
* 检查调试是否启用
*
* @returns 调试状态
*/
public static get isDebugEnabled(): boolean {
return this._instance?._config.debugConfig?.enabled || false;
}
/**
* 场景切换回调
*
@@ -297,6 +392,11 @@ export class Core {
const scene = this._scene as any;
this._ecsAPI = createECSAPI(scene, scene.querySystem, scene.eventSystem);
}
// 通知调试报告器场景已变更
if (this._debugReporter) {
this._debugReporter.onSceneChanged();
}
}
/**

View File

@@ -234,4 +234,207 @@ export interface IPerformanceEventData extends IEventData {
memoryUsage?: number;
/** 额外数据 */
metadata?: Record<string, any>;
}
/**
* ECS调试配置接口
*/
export interface IECSDebugConfig {
/** 是否启用调试 */
enabled: boolean;
/** WebSocket服务器URL */
websocketUrl: string;
/** 是否自动重连 */
autoReconnect?: boolean;
/** 数据更新间隔(毫秒) */
updateInterval?: number;
/** 数据通道配置 */
channels: {
entities: boolean;
systems: boolean;
performance: boolean;
components: boolean;
scenes: boolean;
};
}
/**
* Core配置接口
*/
export interface ICoreConfig {
/** 是否启用调试模式 */
debug?: boolean;
/** 是否启用实体系统 */
enableEntitySystems?: boolean;
/** 调试配置 */
debugConfig?: IECSDebugConfig;
}
/**
* ECS调试数据接口
*/
export interface IECSDebugData {
/** 时间戳 */
timestamp: number;
/** 框架版本 */
frameworkVersion?: string;
/** 是否正在运行 */
isRunning: boolean;
/** 框架是否已加载 */
frameworkLoaded: boolean;
/** 当前场景名称 */
currentScene: string;
/** 实体数据 */
entities?: IEntityDebugData;
/** 系统数据 */
systems?: ISystemDebugData;
/** 性能数据 */
performance?: IPerformanceDebugData;
/** 组件数据 */
components?: IComponentDebugData;
/** 场景数据 */
scenes?: ISceneDebugData;
}
/**
* 实体调试数据接口
*/
export interface IEntityDebugData {
/** 总实体数 */
totalEntities: number;
/** 激活实体数 */
activeEntities: number;
/** 待添加实体数 */
pendingAdd: number;
/** 待移除实体数 */
pendingRemove: number;
/** 按Archetype分组的实体分布 */
entitiesPerArchetype: Array<{
signature: string;
count: number;
memory: number;
}>;
/** 组件数量最多的前几个实体 */
topEntitiesByComponents: Array<{
id: string;
name: string;
componentCount: number;
memory: number;
}>;
/** 实体详情列表 */
entityDetails?: Array<{
id: string | number;
name?: string;
tag?: string;
enabled: boolean;
componentCount: number;
components: string[];
}>;
}
/**
* 系统调试数据接口
*/
export interface ISystemDebugData {
/** 总系统数 */
totalSystems: number;
/** 系统信息列表 */
systemsInfo: Array<{
name: string;
type: string;
entityCount: number;
executionTime?: number;
averageExecutionTime?: number;
minExecutionTime?: number;
maxExecutionTime?: number;
executionTimeHistory?: number[];
memoryUsage?: number;
updateOrder: number;
enabled: boolean;
lastUpdateTime?: number;
}>;
}
/**
* 性能调试数据接口
*/
export interface IPerformanceDebugData {
/** ECS框架执行时间毫秒 */
frameTime: number;
/** 引擎总帧时间(毫秒) */
engineFrameTime?: number;
/** ECS占总帧时间百分比 */
ecsPercentage?: number;
/** 内存使用量MB */
memoryUsage: number;
/** FPS */
fps: number;
/** 平均ECS执行时间毫秒 */
averageFrameTime: number;
/** 最小ECS执行时间毫秒 */
minFrameTime: number;
/** 最大ECS执行时间毫秒 */
maxFrameTime: number;
/** ECS执行时间历史记录 */
frameTimeHistory: number[];
/** 系统性能详情 */
systemPerformance: Array<{
systemName: string;
averageTime: number;
maxTime: number;
minTime: number;
samples: number;
percentage?: number; // 系统占ECS总时间的百分比
}>;
/** 内存分配详情 */
memoryDetails?: {
entities: number;
components: number;
systems: number;
pooled: number;
totalMemory: number;
usedMemory: number;
freeMemory: number;
gcCollections: number;
};
}
/**
* 组件调试数据接口
*/
export interface IComponentDebugData {
/** 组件类型数 */
componentTypes: number;
/** 组件实例总数 */
componentInstances: number;
/** 组件分布统计 */
componentStats: Array<{
typeName: string;
instanceCount: number;
memoryPerInstance: number;
totalMemory: number;
poolSize: number;
poolUtilization: number;
averagePerEntity?: number;
}>;
}
/**
* 场景调试数据接口
*/
export interface ISceneDebugData {
/** 当前场景名称 */
currentSceneName: string;
/** 场景是否已初始化 */
isInitialized: boolean;
/** 场景运行时间(秒) */
sceneRunTime: number;
/** 场景实体数 */
sceneEntityCount: number;
/** 场景系统数 */
sceneSystemCount: number;
/** 场景内存使用量 */
sceneMemory: number;
/** 场景启动时间 */
sceneUptime: number;
}

900
src/Utils/DebugReporter.ts Normal file
View File

@@ -0,0 +1,900 @@
import {
IECSDebugConfig,
IECSDebugData,
IEntityDebugData,
ISystemDebugData,
IPerformanceDebugData,
IComponentDebugData,
ISceneDebugData
} from '../Types';
import { Core } from '../Core';
import { Time } from './Time';
/**
* ECS调试报告器 - WebSocket模式
*
* 负责收集ECS框架的运行时调试数据并通过WebSocket发送到调试服务器
*/
export class DebugReporter {
private config: IECSDebugConfig;
private core: Core;
private timer?: any;
private ws?: WebSocket;
private lastFrameTime: number = 0;
private frameCount: number = 0;
private lastFpsTime: number = 0;
private fps: number = 0;
private sceneStartTime: number = 0;
private isConnected: boolean = false;
private reconnectAttempts: number = 0;
private maxReconnectAttempts: number = 5;
private frameTimeHistory: number[] = [];
private maxHistoryLength: number = 60; // 保存60帧的历史数据
/**
* 构造函数
* @param core Core实例
* @param config 调试配置
*/
constructor(core: Core, config: IECSDebugConfig) {
this.core = core;
this.config = config;
this.sceneStartTime = Date.now();
if (this.config.enabled) {
this.start();
}
}
/**
* 启动调试报告器
*/
private start(): void {
this.connectWebSocket();
}
/**
* 停止调试报告器
*/
public stop(): void {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
if (this.ws) {
this.ws.close();
this.ws = undefined;
}
this.isConnected = false;
}
/**
* 更新配置
* @param newConfig 新配置
*/
public updateConfig(newConfig: IECSDebugConfig): void {
const wasEnabled = this.config.enabled;
const urlChanged = this.config.websocketUrl !== newConfig.websocketUrl;
this.config = newConfig;
if (!newConfig.enabled && wasEnabled) {
this.stop();
} else if (newConfig.enabled && (!wasEnabled || urlChanged)) {
this.stop();
this.start();
}
}
/**
* 连接WebSocket
*/
private connectWebSocket(): void {
if (!this.config.websocketUrl) {
console.error('[ECS Debug] WebSocket URL not provided');
return;
}
try {
this.ws = new WebSocket(this.config.websocketUrl);
this.ws.onopen = () => {
this.isConnected = true;
this.reconnectAttempts = 0;
this.startDataStream();
// 发送初始化消息
this.send({
type: 'init',
data: {
frameworkVersion: this.getFrameworkVersion(),
timestamp: Date.now()
}
});
};
this.ws.onmessage = (event) => {
try {
const message = JSON.parse(event.data);
this.handleMessage(message);
} catch (error) {
console.error('[ECS Debug] Failed to parse message:', error);
}
};
this.ws.onclose = (event) => {
this.isConnected = false;
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
// 自动重连
if (this.config.autoReconnect !== false && this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts - 1), 10000);
setTimeout(() => this.connectWebSocket(), delay);
}
};
this.ws.onerror = (error) => {
console.error('[ECS Debug] WebSocket error:', error);
};
} catch (error) {
console.error('[ECS Debug] Failed to create WebSocket:', error);
}
}
/**
* 启动数据流
*/
private startDataStream(): void {
const interval = this.config.updateInterval || 1000;
this.timer = setInterval(() => {
if (this.isConnected) {
try {
const data = this.collectDebugData();
this.send({ type: 'debug_data', data });
} catch (error) {
console.error('[ECS Debug] Failed to send debug data:', error);
}
}
}, interval);
}
/**
* 发送消息
*/
private send(message: any): void {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(message));
}
}
/**
* 处理接收到的消息
* @param message 消息内容
*/
private handleMessage(message: any): void {
switch (message.type) {
case 'get_debug_data':
const data = this.collectDebugData();
this.send({ type: 'debug_data_response', data, requestId: message.requestId });
break;
case 'update_config':
if (message.config) {
this.updateConfig(message.config);
this.send({ type: 'config_updated', success: true });
}
break;
case 'ping':
this.send({ type: 'pong', timestamp: Date.now() });
break;
default:
console.warn('[ECS Debug] Unknown message type:', message.type);
}
}
/**
* 收集调试数据
* @returns 调试数据对象
*/
private collectDebugData(): IECSDebugData {
const currentTime = Date.now();
// 更新FPS计算
this.updateFPS(currentTime);
const data: IECSDebugData = {
timestamp: currentTime,
frameworkVersion: this.getFrameworkVersion(),
isRunning: true,
frameworkLoaded: true,
currentScene: this.getCurrentSceneName()
};
// 根据配置收集不同类型的数据
if (this.config.channels.entities) {
data.entities = this.collectEntityData();
}
if (this.config.channels.systems) {
data.systems = this.collectSystemData();
}
if (this.config.channels.performance) {
data.performance = this.collectPerformanceData();
}
if (this.config.channels.components) {
data.components = this.collectComponentData();
}
if (this.config.channels.scenes) {
data.scenes = this.collectSceneData();
}
return data;
}
/**
* 更新FPS计算
*/
private updateFPS(currentTime: number): void {
this.frameCount++;
if (currentTime - this.lastFpsTime >= 1000) {
this.fps = this.frameCount;
this.frameCount = 0;
this.lastFpsTime = currentTime;
}
}
/**
* 获取框架版本
*/
private getFrameworkVersion(): string {
return '1.0.0';
}
/**
* 获取当前场景名称
*/
private getCurrentSceneName(): string {
const scene = Core.scene;
return scene ? (scene as any).name || 'Unnamed Scene' : 'No Scene';
}
/**
* 收集实体数据
*/
private collectEntityData(): IEntityDebugData {
const scene = Core.scene;
if (!scene) {
return {
totalEntities: 0,
activeEntities: 0,
pendingAdd: 0,
pendingRemove: 0,
entitiesPerArchetype: [],
topEntitiesByComponents: []
};
}
const entityList = (scene as any).entities;
if (!entityList) {
return {
totalEntities: 0,
activeEntities: 0,
pendingAdd: 0,
pendingRemove: 0,
entitiesPerArchetype: [],
topEntitiesByComponents: []
};
}
const allEntities = entityList.buffer || [];
const activeEntities = allEntities.filter((e: any) => e.enabled && !e._isDestroyed);
return {
totalEntities: allEntities.length,
activeEntities: activeEntities.length,
pendingAdd: entityList.toAdd?.length || 0,
pendingRemove: entityList.toRemove?.length || 0,
entitiesPerArchetype: this.getArchetypeDistribution({ entities: allEntities }),
topEntitiesByComponents: this.getTopEntitiesByComponents({ entities: allEntities }),
entityDetails: this.getEntityDetails({ entities: allEntities })
};
}
/**
* 获取实体详情
*/
private getEntityDetails(entityContainer: any): Array<any> {
if (!entityContainer.entities) return [];
return entityContainer.entities.slice(0, 100).map((entity: any) => ({
id: entity.id,
name: entity.name || `Entity_${entity.id}`,
tag: entity.tag,
enabled: entity.enabled,
componentCount: entity.components?.length || 0,
components: entity.components?.map((c: any) => c.constructor.name) || []
}));
}
/**
* 收集系统数据
*/
private collectSystemData(): ISystemDebugData {
const scene = Core.scene;
if (!scene) {
return {
totalSystems: 0,
systemsInfo: []
};
}
const entityProcessors = (scene as any).entityProcessors;
if (!entityProcessors) {
return {
totalSystems: 0,
systemsInfo: []
};
}
const systems = entityProcessors.processors || [];
// 获取性能监控数据
const monitor = this.core._performanceMonitor;
let systemStats: Map<string, any> = new Map();
let systemData: Map<string, any> = new Map();
if (monitor) {
try {
systemStats = monitor.getAllSystemStats();
systemData = monitor.getAllSystemData();
} catch (error) {
// 忽略错误使用空的Map
}
}
return {
totalSystems: systems.length,
systemsInfo: systems.map((system: any) => {
const systemName = system.systemName || system.constructor.name;
const stats = systemStats.get(systemName);
const data = systemData.get(systemName);
return {
name: systemName,
type: system.constructor.name,
entityCount: system.entities?.length || 0,
executionTime: stats?.averageTime || data?.executionTime || 0,
minExecutionTime: stats?.minTime === Number.MAX_VALUE ? 0 : (stats?.minTime || 0),
maxExecutionTime: stats?.maxTime || 0,
executionTimeHistory: stats?.recentTimes || [],
updateOrder: system.updateOrder || 0,
enabled: system.enabled !== false,
lastUpdateTime: data?.lastUpdateTime || 0
};
})
};
}
/**
* 收集性能数据
*/
private collectPerformanceData(): IPerformanceDebugData {
const frameTimeSeconds = Time.deltaTime;
const engineFrameTimeMs = frameTimeSeconds * 1000;
const currentFps = frameTimeSeconds > 0 ? Math.round(1 / frameTimeSeconds) : 0;
const ecsPerformanceData = this.getECSPerformanceData();
const ecsExecutionTimeMs = ecsPerformanceData.totalExecutionTime;
const ecsPercentage = engineFrameTimeMs > 0 ? (ecsExecutionTimeMs / engineFrameTimeMs * 100) : 0;
let memoryUsage = 0;
if ((performance as any).memory) {
memoryUsage = (performance as any).memory.usedJSHeapSize / 1024 / 1024;
}
// 更新ECS执行时间历史记录
this.frameTimeHistory.push(ecsExecutionTimeMs);
if (this.frameTimeHistory.length > this.maxHistoryLength) {
this.frameTimeHistory.shift();
}
// 计算ECS执行时间统计
const history = this.frameTimeHistory.filter(t => t >= 0);
const averageECSTime = history.length > 0 ? history.reduce((a, b) => a + b, 0) / history.length : ecsExecutionTimeMs;
const minECSTime = history.length > 0 ? Math.min(...history) : ecsExecutionTimeMs;
const maxECSTime = history.length > 0 ? Math.max(...history) : ecsExecutionTimeMs;
return {
frameTime: ecsExecutionTimeMs,
engineFrameTime: engineFrameTimeMs,
ecsPercentage: ecsPercentage,
memoryUsage: memoryUsage,
fps: currentFps,
averageFrameTime: averageECSTime, // ECS平均执行时间
minFrameTime: minECSTime, // ECS最短执行时间
maxFrameTime: maxECSTime, // ECS最长执行时间
frameTimeHistory: [...this.frameTimeHistory],
systemPerformance: this.getSystemPerformance(),
memoryDetails: this.getMemoryDetails()
};
}
/**
* 获取ECS框架整体性能数据
*/
private getECSPerformanceData(): { totalExecutionTime: number; systemBreakdown: Array<any> } {
const monitor = this.core._performanceMonitor;
if (!monitor) {
return { totalExecutionTime: 0, systemBreakdown: [] };
}
try {
let totalTime = 0;
const systemBreakdown = [];
const stats = monitor.getAllSystemStats();
// 计算各系统的执行时间
for (const [systemName, stat] of stats.entries()) {
const systemTime = stat.averageTime || 0;
totalTime += systemTime;
systemBreakdown.push({
systemName: systemName,
executionTime: systemTime,
percentage: 0 // 后面计算
});
}
// 计算各系统占ECS总时间的百分比
systemBreakdown.forEach(system => {
system.percentage = totalTime > 0 ? (system.executionTime / totalTime * 100) : 0;
});
// 按执行时间排序
systemBreakdown.sort((a, b) => b.executionTime - a.executionTime);
return {
totalExecutionTime: totalTime,
systemBreakdown: systemBreakdown
};
} catch (error) {
return { totalExecutionTime: 0, systemBreakdown: [] };
}
}
/**
* 获取系统性能数据
*/
private getSystemPerformance(): Array<any> {
const monitor = this.core._performanceMonitor;
if (!monitor) {
return [];
}
try {
const stats = monitor.getAllSystemStats();
const systemData = monitor.getAllSystemData();
return Array.from(stats.entries()).map(([systemName, stat]) => {
const data = systemData.get(systemName);
return {
systemName: systemName,
averageTime: stat.averageTime,
maxTime: stat.maxTime,
minTime: stat.minTime === Number.MAX_VALUE ? 0 : stat.minTime,
samples: stat.executionCount,
percentage: 0, // 在getECSPerformanceData中计算
entityCount: data?.entityCount || 0,
lastExecutionTime: data?.executionTime || 0
};
});
} catch (error) {
return [];
}
}
/**
* 获取内存详情
*/
private getMemoryDetails(): any {
const scene = Core.scene;
if (!scene) {
return {
entities: 0,
components: 0,
systems: 0,
pooled: 0,
totalMemory: 0,
usedMemory: 0,
freeMemory: 0,
gcCollections: 0
};
}
try {
let entityMemory = 0;
let componentMemory = 0;
let systemMemory = 0;
let pooledMemory = 0;
const entityManager = (scene as any).entityManager;
if (entityManager?.entities) {
// 计算实体和组件内存
entityManager.entities.forEach((entity: any) => {
entityMemory += this.estimateObjectSize(entity);
if (entity.components) {
entity.components.forEach((component: any) => {
componentMemory += this.estimateObjectSize(component);
});
}
});
}
// 计算系统内存(估算)
const entitySystems = (scene as any).entitySystems;
if (entitySystems?.systems) {
entitySystems.systems.forEach((system: any) => {
systemMemory += this.estimateObjectSize(system);
});
}
// 计算对象池内存(估算)
try {
const poolManager = this.core._poolManager;
if (poolManager) {
// 简单估算对象池内存
pooledMemory = 1024 * 1024; // 1MB估算值
}
} catch (error) {
// 忽略对象池内存计算错误
}
// 获取浏览器内存信息
let totalMemory = 512 * 1024 * 1024; // 默认512MB
let usedMemory = entityMemory + componentMemory + systemMemory + pooledMemory;
let gcCollections = 0;
if ((performance as any).memory) {
const perfMemory = (performance as any).memory;
totalMemory = perfMemory.jsHeapSizeLimit || totalMemory;
usedMemory = perfMemory.usedJSHeapSize || usedMemory;
}
return {
entities: entityMemory,
components: componentMemory,
systems: systemMemory,
pooled: pooledMemory,
totalMemory: totalMemory,
usedMemory: usedMemory,
freeMemory: totalMemory - usedMemory,
gcCollections: gcCollections
};
} catch (error) {
return {
entities: 0,
components: 0,
systems: 0,
pooled: 0,
totalMemory: 512 * 1024 * 1024,
usedMemory: 0,
freeMemory: 512 * 1024 * 1024,
gcCollections: 0
};
}
}
/**
* 收集组件数据
*/
private collectComponentData(): IComponentDebugData {
const scene = Core.scene;
if (!scene) {
return {
componentTypes: 0,
componentInstances: 0,
componentStats: []
};
}
const entityList = (scene as any).entities;
if (!entityList?.buffer) {
return {
componentTypes: 0,
componentInstances: 0,
componentStats: []
};
}
const componentStats = new Map<string, { count: number; entities: number }>();
let totalInstances = 0;
entityList.buffer.forEach((entity: any) => {
if (entity.components) {
entity.components.forEach((component: any) => {
const typeName = component.constructor.name;
const stats = componentStats.get(typeName) || { count: 0, entities: 0 };
stats.count++;
totalInstances++;
componentStats.set(typeName, stats);
});
}
});
return {
componentTypes: componentStats.size,
componentInstances: totalInstances,
componentStats: Array.from(componentStats.entries()).map(([typeName, stats]) => {
const poolSize = this.getComponentPoolSize(typeName);
const memoryPerInstance = this.calculateComponentMemorySize(typeName);
return {
typeName,
instanceCount: stats.count,
memoryPerInstance: memoryPerInstance,
totalMemory: stats.count * memoryPerInstance,
poolSize: poolSize,
poolUtilization: poolSize > 0 ? (stats.count / poolSize * 100) : 0,
averagePerEntity: stats.count / entityList.buffer.length
};
})
};
}
/**
* 获取组件池大小
*/
private getComponentPoolSize(typeName: string): number {
try {
const poolManager = this.core._poolManager;
return (poolManager as any).getPoolSize?.(typeName) || 0;
} catch (error) {
return 0;
}
}
/**
* 计算组件实际内存大小
*/
private calculateComponentMemorySize(typeName: string): number {
const scene = Core.scene;
if (!scene) return 32;
const entityList = (scene as any).entities;
if (!entityList?.buffer) return 32;
try {
// 找到第一个包含此组件的实体,分析组件大小
for (const entity of entityList.buffer) {
if (entity.components) {
const component = entity.components.find((c: any) => c.constructor.name === typeName);
if (component) {
return this.estimateObjectSize(component);
}
}
}
} catch (error) {
// 忽略错误,使用默认值
}
// 如果无法计算,返回基础大小
return 32; // 基础对象开销
}
/**
* 估算对象内存大小(字节)
*/
private estimateObjectSize(obj: any, visited = new WeakSet(), depth = 0): number {
// 防止无限递归:限制深度和检测循环引用
if (obj === null || obj === undefined || depth > 10) return 0;
if (visited.has(obj)) return 0; // 已访问过,避免循环引用
let size = 0;
const type = typeof obj;
switch (type) {
case 'boolean':
size = 1;
break;
case 'number':
size = 8; // JavaScript中数字都是64位浮点数
break;
case 'string':
size = Math.min(obj.length * 2, 1024); // UTF-16编码每字符2字节限制最大1KB
break;
case 'object':
visited.add(obj); // 标记为已访问
if (Array.isArray(obj)) {
size = 24; // 数组基础开销
// 只处理前100个元素避免大数组导致性能问题
const maxItems = Math.min(obj.length, 100);
for (let i = 0; i < maxItems; i++) {
size += this.estimateObjectSize(obj[i], visited, depth + 1);
}
} else {
size = 24; // 对象基础开销
let propertyCount = 0;
for (const key in obj) {
// 只处理前50个属性避免复杂对象导致性能问题
if (propertyCount >= 50) break;
if (obj.hasOwnProperty(key)) {
// 跳过一些可能导致问题的属性
if (key === 'scene' || key === 'parent' || key === 'children' ||
key === '_scene' || key === '_parent' || key === '_children' ||
key === 'entity' || key === '_entity') {
continue;
}
try {
size += key.length * 2; // 属性名
size += this.estimateObjectSize(obj[key], visited, depth + 1); // 属性值
propertyCount++;
} catch (error) {
// 忽略访问错误的属性
continue;
}
}
}
}
break;
default:
size = 8; // 其他类型默认8字节
}
return Math.min(size, 10240); // 限制单个对象最大10KB
}
/**
* 收集场景数据
*/
private collectSceneData(): ISceneDebugData {
const scene = Core.scene;
if (!scene) {
return {
currentSceneName: 'No Scene',
isInitialized: false,
sceneRunTime: 0,
sceneEntityCount: 0,
sceneSystemCount: 0,
sceneMemory: 0,
sceneUptime: 0
};
}
const currentTime = Date.now();
const runTime = (currentTime - this.sceneStartTime) / 1000;
const entityList = (scene as any).entities;
const entityProcessors = (scene as any).entityProcessors;
return {
currentSceneName: (scene as any).name || 'Unnamed Scene',
isInitialized: (scene as any)._didSceneBegin || false,
sceneRunTime: runTime,
sceneEntityCount: entityList?.buffer?.length || 0,
sceneSystemCount: entityProcessors?.processors?.length || 0,
sceneMemory: 0, // TODO: 计算实际场景内存
sceneUptime: runTime
};
}
/**
* 手动触发数据收集
* @returns 当前调试数据
*/
public getDebugData(): IECSDebugData {
return this.collectDebugData();
}
/**
* 重置场景时间
*/
public onSceneChanged(): void {
this.sceneStartTime = Date.now();
// 发送场景切换事件
if (this.isConnected) {
this.send({
type: 'scene_changed',
data: {
sceneName: this.getCurrentSceneName(),
timestamp: Date.now()
}
});
}
}
/**
* 获取连接状态
*/
public get connected(): boolean {
return this.isConnected;
}
/**
* 手动重连
*/
public reconnect(): void {
if (this.ws) {
this.ws.close();
}
this.reconnectAttempts = 0;
this.connectWebSocket();
}
/**
* 获取Archetype分布
*/
private getArchetypeDistribution(entityContainer: any): Array<{ signature: string; count: number; memory: number }> {
if (!entityContainer.entities) return [];
const archetypes = new Map<string, { count: number; memory: number }>();
entityContainer.entities.forEach((entity: any) => {
const components = entity.components || [];
const signature = components.map((c: any) => c.constructor.name).sort().join(',') || 'Empty';
const existing = archetypes.get(signature) || { count: 0, memory: 0 };
existing.count++;
// 计算每个组件的实际内存大小
let entityMemory = 0;
components.forEach((component: any) => {
entityMemory += this.estimateObjectSize(component);
});
existing.memory += entityMemory;
archetypes.set(signature, existing);
});
return Array.from(archetypes.entries())
.map(([signature, data]) => ({ signature, ...data }))
.sort((a: any, b: any) => b.count - a.count)
.slice(0, 10); // 只返回前10个
}
/**
* 获取组件数量最多的实体
*/
private getTopEntitiesByComponents(entityContainer: any): Array<{ id: string; name: string; componentCount: number; memory: number }> {
if (!entityContainer.entities) return [];
return entityContainer.entities
.map((entity: any) => {
const components = entity.components || [];
let memory = 0;
// 计算实际内存使用
components.forEach((component: any) => {
memory += this.estimateObjectSize(component);
});
return {
id: entity.id?.toString() || 'unknown',
name: entity.name || `Entity_${entity.id}`,
componentCount: components.length,
memory: memory
};
})
.sort((a: any, b: any) => b.componentCount - a.componentCount)
.slice(0, 10); // 只返回前10个
}
}