Mirror: Prevent destruction of objects with client authority on client disconnect

Hey everyone,

I am working on a multiplayer project using Mirror in the background. It is a VR game, so the server initially takes care of all items lying around in the scene. If a client wishes to pick up an item, the object’s authority will be transferred to the client.

My problem is now: If the client disconnects from the server while having authority over an item, the object gets deleted with him. I need a routine that resets the authority back to the server instead of deleting the item.

My initial idea is to override NetworkManager.OnServerDisconnect(). And at anytime a client disconnects, I ran a loop over all objects to look for the missing ones and respawn them. But keeping track of all objects and their transforms to respawn them in place is a lot of overhead compared to just resetting the authority. Especially, as most objects are not a prefab and therefore not registered with the NetworkManager, as they are gameplay-wise not intended to be respawned. (As far as I understood it, for NetworkServer.Spawn to work, the object needs to be registered first)

Does anyone of you have a smarter solution to it?

3 Likes

In the end, I prevent the destruction of the objects in the first place.

Down “/Assets/Mirror/Runtime/NetworkConnection.cs” there is the function “DestroyOwnedObjects()”. I basically RemoveClientAuthority() for every object except the disconnected client’s avatar gameobject, which gets destroyed. This code is not a beauty, especially that I need to reapply this patch every time I update Mirror, but it works.

1 Like

Hey, having a similar problem as well where I want all Networked objects to persist after the server/client shuts down. I’ll let ya know if I have any solution that could be applicable, but I was considering the same solution as you found.

While my issue is slightly different (all networked objects vs. only networked objects with client authority), I was thinking that in your case, is it possible to avoid giving authority to the client in the first place? Does the client really need authority over the objects they pick up? If you need to run a command that utilizes these picked-up objects, you could have the command header utilize the parameter [Command(ignoreAuthority = true)] while passing the client’s connection as a parameter for the method. In this command you could then validate whether or not the player’s character is holding the object on the server. Hope this helps, if not, glad you found a solution that works.

My solution for removing all client owned objects to stop them despawning is:

Create a NetworkManager of your own:

public class MyNetworkManager : NetworkManager
{
   public override void OnServerDisconnect(NetworkConnection conn)
        {
            var ownedObjects = new NetworkIdentity[conn.clientOwnedObjects.Count];
            conn.clientOwnedObjects.CopyTo(ownedObjects);
            foreach (var networkIdentity in ownedObjects)
            {
                networkIdentity.RemoveClientAuthority();
            }

        }
}

You need to copy the clientOwnedObjects into an array because it’s a HashSet collection that gets changed when you call RemoveClientAuthority().

8 Likes

Still the clearest example I’ve found in 2024, works in the latest version of Mirror 89.0.0:

public class CustomNetworkManager : NetworkManager {

    public override void OnServerDisconnect(NetworkConnectionToClient conn) {
        NetworkIdentity[] ownedObjects = new NetworkIdentity[conn.owned.Count];
        conn.owned.CopyTo(ownedObjects);

        foreach(NetworkIdentity owned in ownedObjects) {
            if(owned != conn.identity) {
                owned.RemoveClientAuthority();
            }
        }

        base.OnServerDisconnect(conn);
    }

}