Network Entities and Components

Creating a networked Entity

You want to spawn new stuff into the world. It is very similar to creating a live query.

// Create a new entity with the following components 
var newEntity = EntityManager.CreateEntity( typeof(Simulated), 
typeof(Translation), typeof(PlayerScore));

// Update the Translation of the entity 
EntityManager.SetComponentData(newEntity, new Translation 
{ Value = new float3(2, 3, 4) });

// Update the PlayerScore of the entity 
EntityManager.SetComponentData(newEntity, new PlayerScore { number = 42 });  

You can add any networked components (from your schema or the coherence SDK) onto the requests.

There is one important thing to point out here -- the Translation component that is added to the new entity will correspond to a WorldPosition on the server. There are several types defined by coherence that behave this way, because the server often needs to know more about the purpose of the data than we do in our code (for example how to compress the data, etc.) In our C# code this information isn't very useful, so instead we get the ubiquitous Translation component from Unity:s ECS libraries there.

In the future there will be even more types that behave like this, and you'll be able to define them yourself too.

Destroy a networked Entity

You can only destroy entities that you own. Check if there is a Simulated component attached to the entity.

To destroy it, you just call DestroyEntity as normal:

EntityManager.DestroyEntity(goblinEntity);

It will be ignored if no Simulated component is attached.

Adding graphics and sound

As soon as you put a Simulated component on an entity it will start syncing its data over the network and create entities on the remote clients. You won't sync anything related to the rendering (or sound for that matter) though, so the game won't appear very much in sync. To fix this, you need to add components like RenderMesh, RenderBounds and LocalToWorld to the entity.

It turns out that doing it that way is unnecessarily cumbersome, since you already have methods for creating whatever kind of entities your game cares about. A better approach is to keep using those methods for setting up your entities and replace the networked entities with those ones.

Here are the recommended steps:

  1. coherence replicates the networked components (without rendering, but you can see them in the Entity Debugger)

  2. The game finds out that it can represent those entities visually (see below)

  3. Create the visual representation and inform the server that it should update this new entity instead

Step 1 is already working if you have set up the SDK properly and have a WorldPositionQuery running.

Step 2 is more interesting. In its simplest form you need a system that looks for entities with some specific components, but are lacking RenderMesh or similar components. Here's an example:

protected override void OnUpdate() 
{ 
    Entities.WithNone().ForEach(( Entity networkEntity, 
                                    in PlayerName playerNameComponent) => 
    { 
        // 'networkEntity' is missing 'RenderMesh'! 
    }).WithStructuralChanges().WithoutBurst().Run(); 
}  

Finally in step 3 you can instantiate a new (local) Entity with all the graphics and other things needed for it to look good. You replace the networked entity with this new, good looking one using a utility method named Replace. It tells the coherence SyncSendSystem about this new entity, copies all the components from the networked entity, and finally removes the networked one. Since the new entity has a RenderMesh now, it won't be processed by the ForEach function again and coherence will keep updating it due to it having all the necessary network components!

protected override void OnUpdate() 
{ 
    Entities.WithNone().ForEach(( Entity networkEntity, 
                            in PlayerName playerNameComponent) => 
    { 
          var newEntity = CreatePlayer(); 
          // This is your own method for creating a Player 
          EntityReplacer.Replace(networkEntity, newEntity); 
    }).WithStructuralChanges().WithoutBurst().Run(); 
}  

Last updated