NetworkComponent

DOTSNET can automatically sync components for you.

For example, let's say we need a Health component with:

  • Current health: this changes when attacked / when recovering.

  • Max health: this never changes.

We can define a Health : NetworkComponent , which DOTSNET will automatically:

  • Include in Spawn messages

  • Synchronize every NetworkServer.snapshotInterval seconds

NetworkComponent Interface

First, we need to create a Health struct that implements the NetworkComponent interface:

public struct Health : NetworkComponent
{
    public int current;
    public int max;

    // server authoritative
    public SyncDirection GetSyncDirection() =>
        SyncDirection.SERVER_TO_CLIENT;

    // only sync current. max is always the same.
    public bool Serialize(ref NetworkWriter128 writer) =>
        writer.WriteInt(current);

    // only sync current. max is always the same.
    public bool Deserialize(ref NetworkReader128 reader) =>
        reader.ReadInt(out current);
}

// need to define a serializer for every NetworkComponent
public class HealthSerializer : NetworkComponentSerializer<Health> {}

Important: we also need to define a NetworkComponentSerializer<T> for every NetworkComponent .

NetworkComponentimplements IComponentData automatically and is burstable.

In the above example, DOTSNET will automatically serialize current health and include it in Snapshots, from client to server. If the client tries to modify it, it will have no effect unless we change sync direction to CLIENT_TO_SERVER which would make it client authoritative.

We could avoid the Serializer defintion with C# Reflection, but it's too slow.

NetworkComponentSerializer<T> Fast

The one-liner NetworkComponentSerializer<T> uses an EntityQuery<T> internally because a generic Entites.ForEach<T> is not supported by ECS.

If necessary, feel free to overwrite the Serializer's SerializeAll / DeserializeAll functions for maximum performance. It's more verbose though:

public class HealthSerializer : NetworkComponentSerializer<Health>
{
    public override void SerializeAll(CurrentWorld currentWorld)
    {
        ushort key = Key; // copy for Burst
        Entities.ForEach((ref NetworkComponentsSerialization serialization, in NetworkIdentity identity, in Health component) =>
        {
            Serialize(currentWorld, key, identity, component, ref serialization);
        })
        .Run();
    }

    public override void DeserializeAll(CurrentWorld currentWorld)
    {
        ushort key = Key; // copy for Burst
        Entities.ForEach((ref NetworkComponentsDeserialization deserialization, ref Health component, in NetworkIdentity identity) =>
        {
            Deserialize(currentWorld, key, identity, ref component, ref deserialization);
        })
        .Run();
    }
}

For your own components, simply copy the above code and replace Health with your components type. Put that code right below where you define your component, in the same file. Don't worry about what it does. it just needs to be defined.

Defining NetworkComponentSerializer<T> might be automated in the future.

Last updated