Skip to content

Parent NetworkBehavior not set on client for spawned prefabs #1040

@magnoahlia

Description

@magnoahlia

Unity Version: 6000.3.13f1
Fish-Net version: 4.6.20
Discord link

Description

When a NetworkObject is spawned with a parent (i.e. when spawning a UI element into a canvas), the parent transform is correctly set for the object spawned on clients, but the NetworkObject parent NetworkBehavior fields are not assigned for the clients. This leads to a warning from NetworkTransform for example: Cursor Party Cursor(Clone) parent was set without calling SetParent. Use networkObject.SetParent(obj) to assign a NetworkObject a new parent. This is being made a requirement in Fish-Networking v4.

Here's a relevant snippet from our spawning logic:

private void SceneManager_OnClientPresenceChangeEnd(ClientPresenceChangeEventArgs args)
{
    if (!networkManager.IsServerStarted) return;
    if (args.Scene != gameObject.scene) return;
    if (!args.Added) return;

    ...

    var nob = networkManager.GetPooledInstantiated(
        playerPrefab.NetworkObject, position, rotation, parent, true
    );

    var networkPlayerObject = nob.GetComponent<NetworkSessionObject>();

    if (parent)
    {
        nob.SetParent(parentNetworkBehaviour);
    }

    playerObjects.Add(player, networkPlayerObject);
    networkManager.ServerManager.Spawn(networkPlayerObject, player);

    //If there are no global scenes
    if (addOwnerToDefaultScene)
    {
        networkManager.SceneManager.AddOwnerToDefaultScene(nob);
    }
}

In the snippet you can see that we are:

  1. Spawning the object with the parent transform via GetPooledInstantiated
  2. Calling SetParent to set the parent NetworkBehaviour
  3. Calling Spawn after SetParent

After chasing down the issue locally, here's what I think is happening:

  1. The server uses the code above to spawn and sets the correct parent (Object ID 5)
  2. The client receives the spawn message and begins spawning the object in ClientObjectCache.Iterate().
  3. ClientObjectCache.<Iterate>g_ProcessObject() calls ClientObjects.GetInstantiatedNetworkObject(). The cnob.ParentObjectId is 5 here, so we know that the parent was sent to the client.
  4. GetInstanantiatedNetworkObject sets up the parent for the transform but does not set the parent network behavior. ProcessObject() explicitly says "Prenting and transform is done during the instantiation process" in a comment, so it assumes that the parent is set.
  5. The parent NetworkBehaviour is never set on the created NetworkObject
  6. The NetworkTransform sees that the transform has a parent but the parent NetworkBehaviour is not set and logs a warning.

I think that ProcessObject() needs to call SetParentAndTransformProperties() after creating the NetworkObject (like it does for scene objects). When I do this manually (using my debugger), it does set the parent and resolve the warning.

Replication

  1. Use the above snippet to spawn a prefab with a NetworkTransform and a parent NetworkBehaviour for players
  2. Start hosting and connect a client
  3. Observe the warning from NetworkTransform

Expected behavior

The client-side prefab's NetworkObject has the same NetworkBehaviour parent as the server-side object and no warnings are logged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions