ECSPowerNetcode
Library to power up your experience with the DOTS Unity Netcode.
Install / Use
/learn @actionk/ECSPowerNetcodeREADME
ECSPowerNetcode
The library is made on top of the Unity Netcode package and saves you some time on configuring it / provides tools for client-server communication.
Table of Contents
- Install
- Getting started
- Groups
- Command builders
- Command handlers
- Synchronizing entities
- Synchronizing components
- Managed RPC commands
Demo
I like to have this repo as a module without a unity project, so please go to another repo which I created just for a demo: ECSPowerNetcodeDemo.
Install
You can either just put the files into Assets/Plugins/ECSEntityBuilder or use it as a submodule:
git submodule add https://github.com/actionk/ECSPowerNetcode.git Assets/Plugins/ECSPowerNetcode
Important!
After adding a plugin, please add the Network prefab into your scene from ECSPowerNetcode/Prefabs folder. This will enable networking.
Dependencies
The library depends on:
These are required dependencies
Getting started
Starting a server and connecting to it locally
ServerManager.Instance.StartServer(7979);
ClientManager.Instance.ConnectToServer(7979);
After doing so, the library will automatically establish a connection and create command handlers for each connection in both client & server world.
Connecting to a remote server
ClientManager.Instance.ConnectToServer(7979, "remote ip address");
Accessing connection's entities
Each connection is described by these parameters:
public struct ConnectionDescription
{
public int networkId; // unique network id value for client-server connection
public Entity connectionEntity;
public Entity commandHandlerEntity;
}
Client side
ClientManager.Instance.IsConnected
ClientManager.Instance.ConnectionToServer -> ConnectionDescription struct
Server side
ServerManager.Instance.AllConnections - getting list of all connected clients of ConnectionDescription struct
ServerManager.Instance.GetClientConnectionByNetworkId
Handlers
Client
You can set your handlers for OnConnected & OnDisconnected events:
ClientManager.Instance.OnConnectedHandler += MyHandler;
ClientManager.Instance.OnDisconnectedHandler += MyHandler;
Server
You can set your handlers for OnConnected & OnDisconnected events for each player:
public delegate void OnPlayerDisconnected(int networkConnectionId);
ServerManager.Instance.OnPlayerConnectedHandler += MyHandler;
ServerManager.Instance.OnPlayerDisconnectedHandler += MyHandler;
Groups
Client
ClientConnectionSystemGroup
ClientRequestProcessingSystemGroup
ClientNetworkEntitySystemGroup
ClientGameSimulationSystemGroup
| Group | Description | | --- | --- | | ClientConnectionSystemGroup | Connection/Disconnection from server | | ClientRequestProcessingSystemGroup | Processing requests from server | | ClientNetworkEntitySystemGroup | Processing network entities | | ClientGameSimulationSystemGroup | All your game simulations on client side |
Server
ServerConnectionSystemGroup
ServerRequestProcessingSystemGroup
ServerNetworkEntitySystemGroup
ServerGameSimulationSystemGroup
| Group | Description | | --- | --- | | ServerConnectionSystemGroup | Connection/Disconnection from clients | | ServerRequestProcessingSystemGroup | Processing requests from clients | | ServerNetworkEntitySystemGroup | Processing network entities | | ServerGameSimulationSystemGroup | All your game simulations on server side |
Command builders
For making your life easier, there are command builders for both client & server commands. First of all, you have to create an IRpcCommand yourself.
Client
ClientToServerRpcCommandBuilder
.Send(new ClientPlayerLoginCommand {localPlayerSide = PlayerManager.LocalPlayerSide.LEFT})
.Build(PostUpdateCommands);
Where ClientPlayerLoginCommand implements IRpcCommand
Server
You can specify which client to send the command to:
ServerToClientRpcCommandBuilder
.SendTo(clientConnectionEntity, command)
.Build(PostUpdateCommands);
ServerToClientRpcCommandBuilder
.SendTo(networkConnectionId, command)
.Build(PostUpdateCommands);
Or you can simply broadcast:
ServerToClientRpcCommandBuilder
.Broadcast(command)
.Build(PostUpdateCommands);
Command handlers
Client
Simply inherit from AClientReceiveRpcCommandSystem to implement a client command handler for RPC command of type ServerPlayerLoginResponseCommand (for example):
public class ClientPlayerLoginResponseSystem : AClientReceiveRpcCommandSystem<ServerPlayerLoginResponseCommand>
{
protected override void OnCommand(ref ServerPlayerLoginResponseCommand command, ConnectionDescription clientConnection)
{
// process your command
}
}
Server
Simply inherit from AServerReceiveRpcCommandSystem to implement a server command handler for RPC command of type ClientDropItemCommand (for example):
public class ServerDropItemSystem : AServerReceiveRpcCommandSystem<ClientDropItemCommand>
{
protected override void OnCommand(ref ClientDropItemCommand command, ConnectionDescription clientConnection)
{
// process your command
}
}
Synchronizing entities
Usually your way of organizing entities in client-server architecture with ECS would look like that:

