mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-16 10:49:17 +07:00
Added logic to check Player- and Game-IDs according to new layout. (#2108)
Backwards compatible to old format.
This commit is contained in:
117
core/src/com/unciv/logic/IdHelper.kt
Normal file
117
core/src/com/unciv/logic/IdHelper.kt
Normal file
@ -0,0 +1,117 @@
|
||||
package com.unciv.logic
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* This class checks whether a Game- or Player-ID matches the old or new format.
|
||||
* If old format is used, checks are skipped and input is returned.
|
||||
* If new format is detected, prefix and checkDigit are checked and UUID returned.
|
||||
*
|
||||
* All input is returned trimmed.
|
||||
*
|
||||
* New format:
|
||||
* G-UUID-CheckDigit for Game IDs
|
||||
* P-UUID-CheckDigit for Player IDs
|
||||
*
|
||||
* Example:
|
||||
* 2ddb3a34-0699-4126-b7a5-38603e665928
|
||||
* Same ID in proposed new Player-ID format:
|
||||
* P-2ddb3a34-0699-4126-b7a5-38603e665928-5
|
||||
* Same ID in proposed new Game-ID format:
|
||||
* G-2ddb3a34-0699-4126-b7a5-38603e665928-5
|
||||
*/
|
||||
class IdChecker {
|
||||
companion object {
|
||||
fun checkAndReturnPlayerUuid(playerId: String): String {
|
||||
return checkAndReturnUuiId(playerId, "P")
|
||||
}
|
||||
|
||||
fun checkAndReturnGameUuid(gameId: String): String {
|
||||
return checkAndReturnUuiId(gameId, "G")
|
||||
}
|
||||
|
||||
fun checkAndReturnUuiId(id: String, prefix: String): String {
|
||||
val trimmedPlayerId = id.trim()
|
||||
if (trimmedPlayerId.length == 40) { // length of a UUID (36) with pre- and postfix
|
||||
if (!trimmedPlayerId.startsWith(prefix, true)) {
|
||||
throw IllegalArgumentException("Not a valid ID. Does not start with prefix " + prefix)
|
||||
}
|
||||
val checkDigit = trimmedPlayerId.substring(trimmedPlayerId.lastIndex, trimmedPlayerId.lastIndex +1)
|
||||
// remember, the format is: P-9e37e983-a676-4ecc-800e-ef8ec721a9b9-5
|
||||
val shortenedPlayerId = trimmedPlayerId.substring(2, 38)
|
||||
val calculatedCheckDigit = getCheckDigit(shortenedPlayerId).toString()
|
||||
if (!calculatedCheckDigit.equals(checkDigit)) {
|
||||
throw IllegalArgumentException("Not a valid ID. Checkdigit invalid.")
|
||||
}
|
||||
return shortenedPlayerId
|
||||
} else if (trimmedPlayerId.length == 36) {
|
||||
return trimmedPlayerId
|
||||
}
|
||||
throw IllegalArgumentException("Not a valid ID. Wrong length.")
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adapted from https://wiki.openmrs.org/display/docs/Check+Digit+Algorithm
|
||||
*/
|
||||
fun getCheckDigit(uuid: String): Int {
|
||||
// allowable characters within identifier
|
||||
val validChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVYWXZ-"
|
||||
var idWithoutCheckdigit = uuid
|
||||
// remove leading or trailing whitespace, convert to uppercase
|
||||
idWithoutCheckdigit = idWithoutCheckdigit.trim().toUpperCase(Locale.ENGLISH)
|
||||
|
||||
// this will be a running total
|
||||
var sum = 0
|
||||
|
||||
// loop through digits from right to left
|
||||
for (i in idWithoutCheckdigit.indices) {
|
||||
|
||||
//set ch to "current" character to be processed
|
||||
val ch = idWithoutCheckdigit.get(idWithoutCheckdigit.length - i - 1)
|
||||
|
||||
// throw exception for invalid characters
|
||||
if (validChars.indexOf(ch) == -1)
|
||||
throw IllegalArgumentException(
|
||||
ch + " is an invalid character")
|
||||
|
||||
// our "digit" is calculated using ASCII value - 48
|
||||
val digit = ch.toInt() - 48
|
||||
|
||||
// weight will be the current digit's contribution to
|
||||
// the running total
|
||||
var weight: Int
|
||||
if (i % 2 == 0) {
|
||||
|
||||
// for alternating digits starting with the rightmost, we
|
||||
// use our formula this is the same as multiplying x 2 and
|
||||
// adding digits together for values 0 to 9. Using the
|
||||
// following formula allows us to gracefully calculate a
|
||||
// weight for non-numeric "digits" as well (from their
|
||||
// ASCII value - 48).
|
||||
weight = (2 * digit) - (digit / 5) * 9
|
||||
|
||||
} else {
|
||||
|
||||
// even-positioned digits just contribute their ascii
|
||||
// value minus 48
|
||||
weight = digit
|
||||
|
||||
}
|
||||
// keep a running total of weights
|
||||
sum += weight
|
||||
|
||||
}
|
||||
// avoid sum less than 10 (if characters below "0" allowed,
|
||||
// this could happen)
|
||||
sum = Math.abs(sum) + 10
|
||||
|
||||
// check digit is amount needed to reach next number
|
||||
// divisible by ten
|
||||
val returnValue= (10 - (sum % 10)) % 10
|
||||
return returnValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,10 @@ package com.unciv.ui
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.*
|
||||
import com.unciv.logic.GameSaver
|
||||
import com.unciv.logic.GameInfo
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.GameInfo
|
||||
import com.unciv.logic.GameSaver
|
||||
import com.unciv.logic.IdChecker
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.pickerscreens.PickerScreen
|
||||
import com.unciv.ui.utils.*
|
||||
@ -115,7 +116,7 @@ class MultiplayerScreen() : PickerScreen() {
|
||||
fun addMultiplayerGame(gameId: String?, gameName: String = ""){
|
||||
try {
|
||||
//since the gameId is a String it can contain anything and has to be checked
|
||||
UUID.fromString(gameId!!.trim())
|
||||
UUID.fromString(IdChecker.checkAndReturnGameUuid(gameId!!))
|
||||
} catch (ex: Exception) {
|
||||
val errorPopup = Popup(this)
|
||||
errorPopup.addGoodSizedLabel("Invalid game ID!".tr())
|
||||
|
@ -9,6 +9,7 @@ import com.unciv.UncivGame
|
||||
import com.unciv.logic.GameInfo
|
||||
import com.unciv.logic.GameSaver
|
||||
import com.unciv.logic.GameStarter
|
||||
import com.unciv.logic.IdChecker
|
||||
import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.models.ruleset.RulesetCache
|
||||
import com.unciv.models.translations.tr
|
||||
@ -49,7 +50,7 @@ class NewGameScreen: PickerScreen(){
|
||||
if (newGameParameters.isOnlineMultiplayer) {
|
||||
for (player in newGameParameters.players.filter { it.playerType == PlayerType.Human }) {
|
||||
try {
|
||||
UUID.fromString(player.playerId)
|
||||
UUID.fromString(IdChecker.checkAndReturnPlayerUuid(player.playerId))
|
||||
} catch (ex: Exception) {
|
||||
val invalidPlayerIdPopup = Popup(this)
|
||||
invalidPlayerIdPopup.addGoodSizedLabel("Invalid player ID!".tr()).row()
|
||||
|
@ -9,13 +9,13 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextField
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.IdChecker
|
||||
import com.unciv.logic.civilization.PlayerType
|
||||
import com.unciv.models.metadata.GameParameters
|
||||
import com.unciv.models.metadata.Player
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.utils.*
|
||||
import com.unciv.ui.utils.Popup
|
||||
import java.util.*
|
||||
|
||||
class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters: GameParameters): Table() {
|
||||
@ -72,8 +72,8 @@ class PlayerPickerTable(val newGameScreen: NewGameScreen, val newGameParameters:
|
||||
|
||||
fun onPlayerIdTextUpdated(){
|
||||
try {
|
||||
val uuid = UUID.fromString(playerIdTextfield.text)
|
||||
player.playerId = playerIdTextfield.text
|
||||
UUID.fromString(IdChecker.checkAndReturnPlayerUuid(playerIdTextfield.text))
|
||||
player.playerId = playerIdTextfield.text.trim()
|
||||
errorLabel.apply { setText("✔");setFontColor(Color.GREEN) }
|
||||
} catch (ex: Exception) {
|
||||
errorLabel.apply { setText("✘");setFontColor(Color.RED) }
|
||||
|
@ -3,9 +3,9 @@ package com.unciv.ui.worldscreen.mainmenu
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.IdChecker
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.CivilopediaScreen
|
||||
import com.unciv.ui.victoryscreen.VictoryScreen
|
||||
import com.unciv.ui.MultiplayerScreen
|
||||
import com.unciv.ui.mapeditor.LoadMapScreen
|
||||
import com.unciv.ui.mapeditor.NewMapScreen
|
||||
@ -13,6 +13,7 @@ import com.unciv.ui.newgamescreen.NewGameScreen
|
||||
import com.unciv.ui.saves.LoadGameScreen
|
||||
import com.unciv.ui.saves.SaveGameScreen
|
||||
import com.unciv.ui.utils.*
|
||||
import com.unciv.ui.victoryscreen.VictoryScreen
|
||||
import com.unciv.ui.worldscreen.WorldScreen
|
||||
import java.util.*
|
||||
import kotlin.concurrent.thread
|
||||
@ -105,7 +106,7 @@ class WorldScreenMenuPopup(val worldScreen: WorldScreen) : Popup(worldScreen) {
|
||||
multiplayerPopup.addButton("Join Game") {
|
||||
val gameId = Gdx.app.clipboard.contents
|
||||
try {
|
||||
UUID.fromString(gameId.trim())
|
||||
UUID.fromString(IdChecker.checkAndReturnGameUuid(gameId))
|
||||
} catch (ex: Exception) {
|
||||
badGameIdLabel.setText("Invalid game ID!")
|
||||
badGameIdLabel.isVisible = true
|
||||
|
Reference in New Issue
Block a user