Migrating from Unity Netcode for GameObjects to Coherence

I want to try and migrate from a project that use Unity Netcode for GameObject to Coherence.
I couldn’t find one place with all the relevant info and tips, so I hope this post would help not just me.

I want to focus on using existing architecture, with minimal changes. While re-writing everything from scratch might be better architecture wise, I don’t find it much practical for this scope.

The project I’m working on is this: GitHub - De-Panther/webxr-multiplayer-template: Unity WebXR Multiplayer Template, based on Unity VR Multiplayer Template.

It has Lobby system (with Relay and Transport).
The Host is one of the Clients, and there’s yet no implementation of server hosting or transferring the Host role.
There are some shared 3D menus and mini-games.

So far I imported Coherence package version 1.3.1. And added the Bridge and Query objects to the scene.

The first prefab I tried to migrate is the player prefab, as I think it is one of the more complicated ones.
It has 2 NetworkBehaviour classes. XRINetworkPlayer and XRHandPoseReplicator.

I removed the NetworkObject component from the prefab, and added CoherenceSync component instead.

I replaced NetworkBehaviour with MonoBehaviour in both classes and added a reference to the CoherenceSync.

And here comes the troubles :slight_smile:

The project is heavily relay on the NetworkBehaviour properties.
IsOwner is now based on coherenceSync.HasStateAuthority.
IsLocalPlayer is also based on coherenceSync.HasStateAuthority but I’m not sure if there’s a more precise property.
IsOwnedByServer in this case is used to check if it’s the host, I don’t know what to use here for now. Any suggestions?
OwnerClientId is ulong but maybe using the string coherenceSync.EntityState.CoherenceUUID would work for the use cases in this project. Is it correct to use CoherenceUUID of a player prefab to identify client?

Next are NetworkVariable and NetworkList.
The CoherenceSync component creates a scheme from selected public variables, and let us sync them.
The NetworkVariable is similar to such variables, but it also allows to Subscribe and Unsubscribe for when the value changed. I tried to find a way to subscribe to CoherenceSync variables events, but found only Rigidbody related ones. Are there events for custom variables as well?
I couldn’t find similar solution to sync lists like the NetworkList does. What would you suggest to sync lists of float and of vector3? (no need to subscribe for changes)

Project question:
While Coherence has Lobby system, I think the way this Unity project was made, it’s better to use only the Rooms system as players are still in the same room while in the mini-games. Any suggestions on how to handle the Host role and transferring it when the host disconnects? (Using the Rooms system)

Thanks :slight_smile:

Yes, coherence has dynamic authority, so in your case where you are not using a simulator (I assume you are not?) then IsOwnedByServer is the same as HasStateAuthority.

Checkout out Client Connections: Client Connections | coherence Documentation

This will allow you to have a guaranteed ClientID (which can also be cast to ulong) provided by coherence. That client ID is guaranteed to remain stable as long as the connection is stable.

Yes, take a look at OnValueSynced [OnValueSynced] Attribute | coherence Documentation

List sync is high on our priority list - don’t have a timeframe right now - but our recommendation is to serialize the list into a byte array. You can either make this a normal sync property that gets set when the list changes, or you can use Commands to send changes depending on your use case.

Since authority is dynamic in our system you can rely on persistent entities and orphan handling to transfer or Adopt network entities when the owner of them changes: Authority | coherence Documentation

In a traditional host scenario, if your host truly has authority over all network entities, you can make them “persistent” (meaning this will stay in the room when the host leaves) and then devise an adoption scheme that you’d like.

2 Likes

Thanks for the help!

Some progress updates:

  • Managed to configure most of the player properties and mechanics.
  • Can log in using the Sample Connect Dialog for Rooms.
  • Managed to sync some of the lists, but it’s not optimal.
  • For now selecting a host is not an issue, the experience can work without it.
  • Baking the scheme, and using the CoherenceSyncConfig of the player prefab to instantiate it from the bridge saved me some time.
  • Had to cache the HasStateAuthority and ClientId on Start() as when OnDestroy() is called, they change. I guess I can subscribe to state authority changed.
  • Had to use int instead of enum for enums that needed sync.

