From 898b1ca0564e91c39cc9d8bb3c128d211eb13b90 Mon Sep 17 00:00:00 2001 From: alexban011 Date: Tue, 3 May 2022 00:41:08 +0300 Subject: [PATCH] check for internet before starting a mp game to avoid freeze (#6679) * Fixed issue #6649 by checking for internet connection before starting the game if "online multiplayer" is selected Many thanks to SomeTroglodyte for most of the code and for explanations * check for internet before starting a mp game to avoid freeze Fixed issue #6649 by checking for internet connection before starting the game if "online multiplayer" is selected. Many thanks to SomeTroglodyte for most of the code and for explanations. A slight modification has been done to the code to catch an error caused by InetAddress * Revert "Merge remote-tracking branch 'origin/master-noInternet' into master-noInternet" This reverts commit bd6474b50de6b0ee25d673053ef5481cfda8d9f8, reversing changes made to f52ad60b516462fc8edd9716b917de3987cd5769. --- android/src/com/unciv/app/AndroidLauncher.kt | 6 +++--- ...d.kt => PlatformSpecificHelpersAndroid.kt} | 21 ++++++++++++++++--- core/src/com/unciv/UncivGame.kt | 8 +++---- core/src/com/unciv/UncivGameParameters.kt | 4 ++-- .../unciv/ui/newgamescreen/NewGameScreen.kt | 7 +++++++ ...r.kt => GeneralPlatformSpecificHelpers.kt} | 13 ++++++------ .../ui/worldscreen/mainmenu/OptionsPopup.kt | 12 +++++------ .../CustomSaveLocationHelperDesktop.kt | 2 +- .../com/unciv/app/desktop/DesktopLauncher.kt | 1 + .../desktop/PlatformSpecificHelpersDesktop.kt | 18 ++++++++++++++++ 10 files changed, 67 insertions(+), 25 deletions(-) rename android/src/com/unciv/app/{LimitOrientationsHelperAndroid.kt => PlatformSpecificHelpersAndroid.kt} (54%) rename core/src/com/unciv/ui/utils/{LimitOrientationsHelper.kt => GeneralPlatformSpecificHelpers.kt} (54%) create mode 100644 desktop/src/com/unciv/app/desktop/PlatformSpecificHelpersDesktop.kt diff --git a/android/src/com/unciv/app/AndroidLauncher.kt b/android/src/com/unciv/app/AndroidLauncher.kt index 5a083a1f65..52c834d029 100644 --- a/android/src/com/unciv/app/AndroidLauncher.kt +++ b/android/src/com/unciv/app/AndroidLauncher.kt @@ -35,15 +35,15 @@ open class AndroidLauncher : AndroidApplication() { val fontFamily = settings.fontFamily // Manage orientation lock - val limitOrientationsHelper = LimitOrientationsHelperAndroid(this) - limitOrientationsHelper.allowPortrait(settings.allowAndroidPortrait) + val platformSpecificHelper = PlatformSpecificHelpersAndroid(this) + platformSpecificHelper.allowPortrait(settings.allowAndroidPortrait) val androidParameters = UncivGameParameters( version = BuildConfig.VERSION_NAME, crashReportSysInfo = CrashReportSysInfoAndroid, fontImplementation = NativeFontAndroid(Fonts.ORIGINAL_FONT_SIZE.toInt(), fontFamily), customSaveLocationHelper = customSaveLocationHelper, - limitOrientationsHelper = limitOrientationsHelper + platformSpecificHelper = platformSpecificHelper ) game = UncivGame(androidParameters) diff --git a/android/src/com/unciv/app/LimitOrientationsHelperAndroid.kt b/android/src/com/unciv/app/PlatformSpecificHelpersAndroid.kt similarity index 54% rename from android/src/com/unciv/app/LimitOrientationsHelperAndroid.kt rename to android/src/com/unciv/app/PlatformSpecificHelpersAndroid.kt index 8ffd91450b..e91431d72d 100644 --- a/android/src/com/unciv/app/LimitOrientationsHelperAndroid.kt +++ b/android/src/com/unciv/app/PlatformSpecificHelpersAndroid.kt @@ -1,15 +1,19 @@ package com.unciv.app import android.app.Activity +import android.content.Context import android.content.pm.ActivityInfo -import com.unciv.ui.utils.LimitOrientationsHelper +import android.net.ConnectivityManager +import android.net.NetworkCapabilities +import com.unciv.ui.utils.GeneralPlatformSpecificHelpers -/** See also interface [LimitOrientationsHelper]. +/** See also interface [GeneralPlatformSpecificHelpers]. * * The Android implementation (currently the only one) effectively ends up doing * [Activity.setRequestedOrientation] */ -class LimitOrientationsHelperAndroid(private val activity: Activity) : LimitOrientationsHelper { +class PlatformSpecificHelpersAndroid(private val activity: Activity) : GeneralPlatformSpecificHelpers { + /* Sources for Info about current orientation in case need: val windowManager = (activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager) @@ -28,4 +32,15 @@ Sources for Info about current orientation in case need: // Comparison ensures ActivityTaskManager.getService().setRequestedOrientation isn't called unless necessary if (activity.requestedOrientation != orientation) activity.requestedOrientation = orientation } + + override fun isInternetConnected(): Boolean { + val connectivityManager = activity.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + for (network in connectivityManager.allNetworks) { + val networkCapabilities = connectivityManager.getNetworkCapabilities(network) ?: continue + val isInternet = networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + val info = connectivityManager.getNetworkInfo(network) ?: continue + if (isInternet && info.isConnected) return true + } + return false + } } diff --git a/core/src/com/unciv/UncivGame.kt b/core/src/com/unciv/UncivGame.kt index 1a49386d5c..034ccce00e 100644 --- a/core/src/com/unciv/UncivGame.kt +++ b/core/src/com/unciv/UncivGame.kt @@ -36,7 +36,7 @@ class UncivGame(parameters: UncivGameParameters) : Game() { val fontImplementation = parameters.fontImplementation val consoleMode = parameters.consoleMode val customSaveLocationHelper = parameters.customSaveLocationHelper - val limitOrientationsHelper = parameters.limitOrientationsHelper + val platformSpecificHelper = parameters.platformSpecificHelper private val audioExceptionHelper = parameters.audioExceptionHelper var deepLinkedMultiplayerGame: String? = null @@ -167,7 +167,7 @@ class UncivGame(parameters: UncivGameParameters) : Game() { worldScreen.shouldUpdate = true // This can set the screen to the policy picker or tech picker screen, so the input processor must come before Gdx.graphics.requestRendering() } - + fun tryLoadDeepLinkedGame() { if (deepLinkedMultiplayerGame != null) { try { @@ -205,7 +205,7 @@ class UncivGame(parameters: UncivGameParameters) : Game() { override fun dispose() { Gdx.input.inputProcessor = null // don't allow ANRs when shutting down, that's silly - + cancelDiscordEvent?.invoke() Sounds.clearCache() if (::musicController.isInitialized) musicController.gracefulShutdown() // Do allow fade-out @@ -214,7 +214,7 @@ class UncivGame(parameters: UncivGameParameters) : Game() { val numThreads = Thread.activeCount() val threadList = Array(numThreads) { _ -> Thread() } Thread.enumerate(threadList) - + if (isGameInfoInitialized()) { val autoSaveThread = threadList.firstOrNull { it.name == "Autosave" } if (autoSaveThread != null && autoSaveThread.isAlive) { diff --git a/core/src/com/unciv/UncivGameParameters.kt b/core/src/com/unciv/UncivGameParameters.kt index 830132f8f0..9b854f2b54 100644 --- a/core/src/com/unciv/UncivGameParameters.kt +++ b/core/src/com/unciv/UncivGameParameters.kt @@ -3,7 +3,7 @@ package com.unciv import com.unciv.logic.CustomSaveLocationHelper import com.unciv.ui.crashhandling.CrashReportSysInfo import com.unciv.ui.utils.AudioExceptionHelper -import com.unciv.ui.utils.LimitOrientationsHelper +import com.unciv.ui.utils.GeneralPlatformSpecificHelpers import com.unciv.ui.utils.NativeFontImplementation class UncivGameParameters(val version: String, @@ -12,6 +12,6 @@ class UncivGameParameters(val version: String, val fontImplementation: NativeFontImplementation? = null, val consoleMode: Boolean = false, val customSaveLocationHelper: CustomSaveLocationHelper? = null, - val limitOrientationsHelper: LimitOrientationsHelper? = null, + val platformSpecificHelper: GeneralPlatformSpecificHelpers? = null, val audioExceptionHelper: AudioExceptionHelper? = null ) diff --git a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt index 1086f7607d..feefc5033d 100644 --- a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt +++ b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt @@ -71,6 +71,13 @@ class NewGameScreen( rightSideButton.setText("Start game!".tr()) rightSideButton.onClick { if (gameSetupInfo.gameParameters.isOnlineMultiplayer) { + if (UncivGame.Current.platformSpecificHelper?.isInternetConnected() != true) { + val noInternetConnectionPopup = Popup(this) + noInternetConnectionPopup.addGoodSizedLabel("No internet connection!".tr()).row() + noInternetConnectionPopup.addCloseButton() + noInternetConnectionPopup.open() + return@onClick + } for (player in gameSetupInfo.gameParameters.players.filter { it.playerType == PlayerType.Human }) { try { UUID.fromString(IdChecker.checkAndReturnPlayerUuid(player.playerId)) diff --git a/core/src/com/unciv/ui/utils/LimitOrientationsHelper.kt b/core/src/com/unciv/ui/utils/GeneralPlatformSpecificHelpers.kt similarity index 54% rename from core/src/com/unciv/ui/utils/LimitOrientationsHelper.kt rename to core/src/com/unciv/ui/utils/GeneralPlatformSpecificHelpers.kt index c3ef776326..e12cbb719a 100644 --- a/core/src/com/unciv/ui/utils/LimitOrientationsHelper.kt +++ b/core/src/com/unciv/ui/utils/GeneralPlatformSpecificHelpers.kt @@ -2,15 +2,16 @@ package com.unciv.ui.utils import com.unciv.models.metadata.GameSettings -/** Interface to support managing orientations - * - * You can turn a mobile device on its side or upside down, and a mobile OS may or may not allow the - * position changes to automatically result in App orientation changes. This is about limiting that feature. - */ -interface LimitOrientationsHelper { +/** Interface to support various platform-specific tools */ +interface GeneralPlatformSpecificHelpers { /** Pass a Boolean setting as used in [allowAndroidPortrait][GameSettings.allowAndroidPortrait] to the OS. + * + * You can turn a mobile device on its side or upside down, and a mobile OS may or may not allow the + * position changes to automatically result in App orientation changes. This is about limiting that feature. * @param allow `true`: allow all orientations (follows sensor as limited by OS settings) * `false`: allow only landscape orientations (both if supported, otherwise default landscape only) */ fun allowPortrait(allow: Boolean) + + fun isInternetConnected(): Boolean } diff --git a/core/src/com/unciv/ui/worldscreen/mainmenu/OptionsPopup.kt b/core/src/com/unciv/ui/worldscreen/mainmenu/OptionsPopup.kt index 09ffa4a18c..9cc3b03875 100644 --- a/core/src/com/unciv/ui/worldscreen/mainmenu/OptionsPopup.kt +++ b/core/src/com/unciv/ui/worldscreen/mainmenu/OptionsPopup.kt @@ -108,7 +108,7 @@ class OptionsPopup(val previousScreen: BaseScreen) : Popup(previousScreen) { addCloseButton { previousScreen.game.musicController.onChange(null) - previousScreen.game.limitOrientationsHelper?.allowPortrait(settings.allowAndroidPortrait) + previousScreen.game.platformSpecificHelper?.allowPortrait(settings.allowAndroidPortrait) if (previousScreen is WorldScreen) previousScreen.enableNextTurnButtonAfterOptions() }.padBottom(10f) @@ -270,17 +270,17 @@ class OptionsPopup(val previousScreen: BaseScreen) : Popup(previousScreen) { val connectionToServerButton = "Check connection to server".toTextButton() - val textToShowForMultiplayerAddress = + val textToShowForMultiplayerAddress = if (settings.multiplayerServer != Constants.dropboxMultiplayerServer) settings.multiplayerServer else "https://..." val multiplayerServerTextField = TextField(textToShowForMultiplayerAddress, BaseScreen.skin) multiplayerServerTextField.programmaticChangeEvents = true val serverIpTable = Table() - serverIpTable.add("Server address".toLabel().onClick { + serverIpTable.add("Server address".toLabel().onClick { multiplayerServerTextField.text = Gdx.app.clipboard.contents }).row() - multiplayerServerTextField.onChange { + multiplayerServerTextField.onChange { settings.multiplayerServer = multiplayerServerTextField.text settings.save() connectionToServerButton.isEnabled = multiplayerServerTextField.text != Constants.dropboxMultiplayerServer @@ -318,11 +318,11 @@ class OptionsPopup(val previousScreen: BaseScreen) : Popup(previousScreen) { addMaxZoomSlider() - if (previousScreen.game.limitOrientationsHelper != null) { + if (previousScreen.game.platformSpecificHelper != null) { addCheckbox("Enable portrait orientation", settings.allowAndroidPortrait) { settings.allowAndroidPortrait = it // Note the following might close the options screen indirectly and delayed - previousScreen.game.limitOrientationsHelper.allowPortrait(it) + previousScreen.game.platformSpecificHelper.allowPortrait(it) } } diff --git a/desktop/src/com/unciv/app/desktop/CustomSaveLocationHelperDesktop.kt b/desktop/src/com/unciv/app/desktop/CustomSaveLocationHelperDesktop.kt index 4d7a8e26e1..b37b3d9ff3 100644 --- a/desktop/src/com/unciv/app/desktop/CustomSaveLocationHelperDesktop.kt +++ b/desktop/src/com/unciv/app/desktop/CustomSaveLocationHelperDesktop.kt @@ -95,4 +95,4 @@ class CustomSaveLocationHelperDesktop : CustomSaveLocationHelper { } loadCompleteCallback(gameInfo, exception) } -} \ No newline at end of file +} diff --git a/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt b/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt index c151796282..6b5dfd0a2e 100644 --- a/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt +++ b/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt @@ -52,6 +52,7 @@ internal object DesktopLauncher { fontImplementation = NativeFontDesktop(Fonts.ORIGINAL_FONT_SIZE.toInt(), settings.fontFamily), customSaveLocationHelper = CustomSaveLocationHelperDesktop(), crashReportSysInfo = CrashReportSysInfoDesktop(), + platformSpecificHelper = PlatformSpecificHelpersDesktop(), audioExceptionHelper = HardenGdxAudio() ) diff --git a/desktop/src/com/unciv/app/desktop/PlatformSpecificHelpersDesktop.kt b/desktop/src/com/unciv/app/desktop/PlatformSpecificHelpersDesktop.kt new file mode 100644 index 0000000000..90539ac95d --- /dev/null +++ b/desktop/src/com/unciv/app/desktop/PlatformSpecificHelpersDesktop.kt @@ -0,0 +1,18 @@ +package com.unciv.app.desktop + +import com.unciv.ui.utils.GeneralPlatformSpecificHelpers +import java.net.InetAddress + +class PlatformSpecificHelpersDesktop : GeneralPlatformSpecificHelpers { + override fun allowPortrait(allow: Boolean) { + // No need to do anything + } + + override fun isInternetConnected(): Boolean { + return try { + InetAddress.getByName("8.8.8.8").isReachable(500) // Parameter timeout in milliseconds + } catch (ex: Throwable) { + false + } + } +}