mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-20 20:59:18 +07:00
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:
@ -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]. */
|
||||||
|
@ -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 = ""
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
Reference in New Issue
Block a user