From 97a69fed093bce079e39d13b957d2f21bd0ca131 Mon Sep 17 00:00:00 2001
From: YHH <359807859@qq.com>
Date: Thu, 9 Oct 2025 17:14:18 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E9=87=8F=E5=BA=8F=E5=88=97=E5=8C=96?=
=?UTF-8?q?=E6=94=AF=E6=8C=81=E4=BA=8C=E8=BF=9B=E5=88=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/guide/serialization.md | 87 ++++++---
.../src/demos/IncrementalSerializationDemo.ts | 47 ++++-
packages/core/src/ECS/Scene.ts | 18 +-
.../Serialization/IncrementalSerializer.ts | 103 +++++++++--
packages/core/src/ECS/Serialization/index.ts | 1 +
.../IncrementalSerialization.test.ts | 175 +++++++++++++++++-
6 files changed, 373 insertions(+), 58 deletions(-)
diff --git a/docs/guide/serialization.md b/docs/guide/serialization.md
index b72e62ad..4b8c7781 100644
--- a/docs/guide/serialization.md
+++ b/docs/guide/serialization.md
@@ -251,13 +251,25 @@ console.log('更新组件:', stats.updatedComponents);
#### 4. 序列化增量数据
```typescript
-// 转换为JSON字符串
-const json = IncrementalSerializer.serializeIncremental(incremental);
+// JSON格式(默认)
+const jsonData = IncrementalSerializer.serializeIncremental(incremental, {
+ format: 'json'
+});
-// 发送到服务器或保存
-socket.send(json);
-// 或
-localStorage.setItem('changes', json);
+// 二进制格式(更小的体积,更高性能)
+const binaryData = IncrementalSerializer.serializeIncremental(incremental, {
+ format: 'binary'
+});
+
+// 美化JSON输出(便于调试)
+const prettyJson = IncrementalSerializer.serializeIncremental(incremental, {
+ format: 'json',
+ pretty: true
+});
+
+// 发送或保存
+socket.send(binaryData); // 网络传输使用二进制
+localStorage.setItem('changes', jsonData); // 本地存储可用JSON
```
#### 5. 应用增量变更
@@ -266,11 +278,16 @@ localStorage.setItem('changes', json);
// 在另一个场景应用变更
const otherScene = new Scene();
-// 从JSON字符串应用
-otherScene.applyIncremental(json);
-
-// 或直接应用增量对象
+// 直接应用增量对象
otherScene.applyIncremental(incremental);
+
+// 从JSON字符串应用
+const jsonData = IncrementalSerializer.serializeIncremental(incremental, { format: 'json' });
+otherScene.applyIncremental(jsonData);
+
+// 从二进制Buffer应用
+const binaryData = IncrementalSerializer.serializeIncremental(incremental, { format: 'binary' });
+otherScene.applyIncremental(binaryData);
```
### 增量快照管理
@@ -322,6 +339,16 @@ interface IncrementalSerializationOptions {
// 是否压缩快照(使用JSON序列化)
// 默认false
compressSnapshot?: boolean;
+
+ // 序列化格式
+ // 'json': JSON格式(可读性好,方便调试)
+ // 'binary': MessagePack二进制格式(体积小,性能高)
+ // 默认 'json'
+ format?: 'json' | 'binary';
+
+ // 是否美化JSON输出(仅在format='json'时有效)
+ // 默认false
+ pretty?: boolean;
}
// 使用选项
@@ -513,17 +540,21 @@ class NetworkSync {
// 只在有变更时发送
if (stats.totalChanges > 0) {
- const json = IncrementalSerializer.serializeIncremental(incremental);
- this.socket.send(json);
+ // 使用二进制格式减少网络传输量
+ const binaryData = IncrementalSerializer.serializeIncremental(incremental, {
+ format: 'binary'
+ });
+ this.socket.send(binaryData);
// 更新基准
this.scene.updateIncrementalSnapshot();
}
}
- private receiveIncremental(data: string): void {
- const incremental = IncrementalSerializer.deserializeIncremental(data);
- this.scene.applyIncremental(incremental);
+ private receiveIncremental(data: ArrayBuffer): void {
+ // 直接应用二进制数据
+ const buffer = Buffer.from(data);
+ this.scene.applyIncremental(buffer);
}
}
```
@@ -750,23 +781,27 @@ class LargeDataComponent extends Component {
### 全量序列化API
-- `scene.serialize(options?): string | Buffer` - 序列化场景
-- `scene.deserialize(data, options?)` - 反序列化场景
-- `SceneSerializer.validate(data)` - 验证序列化数据
-- `SceneSerializer.getInfo(data)` - 获取序列化数据信息
+- [`Scene.serialize()`](/api/classes/Scene#serialize) - 序列化场景
+- [`Scene.deserialize()`](/api/classes/Scene#deserialize) - 反序列化场景
+- [`SceneSerializer`](/api/classes/SceneSerializer) - 场景序列化器
+- [`ComponentSerializer`](/api/classes/ComponentSerializer) - 组件序列化器
### 增量序列化API
-- `scene.createIncrementalSnapshot(options?)` - 创建基础快照
-- `scene.serializeIncremental(options?)` - 获取增量变更
-- `scene.applyIncremental(incremental)` - 应用增量变更
-- `scene.updateIncrementalSnapshot(options?)` - 更新快照基准
-- `scene.clearIncrementalSnapshot()` - 清除快照
-- `scene.hasIncrementalSnapshot()` - 检查是否有快照
-- `IncrementalSerializer.getIncrementalStats(incremental)` - 获取统计信息
+- [`Scene.createIncrementalSnapshot()`](/api/classes/Scene#createincrementalsnapshot) - 创建基础快照
+- [`Scene.serializeIncremental()`](/api/classes/Scene#serializeincremental) - 获取增量变更
+- [`Scene.applyIncremental()`](/api/classes/Scene#applyincremental) - 应用增量变更(支持IncrementalSnapshot对象、JSON字符串或二进制Buffer)
+- [`Scene.updateIncrementalSnapshot()`](/api/classes/Scene#updateincrementalsnapshot) - 更新快照基准
+- [`Scene.clearIncrementalSnapshot()`](/api/classes/Scene#clearincrementalsnapshot) - 清除快照
+- [`Scene.hasIncrementalSnapshot()`](/api/classes/Scene#hasincrementalsnapshot) - 检查是否有快照
+- [`IncrementalSerializer`](/api/classes/IncrementalSerializer) - 增量序列化器
+- [`IncrementalSnapshot`](/api/interfaces/IncrementalSnapshot) - 增量快照接口
+- [`IncrementalSerializationOptions`](/api/interfaces/IncrementalSerializationOptions) - 增量序列化选项
+- [`IncrementalSerializationFormat`](/api/type-aliases/IncrementalSerializationFormat) - 序列化格式类型
### 版本迁移API
+- [`VersionMigrationManager`](/api/classes/VersionMigrationManager) - 版本迁移管理器
- `VersionMigrationManager.registerComponentMigration()` - 注册组件迁移
- `VersionMigrationManager.registerSceneMigration()` - 注册场景迁移
- `VersionMigrationManager.canMigrateComponent()` - 检查是否可以迁移
diff --git a/examples/core-demos/src/demos/IncrementalSerializationDemo.ts b/examples/core-demos/src/demos/IncrementalSerializationDemo.ts
index a9078a7d..0b3c3331 100644
--- a/examples/core-demos/src/demos/IncrementalSerializationDemo.ts
+++ b/examples/core-demos/src/demos/IncrementalSerializationDemo.ts
@@ -166,11 +166,17 @@ export class IncrementalSerializationDemo extends DemoBase {
const incremental = this.scene.serializeIncremental();
const stats = IncrementalSerializer.getIncrementalStats(incremental);
+ // 计算JSON和二进制格式的大小
+ const jsonSize = IncrementalSerializer.getIncrementalSize(incremental, 'json');
+ const binarySize = IncrementalSerializer.getIncrementalSize(incremental, 'binary');
+
this.incrementalHistory.push({
label,
incremental,
stats,
- timestamp: Date.now()
+ timestamp: Date.now(),
+ jsonSize,
+ binarySize
});
this.scene.updateIncrementalSnapshot();
@@ -226,8 +232,16 @@ export class IncrementalSerializationDemo extends DemoBase {
0
-
最后快照大小
-
0B
+
JSON大小
+
0B
+
+
+
总变更数
@@ -358,8 +372,12 @@ export class IncrementalSerializationDemo extends DemoBase {
实体: +${item.stats.addedEntities} -${item.stats.removedEntities} ~${item.stats.updatedEntities} |
- 组件: +${item.stats.addedComponents} -${item.stats.removedComponents} ~${item.stats.updatedComponents} |
- 总变更: ${item.stats.totalChanges}
+ 组件: +${item.stats.addedComponents} -${item.stats.removedComponents} ~${item.stats.updatedComponents}
+
+
+ JSON: ${this.formatBytes(item.jsonSize)} |
+ Binary: ${this.formatBytes(item.binarySize)} |
+ 节省: ${((1 - item.binarySize / item.jsonSize) * 100).toFixed(1)}%
`;
@@ -381,11 +399,19 @@ export class IncrementalSerializationDemo extends DemoBase {
const item = this.incrementalHistory[index];
const detailsPanel = document.getElementById('snapshotDetails')!;
+ const compressionRatio = ((1 - item.binarySize / item.jsonSize) * 100).toFixed(1);
+
const details = {
版本: item.incremental.version,
基础版本: item.incremental.baseVersion,
时间戳: new Date(item.incremental.timestamp).toLocaleString(),
场景名称: item.incremental.sceneName,
+ 格式对比: {
+ JSON大小: this.formatBytes(item.jsonSize),
+ 二进制大小: this.formatBytes(item.binarySize),
+ 压缩率: `${compressionRatio}%`,
+ 节省字节: this.formatBytes(item.jsonSize - item.binarySize)
+ },
统计: item.stats,
实体变更: item.incremental.entityChanges.map((c: any) => ({
操作: c.operation,
@@ -413,8 +439,15 @@ export class IncrementalSerializationDemo extends DemoBase {
if (this.incrementalHistory.length > 0) {
const lastItem = this.incrementalHistory[this.incrementalHistory.length - 1];
- const size = IncrementalSerializer.getIncrementalSize(lastItem.incremental);
- document.getElementById('snapshotSize')!.textContent = this.formatBytes(size);
+
+ document.getElementById('jsonSize')!.textContent = this.formatBytes(lastItem.jsonSize);
+ document.getElementById('binarySize')!.textContent = this.formatBytes(lastItem.binarySize);
+
+ const compressionRatio = ((1 - lastItem.binarySize / lastItem.jsonSize) * 100).toFixed(1);
+ const ratioElement = document.getElementById('compressionRatio')!;
+ ratioElement.textContent = `${compressionRatio}%`;
+ ratioElement.style.color = parseFloat(compressionRatio) > 30 ? '#4ecdc4' : '#ffe66d';
+
document.getElementById('totalChanges')!.textContent = lastItem.stats.totalChanges.toString();
}
}
diff --git a/packages/core/src/ECS/Scene.ts b/packages/core/src/ECS/Scene.ts
index ae0356cc..40865517 100644
--- a/packages/core/src/ECS/Scene.ts
+++ b/packages/core/src/ECS/Scene.ts
@@ -618,24 +618,28 @@ export class Scene implements IScene {
/**
* 应用增量变更到场景
*
- * @param incremental 增量快照数据(JSON字符串或对象)
+ * @param incremental 增量快照数据(IncrementalSnapshot对象、JSON字符串或二进制Buffer)
* @param componentRegistry 组件类型注册表(可选,默认使用全局注册表)
*
* @example
* ```typescript
- * // 应用增量变更
+ * // 应用增量变更对象
* scene.applyIncremental(incrementalSnapshot);
*
- * // 或从JSON字符串应用
- * const incremental = IncrementalSerializer.deserializeIncremental(jsonString);
- * scene.applyIncremental(incremental);
+ * // 从JSON字符串应用
+ * const jsonData = IncrementalSerializer.serializeIncremental(snapshot, { format: 'json' });
+ * scene.applyIncremental(jsonData);
+ *
+ * // 从二进制Buffer应用
+ * const binaryData = IncrementalSerializer.serializeIncremental(snapshot, { format: 'binary' });
+ * scene.applyIncremental(binaryData);
* ```
*/
public applyIncremental(
- incremental: IncrementalSnapshot | string,
+ incremental: IncrementalSnapshot | string | Buffer,
componentRegistry?: Map
): void {
- const snapshot = typeof incremental === 'string'
+ const snapshot = (typeof incremental === 'string' || Buffer.isBuffer(incremental))
? IncrementalSerializer.deserializeIncremental(incremental)
: incremental;
diff --git a/packages/core/src/ECS/Serialization/IncrementalSerializer.ts b/packages/core/src/ECS/Serialization/IncrementalSerializer.ts
index 0e5c964f..95012d5e 100644
--- a/packages/core/src/ECS/Serialization/IncrementalSerializer.ts
+++ b/packages/core/src/ECS/Serialization/IncrementalSerializer.ts
@@ -11,6 +11,7 @@ import { Component } from '../Component';
import { ComponentSerializer, SerializedComponent } from './ComponentSerializer';
import { SerializedEntity } from './EntitySerializer';
import { ComponentType } from '../Core/ComponentStorage';
+import * as msgpack from 'msgpack-lite';
/**
* 变更操作类型
@@ -117,6 +118,11 @@ interface SceneSnapshot {
sceneData: Map; // 使用JSON字符串存储场景数据
}
+/**
+ * 增量序列化格式
+ */
+export type IncrementalSerializationFormat = 'json' | 'binary';
+
/**
* 增量序列化选项
*/
@@ -138,6 +144,20 @@ export interface IncrementalSerializationOptions {
* 默认false,设为true可减少内存占用但增加CPU开销
*/
compressSnapshot?: boolean;
+
+ /**
+ * 序列化格式
+ * - 'json': JSON格式(可读性好,方便调试)
+ * - 'binary': MessagePack二进制格式(体积小,性能高)
+ * 默认 'json'
+ */
+ format?: IncrementalSerializationFormat;
+
+ /**
+ * 是否美化JSON输出(仅在format='json'时有效)
+ * 默认false
+ */
+ pretty?: boolean;
}
/**
@@ -585,40 +605,93 @@ export class IncrementalSerializer {
}
/**
- * 序列化增量快照为JSON
+ * 序列化增量快照
*
* @param incremental 增量快照
- * @param pretty 是否美化输出
- * @returns JSON字符串
+ * @param options 序列化选项
+ * @returns 序列化后的数据(JSON字符串或二进制Buffer)
+ *
+ * @example
+ * ```typescript
+ * // JSON格式(默认)
+ * const jsonData = IncrementalSerializer.serializeIncremental(snapshot);
+ *
+ * // 二进制格式
+ * const binaryData = IncrementalSerializer.serializeIncremental(snapshot, {
+ * format: 'binary'
+ * });
+ *
+ * // 美化JSON
+ * const prettyJson = IncrementalSerializer.serializeIncremental(snapshot, {
+ * format: 'json',
+ * pretty: true
+ * });
+ * ```
*/
public static serializeIncremental(
incremental: IncrementalSnapshot,
- pretty: boolean = false
- ): string {
- return pretty
- ? JSON.stringify(incremental, null, 2)
- : JSON.stringify(incremental);
+ options?: { format?: IncrementalSerializationFormat; pretty?: boolean }
+ ): string | Buffer {
+ const opts = {
+ format: 'json' as IncrementalSerializationFormat,
+ pretty: false,
+ ...options
+ };
+
+ if (opts.format === 'binary') {
+ return msgpack.encode(incremental);
+ } else {
+ return opts.pretty
+ ? JSON.stringify(incremental, null, 2)
+ : JSON.stringify(incremental);
+ }
}
/**
- * 从JSON反序列化增量快照
+ * 反序列化增量快照
*
- * @param json JSON字符串
+ * @param data 序列化的数据(JSON字符串或二进制Buffer)
* @returns 增量快照
+ *
+ * @example
+ * ```typescript
+ * // 从JSON反序列化
+ * const snapshot = IncrementalSerializer.deserializeIncremental(jsonString);
+ *
+ * // 从二进制反序列化
+ * const snapshot = IncrementalSerializer.deserializeIncremental(buffer);
+ * ```
*/
- public static deserializeIncremental(json: string): IncrementalSnapshot {
- return JSON.parse(json);
+ public static deserializeIncremental(data: string | Buffer): IncrementalSnapshot {
+ if (typeof data === 'string') {
+ // JSON格式
+ return JSON.parse(data);
+ } else {
+ // 二进制格式(MessagePack)
+ return msgpack.decode(data);
+ }
}
/**
* 计算增量快照的大小(字节)
*
* @param incremental 增量快照
+ * @param format 序列化格式,默认为 'json'
* @returns 字节数
*/
- public static getIncrementalSize(incremental: IncrementalSnapshot): number {
- const json = this.serializeIncremental(incremental);
- return new Blob([json]).size;
+ public static getIncrementalSize(
+ incremental: IncrementalSnapshot,
+ format: IncrementalSerializationFormat = 'json'
+ ): number {
+ const data = this.serializeIncremental(incremental, { format });
+
+ if (typeof data === 'string') {
+ // JSON格式:计算UTF-8编码后的字节数
+ return Buffer.byteLength(data, 'utf8');
+ } else {
+ // 二进制格式:直接返回Buffer长度
+ return data.length;
+ }
}
/**
diff --git a/packages/core/src/ECS/Serialization/index.ts b/packages/core/src/ECS/Serialization/index.ts
index fff7789f..154c9df1 100644
--- a/packages/core/src/ECS/Serialization/index.ts
+++ b/packages/core/src/ECS/Serialization/index.ts
@@ -55,6 +55,7 @@ export { IncrementalSerializer, ChangeOperation } from './IncrementalSerializer'
export type {
IncrementalSnapshot,
IncrementalSerializationOptions,
+ IncrementalSerializationFormat,
EntityChange,
ComponentChange,
SceneDataChange
diff --git a/packages/core/tests/ECS/Serialization/IncrementalSerialization.test.ts b/packages/core/tests/ECS/Serialization/IncrementalSerialization.test.ts
index e2f52851..53ae0fdf 100644
--- a/packages/core/tests/ECS/Serialization/IncrementalSerialization.test.ts
+++ b/packages/core/tests/ECS/Serialization/IncrementalSerialization.test.ts
@@ -436,20 +436,42 @@ describe('Incremental Serialization System', () => {
});
describe('Incremental Serialization', () => {
- it('应该序列化和反序列化增量快照', () => {
+ it('应该序列化和反序列化增量快照(JSON格式)', () => {
scene.createIncrementalSnapshot();
const entity = scene.createEntity('Entity');
entity.addComponent(new PositionComponent(50, 100));
const incremental = scene.serializeIncremental();
- const json = IncrementalSerializer.serializeIncremental(incremental);
+ const json = IncrementalSerializer.serializeIncremental(incremental, { format: 'json' });
expect(typeof json).toBe('string');
const deserialized = IncrementalSerializer.deserializeIncremental(json);
expect(deserialized.version).toBe(incremental.version);
expect(deserialized.entityChanges.length).toBe(incremental.entityChanges.length);
+ expect(deserialized.componentChanges.length).toBe(incremental.componentChanges.length);
+ });
+
+ it('应该序列化和反序列化增量快照(二进制格式)', () => {
+ scene.createIncrementalSnapshot();
+
+ const entity = scene.createEntity('Entity');
+ entity.addComponent(new PositionComponent(50, 100));
+ entity.tag = 42;
+ scene.sceneData.set('weather', 'sunny');
+
+ const incremental = scene.serializeIncremental();
+ const binary = IncrementalSerializer.serializeIncremental(incremental, { format: 'binary' });
+
+ expect(Buffer.isBuffer(binary)).toBe(true);
+
+ const deserialized = IncrementalSerializer.deserializeIncremental(binary);
+ expect(deserialized.version).toBe(incremental.version);
+ expect(deserialized.sceneName).toBe(incremental.sceneName);
+ expect(deserialized.entityChanges.length).toBe(incremental.entityChanges.length);
+ expect(deserialized.componentChanges.length).toBe(incremental.componentChanges.length);
+ expect(deserialized.sceneDataChanges.length).toBe(incremental.sceneDataChanges.length);
});
it('应该美化JSON输出', () => {
@@ -458,11 +480,158 @@ describe('Incremental Serialization System', () => {
entity.addComponent(new PositionComponent(10, 20));
const incremental = scene.serializeIncremental();
- const prettyJson = IncrementalSerializer.serializeIncremental(incremental, true);
+ const prettyJson = IncrementalSerializer.serializeIncremental(incremental, { format: 'json', pretty: true });
+ expect(typeof prettyJson).toBe('string');
expect(prettyJson).toContain('\n');
expect(prettyJson).toContain(' ');
});
+
+ it('二进制格式应该比JSON格式更小', () => {
+ const entities = [];
+ for (let i = 0; i < 50; i++) {
+ const entity = scene.createEntity(`Entity_${i}`);
+ entity.addComponent(new PositionComponent(i * 10, i * 20));
+ entity.addComponent(new VelocityComponent());
+ entities.push(entity);
+ }
+
+ scene.createIncrementalSnapshot();
+
+ for (const entity of entities) {
+ const pos = entity.getComponent(PositionComponent)!;
+ pos.x += 100;
+ pos.y += 200;
+ }
+
+ const incremental = scene.serializeIncremental();
+
+ const jsonData = IncrementalSerializer.serializeIncremental(incremental, { format: 'json' });
+ const binaryData = IncrementalSerializer.serializeIncremental(incremental, { format: 'binary' });
+
+ const jsonSize = Buffer.byteLength(jsonData as string);
+ const binarySize = (binaryData as Buffer).length;
+
+ expect(binarySize).toBeLessThan(jsonSize);
+ });
+
+ it('二进制和JSON格式应该包含相同的数据', () => {
+ scene.createIncrementalSnapshot();
+
+ const entity1 = scene.createEntity('Entity1');
+ entity1.addComponent(new PositionComponent(10, 20));
+ entity1.addComponent(new VelocityComponent());
+ entity1.tag = 99;
+
+ const entity2 = scene.createEntity('Entity2');
+ entity2.addComponent(new HealthComponent());
+
+ scene.sceneData.set('level', 5);
+ scene.sceneData.set('score', 1000);
+
+ const incremental = scene.serializeIncremental();
+
+ const jsonData = IncrementalSerializer.serializeIncremental(incremental, { format: 'json' });
+ const binaryData = IncrementalSerializer.serializeIncremental(incremental, { format: 'binary' });
+
+ const fromJson = IncrementalSerializer.deserializeIncremental(jsonData);
+ const fromBinary = IncrementalSerializer.deserializeIncremental(binaryData);
+
+ expect(fromJson.version).toBe(fromBinary.version);
+ expect(fromJson.timestamp).toBe(fromBinary.timestamp);
+ expect(fromJson.sceneName).toBe(fromBinary.sceneName);
+ expect(fromJson.entityChanges.length).toBe(fromBinary.entityChanges.length);
+ expect(fromJson.componentChanges.length).toBe(fromBinary.componentChanges.length);
+ expect(fromJson.sceneDataChanges.length).toBe(fromBinary.sceneDataChanges.length);
+
+ expect(fromJson.entityChanges[0].entityName).toBe(fromBinary.entityChanges[0].entityName);
+ expect(fromJson.entityChanges[0].entityData?.tag).toBe(fromBinary.entityChanges[0].entityData?.tag);
+ });
+
+ it('应该正确应用二进制格式反序列化的增量快照', () => {
+ const scene1 = new Scene({ name: 'Scene1' });
+ scene1.createIncrementalSnapshot();
+
+ const entity = scene1.createEntity('TestEntity');
+ entity.addComponent(new PositionComponent(100, 200));
+ entity.tag = 77;
+
+ const incremental = scene1.serializeIncremental();
+ const binaryData = IncrementalSerializer.serializeIncremental(incremental, { format: 'binary' });
+
+ const deserializedIncremental = IncrementalSerializer.deserializeIncremental(binaryData);
+
+ const scene2 = new Scene({ name: 'Scene2' });
+ scene2.applyIncremental(deserializedIncremental);
+
+ expect(scene2.entities.count).toBe(1);
+ const restoredEntity = scene2.findEntity('TestEntity');
+ expect(restoredEntity).not.toBeNull();
+ expect(restoredEntity!.tag).toBe(77);
+ expect(restoredEntity!.hasComponent(PositionComponent)).toBe(true);
+
+ const pos = restoredEntity!.getComponent(PositionComponent)!;
+ expect(pos.x).toBe(100);
+ expect(pos.y).toBe(200);
+
+ scene1.end();
+ scene2.end();
+ });
+
+ it('Scene.applyIncremental应该直接支持二进制Buffer', () => {
+ const scene1 = new Scene({ name: 'Scene1' });
+ scene1.createIncrementalSnapshot();
+
+ const entity1 = scene1.createEntity('Entity1');
+ entity1.addComponent(new PositionComponent(10, 20));
+ entity1.addComponent(new VelocityComponent());
+
+ const entity2 = scene1.createEntity('Entity2');
+ entity2.addComponent(new HealthComponent());
+
+ const incremental = scene1.serializeIncremental();
+ const binaryData = IncrementalSerializer.serializeIncremental(incremental, { format: 'binary' });
+
+ const scene2 = new Scene({ name: 'Scene2' });
+ scene2.applyIncremental(binaryData);
+
+ expect(scene2.entities.count).toBe(2);
+
+ const e1 = scene2.findEntity('Entity1');
+ expect(e1).not.toBeNull();
+ expect(e1!.hasComponent(PositionComponent)).toBe(true);
+ expect(e1!.hasComponent(VelocityComponent)).toBe(true);
+
+ const e2 = scene2.findEntity('Entity2');
+ expect(e2).not.toBeNull();
+ expect(e2!.hasComponent(HealthComponent)).toBe(true);
+
+ scene1.end();
+ scene2.end();
+ });
+
+ it('Scene.applyIncremental应该直接支持JSON字符串', () => {
+ const scene1 = new Scene({ name: 'Scene1' });
+ scene1.createIncrementalSnapshot();
+
+ const entity = scene1.createEntity('TestEntity');
+ entity.addComponent(new PositionComponent(50, 100));
+ entity.tag = 99;
+
+ const incremental = scene1.serializeIncremental();
+ const jsonData = IncrementalSerializer.serializeIncremental(incremental, { format: 'json' });
+
+ const scene2 = new Scene({ name: 'Scene2' });
+ scene2.applyIncremental(jsonData);
+
+ expect(scene2.entities.count).toBe(1);
+ const restoredEntity = scene2.findEntity('TestEntity');
+ expect(restoredEntity).not.toBeNull();
+ expect(restoredEntity!.tag).toBe(99);
+
+ scene1.end();
+ scene2.end();
+ });
});
describe('Snapshot Management', () => {