Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question About Ghost spawning and components synchronization

Discussion in 'NetCode for ECS' started by Hecocos, Sep 6, 2023.

  1. Hecocos

    Hecocos

    Joined:
    Nov 29, 2021
    Posts:
    11
    Hey:
    I am a beginner at NetCode For ECS. I implemented [netcode for objects] in my project now, but in consideration of performance, i want to implement dots to my project as well as [netcode for entities].
    So my project is a lot of difference with unity dots samples. Here is the scenario:
    I have lots of prefabs in my scene, and each of them may have different component that's decided by custom configs, say excel data by others. So in the implemention of Netcode For Objects, I can do the following steps to make it right:
    1. Create a prefab with [NetworkObject] behaviour attached.
    2. In server side, instantiate the prafab above and fill lots of components which inherit from NetworkBehaviour.
    3. Then in client side, implements INetworkPrefabInstanceHandler, hook the networkObject's spawn to add same component list.
    4. Finally, the field that marked with NetworkVariable in components can be synced correctlly.


    Now, with [netcode for entities], what i can get from documents is that Ghost prefab should determine its component list in compile time, and bake it in subscene. But the number of components is indeterminate at compile time, and it's not a good way to bake all my prefabs in subscene because of it's quantity.

    So, how can i do for this scenario.appreciate it.
     
  2. NikiWalker

    NikiWalker

    Unity Technologies

    Joined:
    May 18, 2021
    Posts:
    224
    Hey Hecocos!
    This is broadly correct, yes. The issue is that: If you want to create a ghost with an entirely runtime-selected component list, netcode has no knowledge of said ghost, and therefore has not stored the necessary logic to properly deserialize it.

    You can solve this in 2 ways:
    1. GhostPrefabCreation.ConvertToGhostPrefab - This API converts an Entities prefab into a ghost, storing the necessary logic to properly deserialize it into a BlobAsset. The difficulty here is that you must call this API identically on all the clients, and the server. E.g. If the server defines a prefab with components A,C,F, all clients must also define a prefab with components A,C,F. If I remember correctly, they must also define these ghosts in the same order, too. This means you'll need to replicate (via RPCs) any dynamic prefab types that arise through gameplay.

      Not impossible, but non-trivial. Some users define 100% of their ghost prefabs in this way.

    2. Alternatively: You write custom serialization logic for your components yourself, taking an entity (and all of it's components) and converting it into a NativeArray<byte>, which you then replicate via an IBufferElementData (with a [GhostField] public byte Value;). This supports "arbitrary" dynamic components, but it does mean you'll need to do most of the work of replicating and optimizing yourself. We see customers using this "mix of static and dynamic components" for their scripting DSL use-cases (example: designers can define arbitrary blackboard variables, which need to be synced).
     
  3. Hecocos

    Hecocos

    Joined:
    Nov 29, 2021
    Posts:
    11
    1. GhostPrefabCreation.ConvertToGhostPrefab - This API converts an Entities prefab into a ghost, storing the necessary logic to properly deserialize it into a BlobAsset. The difficulty here is that you must call this API identically on all the clients, and the server. E.g. If the server defines a prefab with components A,C,F, all clients must also define a prefab with components A,C,F. If I remember correctly, they must also define these ghosts in the same order, too. This means you'll need to replicate (via RPCs) any dynamic prefab types that arise through gameplay.

    In this way, what i can do shoud be:
    1. In server, create a temp entity(named A) and adding all components needed with fixed order, then call GhostPrefabCreation.ConvertToGhostPrefab, then send [CreateNewGhostPrefabRpc] to client. Then i can create ghost entity by calling Instantiate(A), without do anthing else.
    2. In Client, handler CreateNewGhostPrefabRPC, create temp entity and adding all components like server doese and call GhostPrefabCreation.ConvertToGhostPrefab.

    Is right for that ?
     
    Last edited: Sep 7, 2023
  4. NikiWalker

    NikiWalker

    Unity Technologies

    Joined:
    May 18, 2021
    Posts:
    224
    Broadly yes. You should also make sure not to register the same ghost type multiple times (so probably generate a hash using the Archetype), and obviously make use of the ComponentType TypeManager API to replicate a list of stable hashes. You'll need to write a custom serializer for that RPC to ensure it can handle a FixedList of types too.
     
  5. optimise

    optimise

    Joined:
    Jan 22, 2014
    Posts:
    2,024
    Recently I found that I netcode needs to support modify ghost entity at runtime. Basically I want to add and remove child entity at ghost entity at server and it will automatically sync to all clients. And also if the newly child entity has ghost component, it will also work like other ghost component like parent ghost entity that able to sync data between client and server.


    Will official provide sample for this or even better make it into official netcode as official feature? I'm quite curious how to replicate "arbitrary" dynamic components between client and server that I believe it's sync arbitrary count of components and its data between client and server? Btw for DSL do u mean Domain-specific language?
     
    Last edited: Sep 7, 2023
  6. Hecocos

    Hecocos

    Joined:
    Nov 29, 2021
    Posts:
    11
    I used a Dict to maintain the ghost prefab's component list, and each have different components. And this dict data exist both side. So i can just send prafab's key to client, it can get component list from that Dict. I think this way can be simpler.
     
    NikiWalker likes this.
  7. NikiWalker

    NikiWalker

    Unity Technologies

    Joined:
    May 18, 2021
    Posts:
    224
    I can't promise yes, but it would be a good thing to demo, definitely. And yes, re DSL.
     
    optimise likes this.
  8. CMarastoni

    CMarastoni

    Unity Technologies

    Joined:
    Mar 18, 2020
    Posts:
    762
    If the archetype are know by both end (the client know that that ghost X has these component set) there is even not need to keep the list itself.
    And would also not requires any rpc at all, if we are using the GhostType has key (this actually sent by the server as part of snapshot and the client need to ack that has loaded that prefab type) and having generator functions/method/factory for that specific ghost type hash.
    Require some extra setup to pre-calculate that mapping, but once done it is a powerful mechanics.

    If the archetype is more dynamic, and server driven, passing the list of stable-hash in an rpc is kinda necessary. you can also indeed reduce the size by a large margin by knowing all the replicated component types and store these in a sorted list, and using the index (8 bits or less per index suffice).