Skip to content

Network System

@esengine/network provides a type-safe network synchronization solution based on @esengine/rpc for multiplayer games, including entity synchronization, input handling, and state interpolation.

The network module consists of two core packages:

PackageDescription
@esengine/rpcType-safe RPC communication library
@esengine/networkRPC-based game networking plugin
Terminal window
npm install @esengine/network

@esengine/rpc is automatically installed as a dependency.

Client Server
┌────────────────────┐ ┌────────────────┐
│ NetworkPlugin │◄── WS ───►│ RpcServer │
│ ├─ NetworkService │ │ ├─ Protocol │
│ ├─ SyncSystem │ │ └─ Handlers │
│ ├─ SpawnSystem │ └────────────────┘
│ └─ InputSystem │
└────────────────────┘
import { Core, Scene } from '@esengine/ecs-framework';
import { NetworkPlugin, NetworkIdentity, NetworkTransform } from '@esengine/network';
// Define game scene
class GameScene extends Scene {
initialize(): void {
this.name = 'Game';
}
}
// Initialize
Core.create({ debug: false });
const scene = new GameScene();
Core.setScene(scene);
// Install network plugin
const networkPlugin = new NetworkPlugin();
await Core.installPlugin(networkPlugin);
// Register prefab factory
networkPlugin.registerPrefab('player', (scene, spawn) => {
const entity = scene.createEntity(`player_${spawn.netId}`);
const identity = entity.addComponent(new NetworkIdentity());
identity.netId = spawn.netId;
identity.ownerId = spawn.ownerId;
identity.bIsLocalPlayer = spawn.ownerId === networkPlugin.localPlayerId;
entity.addComponent(new NetworkTransform());
return entity;
});
// Connect to server
const success = await networkPlugin.connect({
url: 'ws://localhost:3000',
playerName: 'Player1',
roomId: 'room-1' // optional
});
if (success) {
console.log('Connected! Player ID:', networkPlugin.localPlayerId);
}
import { serve } from '@esengine/rpc/server';
import { gameProtocol } from '@esengine/network';
let nextPlayerId = 1;
const server = serve(gameProtocol, {
port: 3000,
api: {
join: async (input, conn) => {
const playerId = nextPlayerId++;
console.log(`Player joined: ${input.playerName} (ID: ${playerId})`);
return { playerId, roomId: input.roomId ?? 'default' };
},
leave: async (_input, conn) => {
console.log(`Player left: ${conn.id}`);
},
reconnect: async (input, conn) => {
// Handle reconnection logic
return { success: true };
},
},
onConnect: (conn) => console.log(`Client connected: ${conn.id}`),
onDisconnect: (conn) => console.log(`Client disconnected: ${conn.id}`),
onStart: (port) => console.log(`Server running on ws://localhost:${port}`),
});
await server.start();

You can define your own protocol using @esengine/rpc:

import { rpc } from '@esengine/rpc';
// Define custom protocol
export const myProtocol = rpc.define({
api: {
login: rpc.api<{ username: string }, { token: string }>(),
getData: rpc.api<{ id: number }, { data: object }>(),
},
msg: {
chat: rpc.msg<{ from: string; text: string }>(),
notification: rpc.msg<{ type: string; content: string }>(),
},
});
// Create service with custom protocol
import { RpcService } from '@esengine/network';
const service = new RpcService(myProtocol);
await service.connect({ url: 'ws://localhost:3000' });
// Type-safe API calls
const result = await service.call('login', { username: 'test' });
console.log(result.token);
// Type-safe message listening
service.on('chat', (data) => {
console.log(`${data.from}: ${data.text}`);
});

Experience the network synchronization system with interactive demos:

For dependency injection:

import {
NetworkServiceToken,
NetworkSyncSystemToken,
NetworkSpawnSystemToken,
NetworkInputSystemToken,
NetworkPredictionSystemToken,
NetworkAOISystemToken,
} from '@esengine/network';
const networkService = services.get(NetworkServiceToken);
const predictionSystem = services.get(NetworkPredictionSystemToken);
const aoiSystem = services.get(NetworkAOISystemToken);

The network module provides visual scripting support:

  • IsLocalPlayer - Check if entity is local player
  • IsServer - Check if running on server
  • HasAuthority - Check if has authority over entity
  • GetNetworkId - Get entity’s network ID
  • GetLocalPlayerId - Get local player ID