That's for, the library provides you with a way of synchronizing entities without using ghost components:

Creating an entity on server side
You start with creating an entity builder by inheriting your builder from ServerNetworkEntityBuilder:
public class ServerPlayerBuilder : ServerNetworkEntityBuilder<ServerPlayerBuilder>
{
protected override ServerPlayerBuilder Self => this;
public static ServerPlayerBuilder Create(int networkId, Entity connection, uint playerId, PlayerManager.LocalPlayerSide localPlayerSide)
{
return new ServerPlayerBuilder(networkId, connection, playerId, localPlayerSide);
}
private ServerPlayerBuilder(int networkId, Entity connection, uint playerId, PlayerManager.LocalPlayerSide localPlayerSide) : base()
{
CreateFromArchetype<PlayerArchetype>(WorldType.SERVER);
SetComponentData(new Scale {Value = 1});
AddComponentData(new ServerPlayer
{
networkId = networkId,
connection = connection,
playerId = playerId,
localPlayerSide = localPlayerSide
});
}
}
Transferring the entity
Then, you create an RPC command to send the entity to the clients:
[BurstCompile]
public struct PlayerTransferCommand : INetworkEntityCopyRpcCommand, IRpcCommand
{
public ulong NetworkEntityId => networkEntityId;
public int networkId;
public ulong networkEntityId;
public uint playerId;
public PlayerManager.LocalPlayerSide localPlayerSide;
public float3 position;
}
Then, for creating the command, you create a system inherited from AServerNetworkEntityTransferSystem:
[UpdateInGroup(typeof(ServerNetworkEntitySystemGroup))]
public class ServerPlayerTransferSystem : AServerNetworkEntityTransferSystem<ServerPlayer, PlayerTransferCommand>
{
protected override PlayerTransferCommand CreateTransferCommandForEntity(Entity entity, NetworkEntity networkEntity, ServerPlayer selectorComponent)
{
return new PlayerTransferCommand
{
networkId = selectorComponent.networkId,
networkEntityId = networkEntity.networkEntityId,
playerId = selectorComponent.playerId,
localPlayerSide = selectorComponent.localPlayerSide,
position = EntityManager.GetComponentData<Translation>(entity).Value
};
}
}
There are also options for selection more components (2 and 3), such as AServerNetworkEntityTransferSystemT2 and AServerNetworkEntityTransferSystemT3.
Creating the entity on the client side
And the system for consuming this command on the client side:
[UpdateInGroup(typeof(ClientEarlyUpdateSystemGroup))]
public class ClientPlayerTransferSystem : AClientNetworkEntityTransferSystem<PlayerTransferCommand>
{
protected override void CreateNetworkEntity(ulong networkEntityId, PlayerTransferCommand command)
{
ClientPlayerBuilder
.Create(command)
.Build(EntityManager);
}
protected override void SynchronizeNetworkEntity(Entity entity, PlayerTransferCommand command)
{
EntityWrapper.Wrap(entity, PostUpdateCommands)
Related Skills
node-connect
339.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
339.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.9kCommit, push, and open a PR

