I have some ghost player objects in my server, basically objects owned by players that have disconnected.
I have no ideia why these objects persist after a disconnect, my guess is that I don't understand how the NetworkServer.RemovePlayerForConnection(conn, RemovePlayerOptions.Unspawn); works, and maybe this is why I have these ghosts?
#What happens with unspawn player objects when the owner disconnects?
11 messages · Page 1 of 1 (latest)
NetworkServer.RemovePlayerForConnection(conn, RemovePlayerOptions.Unspawn)
- This keeps the object on server, destroys on all clients.
Awesome! I can hunt those ghosts now.
@regal oliveHey, I'm having this same issue you posted about 1 year ago, haven't any solution being found already? I can't hit production because of this: https://github.com/MirrorNetworking/Mirror/issues/3930
@subtle spindle or @sullen shore Will have to work on this one ^
I don't know if this was saracasm, but if you have a custom network manager overriding OnServerDisconnect and you don't call the base method from there, you're preventing Mirror from cleaning up after the client that disconnected. By default, Mirror destroys on server and all clients anything the client owned, including its Player object.
👋
haven't seen that issue before - do we know if it's transport specific or not (cc @vestal wraith - what are you using nvm, just saw the comment on the issue)
I can see if I can reproduce it sometime this week (likely on the weekend)
not TX specific - I reproduced it with the Benchmark example as it comes out of the box. That's a good example to use because it ramps up the memory quick enough.
I might have fixed this bug on my side, here are my findings:
This is related to the "ghosts" problem I was having. Basically, my game relies on a room-based system, when a player changes room, the server will perform the following sequence:
- Send a scene unload msg to client.
- Wait for fade in to happen.
- Unspawn the connection identity and destroy other owned objects.
- Wait one frame for interest management to happen. <-- bug happens if player disconnects here
- Add player for connection and send other messages.
In that single frame, if the player disconnects, the identity won't be destroyed because we unspawned it. We would need to destroy it if NetworkServer.AddPlayerForConnection fail, which never happens!
As a result, the player identity then stays alive, holding the NetworkConnectionToClient, which keeps enqueuing messages in the batcher that are never sent over.
I fixed this by adding the following check inside of NetworkServer.AddPlayerForConnection:
{
Debug.LogError($"AddPlayer: connection {conn} not found in server connections");
return false;
}```
I also got this console error:
```Still had 1 batches remaining after processing, even though processing was not interrupted by a scene change. This should never happen, as it would cause ever growing batches.
Possible reasons:
* A message didn't deserialize as much as it serialized
*There was no message handler for a message id, so the reader wasn't read until the end.
UnityEngine.Debug:LogError (object)
Mirror.NetworkServer:OnTransportData (int,System.ArraySegment`1<byte>,int) (at Assets/Mirror/Core/NetworkServer.cs:867)
Mirror.ThreadedTransport:ServerEarlyUpdate () (at Assets/Mirror/Transports/Threaded/ThreadedTransport.cs:611)
Mirror.NetworkServer:NetworkEarlyUpdate () (at Assets/Mirror/Core/NetworkServer.cs:2053)
Mirror.NetworkLoop:NetworkEarlyUpdate () (at Assets/Mirror/Core/NetworkLoop.cs:192)
Here is my room change code:
IEnumerator SendPlayerToNewScene(NetworkConnectionToClient conn, ServerRoomInfo room)
{
if (conn == null || conn.identity == null) yield break;
GameObject player = conn.identity.gameObject;
ServerRoomInfo currentRoom = _rooms.FirstOrDefault(x => x.Scene == player.scene);
if (currentRoom != null)
{
currentRoom.Players.Remove(conn.connectionId);
ServerPlayerLeftRoom(currentRoom);
}
room.Players.Add(conn.connectionId);
// Tell client to unload previous subscene with custom handling (see NetworkManager::OnClientChangeScene).
conn.Send(new SceneMessage { sceneName = player.scene.path, sceneOperation = SceneOperation.UnloadAdditive, customHandling = true });
// wait for fader to complete.
yield return new WaitForSeconds((NetworkManager.singleton as EBRNetworkManager).FadeInOut.GetFadeInTime());
// If the conn disconnected, player will be null
if (player == null) yield break;
// Remove player after fader has completed
NetworkServer.RemovePlayerForConnection(conn, RemovePlayerOptions.Unspawn);
// Remove player owned objects
conn.DestroyOwnedObjects();
// yield a frame allowing interest management to update
// and all spawned objects to be destroyed on client
yield return null;
// reposition player on server and client
//AvailableRoom availableRoom = _loadedDragRacingRooms[room.Index];
MirrorPlayerSetup playerSetup = MirrorPlayerSetup.GetInstance(room.Scene);
if(playerSetup != null) playerSetup.Teleport(player);
// Move player to new subscene.
//Debug.Log($"Moving player {player.name} to scene {room.RoomId} path {room.Scene.name}");
SceneManager.MoveGameObjectToScene(player, room.Scene);
// Tell client to load the new subscene with custom handling (see NetworkManager::OnClientChangeScene).
conn.Send(new SceneIndexMessage { index = (byte)room.Index });
conn.Send(new SceneMessage { sceneName = room.Scene.path, sceneOperation = SceneOperation.LoadAdditive, customHandling = true });
// Player will be spawned after destination scene is loaded
if (!NetworkServer.AddPlayerForConnection(conn, player))
{
NetworkServer.Destroy(player);
yield break;
}
// Remove from switching list
_playersSwitchingRoom.Remove(conn.connectionId);
// host client playerController would have been disabled by OnTriggerEnter above
// Remote client players are respawned with playerController already enabled
//if (NetworkClient.localPlayer != null && NetworkClient.localPlayer.TryGetComponent(out Common.Controllers.Player.PlayerControllerBase playerController))
// playerController.enabled = true;
}```
can't repro in unity 6.2 on linux @regal olive
the resident going up is probably just fragmentation?
both with a connected player and just an idle server