Following previous comment:

  • IsOwnedByServer - I’ll skip for now. Using HasStateAuthority is not the same, and in the context of this experience, it doesn’t have much importance. I set it to always return false.
  • Thanks for the tip. coherenceSync.EntityState.ClientConnection.ClientId.GetHashCode() did the trick.
  • OnValueSynced worked great. It’s not the same one to one, but close enough.
  • I managed to use byte array, but it forces me to set it as new byte[] each frame that I want to update it. So I’m looking for another solution.

Current issues:

  • There are 2 float arrays and 2 Vector3 arrays the I know the size of only when player joins. They don’t change size when connected. In some cases all their items updates each frame, and in some cases only few or none. They are used for fingers joints rotations and fingers states. I read about sync and commands, but I’m not sure what would work better and how for this case.
  • Netcode for GameObjects has NetworkTransform component, that can sync child transforms of NetworkObject. I ended up adding a bunch of Vector3 and Quaternion to sync a few child transforms. Couldn’t find a quick option for that. Is there an equivalent for NetworkTransform?

Thanks

Hey Oren!

This is actually so much simpler than you think! You can just sync the children’s position and rotation just like you sync the root, from the Config window. It’s all described here:


Ideally you’d want synced lists, which is something we don’t have at the moment but it’s in development.

What do these arrays represent in practice? Maybe there’s a solution we can find using the tools that are available.

1 Like
  • Child Sync. WOW. I was trying to find something like that on the menu but couldn’t. I’ll check this. Seems like what I was needed.
  • They represents 2 lists of Vector3 for fingers joints. And 2 lists of float for fingers curls. For different avatars it might be different size, but I can figure the length on validation instead of runtime. I was thinking of using custom bindings / syncable member https://docs.coherence.io/manual/networking-state-changes/custom-bindings as I see that it can handle changes in arrays.

I’ll update once I tested those solutions. Thanks

  • Child Sync works great!
    I think that my issue was that I was trying to select a child object by clicking on the name of the GameObject in the Configure window, and trying to open the Configure window from the child GameObject. But didn’t try to stay in the Configure window and switch to the child GameObject.

  • Managed to use the custom bindings for the float arrays, but the array sizes of the Vector3 are too large, so it fails for them.
    I also had lots of other issues with that solution. Mainly the sample in the doc, that suggest storing int in the Descriptor.CustomData, and the variable description that suggest to use it for id, hash, or name.
    It uses [SerializeReference] which can’t serialize value types and structs, only classes and objects which are not derived from UnityEngine.Object Unity - Scripting API: SerializeReference
    so I guess it should be [SerializeField] if it was intended for id/hash/name.
    I ended up parsing index number from the Descriptor.Name.
    Another related bug, is that the generated code ignores the namespace of the binding classes. At the start I created the custom binding under the same class as the rest of the project code and I got errors of unknown classes. I was thinking that it’s related to the .asmdef files in the project, but then I realized that if the binding classes are in the same .asmdef but with no namespace, there are no more errors.

I’ll look to refresh and correct the custom bindings page, it’s an old one!

This sounds pretty bad, we should look into it. I’ll ask the team if it’s a known issue.

1 Like

I reported the name clash issue to the team. We are looking into it, and will probably be fixed in a future release.

For now, as you already did, a solution is to just give the class a unique name to avoid clashes.

1 Like

For the list of finger rotations (in cases of hands tracking), I ended up sending Commands.

I’m using Unity NativeArray and Reinterpret from Vector3 to byte.
Sending byte array, read it as NativeArray, and Reinterpret from byte to Vector3.

Not sure if it’s the most efficient way to send 2 arrays of 19 Vector3 (38 Vector3), but it seems to work ok.
Also made sure to send them in a rate of 10 times a second.

That works (if it works for you!)

There are advantages to using normal syncing though, instead of Commands:

  • You can configure and adjust the precision and frequency of those Vector3 from the Optimise window
  • Another thing is you would benefit of LODs (again, defined in the Optimise window) and areas of interest, automatically. But this is only interesting if other players can be far from you.

Out of curiosity, did you end up using Commands because you couldn’t have so many synced Vector3s per individual entity? (you hit the limit, what is it… 32?)

But again, if Commands work for you… keep it as it is :slight_smile:

Yes, I had to use it because I hit the limit.
Also the configure window is really struggling with so many items.

1 Like

I see! Btw, it is possible (if you didn’t know) to parent network entities at Edit time. I believe that allows you to go over the limit of components per-entity.

1 Like