feat(ecs): 添加 @NetworkEntity 装饰器,支持自动广播实体生成/销毁 (#395)
* docs: add editor-app README with setup instructions * docs: add separate EN/CN editor setup guides * feat(ecs): add @NetworkEntity decorator for auto spawn/despawn broadcasting - Add @NetworkEntity decorator to mark components for automatic network broadcasting - ECSRoom now auto-broadcasts spawn on component:added event - ECSRoom now auto-broadcasts despawn on entity:destroyed event - Entity.destroy() emits entity:destroyed event via ECSEventType - Entity active state changes emit ENTITY_ENABLED/ENTITY_DISABLED events - Add enableAutoNetworkEntity config option to ECSRoom (default true) - Update documentation for both Chinese and English
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
# @esengine/behavior-tree
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @esengine/ecs-framework@2.6.0
|
||||
|
||||
## 2.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esengine/behavior-tree",
|
||||
"version": "2.0.1",
|
||||
"version": "3.0.0",
|
||||
"description": "ECS-based AI behavior tree system - works with any ECS framework (ESEngine, Cocos, Laya, etc.)",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.js",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @esengine/blueprint
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @esengine/ecs-framework@2.6.0
|
||||
|
||||
## 2.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esengine/blueprint",
|
||||
"version": "2.0.1",
|
||||
"version": "3.0.0",
|
||||
"description": "Visual scripting system - works with any ECS framework (ESEngine, Cocos, Laya, etc.)",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.js",
|
||||
|
||||
@@ -1,5 +1,48 @@
|
||||
# @esengine/ecs-framework
|
||||
|
||||
## 2.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat(ecs): 添加 @NetworkEntity 装饰器,支持自动广播实体生成/销毁
|
||||
|
||||
### 新功能
|
||||
|
||||
**@NetworkEntity 装饰器**
|
||||
- 标记组件为网络实体,自动广播 spawn/despawn 消息
|
||||
- 支持 `autoSpawn` 和 `autoDespawn` 配置选项
|
||||
- 通过事件系统(`ECSEventType.COMPONENT_ADDED` / `ECSEventType.ENTITY_DESTROYED`)实现
|
||||
|
||||
**ECSRoom 增强**
|
||||
- 新增 `enableAutoNetworkEntity` 配置选项(默认启用)
|
||||
- 自动监听组件添加和实体销毁事件
|
||||
- 简化 GameRoom 实现,无需手动回调
|
||||
|
||||
### 改进
|
||||
|
||||
**Entity 事件**
|
||||
- `Entity.destroy()` 现在发出 `entity:destroyed` 事件
|
||||
- `Entity.active` 变化时发出 `entity:enabled` / `entity:disabled` 事件
|
||||
- 使用 `ECSEventType` 常量替代硬编码字符串
|
||||
|
||||
### 使用示例
|
||||
|
||||
```typescript
|
||||
import { Component, ECSComponent, sync, NetworkEntity } from '@esengine/ecs-framework';
|
||||
|
||||
@ECSComponent('Enemy')
|
||||
@NetworkEntity('Enemy')
|
||||
class EnemyComponent extends Component {
|
||||
@sync('float32') x: number = 0;
|
||||
@sync('float32') y: number = 0;
|
||||
}
|
||||
|
||||
// 服务端
|
||||
const entity = scene.createEntity('Enemy');
|
||||
entity.addComponent(new EnemyComponent()); // 自动广播 spawn
|
||||
entity.destroy(); // 自动广播 despawn
|
||||
```
|
||||
|
||||
## 2.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
{
|
||||
"name": "@esengine/ecs-framework",
|
||||
"version": "2.5.1",
|
||||
"version": "2.6.0",
|
||||
"description": "用于Laya、Cocos Creator等JavaScript游戏引擎的高性能ECS框架",
|
||||
"main": "dist/index.cjs",
|
||||
"module": "dist/index.mjs",
|
||||
"types": "dist/index.d.ts",
|
||||
"unpkg": "dist/index.umd.js",
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.cjs"
|
||||
"require": "./dist/index.cjs",
|
||||
"source": "./src/index.ts"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
@@ -50,23 +52,24 @@
|
||||
"@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1",
|
||||
"@babel/plugin-transform-optional-chaining": "^7.27.1",
|
||||
"@babel/preset-env": "^7.28.3",
|
||||
"@eslint/js": "^9.37.0",
|
||||
"@jest/globals": "^29.7.0",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-commonjs": "^28.0.3",
|
||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@jest/globals": "^29.7.0",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^20.19.17",
|
||||
"@eslint/js": "^9.37.0",
|
||||
"eslint": "^9.37.0",
|
||||
"typescript-eslint": "^8.46.1",
|
||||
"jest": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"rimraf": "^5.0.0",
|
||||
"rollup": "^4.42.0",
|
||||
"rollup-plugin-dts": "^6.2.1",
|
||||
"rollup-plugin-sourcemaps": "^0.6.3",
|
||||
"ts-jest": "^29.4.0",
|
||||
"typescript": "^5.8.3"
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.46.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
|
||||
@@ -7,14 +7,7 @@ import { getComponentInstanceTypeName, getComponentTypeName } from './Decorators
|
||||
import { generateGUID } from '../Utils/GUID';
|
||||
import type { IScene } from './IScene';
|
||||
import { EntityHandle, NULL_HANDLE } from './Core/EntityHandle';
|
||||
|
||||
/**
|
||||
* @zh 组件活跃状态变化接口
|
||||
* @en Interface for component active state change
|
||||
*/
|
||||
interface IActiveChangeable {
|
||||
onActiveChanged(): void;
|
||||
}
|
||||
import { ECSEventType } from './CoreEvents';
|
||||
|
||||
/**
|
||||
* @zh 比较两个实体的优先级
|
||||
@@ -482,7 +475,7 @@ export class Entity {
|
||||
}
|
||||
|
||||
if (this.scene.eventSystem) {
|
||||
this.scene.eventSystem.emitSync('component:added', {
|
||||
this.scene.eventSystem.emitSync(ECSEventType.COMPONENT_ADDED, {
|
||||
timestamp: Date.now(),
|
||||
source: 'Entity',
|
||||
entityId: this.id,
|
||||
@@ -639,7 +632,7 @@ export class Entity {
|
||||
component.entityId = null;
|
||||
|
||||
if (this.scene?.eventSystem) {
|
||||
this.scene.eventSystem.emitSync('component:removed', {
|
||||
this.scene.eventSystem.emitSync(ECSEventType.COMPONENT_REMOVED, {
|
||||
timestamp: Date.now(),
|
||||
source: 'Entity',
|
||||
entityId: this.id,
|
||||
@@ -770,19 +763,23 @@ export class Entity {
|
||||
}
|
||||
|
||||
/**
|
||||
* 活跃状态改变时的回调
|
||||
* @zh 活跃状态改变时的回调
|
||||
* @en Callback when active state changes
|
||||
*
|
||||
* @zh 通过事件系统发出 ENTITY_ENABLED 或 ENTITY_DISABLED 事件,
|
||||
* 组件可以通过监听这些事件来响应实体状态变化。
|
||||
* @en Emits ENTITY_ENABLED or ENTITY_DISABLED event through the event system.
|
||||
* Components can listen to these events to respond to entity state changes.
|
||||
*/
|
||||
private onActiveChanged(): void {
|
||||
for (const component of this.components) {
|
||||
if ('onActiveChanged' in component && typeof component.onActiveChanged === 'function') {
|
||||
(component as IActiveChangeable).onActiveChanged();
|
||||
}
|
||||
}
|
||||
if (this.scene?.eventSystem) {
|
||||
const eventType = this._active
|
||||
? ECSEventType.ENTITY_ENABLED
|
||||
: ECSEventType.ENTITY_DISABLED;
|
||||
|
||||
if (this.scene && this.scene.eventSystem) {
|
||||
this.scene.eventSystem.emitSync('entity:activeChanged', {
|
||||
this.scene.eventSystem.emitSync(eventType, {
|
||||
entity: this,
|
||||
active: this._active
|
||||
scene: this.scene,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -801,6 +798,15 @@ export class Entity {
|
||||
|
||||
this._isDestroyed = true;
|
||||
|
||||
// 在清理之前发出销毁事件(组件仍然可访问)
|
||||
if (this.scene?.eventSystem) {
|
||||
this.scene.eventSystem.emitSync(ECSEventType.ENTITY_DESTROYED, {
|
||||
entity: this,
|
||||
entityId: this.id,
|
||||
scene: this.scene,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.scene && this.scene.referenceTracker) {
|
||||
this.scene.referenceTracker.clearReferencesTo(this.id);
|
||||
this.scene.referenceTracker.unregisterEntityScene(this.id);
|
||||
|
||||
147
packages/framework/core/src/ECS/Sync/NetworkEntityDecorator.ts
Normal file
147
packages/framework/core/src/ECS/Sync/NetworkEntityDecorator.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* @zh 网络实体装饰器
|
||||
* @en Network entity decorator
|
||||
*
|
||||
* @zh 提供 @NetworkEntity 装饰器,用于标记需要自动广播生成/销毁的组件
|
||||
* @en Provides @NetworkEntity decorator to mark components for automatic spawn/despawn broadcasting
|
||||
*/
|
||||
|
||||
/**
|
||||
* @zh 网络实体元数据的 Symbol 键
|
||||
* @en Symbol key for network entity metadata
|
||||
*/
|
||||
export const NETWORK_ENTITY_METADATA = Symbol('NetworkEntityMetadata');
|
||||
|
||||
/**
|
||||
* @zh 网络实体元数据
|
||||
* @en Network entity metadata
|
||||
*/
|
||||
export interface NetworkEntityMetadata {
|
||||
/**
|
||||
* @zh 预制体类型名称(用于客户端重建实体)
|
||||
* @en Prefab type name (used by client to reconstruct entity)
|
||||
*/
|
||||
prefabType: string;
|
||||
|
||||
/**
|
||||
* @zh 是否自动广播生成
|
||||
* @en Whether to auto-broadcast spawn
|
||||
* @default true
|
||||
*/
|
||||
autoSpawn: boolean;
|
||||
|
||||
/**
|
||||
* @zh 是否自动广播销毁
|
||||
* @en Whether to auto-broadcast despawn
|
||||
* @default true
|
||||
*/
|
||||
autoDespawn: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 网络实体装饰器配置选项
|
||||
* @en Network entity decorator options
|
||||
*/
|
||||
export interface NetworkEntityOptions {
|
||||
/**
|
||||
* @zh 是否自动广播生成
|
||||
* @en Whether to auto-broadcast spawn
|
||||
* @default true
|
||||
*/
|
||||
autoSpawn?: boolean;
|
||||
|
||||
/**
|
||||
* @zh 是否自动广播销毁
|
||||
* @en Whether to auto-broadcast despawn
|
||||
* @default true
|
||||
*/
|
||||
autoDespawn?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 网络实体装饰器
|
||||
* @en Network entity decorator
|
||||
*
|
||||
* @zh 标记组件类为网络实体。当包含此组件的实体被创建或销毁时,
|
||||
* ECSRoom 会自动广播相应的 spawn/despawn 消息给所有客户端。
|
||||
* @en Marks a component class as a network entity. When an entity containing
|
||||
* this component is created or destroyed, ECSRoom will automatically broadcast
|
||||
* the corresponding spawn/despawn messages to all clients.
|
||||
*
|
||||
* @param prefabType - @zh 预制体类型名称 @en Prefab type name
|
||||
* @param options - @zh 可选配置 @en Optional configuration
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Component, ECSComponent, NetworkEntity, sync } from '@esengine/ecs-framework';
|
||||
*
|
||||
* @ECSComponent('Enemy')
|
||||
* @NetworkEntity('Enemy')
|
||||
* class EnemyComponent extends Component {
|
||||
* @sync('float32') x: number = 0;
|
||||
* @sync('float32') y: number = 0;
|
||||
* @sync('uint16') health: number = 100;
|
||||
* }
|
||||
*
|
||||
* // 当添加此组件到实体时,ECSRoom 会自动广播 spawn
|
||||
* const enemy = scene.createEntity('Enemy');
|
||||
* enemy.addComponent(new EnemyComponent()); // 自动广播给所有客户端
|
||||
*
|
||||
* // 当实体销毁时,自动广播 despawn
|
||||
* enemy.destroy(); // 自动广播给所有客户端
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // 只自动广播生成,销毁由手动控制
|
||||
* @ECSComponent('Bullet')
|
||||
* @NetworkEntity('Bullet', { autoDespawn: false })
|
||||
* class BulletComponent extends Component {
|
||||
* @sync('float32') x: number = 0;
|
||||
* @sync('float32') y: number = 0;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function NetworkEntity(prefabType: string, options?: NetworkEntityOptions) {
|
||||
return function <T extends new (...args: any[]) => any>(target: T): T {
|
||||
const metadata: NetworkEntityMetadata = {
|
||||
prefabType,
|
||||
autoSpawn: options?.autoSpawn ?? true,
|
||||
autoDespawn: options?.autoDespawn ?? true,
|
||||
};
|
||||
|
||||
(target as any)[NETWORK_ENTITY_METADATA] = metadata;
|
||||
|
||||
return target;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 获取组件类的网络实体元数据
|
||||
* @en Get network entity metadata for a component class
|
||||
*
|
||||
* @param componentClass - @zh 组件类或组件实例 @en Component class or instance
|
||||
* @returns @zh 网络实体元数据,如果不存在则返回 null @en Network entity metadata, or null if not exists
|
||||
*/
|
||||
export function getNetworkEntityMetadata(componentClass: any): NetworkEntityMetadata | null {
|
||||
if (!componentClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const constructor = typeof componentClass === 'function'
|
||||
? componentClass
|
||||
: componentClass.constructor;
|
||||
|
||||
return constructor[NETWORK_ENTITY_METADATA] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 检查组件是否标记为网络实体
|
||||
* @en Check if a component is marked as a network entity
|
||||
*
|
||||
* @param component - @zh 组件类或组件实例 @en Component class or instance
|
||||
* @returns @zh 如果是网络实体返回 true @en Returns true if is a network entity
|
||||
*/
|
||||
export function isNetworkEntity(component: any): boolean {
|
||||
return getNetworkEntityMetadata(component) !== null;
|
||||
}
|
||||
@@ -51,5 +51,15 @@ export {
|
||||
hasChanges
|
||||
} from './decorators';
|
||||
|
||||
// Network Entity Decorator
|
||||
export {
|
||||
NetworkEntity,
|
||||
getNetworkEntityMetadata,
|
||||
isNetworkEntity,
|
||||
NETWORK_ENTITY_METADATA,
|
||||
type NetworkEntityMetadata,
|
||||
type NetworkEntityOptions
|
||||
} from './NetworkEntityDecorator';
|
||||
|
||||
// Encoding
|
||||
export * from './encoding';
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @esengine/fsm
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @esengine/ecs-framework@2.6.0
|
||||
- @esengine/blueprint@3.0.0
|
||||
|
||||
## 2.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esengine/fsm",
|
||||
"version": "2.0.1",
|
||||
"version": "3.0.0",
|
||||
"description": "Finite State Machine for ECS Framework / ECS 框架的有限状态机",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @esengine/network
|
||||
|
||||
## 4.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @esengine/ecs-framework@2.6.0
|
||||
- @esengine/blueprint@3.0.0
|
||||
|
||||
## 3.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esengine/network",
|
||||
"version": "3.0.1",
|
||||
"version": "4.0.0",
|
||||
"description": "Network synchronization for multiplayer games",
|
||||
"esengine": {
|
||||
"plugin": true,
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @esengine/pathfinding
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @esengine/ecs-framework@2.6.0
|
||||
- @esengine/blueprint@3.0.0
|
||||
|
||||
## 2.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esengine/pathfinding",
|
||||
"version": "2.0.1",
|
||||
"version": "3.0.0",
|
||||
"description": "寻路系统 | Pathfinding System - A*, Grid, NavMesh",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @esengine/procgen
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @esengine/ecs-framework@2.6.0
|
||||
- @esengine/blueprint@3.0.0
|
||||
|
||||
## 2.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esengine/procgen",
|
||||
"version": "2.0.1",
|
||||
"version": "3.0.0",
|
||||
"description": "Procedural generation tools for ECS Framework / ECS 框架的程序化生成工具",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,5 +1,53 @@
|
||||
# @esengine/server
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat(ecs): 添加 @NetworkEntity 装饰器,支持自动广播实体生成/销毁
|
||||
|
||||
### 新功能
|
||||
|
||||
**@NetworkEntity 装饰器**
|
||||
- 标记组件为网络实体,自动广播 spawn/despawn 消息
|
||||
- 支持 `autoSpawn` 和 `autoDespawn` 配置选项
|
||||
- 通过事件系统(`ECSEventType.COMPONENT_ADDED` / `ECSEventType.ENTITY_DESTROYED`)实现
|
||||
|
||||
**ECSRoom 增强**
|
||||
- 新增 `enableAutoNetworkEntity` 配置选项(默认启用)
|
||||
- 自动监听组件添加和实体销毁事件
|
||||
- 简化 GameRoom 实现,无需手动回调
|
||||
|
||||
### 改进
|
||||
|
||||
**Entity 事件**
|
||||
- `Entity.destroy()` 现在发出 `entity:destroyed` 事件
|
||||
- `Entity.active` 变化时发出 `entity:enabled` / `entity:disabled` 事件
|
||||
- 使用 `ECSEventType` 常量替代硬编码字符串
|
||||
|
||||
### 使用示例
|
||||
|
||||
```typescript
|
||||
import { Component, ECSComponent, sync, NetworkEntity } from '@esengine/ecs-framework';
|
||||
|
||||
@ECSComponent('Enemy')
|
||||
@NetworkEntity('Enemy')
|
||||
class EnemyComponent extends Component {
|
||||
@sync('float32') x: number = 0;
|
||||
@sync('float32') y: number = 0;
|
||||
}
|
||||
|
||||
// 服务端
|
||||
const entity = scene.createEntity('Enemy');
|
||||
entity.addComponent(new EnemyComponent()); // 自动广播 spawn
|
||||
entity.destroy(); // 自动广播 despawn
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @esengine/ecs-framework@2.6.0
|
||||
|
||||
## 2.0.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esengine/server",
|
||||
"version": "2.0.0",
|
||||
"version": "3.0.0",
|
||||
"description": "Game server framework for ESEngine with file-based routing",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
@@ -51,7 +51,7 @@
|
||||
"peerDependencies": {
|
||||
"ws": ">=8.0.0",
|
||||
"jsonwebtoken": ">=9.0.0",
|
||||
"@esengine/ecs-framework": ">=2.5.1"
|
||||
"@esengine/ecs-framework": ">=2.6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"jsonwebtoken": {
|
||||
|
||||
@@ -20,6 +20,11 @@ import {
|
||||
encodeSpawn,
|
||||
encodeDespawn,
|
||||
initChangeTracker,
|
||||
// Network Entity
|
||||
NETWORK_ENTITY_METADATA,
|
||||
type NetworkEntityMetadata,
|
||||
// Events
|
||||
ECSEventType,
|
||||
} from '@esengine/ecs-framework';
|
||||
|
||||
import { Room, type RoomOptions } from '../room/Room.js';
|
||||
@@ -45,11 +50,19 @@ export interface ECSRoomConfig {
|
||||
* @en Whether to enable delta sync
|
||||
*/
|
||||
enableDeltaSync: boolean;
|
||||
|
||||
/**
|
||||
* @zh 是否启用自动网络实体广播(基于 @NetworkEntity 装饰器)
|
||||
* @en Whether to enable automatic network entity broadcasting (based on @NetworkEntity decorator)
|
||||
* @default true
|
||||
*/
|
||||
enableAutoNetworkEntity: boolean;
|
||||
}
|
||||
|
||||
const DEFAULT_ECS_CONFIG: ECSRoomConfig = {
|
||||
syncInterval: 50, // 20 Hz
|
||||
enableDeltaSync: true,
|
||||
enableAutoNetworkEntity: true,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -116,6 +129,12 @@ export abstract class ECSRoom<TState = any, TPlayerData = Record<string, unknown
|
||||
*/
|
||||
private readonly _playerEntities: Map<string, Entity> = new Map();
|
||||
|
||||
/**
|
||||
* @zh 网络实体映射(实体 ID -> prefabType)
|
||||
* @en Network entity mapping (entity ID -> prefabType)
|
||||
*/
|
||||
private readonly _networkEntities: Map<number, string> = new Map();
|
||||
|
||||
/**
|
||||
* @zh 上次同步时间
|
||||
* @en Last sync time
|
||||
@@ -131,6 +150,47 @@ export abstract class ECSRoom<TState = any, TPlayerData = Record<string, unknown
|
||||
this.scene = this.world.createScene('game');
|
||||
this.world.setSceneActive('game', true);
|
||||
this.world.start();
|
||||
|
||||
// 设置自动网络实体广播
|
||||
if (this.ecsConfig.enableAutoNetworkEntity) {
|
||||
this._setupAutoNetworkEntity();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh 设置自动网络实体广播
|
||||
* @en Setup automatic network entity broadcasting
|
||||
*/
|
||||
private _setupAutoNetworkEntity(): void {
|
||||
// 监听组件添加事件,自动广播 spawn
|
||||
this.scene.eventSystem.on(ECSEventType.COMPONENT_ADDED, (event: any) => {
|
||||
const { entity, component } = event;
|
||||
const metadata: NetworkEntityMetadata | undefined =
|
||||
(component.constructor as any)[NETWORK_ENTITY_METADATA];
|
||||
|
||||
if (metadata?.autoSpawn) {
|
||||
// 避免重复广播同一实体
|
||||
if (!this._networkEntities.has(entity.id)) {
|
||||
this._networkEntities.set(entity.id, metadata.prefabType);
|
||||
this.broadcastSpawn(entity, metadata.prefabType);
|
||||
}
|
||||
}
|
||||
|
||||
// 记录需要自动 despawn 的实体
|
||||
if (metadata?.autoDespawn && !this._networkEntities.has(entity.id)) {
|
||||
this._networkEntities.set(entity.id, metadata.prefabType);
|
||||
}
|
||||
});
|
||||
|
||||
// 监听实体销毁事件,自动广播 despawn
|
||||
this.scene.eventSystem.on(ECSEventType.ENTITY_DESTROYED, (event: any) => {
|
||||
const { entityId } = event;
|
||||
if (this._networkEntities.has(entityId)) {
|
||||
const despawnData = encodeDespawn(entityId);
|
||||
this.broadcastBinary(despawnData);
|
||||
this._networkEntities.delete(entityId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @esengine/spatial
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @esengine/ecs-framework@2.6.0
|
||||
- @esengine/blueprint@3.0.0
|
||||
|
||||
## 2.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esengine/spatial",
|
||||
"version": "2.0.1",
|
||||
"version": "3.0.0",
|
||||
"description": "Spatial query and indexing system for ECS Framework / ECS 框架的空间查询和索引系统",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @esengine/timer
|
||||
|
||||
## 3.0.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @esengine/ecs-framework@2.6.0
|
||||
- @esengine/blueprint@3.0.0
|
||||
|
||||
## 2.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esengine/timer",
|
||||
"version": "2.0.1",
|
||||
"version": "3.0.0",
|
||||
"description": "Timer and cooldown system for ECS Framework / ECS 框架的定时器和冷却系统",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @esengine/transaction
|
||||
|
||||
## 2.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @esengine/server@3.0.0
|
||||
|
||||
## 2.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@esengine/transaction",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"description": "Game transaction system with distributed support | 游戏事务系统,支持分布式事务",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
Reference in New Issue
Block a user