Hey, I’m having issues with Scene placed NetworkObjects being destroyed when server refuses client connection approval. This is the part of the code in NetworkSpawnManager.cs which is responsible for this:
internal void DespawnAndDestroyNetworkObjects()
{
var networkObjects = UnityEngine.Object.FindObjectsOfType<NetworkObject>();
...
// If it is an in-scene placed NetworkObject then just despawn and let it be destroyed when the scene
// is unloaded. Otherwise, despawn and destroy it.
var shouldDestroy = !(networkObjects[i].IsSceneObject != null && networkObjects[i].IsSceneObject.Value);
if (shouldDestroy)
{
UnityEngine.Object.Destroy(networkObjects[i].gameObject);
}
...
}
The problem that I’m facing is that when server rejects clients connection approval, these network objects are not yet spawned, so even though they are placed in scene, the IsSceneObject bool is false, as explained in this code:
/// <summary>
/// Gets if the object is a SceneObject, null if it's not yet spawned but is a scene object.
/// </summary>
public bool? IsSceneObject { get; internal set; }
So what happens is that these objects are immediately destroyed when they shouldn’t be, which seems really odd to me. I’m not sure what to do to avoid this behavior, but it seems like a bug to me.
I have a hunch that you are entering the game in the same scene where clients join the network session. In that case, the scene on the client side is an offline scene, but it will then destroy any NetworkObjects in that scene if the client does not get approved but also likely when the client does get approved but later leaves the session or disconnects.
It would be wise to have the server/host single-loads a scene with NetworkSceneManager, so that clients joining will also be pulled into that scene, but remain in their supposedly menu scene if approval fails.
This is not the case, because in this situation the objects are already spawned… That means IsSceneObject will be true and NetworkSpawnManager.cs will just despawn the objects instead of destroying them. This only happens if the scene placed objects are not spawned yet.
My current setup is that I have MainMenu scene from where I have 2 gameMode options - SinglePlayer, Coop. If player chooses Coop then NetworkManager Starts and everything stays in that scene. So you are saying I should move this logic to another scene?
Ideally yes. I would not mix offline with online scenes but keep them separate.
But not for singleplayer?
That means you’re effectively programming each feature twice, and any change made to a working feature in one mode may break this or other features in the other mode.
Make sure the singleplayer plays as host in an isolated network session (ip 127.0.0.1 and port = 0 effectively shut off the session from the outside). Then you won’t have (m)any issues when moving a singleplayer feature to online coop because it’s already programmed with networking in mind.
I have a similar problem…
I recently added the accept/refuse logic via NetworkManager.Singleton.ConnectionApprovalCallback.
Before adding it everythings worked fine. Now as soon as a connection is refused, every network object gets destroyed…
Please help me!
Ok I’ve made some test and is something related to NetworkManager.Singleton.DisconnectClient(id), not in the accept/refuse logic.
If the client itself disconnects, by closing or calling NetworkManager.Singleton.Shutdown(), no problem.
But if is the server that calls DisconnectClient, every networkObject disappears…
Is it a bug?
I’m experiencing the same issue; we have a game manager with a NetworkObject that live sin DDOL scene, which gets destroyed when a client tries to connect to server but the connection timeouts (that is, server is offline).
DontDestroyWithOwner has no effect on this scenario unfortunately.
What we want is to let the manager persists in the DDOL scene (with a NetworkObject attached to it) between connects/disconnects.
Because unless something explicitly calls Destroy on the object, or another scene loads, the NetworkManager can’t get destroyed. Do a quick check to find any Destroy call in NetworkManager’s code but I’m 99.99999% sure there isn’t anything like that. I suspect that the time out triggers some other code.
Btw, the NetworkManager should be in a scene that never ever gets loaded a second time during the lifetime of the app, such as an initial “launch” scene.
Hi! Sorry for the confusion; my problem is not with the NetworkManager, but my own game managers (I have a CoreManager with a NetworkObject on it that handles game state).
The issue only occurs when clients cannot connect to remote endpoint, since all in-scene placed NetworkObject.IsSceneObject is null (since they are not even spawned at that point) and then gets removed in the NetworkSpawnManager.DespawnAndDestroyNetworkObjects().
If a client gets disconnected by server later on in the process, it works fine since NetworkObject.IsSceneObject = true, but not during the initial connect, which also applies to the ConnectionApproval check since that can refuse the connection (in my case, when a server is full).
I have debugged it yes, thus coming to the conclusion above.
I have a initial Bootstrap scene that gets loaded first, it has the CoreManager in it which on Start() puts itself in DDOL scene, then attempts to connect.
Again, all works great unless in the scenario when client connection is refused.
It is the same issue as digifoxreg is having; keeping in-scene placed NetworkObjects during the whole lifespan of the game, but they gets destroyed on connection refusal when they shouldn’t.
I looked into this and there’s a fix for it on the develop branch. If you want to try it yourself open your project’s Packages/manifest.json file and replace the NGO package reference with this:
Thank you for posting this! I just tried it out and can confirm it works and resolves my issue!
Good to see they are actually implementing it as well in the next release. Cheers!