Allow Spectator to force-resign any human in multiplayer, and allow anyone to do so if player is inactive for 48h

This commit is contained in:
yairm210
2024-08-08 12:42:52 +03:00
parent f3129dc0af
commit e74abce5dc
3 changed files with 42 additions and 15 deletions

View File

@ -787,6 +787,7 @@ class GameInfoPreview() {
fun getCivilization(civName: String) = civilizations.first { it.civName == civName } fun getCivilization(civName: String) = civilizations.first { it.civName == civName }
fun getCurrentPlayerCiv() = getCivilization(currentPlayer) fun getCurrentPlayerCiv() = getCivilization(currentPlayer)
fun getPlayerCiv(playerId: String) = civilizations.firstOrNull { it.playerId == playerId }
} }
/** Class to use when parsing jsons if you only want the serialization [version]. */ /** Class to use when parsing jsons if you only want the serialization [version]. */

View File

@ -146,17 +146,16 @@ class Multiplayer {
* @throws MultiplayerAuthException if the authentication failed * @throws MultiplayerAuthException if the authentication failed
* @return false if it's not the user's turn and thus resigning did not happen * @return false if it's not the user's turn and thus resigning did not happen
*/ */
suspend fun resign(game: MultiplayerGame): Boolean { suspend fun resignCurrentPlayer(game: MultiplayerGame): Boolean {
val preview = game.preview ?: throw game.error!! val preview = game.preview ?: throw game.error!!
// download to work with the latest game state // download to work with the latest game state
val gameInfo = multiplayerServer.tryDownloadGame(preview.gameId) val gameInfo = multiplayerServer.tryDownloadGame(preview.gameId)
if (gameInfo.currentTurnStartTime != preview.currentTurnStartTime)
return false // Game was updated since we tried
val playerCiv = gameInfo.getCurrentPlayerCivilization() val playerCiv = gameInfo.getCurrentPlayerCivilization()
if (!gameInfo.isUsersTurn()) { //Set civ info to AI
return false
}
//Set own civ info to AI
playerCiv.playerType = PlayerType.AI playerCiv.playerType = PlayerType.AI
playerCiv.playerId = "" playerCiv.playerId = ""

View File

@ -10,6 +10,7 @@ import com.unciv.models.translations.tr
import com.unciv.ui.components.widgets.UncivTextField import com.unciv.ui.components.widgets.UncivTextField
import com.unciv.ui.components.extensions.disable import com.unciv.ui.components.extensions.disable
import com.unciv.ui.components.extensions.enable import com.unciv.ui.components.extensions.enable
import com.unciv.ui.components.extensions.isEnabled
import com.unciv.ui.components.extensions.toTextButton import com.unciv.ui.components.extensions.toTextButton
import com.unciv.ui.components.input.KeyCharAndCode import com.unciv.ui.components.input.KeyCharAndCode
import com.unciv.ui.components.input.keyShortcuts import com.unciv.ui.components.input.keyShortcuts
@ -24,6 +25,8 @@ import com.unciv.ui.screens.savescreens.LoadGameScreen
import com.unciv.utils.Concurrency import com.unciv.utils.Concurrency
import com.unciv.utils.Log import com.unciv.utils.Log
import com.unciv.utils.launchOnGLThread import com.unciv.utils.launchOnGLThread
import java.time.Duration
import java.time.Instant
import com.unciv.ui.components.widgets.AutoScrollPane as ScrollPane import com.unciv.ui.components.widgets.AutoScrollPane as ScrollPane
class MultiplayerScreen : PickerScreen() { class MultiplayerScreen : PickerScreen() {
@ -31,8 +34,10 @@ class MultiplayerScreen : PickerScreen() {
private val copyGameIdButton = createCopyGameIdButton() private val copyGameIdButton = createCopyGameIdButton()
private val resignButton = createResignButton() private val resignButton = createResignButton()
private val forceResignButton = createForceResignButton()
private val deleteButton = createDeleteButton() private val deleteButton = createDeleteButton()
private val renameButton = createRenameButton() private val renameButton = createRenameButton()
private val gameSpecificButtons = listOf(copyGameIdButton, resignButton, deleteButton, renameButton) private val gameSpecificButtons = listOf(copyGameIdButton, resignButton, deleteButton, renameButton)
private val addGameButton = createAddGameButton() private val addGameButton = createAddGameButton()
@ -51,7 +56,6 @@ class MultiplayerScreen : PickerScreen() {
topTable.add(createMainContent()).row() topTable.add(createMainContent()).row()
setupHelpButton() setupHelpButton()
setupRightSideButton() setupRightSideButton()
game.onlineMultiplayer.requestUpdate() game.onlineMultiplayer.requestUpdate()
@ -80,6 +84,7 @@ class MultiplayerScreen : PickerScreen() {
gameSpecificActions.add(copyGameIdButton).row() gameSpecificActions.add(copyGameIdButton).row()
gameSpecificActions.add(renameButton).row() gameSpecificActions.add(renameButton).row()
gameSpecificActions.add(resignButton).row() gameSpecificActions.add(resignButton).row()
gameSpecificActions.add(forceResignButton).row()
gameSpecificActions.add(deleteButton).row() gameSpecificActions.add(deleteButton).row()
table.add(gameSpecificActions) table.add(gameSpecificActions)
@ -116,7 +121,23 @@ class MultiplayerScreen : PickerScreen() {
"Are you sure you want to resign?", "Are you sure you want to resign?",
"Resign", "Resign",
) { ) {
resign(selectedGame!!) resignCurrentPlayer(selectedGame!!)
}
askPopup.open()
}
return resignButton
}
fun createForceResignButton(): TextButton {
val negativeButtonStyle = skin.get("negative", TextButton.TextButtonStyle::class.java)
val resignButton = "Force current player to resign".toTextButton(negativeButtonStyle).apply { isVisible = false }
resignButton.onClick {
val askPopup = ConfirmPopup(
this,
"Are you sure you want to force the current player to resign?",
"Yes",
) {
resignCurrentPlayer(selectedGame!!)
} }
askPopup.open() askPopup.open()
} }
@ -124,10 +145,9 @@ class MultiplayerScreen : PickerScreen() {
} }
/** /**
* Helper function to decrease indentation
* Turns the current playerCiv into an AI civ and uploads the game afterwards. * Turns the current playerCiv into an AI civ and uploads the game afterwards.
*/ */
private fun resign(multiplayerGame: MultiplayerGame) { private fun resignCurrentPlayer(multiplayerGame: MultiplayerGame) {
//Create a popup //Create a popup
val popup = Popup(this) val popup = Popup(this)
popup.addGoodSizedLabel(Constants.working).row() popup.addGoodSizedLabel(Constants.working).row()
@ -135,7 +155,7 @@ class MultiplayerScreen : PickerScreen() {
Concurrency.runOnNonDaemonThreadPool("Resign") { Concurrency.runOnNonDaemonThreadPool("Resign") {
try { try {
val resignSuccess = game.onlineMultiplayer.resign(multiplayerGame) val resignSuccess = game.onlineMultiplayer.resignCurrentPlayer(multiplayerGame)
launchOnGLThread { launchOnGLThread {
if (resignSuccess) { if (resignSuccess) {
@ -151,7 +171,7 @@ class MultiplayerScreen : PickerScreen() {
if (ex is MultiplayerAuthException) { if (ex is MultiplayerAuthException) {
launchOnGLThread { launchOnGLThread {
AuthPopup(this@MultiplayerScreen) { success -> AuthPopup(this@MultiplayerScreen) { success ->
if (success) resign(multiplayerGame) if (success) resignCurrentPlayer(multiplayerGame)
}.open(true) }.open(true)
} }
return@runOnNonDaemonThreadPool return@runOnNonDaemonThreadPool
@ -281,6 +301,8 @@ class MultiplayerScreen : PickerScreen() {
rightSideButton.disable() rightSideButton.disable()
for (button in gameSpecificButtons) for (button in gameSpecificButtons)
button.disable() button.disable()
forceResignButton.isVisible = false
descriptionLabel.setText("") descriptionLabel.setText("")
} }
@ -301,10 +323,15 @@ class MultiplayerScreen : PickerScreen() {
copyGameIdButton.disable() copyGameIdButton.disable()
} }
if (multiplayerGame.preview?.getCurrentPlayerCiv()?.playerId == game.settings.multiplayer.userId) { resignButton.isEnabled = multiplayerGame.preview?.getCurrentPlayerCiv()?.playerId == game.settings.multiplayer.userId
resignButton.enable()
if (resignButton.isEnabled || multiplayerGame.preview == null){
forceResignButton.isVisible = false
} else { } else {
resignButton.disable() val durationInactive = Duration.between(Instant.ofEpochMilli(multiplayerGame.preview!!.currentTurnStartTime), Instant.now())
forceResignButton.isVisible =
multiplayerGame.preview?.getPlayerCiv(game.settings.multiplayer.userId)?.civName == Constants.spectator
|| durationInactive > Duration.ofDays(2)
} }
rightSideButton.enable() rightSideButton.enable()