Problem with object duplication

To reproduce the problem:

  • Open the Asteroid example project GitHub - Unity-Technologies/multiplayer: Unity multiplayer packages and samples
  • Add a child TextMesh object to Ship prefab. (it also can be SpriteRender) see scr1.png
  • Make a build using “Win-ClientServer” build configuration
  • Run build, start “Client+Server” mode in frontend and move the ship. I see that two TextMeshes have been created. One is correctly attached to the ship, the other follows the ship with delay like an interpolated ghost. see scr2.png.
  • All ok when I start an example in editor, I see only one TextMesh. All ok also if I start the build as a client and editor as a server.

Is TextMesh child entity being replicated as a separate interpolated ghost ? How to fix this problem ? Can it be a bug in the netcode package ?


Isn’t this the text being visible in both the client and server visualizations?

what is server visualization ? the problem is reproduced only in the build (standalone application). Everything is ok if I run from the Unity editor.

The TextMesh is a normal unity component, as such when you create it you’ll create something being rendered in GameObject land. If the client and server world both run in the same executable and you add the component on both, you will get two GameObjects - one for client and one for server. Because GameObjects do not have any concept of world, both of them will render. Predicted ghosts are ahead of the server position, so the server will be lagging a little bit behind.
I’m not sure why you are not seeing the issue in playmode, but it could be because you have no latency so they end up overlapping. If you open Multiplayer > Playmode tools and enable latency emulation you might get two rendered meshes in playmode too.
The fix for this is to make sure that the text mesh is only added on the client, not on the server.

1 Like

Thanks. I checked. There is no issue in the playmode and this is not due to the lack of latency in playmode.

If I’m not mistaken, TextMesh and other hybrid render components should not be created in the server world. There are no TextMesh, MeshRenderer, CompanionLink components in the server world.

The Ship (with a TextMesh child element) is the predictable ghost. But for some reason the TextMesh child is created/replicated twice on the client.

It would be convenient to mark some children as client-only and some as server-only when the prefab authoring, but as far as I understand, this is not possible.

The TextMesh is any hybrid component and the companion game object is created also for the server unless the assembly that do the conversion is added the ConversionSystemFilterSettings.
In Asteroid, for client and server build, there is not such a filter (because the prefabs are used for both client and server worlds). As such, the components are always present.

That being said, in the Editor the used build configuration when you enter playmode is, so I would imagine the text mesh rendering also occurs there.
The only case I think of it is the fact in the Editor the BuildConfigurationGUID is setup to point to a server-only build config for the server world. This will trigger a re-conversion of the sub-scene for the server world (this happen only at runtime in the editor), that the prefab in that case will not have the mesh rendered and text-mesh renderer.
But I’m making an hypotesis here.

Can you please verify that if you create a simple Client build (not a client/server) and connect to the editor, the client will only show one text mesh?

A very simple and effective solution for this is to split the text and and ship entities.
The text entity is created only by the client, and parented to the ship (after the ghost is spawned for example).

If I run “Join an existing game” in the frontend there is no problem even in the Client+Server config.

I was able to reproduce the issue in the editor. The text mesh is duplicated and the hybrid components are created in the server world if I comment out the code that sets the BuildConfigurationGUID in the ConfigureSystems.cs file.

Is there a way to not create hybrid components in the server world in Client+Server build ? Can I set BuildConfigurationGUID for Client+Server build to get editor/playmode similar behavior but in build ? Commenting lines #if UNITY_CLIENT || UNITY_EDITOR in ConfigureSystems.cs doesn’t help.

Thanks for the advice, the Client+Server build creates hybrid components in the server world, not only with companion objects like TextMesh but also other rendering components like RenderMesh. Does this mean that any prefab for a character/game item should be split into a 1) network/shared part and a 2) client only visual part ? I’m not sure it will be convenient to work in editor (authoring) with two prefabs if the prefabs have a hierarchy of children. For example, the same child can have MeshRenderer and PhysicShape. But the MeshRenderer should be in the client part, and the PhysicShape in the network/shared part.

The issue can be described more simply:

Ship, asteroids and other ghosts have a RenderMesh component in the server world if we build the example using the ClientServer (Win-ClientServer.buildconfiguration) configuration,
because setting ServerBuildSettingsGUID in ConfigureSystems.cs doesn’t work for ClientServer build config.

When you build for client server, we can’t exclude systems from adding the components (since the scene is used by both client and server).
These components can be stripped from the entity at runtime (for the server) by setting up a DefaultVariant system that set them as ClientOnly. Like

class MyDefaultVariants : DefaultVariantSystemBase
{
  public override void RegisterDefaultVariants(Dictionary<ComponentType, Type> defaultVariants)
  {
        defaultVariants.Add(ComponentType(typeof(RenderMesh)), NetCode.ClientOnlyVariant);
        ... etc etc
  }
}

This is not as effective as preventing the conversion to run (because in presence of certain material more than one entitiy is created, ex: blend probe). But at least remove the rendering issue and reduce some memory cost.

Thanks. I added the code

class MyDefaultVariants : DefaultVariantSystemBase
{
    protected override void RegisterDefaultVariants(Dictionary<ComponentType, Type> defaultVariants)
    {
        defaultVariants.Add(new ComponentType(Type.GetType("Unity.Rendering.RenderMesh, Unity.Rendering.Hybrid")),  typeof(ClientOnlyVariant));
        defaultVariants.Add(new ComponentType(Type.GetType("Unity.Rendering.RenderBounds, Unity.Rendering.Hybrid")),  typeof(ClientOnlyVariant));
        defaultVariants.Add(new ComponentType(Type.GetType("Unity.Rendering.WorldRenderBounds, Unity.Rendering.Hybrid")),  typeof(ClientOnlyVariant));

        defaultVariants.Add(new ComponentType(Type.GetType("UnityEngine.MeshRenderer, UnityEngine")),  typeof(ClientOnlyVariant));
        defaultVariants.Add(new ComponentType(Type.GetType("UnityEngine.TextMesh, UnityEngine")),  typeof(ClientOnlyVariant));
        defaultVariants.Add(new ComponentType(Type.GetType("Unity.Entities.CompanionLink, Unity.Entities.Hybrid")),  typeof(ClientOnlyVariant));
    }
}

this removes the RenderMesh and all other components except for the CompanionLink. CompanionLink remains on the server. The issue with TextMesh duplication remains.

if there are no easy solutions, I will remove the TextMesh from the prefab and will create the TextMesh at runtime on the client.