Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS\Android client disconnects when minimized or network is switched #2698

Closed
uladzislaubasin opened this issue Apr 26, 2021 · 9 comments
Closed

Comments

@uladzislaubasin
Copy link

uladzislaubasin commented Apr 26, 2021

Describe the bug
When you switch the app onto another one on iOS\Android and then come back, you get disconnected from the server.
The same thing happens when you turn off Wi-Fi and the system quickly switches you to 4G internet.
NOTE: this happens even when NetworkManager setting runInBackround == true.

How to reproduce the issue, step by step
Reproducible with KCP transport on iOS\Android for all related examples.

Expected behavior
KCP transport has a timeout property. In case of internet connection is lost for a shorter period, the client must NOT be disconnected.

Desktop (please complete the following information):

  • OS: Unity for MacOS
  • Build target: iOS/Android
  • Unity version: 2020.3.0f1
  • Mirror branch: v35.1.0

Additional context
I believe that this happens because once you lose focus on the app, iOS\Android pauses it and Mirror does not properly handle resume.

@MrGadget1024
Copy link
Collaborator

This isn't something we can fix...the device killed the connection.

@uladzislaubasin
Copy link
Author

@MrGadget1024, what about reopening the connection in such case?

@JesusLuvsYooh
Copy link
Contributor

Yeah some devices handle this differently, minimising on PC usually keeps game open and running, Android freezes game but keeps connections, Apple tends to freeze the game and kill the connection like Gadget said.

"what about reopening the connection in such case?"
You would handle this manually, theres a Unity OnApplicationResume, or OnApplicationQuit, or OnApplicationPaused
use these to reconnection to a saved ip/port of previous host. :) @uladzislaubasin

@SoftwareGuy
Copy link
Contributor

SoftwareGuy commented Apr 27, 2021

Just to add onto MrGadget's comment:

Run in background is patchy on mobile, because Unity requests said permission to run in the background on mobile OS. However, it is up to iOS or Android to allow said permission. It may be denied due to configuration or system state.

Some custom versions of Android like Samsung's Android variants may also have a battery optimizer system that kill inactive programs aggressively. There's nothing we can do about that. We have zero control over what the mobile operating system does with its processes. Usually on iOS you get a very short period of time to handle the suspension of the application (10 - 15 seconds), on Android it can be immediate or delayed.

About reconnecting - that's up to you to implement. Maybe if you detect a unclean shutdown of the connection or disconnection then you attempt to reconnect and deal with it that way. Mirror is not designed to auto-reconnect but it is possible to implement said mechanic.

TL;DR: Nothing us Mirror developers can do. Implement a reconnection mechanic yourself or deal with the disconnection. There is a reason why Android/iOS can be a thorn in a devs' backside, and this "connection dying when minimized" is one of them.

EDIT: Consoles do this too. Nintendo Switch is known to cut communications when you press the home button as it "suspends" the application in use.

@uladzislaubasin
Copy link
Author

@JesusLuvsYooh @SoftwareGuy the problem is that Mirror automatically destroys all player related resources. Because it treats that as disconnect BY USER, rather than waiting for a timeout specified in transport. And disconnected player simply disappears. This is a way for cheating. E.g. if you are in a complex situation, simply minimize the app and then activate it again, because next time connecting Mirror will spawn you elsewhere (player spawn location).

Is there something already in the library we can use that may keep player related objects for some time to be able to connect again? Otherwise, we have to save player state, create a "ghost" that correspond to disconnected player so that other players can interact with it. And once player is connected we should restore the state while replacing the ghost. This need sounds very complicated and bugs vulnerable.

@JesusLuvsYooh
Copy link
Contributor

There will be many ways you can handle this, however it is not upto Mirror to do this, you can detect it and add yourself.
One way could be a punishment system, if they leave when they shouldn't do, or don't press quit, logout, and go back to menu, etc
Spawn them back with 50% health and magic, nerf their arse XD

I show an angry message if they do this in one of my games, along with the health and magic nerf.
It also doesnt save some of their progress, such as XP earnt, but once again, all for you to do as you please.
Screenshot 2021-04-30 at 20 17 40

@uladzislaubasin
Copy link
Author

uladzislaubasin commented May 2, 2021

My personal opinion (I may be wrong) is that destroying Player object after disconnect is not a good design choice for a modern multiplayer library, because nowadays users expect the ability to reconnect smoothly. Especially on mobile devices, when the connection may not be 100% stable.

Nevertheless, I have extended Mirror library so that Player resources are not destroyed after disconnect and they can be reused if the user connects again.

I may create PR for review to introduce this functionality as out-of-the-box for Mirror. Let me know if you are interested.

@SoftwareGuy
Copy link
Contributor

My personal opinion (I may be wrong) is that destroying Player object after disconnect is not a good design choice for a modern multiplayer library, because nowadays users expect the ability to reconnect smoothly. Especially on mobile devices, when the connection may not be 100% stable.

I disagree. Why should the server have a slot occupied waiting for a disconnected player to reconnect, when if you disconnect because your connection shat itself or Android/iOS got an incoming call and minimized your game? Too bad, let someone else take your slot that you were previously occupying. Sure, on mobile it can hurt the experience if someone checks a text message and the game disconnects because of that.

Some UDP-based protocols will "persist" the connection for some time, I remember when I was testing Tanks with Ignorance that it would synchronize up after a 3 - 5 second minimized period. If the client can sync back up then well that's fine and dandy.

Nevertheless, I have extended Mirror library so that Player resources are not destroyed after disconnect and they can be reused if the user connects again.

I may create PR for review to introduce this functionality as out-of-the-box for Mirror. Let me know if you are interested.

By all means do so, or make it into a module/component that handles this behaviour, be it session tokens or whatnot. We'll give it review and if it doesn't make it into the core then you can still let others know that a solution does exist and you can offer them your solution.

IMO, this is considered a "luxury" feature. But I can see the use in it, some games like World of Warships Blitz on mobile that use Unity Engine do have a grace period (even the desktop version that uses BigWorld Game Engine) before they mark you as ghost user/disconnected.

@calamas
Copy link

calamas commented Mar 29, 2023

Hello, @uladzislaubasin. How are you?
I am interested in your code. If you still have it, I would be very grateful if you post it.
What I am trying to archieve is the following: My game is some kind of battle royale shooter and when a player disconnects I would like to keep the player game object still in the scene waiting for the user to reconnect.
In that time, if the player reconnects can take the control of the player again where it was before disconnecting (In the mean time the player can be killed by other players). and if the player does not reconnect after 30 seconds set the player as killed and removed. Would your solution be suited for this case?

Thanks in advance

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants