Search Unity

Targeting an Entity via RPC Commands in Netcode.

Discussion in 'Data Oriented Technology Stack' started by pal_trefall, Sep 3, 2019.

  1. pal_trefall

    pal_trefall

    Joined:
    Feb 5, 2019
    Posts:
    40
    I have a use case where I want to target an entity to update its health on a client (not necessarily the local player's health). This is an event that doesn't happen often enough that I think it necessary to be part of the snapshot, so the server will send an RPC command with the updated health.

    How would I target a specific Entity over the wire though? Are we guaranteed that the server entity has the same index on the client? And is there an effective way to replicate it on the client? Since Entity is just an index and version number, is it enough to just recreate it as I read from the context, in the RPC command implementation? This would assume that an entity index is the same on the server and client.
     
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,730
    Entities are not guaranteed to be the same.

    There are many ways to handle server/client syncing and you can employ plenty of classical approaches. For example the simplest is to simply create a NetworkEntity component with a ID field and set the ID yourself and use that to keep entities in sync.
     
    pal_trefall, wobes and Opeth001 like this.
  3. pal_trefall

    pal_trefall

    Joined:
    Feb 5, 2019
    Posts:
    40
    Yes that is what I thought, but wanted to double check that Netcode didn't have something already.

    Thank you!
     
  4. pal_trefall

    pal_trefall

    Joined:
    Feb 5, 2019
    Posts:
    40
    I noticed that ConnectionReceiveJob has a AssignNetworkIdJob which models network ID generation and reuse (when a connection disconnects) for player connections. I'll be adopting this to my more general purpose entity network sync.
     
  5. pal_trefall

    pal_trefall

    Joined:
    Feb 5, 2019
    Posts:
    40
    Hm. The problem still will be that I only know the connection entity on the other end, and can't "look up" a target. Now if I add the NetworkEntity Id to the snapshot of this entity, I am able to get the NetworkEntity Id set correctly for the entity on the client-side, but now its part of the snapshot that ticks regularly, which I don't think is necessary.

    Which got me thinking "how does the ghost system deal with this?". And in GhostSystemStateComponent there seems to be a ghostId it uses. But again doesn't seem applicable to my problem.

    So I'm still a bit at a loss here, but I have a sub-optimal solution for now, and can wait for more documentation and samples.
     
  6. pal_trefall

    pal_trefall

    Joined:
    Feb 5, 2019
    Posts:
    40
    That said, I'm probably over-thinking things. Since we're able to extend the *GhostSpawnSystem with partials, my best guess is I can do something here to replicate the NetworkEntity Id on the client here.
     
  7. pal_trefall

    pal_trefall

    Joined:
    Feb 5, 2019
    Posts:
    40
    Hm, I think I'm closer to an answer now, but it does involve a "light" hack.

    Internally the Ghost Spawn System does something like this on the Client:

    Code (CSharp):
    1. ghostMap.TryAdd(delayedGhost[i].ghostId, new GhostEntity
    2.  {
    3.          entity = entities[i],
    4. });
    where ghostMap is NativeHashMap<int, GhostEntity>.

    In GhostSendSystem on the server, in SpawnGhostJob, Netcode does this:

    Code (CSharp):
    1. ghostState[ent] = new GhostSystemStateComponent {ghostId = newId, ghostTypeIndex = ghostType, despawnTick = 0};
    2.  
    3. commandBuffer.SetComponent(entities[ent], ghostState[ent]);
    This means that every entity on the server has a GhostSystemStateComponent with a ghostId, and that on the client we have World.GetOrCreateSystem<GhostReceiveSystemGroup>().GhostEntityMap. This GhostEntityMap is internal on GhostReceiveSystemGroup however, so looks like we've got to hack private NativeHashMap<int, GhostEntity> m_GhostMap; on DefaultGhostSpawnSystem to be at protected level, which would mean we can access it in our GhostSpawnSystem partial extensions.
     
  8. Enzi

    Enzi

    Joined:
    Jan 28, 2013
    Posts:
    213
    I made a simple WorldID system running on server/client and the IDs are synced in the snapshot.

    Prototype componentsystem code but it works and I'm holding off until the netcode is more refined. I guess they'll implement their own ID system.
    Fingers crossed for a new commit before Unite Copenhagen!
     

    Attached Files:

    pal_trefall likes this.
  9. pal_trefall

    pal_trefall

    Joined:
    Feb 5, 2019
    Posts:
    40
    Yes, I'll just do the same then and wait. I also have it working through snapshot, and Netcode is so early still that I'll hold off and wait rather than spend more time on a spawn solution. Really excited for the next version!
     
  10. pal_trefall

    pal_trefall

    Joined:
    Feb 5, 2019
    Posts:
    40
    Actually... with Delta Compression, as long as the Network Entity Id doesn't change, snapshot packets might get the Id optimized out?