I’m not sure why OnNetworkDespawn does not gets called on the Hosting Player when a connected Client disconnects from the game. Their associated Player NetworkObjects gets disabled but that’s about it. The OnNetworkDespawn and OnDestroy of NetworkBehaviour does not get called.
It only gets called when the Host disconnects, but not for Clients that disconnects.
This is my class that inherits from NGO’s INetworkPrefabInstanceHandler class (It is essentially using my own pooling system):
using System.Collections;
using System.Collections.Generic;
using Unity.Netcode;
using Unity.VisualScripting;
using UnityEngine;
public class NetcodeSpawnableHandler : INetworkPrefabInstanceHandler
{
private readonly SpawnableData spawnableData;
public NetcodeSpawnableHandler(SpawnableData spawnableData)
{
this.spawnableData = spawnableData;
}
public void Destroy(NetworkObject networkObject)
{
var spawnable = networkObject.GetComponent<Spawnable>();
if (spawnable != null)
{
Debug.Log("NetcodeSpawnableHandler Destroy: " + networkObject.name + " is spawned: " + networkObject.IsSpawned);
networkObject.gameObject.SetActive(false);
}
else
{
Debug.LogWarning("Attempted to despawn an object not managed by SpawnableData.");
}
}
public NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation)
{
Debug.Log("NetcodeSpawnableHandler: " + spawnableData.name);
var spawnable = spawnableData.Spawn(null, position, rotation);
return spawnable.GetComponent<NetworkObject>();
}
}
The pooling works fine, and when any Clients disconnects the above code’s “Destroy” function gets executed. I just don’t understand why OnNetworkDespawn and OnDestroy in the NetworkBehaviour itself does not get executed.
Digging further, I realize there’s a bug as well. The “Destroy” function above in INetworkPrefabInstanceHandler is called twice on the host, on each of the respective gameobjects associated with the disconnecting client, whenever a Client disconnects! Because of this, I cannot directly using networkObject.Despawn() in the Destroy function above as the Despawn() will execute twice, and cause an error “The object is not spawn”. Why is that? Can someone test on their end?
I’ve had a play with this and I’m not seeing too much untoward but it’s the first time I’ve used it and I see plenty potential for confusion, at least on my end.
I’m testing with a Player and an owned Spawn object for each client and from what I can see OnNetworkDespawn is called for both on the host when the client disconnects. They’re not disabled, is that part of your pooling?
I’m assuming this is down to you to handle in the prefab handler’s Destroy method, destroy them on client disconnect or return to the pool otherwise.
I’m seeing this as well which doesn’t look right.
My understanding is the prefab handler isn’t concerned with the spawning and the despawning. Instantiate is used for you to provide the network object you want spawned, Destroy is used to decide what happens to the network object after it’s despawned. So for object pooling in Instantiate grab one from the pool, in Destroy return it. I could be wrong though.
Thank you for testing on your end and sharing the info.
Meaning the Destroy function also executes twice on each Client PlayerObject on the host Client for you? In this case is this a bug?
In my Prefab Handler’s Destroy method, this is what I do now:
public class NetcodeSpawnableHandler : INetworkPrefabInstanceHandler
{
private readonly SpawnableData spawnableData;
public NetcodeSpawnableHandler(SpawnableData spawnableData)
{
this.spawnableData = spawnableData;
}
public void Destroy(NetworkObject networkObject)
{
var spawnable = networkObject.GetComponent<Spawnable>();
if (spawnable != null)
{
Debug.Log("NetcodeSpawnableHandler Destroy: " + networkObject.name + " is spawned: " + networkObject.IsSpawned);
if (networkObject.IsSpawned)
{
networkObject.Despawn();
}
networkObject.gameObject.SetActive(false);
}
else
{
Debug.LogWarning("Attempted to despawn an object not managed by SpawnableData.");
}
}
public NetworkObject Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation)
{
Debug.Log("NetcodeSpawnableHandler: " + spawnableData.name);
var spawnable = spawnableData.Spawn(null, position, rotation);
return spawnable.GetComponent<NetworkObject>();
}
}
I see that you’re stating Despawn shouldn’t be called in the Prefab Handler Destroy function, in this case my approach is assumingly wrong. But this is what I’m doing to resolve the issue. I would like to know the correct approach which I’m assuming is to have the OnNetworkDespawn triggered by NGO.
You’re stating that the OnNetworkDespawn does in fact executes for all client objects on the Server when each of the respective Clients disconnects from the server is that right? If this is accurate than I’m wondering what am I doing wrong? When I spawn each playerobject I set ownership to their respective ClientID.
It looks like it does for objects owned by other clients. BossRoom uses prefab handlers so I lifted out the object pool from there to test and I’m seeing the same issue. When the client disconnects Destroy is called twice on the host and there’s an exception thrown for trying to return an existing object to the pool, then it just constantly errors.
This was tested with NGO 2.1.1, I just tried 1.12.0 and I’m not seeing the error as Destroy is only called once. 2.2.0 has the same error. It’ll be worth raising the issue on Github as there’s something strange going on.
I think the lack of despawning on the host might be a 1.12.0 issue as I’m seeing the same. 2.2.0 does despawn the object correctly.
I’ve updated to Unity 6 and NGO 2.1.1 and the OnNetworkDespawn gets called on my side as well! Hence since the both of us experience the same issue, I think it’s safe to say that NGO 1.12.0 and below are bugged out.
Thank you for testing this with me!