Files
esengine/extensions/cocos/cocos-ecs/assets/scripts/ecs/components/NetworkComponent.ts
YHH bb19f752a1 优化性能结构/延迟加载
新增测试代码用于测试性能
2025-07-02 00:13:29 +08:00

413 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Component } from '@esengine/ecs-framework';
/**
* 网络组件 - 模拟复杂的网络连接和数据同步(已移除循环引用)
*/
export class NetworkComponent extends Component {
/** 网络ID */
public networkId: string = '';
/** 连接状态 */
public connectionState: 'disconnected' | 'connecting' | 'connected' | 'error' = 'disconnected';
/** 网络连接信息 */
public connection: {
sessionId: string;
serverId: string;
roomId: string;
playerId: string;
ping: number;
packetLoss: number;
bandwidth: number;
lastHeartbeat: number;
};
/** 同步数据 */
public syncData: {
dirtyFlags: Set<string>;
lastSyncTime: number;
syncHistory: Array<{
timestamp: number;
dataSize: number;
properties: string[];
success: boolean;
}>;
queuedUpdates: Array<{
property: string;
value: any;
timestamp: number;
priority: number;
}>;
};
/** 网络统计 */
public networkStats: {
totalBytesSent: number;
totalBytesReceived: number;
packetsPerSecond: number;
averageLatency: number;
latencyHistory: number[];
connectionQuality: 'excellent' | 'good' | 'fair' | 'poor';
errorCount: number;
reconnectCount: number;
lastErrorTime: number;
errorLog: Array<{
timestamp: number;
errorType: string;
message: string;
stack?: string;
}>;
};
/** 连接的玩家ID列表避免循环引用 */
public connectedPlayerIds: Set<string> = new Set();
/** 群组成员ID避免循环引用 */
public groupMemberIds: string[] = [];
/** 群组领导者ID避免循环引用 */
public groupLeaderId: string | null = null;
/** 复杂的网络配置 */
public config: {
autoReconnect: boolean;
maxReconnectAttempts: number;
heartbeatInterval: number;
syncFrequency: number;
compressionEnabled: boolean;
encryptionEnabled: boolean;
priorityLevels: Map<string, number>;
filters: Array<{
property: string;
condition: (value: any) => boolean;
action: 'allow' | 'deny' | 'transform';
transformer?: (value: any) => any;
}>;
bufferSettings: {
maxBufferSize: number;
flushInterval: number;
compressionThreshold: number;
};
};
/** 消息队列 */
public messageQueue: {
incoming: Array<{
senderId: string;
messageType: string;
data: any;
timestamp: number;
processed: boolean;
}>;
outgoing: Array<{
targetId: string;
messageType: string;
data: any;
priority: number;
attempts: number;
maxAttempts: number;
}>;
processing: Map<string, {
messageId: string;
startTime: number;
expectedDuration: number;
status: 'processing' | 'completed' | 'failed';
}>;
};
/** 复杂的网络缓存系统 */
public cacheSystem: {
playerCache: Map<string, {
playerId: string;
lastSeen: number;
cachedData: any;
cacheExpiry: number;
}>;
messageCache: Map<string, {
messageId: string;
content: any;
timestamp: number;
recipients: string[];
}>;
syncCache: Map<string, {
propertyPath: string;
value: any;
lastUpdated: number;
version: number;
}>;
};
constructor(networkId: string = '') {
super();
this.networkId = networkId || this.generateNetworkId();
this.connection = {
sessionId: '',
serverId: '',
roomId: '',
playerId: '',
ping: 0,
packetLoss: 0,
bandwidth: 0,
lastHeartbeat: 0
};
this.syncData = {
dirtyFlags: new Set(),
lastSyncTime: 0,
syncHistory: [],
queuedUpdates: []
};
this.networkStats = {
totalBytesSent: 0,
totalBytesReceived: 0,
packetsPerSecond: 0,
averageLatency: 0,
latencyHistory: [],
connectionQuality: 'excellent',
errorCount: 0,
reconnectCount: 0,
lastErrorTime: 0,
errorLog: []
};
this.config = {
autoReconnect: true,
maxReconnectAttempts: 5,
heartbeatInterval: 1000,
syncFrequency: 60,
compressionEnabled: true,
encryptionEnabled: false,
priorityLevels: new Map([
['critical', 10],
['high', 7],
['medium', 5],
['low', 2]
]),
filters: [],
bufferSettings: {
maxBufferSize: 1024 * 1024, // 1MB
flushInterval: 100,
compressionThreshold: 1024
}
};
this.messageQueue = {
incoming: [],
outgoing: [],
processing: new Map()
};
this.cacheSystem = {
playerCache: new Map(),
messageCache: new Map(),
syncCache: new Map()
};
}
/**
* 生成网络ID
*/
private generateNetworkId(): string {
return 'net_' + Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15);
}
/**
* 连接到其他网络组件(避免循环引用)
*/
public connectToPlayer(playerNetworkId: string): void {
if (!this.connectedPlayerIds.has(playerNetworkId)) {
this.connectedPlayerIds.add(playerNetworkId);
// 记录连接事件
this.logNetworkEvent('player_connected', {
playerId: playerNetworkId,
timestamp: Date.now()
});
}
}
/**
* 加入群组(避免循环引用)
*/
public joinGroup(memberIds: string[], leaderId?: string): void {
this.groupMemberIds = [...memberIds];
this.groupLeaderId = leaderId || null;
// 更新缓存
memberIds.forEach(memberId => {
this.cacheSystem.playerCache.set(memberId, {
playerId: memberId,
lastSeen: Date.now(),
cachedData: {},
cacheExpiry: Date.now() + 300000 // 5分钟缓存
});
});
}
/**
* 发送消息
*/
public sendMessage(targetId: string, messageType: string, data: any, priority: number = 5): void {
const message = {
targetId,
messageType,
data: this.processOutgoingData(data),
priority,
attempts: 0,
maxAttempts: 3
};
this.messageQueue.outgoing.push(message);
this.messageQueue.outgoing.sort((a, b) => b.priority - a.priority);
// 更新统计
this.networkStats.totalBytesSent += JSON.stringify(data).length;
}
/**
* 处理传出数据
*/
private processOutgoingData(data: any): any {
let processedData = data;
// 应用过滤器
this.config.filters.forEach(filter => {
if (filter.condition(processedData)) {
if (filter.action === 'transform' && filter.transformer) {
processedData = filter.transformer(processedData);
}
}
});
// 压缩数据
if (this.config.compressionEnabled) {
processedData = this.compressData(processedData);
}
return processedData;
}
/**
* 压缩数据(模拟)
*/
private compressData(data: any): any {
// 模拟压缩算法
const serialized = JSON.stringify(data);
if (serialized.length > this.config.bufferSettings.compressionThreshold) {
// 模拟压缩
return {
compressed: true,
originalSize: serialized.length,
compressedSize: Math.floor(serialized.length * 0.6),
data: serialized.substring(0, Math.floor(serialized.length * 0.6))
};
}
return data;
}
/**
* 标记属性为脏
*/
public markDirty(property: string): void {
this.syncData.dirtyFlags.add(property);
}
/**
* 更新网络统计
*/
public updateNetworkStats(deltaTime: number): void {
// 更新延迟历史
if (this.networkStats.latencyHistory.length > 100) {
this.networkStats.latencyHistory.shift();
}
this.networkStats.latencyHistory.push(this.connection.ping);
// 计算平均延迟
this.networkStats.averageLatency = this.networkStats.latencyHistory.reduce((a, b) => a + b, 0) /
this.networkStats.latencyHistory.length;
// 更新连接质量
if (this.networkStats.averageLatency < 50) {
this.networkStats.connectionQuality = 'excellent';
} else if (this.networkStats.averageLatency < 100) {
this.networkStats.connectionQuality = 'good';
} else if (this.networkStats.averageLatency < 200) {
this.networkStats.connectionQuality = 'fair';
} else {
this.networkStats.connectionQuality = 'poor';
}
// 更新包率
this.networkStats.packetsPerSecond = this.messageQueue.outgoing.length / deltaTime;
// 清理过期缓存
this.cleanupExpiredCache();
}
/**
* 清理过期缓存
*/
private cleanupExpiredCache(): void {
const now = Date.now();
// 清理玩家缓存
for (const [key, value] of this.cacheSystem.playerCache) {
if (value.cacheExpiry < now) {
this.cacheSystem.playerCache.delete(key);
}
}
// 清理消息缓存
for (const [key, value] of this.cacheSystem.messageCache) {
if (value.timestamp < now - 600000) { // 10分钟过期
this.cacheSystem.messageCache.delete(key);
}
}
}
/**
* 记录网络事件
*/
private logNetworkEvent(eventType: string, data: any): void {
this.networkStats.errorLog.push({
timestamp: Date.now(),
errorType: eventType,
message: JSON.stringify(data)
});
// 限制日志大小
if (this.networkStats.errorLog.length > 1000) {
this.networkStats.errorLog = this.networkStats.errorLog.slice(-500);
}
}
/**
* 重置组件
*/
public reset(): void {
// 清理ID列表不再需要处理循环引用
this.connectedPlayerIds.clear();
this.groupMemberIds = [];
this.groupLeaderId = null;
this.connectionState = 'disconnected';
this.syncData.dirtyFlags.clear();
this.syncData.syncHistory = [];
this.syncData.queuedUpdates = [];
this.messageQueue.incoming = [];
this.messageQueue.outgoing = [];
this.messageQueue.processing.clear();
this.cacheSystem.playerCache.clear();
this.cacheSystem.messageCache.clear();
this.cacheSystem.syncCache.clear();
this.networkStats.errorLog = [];
this.networkStats.latencyHistory = [];
}
}