mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-04 23:40:01 +07:00
Allow non-SSL-encrypted HTTP traffic & warn Dropbox users (#7013)
* Add usesCleartextTrafic permission to Android manifest * Add warning for starting a multiplayer game with the default Dropbox server * Improve multiplayer server documentation * Only update the current game if we're using a custom server or it's not our turn * Refactor: Nicer variable name * Fix compilation * Fix type Don't know what happened there
This commit is contained in:
@ -15,7 +15,9 @@
|
||||
UnusedAttribute: Since we're targeting a range of API levels, it's OK that e.g. appCategory will be ignored by OLD devices
|
||||
IconDensities: See https://developer.android.com/training/tv/start/start#banner for the banner attribute, where they recommend supplying only one density.
|
||||
-->
|
||||
<!-- Cleartext traffic permission solely so users can host their own server without setting up https -->
|
||||
<application
|
||||
android:usesCleartextTraffic="true"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/uncivicon"
|
||||
android:roundIcon="@mipmap/uncivicon_round"
|
||||
|
@ -393,6 +393,9 @@ Biome areas extension =
|
||||
Water level =
|
||||
|
||||
Online Multiplayer =
|
||||
You're currently using the default multiplayer server, which is based on a free Dropbox account. Because a lot of people use this, it is uncertain if you'll actually be able to access it consistently. Consider using a custom server instead. =
|
||||
Open Documentation =
|
||||
Don't show again =
|
||||
|
||||
World Size =
|
||||
Tiny =
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.logic.multiplayer
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.GameInfo
|
||||
import com.unciv.logic.GameInfoPreview
|
||||
@ -8,6 +9,7 @@ import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.logic.event.EventBus
|
||||
import com.unciv.logic.multiplayer.storage.FileStorageRateLimitReached
|
||||
import com.unciv.logic.multiplayer.storage.OnlineMultiplayerGameSaver
|
||||
import com.unciv.models.metadata.GameSettings
|
||||
import com.unciv.ui.crashhandling.CRASH_HANDLING_DAEMON_SCOPE
|
||||
import com.unciv.ui.crashhandling.launchCrashHandling
|
||||
import com.unciv.ui.crashhandling.postCrashHandlingRunnable
|
||||
@ -53,7 +55,8 @@ class OnlineMultiplayer {
|
||||
|
||||
val currentGame = getCurrentGame()
|
||||
val multiplayerSettings = UncivGame.Current.settings.multiplayer
|
||||
if (currentGame != null) {
|
||||
val preview = currentGame?.preview
|
||||
if (currentGame != null && (usesCustomServer() || preview == null || !preview.isUsersTurn())) {
|
||||
throttle(lastCurGameRefresh, multiplayerSettings.currentGameRefreshDelay, {}) { currentGame.requestUpdate() }
|
||||
}
|
||||
|
||||
@ -318,6 +321,11 @@ class OnlineMultiplayer {
|
||||
return preview1.turns > preview2.turns
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun usesCustomServer() = UncivGame.Current.settings.multiplayer.server != Constants.dropboxMultiplayerServer
|
||||
fun usesDropbox() = !usesCustomServer()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,6 +116,5 @@ private enum class GameUpdateResult {
|
||||
* How often games can be checked for remote updates. More attempted checks within this time period will do nothing.
|
||||
*/
|
||||
private fun getUpdateThrottleInterval(): Duration {
|
||||
val isDropbox = UncivGame.Current.settings.multiplayer.server == Constants.dropboxMultiplayerServer
|
||||
return Duration.ofSeconds(if (isDropbox) DROPBOX_THROTTLE_PERIOD else CUSTOM_SERVER_THROTTLE_PERIOD)
|
||||
return Duration.ofSeconds(if (OnlineMultiplayer.usesCustomServer()) CUSTOM_SERVER_THROTTLE_PERIOD else DROPBOX_THROTTLE_PERIOD)
|
||||
}
|
||||
|
@ -165,4 +165,5 @@ class GameSettingsMultiplayer {
|
||||
var statusButtonInSinglePlayer = false
|
||||
var currentGameRefreshDelay = Duration.ofSeconds(10)
|
||||
var allGameRefreshDelay = Duration.ofMinutes(5)
|
||||
var hideDropboxWarning = false
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package com.unciv.ui.multiplayer
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.UncivShowableException
|
||||
import com.unciv.logic.multiplayer.OnlineMultiplayer
|
||||
import com.unciv.logic.multiplayer.OnlineMultiplayerGame
|
||||
import com.unciv.logic.multiplayer.storage.FileStorageRateLimitReached
|
||||
import com.unciv.models.translations.tr
|
||||
@ -9,6 +11,7 @@ import com.unciv.ui.crashhandling.launchCrashHandling
|
||||
import com.unciv.ui.crashhandling.postCrashHandlingRunnable
|
||||
import com.unciv.ui.popup.Popup
|
||||
import com.unciv.ui.utils.BaseScreen
|
||||
import com.unciv.ui.utils.toCheckBox
|
||||
import java.io.FileNotFoundException
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
@ -67,4 +70,25 @@ object MultiplayerHelpers {
|
||||
return "[${durationToNow.toDays()}] [Days]"
|
||||
}
|
||||
}
|
||||
|
||||
fun showDropboxWarning(screen: BaseScreen) {
|
||||
if (!OnlineMultiplayer.usesDropbox() || UncivGame.Current.settings.multiplayer.hideDropboxWarning) return
|
||||
|
||||
val dropboxWarning = Popup(screen)
|
||||
dropboxWarning.addGoodSizedLabel(
|
||||
"You're currently using the default multiplayer server, which is based on a free Dropbox account. " +
|
||||
"Because a lot of people use this, it is uncertain if you'll actually be able to access it consistently. " +
|
||||
"Consider using a custom server instead."
|
||||
).colspan(2).row()
|
||||
dropboxWarning.addButton("Open Documentation") {
|
||||
Gdx.net.openURI("https://yairm210.github.io/Unciv/Other/Hosting-a-Multiplayer-server/")
|
||||
}.colspan(2).row()
|
||||
|
||||
val checkBox = "Don't show again".toCheckBox()
|
||||
dropboxWarning.add(checkBox)
|
||||
dropboxWarning.addCloseButton {
|
||||
UncivGame.Current.settings.multiplayer.hideDropboxWarning = checkBox.isChecked
|
||||
}
|
||||
dropboxWarning.open()
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
package com.unciv.ui.newgamescreen
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.CheckBox
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.civilization.CityStateType
|
||||
import com.unciv.logic.multiplayer.OnlineMultiplayer
|
||||
import com.unciv.models.metadata.GameSpeed
|
||||
import com.unciv.models.ruleset.RulesetCache
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
@ -10,6 +14,8 @@ import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.audio.MusicMood
|
||||
import com.unciv.ui.audio.MusicTrackChooserFlags
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
import com.unciv.ui.multiplayer.MultiplayerHelpers
|
||||
import com.unciv.ui.popup.Popup
|
||||
import com.unciv.ui.popup.ToastPopup
|
||||
import com.unciv.ui.utils.*
|
||||
|
||||
@ -100,9 +106,12 @@ class GameOptionsTable(
|
||||
|
||||
private fun Table.addIsOnlineMultiplayerCheckbox() =
|
||||
addCheckbox("Online Multiplayer", gameParameters.isOnlineMultiplayer)
|
||||
{
|
||||
gameParameters.isOnlineMultiplayer = it
|
||||
{ shouldUseMultiplayer ->
|
||||
gameParameters.isOnlineMultiplayer = shouldUseMultiplayer
|
||||
updatePlayerPickerTable("")
|
||||
if (shouldUseMultiplayer) {
|
||||
MultiplayerHelpers.showDropboxWarning(previousScreen as BaseScreen)
|
||||
}
|
||||
}
|
||||
|
||||
private fun numberOfCityStates() = ruleset.nations.values.count {
|
||||
|
@ -73,10 +73,9 @@ class NewGameScreen(
|
||||
rightSideButton.setText("Start game!".tr())
|
||||
rightSideButton.onClick {
|
||||
if (gameSetupInfo.gameParameters.isOnlineMultiplayer) {
|
||||
val isDropbox = UncivGame.Current.settings.multiplayer.server == Constants.dropboxMultiplayerServer
|
||||
if (!checkConnectionToMultiplayerServer()) {
|
||||
val noInternetConnectionPopup = Popup(this)
|
||||
val label = if (isDropbox) "Couldn't connect to Dropbox!" else "Couldn't connect to Multiplayer Server!"
|
||||
val label = if (OnlineMultiplayer.usesCustomServer()) "Couldn't connect to Multiplayer Server!" else "Couldn't connect to Dropbox!"
|
||||
noInternetConnectionPopup.addGoodSizedLabel(label.tr()).row()
|
||||
noInternetConnectionPopup.addCloseButton()
|
||||
noInternetConnectionPopup.open()
|
||||
|
@ -8,6 +8,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextField
|
||||
import com.badlogic.gdx.utils.Array
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.multiplayer.OnlineMultiplayer
|
||||
import com.unciv.logic.multiplayer.storage.SimpleHttp
|
||||
import com.unciv.models.metadata.GameSettings
|
||||
import com.unciv.models.translations.tr
|
||||
@ -64,7 +65,7 @@ fun multiplayerTab(
|
||||
val connectionToServerButton = "Check connection to server".toTextButton()
|
||||
|
||||
val textToShowForMultiplayerAddress =
|
||||
if (!usesDropbox(settings)) settings.multiplayer.server
|
||||
if (OnlineMultiplayer.usesCustomServer()) settings.multiplayer.server
|
||||
else "https://..."
|
||||
val multiplayerServerTextField = TextField(textToShowForMultiplayerAddress, BaseScreen.skin)
|
||||
multiplayerServerTextField.setTextFieldFilter { _, c -> c !in " \r\n\t\\" }
|
||||
@ -203,8 +204,6 @@ private fun <T> List<T>.toGdxArray(): Array<T> {
|
||||
return arr
|
||||
}
|
||||
|
||||
private fun usesDropbox(settings: GameSettings) = settings.multiplayer.server == Constants.dropboxMultiplayerServer
|
||||
|
||||
private fun addRefreshSelect(
|
||||
table: Table,
|
||||
settings: GameSettings,
|
||||
@ -216,10 +215,10 @@ private fun addRefreshSelect(
|
||||
table.add(label).left()
|
||||
|
||||
val refreshSelectBox = SelectBox<RefreshOptions>(table.skin)
|
||||
val options = if (usesDropbox(settings)) {
|
||||
dropboxOptions
|
||||
} else {
|
||||
val options = if (OnlineMultiplayer.usesCustomServer()) {
|
||||
customServerOptions
|
||||
} else {
|
||||
dropboxOptions
|
||||
}
|
||||
refreshSelectBox.items = options
|
||||
|
||||
|
@ -2,35 +2,37 @@
|
||||
|
||||
Due to certain limitations on Dropbox's API, with the current influx of players, we've many times reached the point that Dropbox has become unavailable.
|
||||
|
||||
Therefore, you can now host your own Unciv server, when not on Android.
|
||||
Therefore, you can now host your own Unciv server on any computer that can run Java programs.
|
||||
|
||||
To do so, you must have a JDK installed.
|
||||
This guide is written for people with a moderate amount of technical knowledge about computer software and who are able to search the web to learn stuff they might not know. If you're completely new to this, you'll likely not be able to follow without some larger time investment to learn.
|
||||
|
||||
From the directory where the UncivServer.jar file is located, create a folder named "MultiplayerFiles", open a terminal and run the following line:
|
||||
If you're proficient in server hosting, there's another how-to for you at the end.
|
||||
|
||||
## How To
|
||||
|
||||
Before starting, you must have a Java JDK installed. You'll also have to download the [latest UncivServer.jar](https://github.com/yairm210/Unciv/releases/latest/download/UncivServer.jar).
|
||||
|
||||
From the directory where the `UncivServer.jar` file is located, create a folder named "MultiplayerFiles", open a terminal (in Windows, Shift+RightClick in the folder) and run the following command in the directory:
|
||||
`java -jar UncivServer.jar`
|
||||
|
||||
Don't forget to use 'cd' to switch to the correct dictionary. Here's an example in Windows.
|
||||
|
||||
```
|
||||
D:
|
||||
cd Games
|
||||
cd unciv
|
||||
mkdir MultiplayerFiles
|
||||
java -jar UncivServer.jar
|
||||
```
|
||||
|
||||
Your server has now started!
|
||||
|
||||
In Unciv itself, from the same computer, enter Options > Multiplayer.
|
||||
To check if everything works, you can start Unciv on the same computer, go to "Options > Multiplayer", then enter `http://localhost` as the "Server address" and click "Check connection to server". You should now get a "Success!" result, which means it's working!
|
||||
|
||||
Enter the URL of the computer you ran the server on (or http://localhost)
|
||||
To connect with other devices, you'll need the port (default 80) the server is running on to be visible externally (port forwarding) and know your external IP-address.
|
||||
|
||||
If you click "check connection to server" you should now get "Return result: true", which means it's working!
|
||||
On the other device, enter the URL to your server, click 'check connection' from the new device, and if you get the same "Success!" result - congratulations, you're connected to the same server and can start a multiplayer game!
|
||||
|
||||
For other devices, you'll need an external IP, which is out of scope for this documentation since there are many ways of achieving it.
|
||||
Please note:
|
||||
* Devices *not* connected to the same server will *not* be able to participate in multiplayer games together
|
||||
* In many places, your external IP address changes periodically. If that is the case, you either have to update the IP all the time or use something like a dynamic DNS service.
|
||||
|
||||
On the other device, do the same - enter the URL, click 'check connection' from the new device, and if you got the same result - congratulations, you're both connected to the same server and can start a multiplayer game on the server!
|
||||
## How To for people with hosting experience
|
||||
|
||||
Android has some restrictions and does not allow unencrypted HTTP traffic from the Unciv app to a server. So you need to have a reverse proxy that sits between your (Android) client(s) and the Unciv server. The reverse proxy then needs to have a valid certificate and handles the TLS sessions for your Unciv server.
|
||||
|
||||
Please note that devices NOT connected to the same server will NOT be able to participate in multiplayer games together!
|
||||
* Have a Java JDK installed
|
||||
* Download the [latest UncivServer.jar](https://github.com/yairm210/Unciv/releases/latest/download/UncivServer.jar) (can also use that link to automatically update probably)
|
||||
* See options with `java -jar UncivServer.jar --help`
|
||||
* The server will run on a specified port (`-p`, default `80`), writing files in a folder (`-f`, default `./MultiplayerGames/`), so it needs appropriate permissions.
|
||||
* Run it: `java -jar UncivServer.jar -p 8080 -f /some/folder/`
|
||||
* It basically just does simple file storage over HTTP.
|
||||
* Files are not cleaned automatically if a game ends or is deleted on the client-side
|
||||
|
Reference in New Issue
Block a user