Files
esengine/packages/network/src/NetworkComponent.ts

161 lines
4.8 KiB
TypeScript
Raw Normal View History

import { Component } from '@esengine/ecs-framework';
import { INetworkSyncable } from './INetworkSyncable';
/**
*
*
* ECS的Component类
*
*
* @example
* ```typescript
* import { NetworkComponent } from '@esengine/ecs-framework-network';
* import { ProtoSerializable, ProtoFloat } from '@esengine/ecs-framework-network';
*
* @ProtoSerializable('Position')
* class PositionComponent extends NetworkComponent {
* @ProtoFloat(1)
* public x: number = 0;
*
* @ProtoFloat(2)
* public y: number = 0;
*
* constructor(x: number = 0, y: number = 0) {
* super();
* this.x = x;
* this.y = y;
* }
* }
* ```
*/
export abstract class NetworkComponent extends Component implements INetworkSyncable {
/**
*
*
*
*/
private _dirtyFields: Set<number> = new Set();
/**
*
*
*
*/
private _fieldTimestamps: Map<number, number> = new Map();
/**
*
*
*
* @returns
*/
public getNetworkState(): Uint8Array {
const { isProtoSerializable } = require('./Serialization/ProtobufDecorators');
const { ProtobufSerializer } = require('./Serialization/ProtobufSerializer');
if (!isProtoSerializable(this)) {
throw new Error(`组件 ${this.constructor.name} 不支持网络同步,请添加@ProtoSerializable装饰器`);
}
try {
const serializer = ProtobufSerializer.getInstance();
const serializedData = serializer.serialize(this);
return serializedData.data;
} catch (error) {
throw new Error(`获取网络状态失败: ${error}`);
}
}
/**
*
*
*
* @param data -
*/
public applyNetworkState(data: Uint8Array): void {
const { isProtoSerializable } = require('./Serialization/ProtobufDecorators');
const { ProtobufSerializer } = require('./Serialization/ProtobufSerializer');
if (!isProtoSerializable(this)) {
throw new Error(`组件 ${this.constructor.name} 不支持网络同步,请添加@ProtoSerializable装饰器`);
}
try {
const serializer = ProtobufSerializer.getInstance();
const serializedData = {
type: 'protobuf' as const,
componentType: this.constructor.name,
data: data,
size: data.length
};
serializer.deserialize(this, serializedData);
// 应用后清理脏字段标记
this.markClean();
} catch (error) {
throw new Error(`应用网络状态失败: ${error}`);
}
}
/**
*
*
* @returns
*/
public getDirtyFields(): number[] {
return Array.from(this._dirtyFields);
}
/**
*
*
*
*/
public markClean(): void {
this._dirtyFields.clear();
}
/**
*
*
*
* @param fieldNumber -
*/
public markFieldDirty(fieldNumber: number): void {
this._dirtyFields.add(fieldNumber);
this._fieldTimestamps.set(fieldNumber, Date.now());
}
/**
*
*
* @param fieldNumber -
* @returns
*/
public isFieldDirty(fieldNumber: number): boolean {
return this._dirtyFields.has(fieldNumber);
}
/**
*
*
* @param fieldNumber -
* @returns 0
*/
public getFieldTimestamp(fieldNumber: number): number {
return this._fieldTimestamps.get(fieldNumber) || 0;
}
/**
*
*
* @returns
*/
public getDirtyFieldsWithTimestamps(): Map<number, number> {
const result = new Map<number, number>();
for (const fieldNumber of this._dirtyFields) {
result.set(fieldNumber, this._fieldTimestamps.get(fieldNumber) || 0);
}
return result;
}
}