IsOwner false on a NetworkBehaviour with 'NetworkObject that has IsOwner = True'
Description
I have a class Fighter inheriting from NetworkBehaviour. Then a more specific class for the Fighter innheriting from Fighter. That class is attached to an object with NetworkObject component attached. I start server, spawn the object on Server (dynamically) with ownership = client (btw I spawn this new NetworkObject by Instantiating it under our Player default object, which is spawned by Network Manager under the Default Player Prefab field. Then after Instantiating it under that, only 1 line after I spawn it on the Network using its NetworkObject through the server). NetworkObject says IsOwner true, NetworkBehaviour script says IsOwner = false.
Reproduce Steps
Idk the steps exclusively. Though it could be related to Inheriting or how I instantiated it.
Actual Outcome
IsOwner is false on NetworkBehaviour but true on NetworkObject.
Expected Outcome
IsOwner should have been true in both NetworkObject and all NetworkBehaviours attached to it.
Screenshots
Console is logging IsOwner from the NetworkBehaviour script
Environment
- OS: Windows 10
- Unity Version: 6000.0.24f1
- Netcode Version: 2.2.0
- Netcode Commit: Idk specifically, but the Package manager says released on December 16, 2024
What NetworkTopology are you using (Client-Server or Distributed Authority)? Could you post the code showing how you're instantiating the NetworkObject and the NetworkBehaviour?
Sorry, didn't mean to close the issue lmao.
This is the part where the network object is spawned. The OnNetworkSpawn method is on the "Player" object which is instantiated through the default player reference in NetworkManager which instantiates the "Player" object as soon as a client joins.
Thank you for the code snippet. Do you mind explaining more about what behaviour you were expecting vs what was happening?
I am spawning the FIGHTER object with SpawnWithOwnership so I am expecting all the NetworkBehaviours attached on that FIGHTER object to also have isOwner = true for owners.
But as it turns out, only the NetworkObject component has isOwner = true for owner clients, and not the network behaviours.
I am currently working around this by using reference of the NetworkObject and checking NetworkObj.IsOwner.
Hi @MaybeKush,
There might be some additional script I will need to better help you, but before we do that I have some recommendations based on the script segment you provided us:
- Your script looks like it is Instantiating a
NetworkObjectand not the entire network prefabGameObject?- i.e.
NetworkObject nObj = Instantiate(_fighters[1], transform);- My assumption is you are not getting any form of compilation error so
_fighters[1]is an array of NetworkObjects?
- My assumption is you are not getting any form of compilation error so
- This will not create a full network prefab instance.
- You might try:
- Instantiating the root
GameObjectof the network prefab asset. - Get the
NetworkObjectcomponent of the instance.- Use this to invoke the
Spawnmethod.
- Use this to invoke the
- =or=
- Use
NetworkObject.InstantiateAndSpawnusing the rootGameObjectof the network prefab asset.
- Instantiating the root
- i.e.
- I would recommend doing any spawning within the
OnNetworkPostSpawnand notOnNetworkSpawn.- The reason being is that
OnNetworkSpawnis while theNetworkObjectis still in the middle of spawning (i.e. not allNetworkBehaviourcomponents will have run through the spawn process yet) whileOnNetworkPostSpawnassures that allNetworkBehaviourcomponents have run through the spawn process (i.e. all spawned properties will be set on all of the associatedNetworkBehaviourcomponents).
- The reason being is that
- Since you are spawning instances for each client connected, I would actually check against the
NetworkBehaviourcomponent'sOwnerClientIdrelative to the default player prefab instance'sOwnerClientIdjust to make sure you aren't checking forIsOwneron the Server/Host side when it is actually a newly connected client's player. - I noticed that you are passing in a direct
NetworkObjectas a parameter inInitializeOnTargetRpc. This will not work as you must use aNetworkObjectReferenceto do this (so you will want to make that adjustment too).
Once you have made those adjustments, let me know if you are still getting the same result.
@NoelStephensUnity you say that instantiating the NetworkObject component of a NetworkPrefab "will not create a full network prefab instance".
Is that specific to netcode ?
Because with pure Unity, instantiating a gameobject, or one of its root component, will still instantiate the whole gameobject. Only the reference returned by the Instantiate method will change (gameobject vs the root component)
@NoelStephensUnity could you please confirm or deny the above info ? It is important info if there is netcode specific restriction on how to instantiate a network prefab.
@NoelStephensUnity Sorry for the late reply, must have missed the notification email.
Your script looks like it is Instantiating a NetworkObject and not the entire network prefab GameObject
This is a common instantiating method, if we want to use a specific component on an instantiated object, we can directly spawn the component of that type, instead of spawning gameobject then fetching the component on it. But I'll still try if spawning a gameobject makes any difference.
I would recommend doing any spawning within the OnNetworkPostSpawn and not OnNetworkSpawn
This, I can get behind. I'll try and return with the results
Passing NetworkObject into a RPC automatically turns it into a NetworkObjectReference. I think this is how they do in the official docs as well
@NoelStephensUnity Sorry for the late reply, must have missed the notification email.
Your script looks like it is Instantiating a NetworkObject and not the entire network prefab GameObject
This is a common instantiating method, if we want to use a specific component on an instantiated object, we can directly spawn the component of that type, instead of spawning gameobject then fetching the component on it. But I'll still try if spawning a gameobject makes any difference.
I would recommend doing any spawning within the OnNetworkPostSpawn and not OnNetworkSpawn
This, I can get behind. I'll try and return with the results
Passing
NetworkObjectinto a RPC automatically turns it into aNetworkObjectReference. I think this is how they do in the official docs as well
@kevincastejon @MaybeKush
Your script looks like it is Instantiating a NetworkObject and not the entire network prefab GameObject
This was my mistake and I am not really sure why I added that comment other than I was thinking about "new" as opposed to Instantiate which creates a new instance of the GameObject and its components itself. >.< That is definitely a perfectly valid way to approach it.
I would recommend doing any spawning within the OnNetworkPostSpawn and not OnNetworkSpawn
This, I can get behind. I'll try and return with the results
This should help with things a bit. I am going put together a replication project for this and will see if I can replicate what you are describing.
@MaybeKush
I have verified there is an issue specifically when using a client server network topology and spawning a NetworkObject from within OnNetworkSpawn, OnNetworkPostSpawn, OnInSceneObjectsSpawned, and OnNetworkSessionSynchronized of a NetworkBehaviour attached to the player prefab and using the NetworkManager defined player prefab to handle the spawning of the player prefab.
Until the issue has been resolved, you have two primary options:
Player Prefab Spawning (Client-Server)
- Player Prefab Spawns Child: Continue to use the NetworkManager to spawn the player and have a NetworkBehaviour component on the player prefab spawn the child.
- Manual Player Prefab Spawning: Use a
MonoBehaviourthat is attached to theNetworkManagerGameObject(to keep it persistent during the network session).
Below is a project providing you with both examples of how to do this: PlayerSpawnChild.zip
When you open the project, you should first open the BootStrapScene and look at the ExtendedNetworkManager:
The PlayerSpawnHandler provides you with three possible ways to handle spawning a player prefab and then spawning another network prefab to be parented under the player prefab:
- NetworkManager Player Prefab
- Client Connected Callback
- Client Connected Event
NetworkManager Player Prefab
This option would follow the same flow you have been using with the exception that a client's child object is spawned upon the client finishing being synchronized. The script of interest here is the PlayerSpawnChildAndParent component:
Client Connected Callback and Client Connected Event
Both of these options override the NetworkManager player prefab spawning and will handle spawning the player prefab when either the NetworkManager.OnClientConnectedCallback or NetworkManager.ConnectionEvent actions have been invoked (depending upon which one you pick). The host always spawns its player and child upon starting since it doesn't need to synchronize itself.
Why Is This Required (for the player spawning)
Currently (for connecting clients), this is the logical flow for NetworkManager defined player prefab spawning:
- When the client is approved for a connection, their player prefab is spawned locally on the server
- i.e. no CreateObjectMessage is sent (at this point)
- If you instantiate and spawn a prefab (i.e. the child) at this time a CreateObjectMessage will be sent to all clients.
- If you parent the spawned (child) object, then a ParentSyncMessage will be sent.
- Both of the above messages will be sent prior to the synchronization message.
- i.e. no CreateObjectMessage is sent (at this point)
- Next, the server then builds the synchronization scene event and sends that message to the client so the client can synchronize everything that is spawned.
- This includes the locally spawned player prefab.
- This will also include any additional network prefabs you spawned during the player prefab spawn process.
- This means the connecting client will spawn the child network prefab prior to synchronizing.
- This also means that the client's player is not spawned yet, so any parenting message received will be deferred until the client is synchronized.
- While the client is being synchronized (which includes handling synchronizing parenting for the first time), it will see the child object is already spawned and ignore that portion of the synchronization.
- This means the child will not properly be parented.
Either case, I am marking this issue as a bug because I believe we can change the order of operations to:
- Server/Host builds the synchronization data and sends the synchronization message to the client.
- Server spawns the player prefab like it would a dynamically spawned prefab (with the exception that it is the player).
- This would generate the
CreateObjectMessagethat would proceed the synchronization message.- If the player prefab spawned any network prefabs during this time and/or parented them those messages would proceed the player prefab's
CreateObjectMessage.
- If the player prefab spawned any network prefabs during this time and/or parented them those messages would proceed the player prefab's
- This would generate the
However, until we get this fix in place you will need to use one of the other techniques I provided in the above attached example project.
Thank you for your patience on this issue.
@MaybeKush @kevincastejon If you have using NGO v2.x then you might update to v2.3.1 and see if that fixes the issue with instantiating, spawning, and parenting within the OnNetworkSpawn or OnNetworkPostSpawn. There was a bug found within the ParentSyncMessage that did not properly defer the parenting message if the parent was not yet spawned (which is what would happen if you instantiate, spawn, and parent within another NetworkObjet's OnNetworkSpawn or OnNetworkPostSpawn methods).
This same fix will be in v1.13.0 via the #3388 backport (this should be soon but I can't give an exact date of when this package will be available).
Closing this issue as it cannot be replicated using newer versions of NGO and appears to have been fixed in #3388.
I have started hitting this problem on NGO 2.7.0, Unity 6000.0.60 while using MPPM to run a client and a host locally (Not tested on two computers yet.)
I have been debugging it for a couple days but so far have not identified the cause. In my case I am handling the Player spawn myself during Connection Approval. Additionally I spawn another object for the connecting clients using SpawnWithOwnership. Both the Player object and the other object have IsOwner true on their NetworkObjects but IsOwner is false on all of their NetworkBehaviours
I additionally see a log like this on the client side when connecting "[NetworkManager] Trying to spawn Player(Clone) with a NetworkObjectId of 21 but it is already in the spawned list!" Which is confusing.
An additional thing I have noticed is that their is a floating, none spawned Player(clone) GameObject on the connecting client.
I will attempt to reduce my project into a repro project this weekend, and continue to debug. Its currently blocking us from testing our remote MP 😅
Thanks for reporting this! The specific bug that this issue was pointing to has been fixed, it looks like what you're running into is something new. So we can better help you, do you mind making a new issue for this problem?
Will do! I have a repro project and think I have a bit of an understanding as to the cause kind of. Will open a new issue now :)