summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoffrey Bion <joffrey.bion@booking.com>2020-03-29 18:02:47 +0200
committerJoffrey Bion <joffrey.bion@booking.com>2020-03-29 18:07:31 +0200
commit57a6e5135ee554079c6064bd770d51545800969d (patch)
tree9c688d1fc261cf6740c63a604695f9301220830f
parentEnsure error saga starts first (diff)
downloadseven-wonders-57a6e5135ee554079c6064bd770d51545800969d.tar.gz
seven-wonders-57a6e5135ee554079c6064bd770d51545800969d.tar.bz2
seven-wonders-57a6e5135ee554079c6064bd770d51545800969d.zip
Fix duplicated inconsistent state
-rw-r--r--sw-client/src/commonMain/kotlin/org/luxons/sevenwonders/client/SevenWondersClient.kt9
-rw-r--r--sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/model/api/Api.kt37
-rw-r--r--sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt10
-rw-r--r--sw-server/src/main/kotlin/org/luxons/sevenwonders/server/api/Converters.kt19
-rw-r--r--sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/GameBrowserController.kt8
-rw-r--r--sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/GameController.kt2
-rw-r--r--sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/HomeController.kt6
-rw-r--r--sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/LobbyController.kt15
-rw-r--r--sw-server/src/main/kotlin/org/luxons/sevenwonders/server/lobby/Lobby.kt28
-rw-r--r--sw-server/src/test/kotlin/org/luxons/sevenwonders/server/controllers/GameBrowserControllerTest.kt8
-rw-r--r--sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt2
-rw-r--r--sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameList.kt104
-rw-r--r--sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt8
-rw-r--r--sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/Lobby.kt7
-rw-r--r--sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt20
-rw-r--r--sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt4
-rw-r--r--sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt9
17 files changed, 155 insertions, 141 deletions
diff --git a/sw-client/src/commonMain/kotlin/org/luxons/sevenwonders/client/SevenWondersClient.kt b/sw-client/src/commonMain/kotlin/org/luxons/sevenwonders/client/SevenWondersClient.kt
index d95c32f5..b97413c3 100644
--- a/sw-client/src/commonMain/kotlin/org/luxons/sevenwonders/client/SevenWondersClient.kt
+++ b/sw-client/src/commonMain/kotlin/org/luxons/sevenwonders/client/SevenWondersClient.kt
@@ -2,8 +2,8 @@ package org.luxons.sevenwonders.client
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerializationStrategy
-import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.builtins.list
+import kotlinx.serialization.builtins.serializer
import org.hildan.krossbow.stomp.StompClient
import org.hildan.krossbow.stomp.StompSubscription
import org.hildan.krossbow.stomp.conversions.kxserialization.StompSessionWithKxSerialization
@@ -12,11 +12,10 @@ import org.hildan.krossbow.stomp.conversions.kxserialization.withJsonConversions
import org.hildan.krossbow.stomp.sendEmptyMsg
import org.hildan.krossbow.stomp.subscribeEmptyMsg
import org.luxons.sevenwonders.model.CustomizableSettings
-import org.luxons.sevenwonders.model.GameState
import org.luxons.sevenwonders.model.PlayerMove
import org.luxons.sevenwonders.model.PlayerTurnInfo
+import org.luxons.sevenwonders.model.api.ConnectedPlayer
import org.luxons.sevenwonders.model.api.LobbyDTO
-import org.luxons.sevenwonders.model.api.PlayerDTO
import org.luxons.sevenwonders.model.api.SEVEN_WONDERS_WS_ENDPOINT
import org.luxons.sevenwonders.model.api.actions.ChooseNameAction
import org.luxons.sevenwonders.model.api.actions.CreateGameAction
@@ -58,12 +57,12 @@ class SevenWondersSession(private val stompSession: StompSessionWithKxSerializat
suspend fun watchErrors(): StompSubscription<ErrorDTO> =
stompSession.subscribe("/user/queue/errors", ErrorDTO.serializer())
- suspend fun chooseName(displayName: String): PlayerDTO = stompSession.request(
+ suspend fun chooseName(displayName: String): ConnectedPlayer = stompSession.request(
sendDestination = "/app/chooseName",
receiveDestination = "/user/queue/nameChoice",
payload = ChooseNameAction(displayName),
serializer = ChooseNameAction.serializer(),
- deserializer = PlayerDTO.serializer()
+ deserializer = ConnectedPlayer.serializer()
)
suspend fun watchGames(): StompSubscription<List<LobbyDTO>> =
diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/model/api/Api.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/model/api/Api.kt
index b648b72b..946c93c7 100644
--- a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/model/api/Api.kt
+++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/model/api/Api.kt
@@ -15,9 +15,33 @@ data class LobbyDTO(
val owner: String,
val players: List<PlayerDTO>,
val state: State,
- val joinAction: Actionability,
- val startAction: Actionability
-)
+ val hasEnoughPlayers: Boolean,
+ val maxPlayersReached: Boolean
+) {
+ fun joinability(userDisplayName: String): Actionability = when {
+ state != State.LOBBY -> Actionability(false, "Cannot join: the game has already started")
+ maxPlayersReached -> Actionability(
+ false,
+ "Cannot join: the game is full"
+ )
+ playerNameAlreadyUsed(userDisplayName) -> Actionability(
+ false,
+ "Cannot join: already a player named '$userDisplayName' in this game"
+ )
+ else -> Actionability(true, "Join game")
+ }
+
+ fun startability(username: String): Actionability = when {
+ !hasEnoughPlayers -> Actionability(
+ false,
+ "Cannot start the game, more players needed"
+ )
+ owner != username -> Actionability(false, "Cannot start the game: only the owner can")
+ else -> Actionability(true, "Start game")
+ }
+
+ private fun playerNameAlreadyUsed(name: String): Boolean = players.any { it.displayName == name }
+}
@Serializable
data class Actionability(
@@ -26,11 +50,16 @@ data class Actionability(
)
@Serializable
+data class ConnectedPlayer(
+ val username: String,
+ val displayName: String
+)
+
+@Serializable
data class PlayerDTO(
val username: String,
val displayName: String,
val index: Int,
val isGameOwner: Boolean,
- val isMe: Boolean,
val isReady: Boolean
)
diff --git a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt
index 935d66e5..ad3c28d4 100644
--- a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt
+++ b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt
@@ -50,7 +50,7 @@ class GameTest {
assertEquals(nbPlayers, turnInfos.size)
turnInfos.forEach {
assertEquals(ageToCheck, it.currentAge)
- assertEquals(handSize, it.hand.size)
+ assertEquals(handSize, it.hand?.size)
}
val moveExpectations = turnInfos.mapNotNull { it.firstAvailableMove() }
@@ -67,20 +67,20 @@ class GameTest {
private fun PlayerTurnInfo.firstAvailableMove(): MoveExpectation? = when (action) {
Action.PLAY, Action.PLAY_2, Action.PLAY_LAST -> createPlayCardMove(this)
Action.PICK_NEIGHBOR_GUILD -> createPickGuildMove(this)
- Action.WAIT -> null
+ Action.WAIT, Action.SAY_READY -> null
}
private fun createPlayCardMove(turnInfo: PlayerTurnInfo): MoveExpectation {
val wonderBuildability = turnInfo.wonderBuildability
if (wonderBuildability.isBuildable) {
val transactions = wonderBuildability.cheapestTransactions.first()
- return planMove(turnInfo, MoveType.UPGRADE_WONDER, turnInfo.hand.first(), transactions)
+ return planMove(turnInfo, MoveType.UPGRADE_WONDER, turnInfo.hand!!.first(), transactions)
}
- val playableCard = turnInfo.hand.firstOrNull { it.playability.isPlayable }
+ val playableCard = turnInfo.hand!!.firstOrNull { it.playability.isPlayable }
return if (playableCard != null) {
planMove(turnInfo, MoveType.PLAY, playableCard, playableCard.playability.cheapestTransactions.first())
} else {
- planMove(turnInfo, MoveType.DISCARD, turnInfo.hand.first(),
+ planMove(turnInfo, MoveType.DISCARD, turnInfo.hand!!.first(),
noTransactions()
)
}
diff --git a/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/api/Converters.kt b/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/api/Converters.kt
index a2390a7d..7c3ccfbb 100644
--- a/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/api/Converters.kt
+++ b/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/api/Converters.kt
@@ -5,12 +5,15 @@ import org.luxons.sevenwonders.model.api.PlayerDTO
import org.luxons.sevenwonders.server.lobby.Lobby
import org.luxons.sevenwonders.server.lobby.Player
-fun Lobby.toDTO(currentPlayer: Player): LobbyDTO {
- val players = getPlayers().map { it.toDTO(currentPlayer.username) }
- val joinability = joinability(currentPlayer.displayName)
- val startability = startability(currentPlayer.username)
- return LobbyDTO(id, name, owner.username, players, state, joinability, startability)
-}
+fun Lobby.toDTO(): LobbyDTO = LobbyDTO(
+ id = id,
+ name = name,
+ owner = owner.username,
+ players = getPlayers().map { it.toDTO() },
+ state = state,
+ hasEnoughPlayers = hasEnoughPlayers(),
+ maxPlayersReached = maxPlayersReached()
+)
+
+fun Player.toDTO() = PlayerDTO(username, displayName, index, isGameOwner, isReady)
-fun Player.toDTO(currentUser: String) =
- PlayerDTO(username, displayName, index, isGameOwner, username === currentUser, isReady)
diff --git a/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/GameBrowserController.kt b/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/GameBrowserController.kt
index 0bd1de79..3de0de97 100644
--- a/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/GameBrowserController.kt
+++ b/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/GameBrowserController.kt
@@ -42,7 +42,7 @@ class GameBrowserController @Autowired constructor(
fun listGames(principal: Principal): Collection<LobbyDTO> {
logger.info("Player '{}' subscribed to /topic/games", principal.name)
val player = playerRepository.find(principal.name)
- return lobbyRepository.list().map { it.toDTO(player) }
+ return lobbyRepository.list().map { it.toDTO() }
}
/**
@@ -64,7 +64,7 @@ class GameBrowserController @Autowired constructor(
logger.info("Game '{}' ({}) created by {} ({})", lobby.name, lobby.id, player.displayName, player.username)
// notify everyone that a new game exists
- val lobbyDto = lobby.toDTO(player)
+ val lobbyDto = lobby.toDTO()
template.convertAndSend("/topic/games", listOf(lobbyDto))
return lobbyDto
}
@@ -87,8 +87,8 @@ class GameBrowserController @Autowired constructor(
lobby.addPlayer(player)
logger.info("Player '{}' ({}) joined game {}", player.displayName, player.username, lobby.name)
- val lobbyDTO = lobby.toDTO(player)
- lobbyController.sendLobbyUpdateToPlayers(lobby, player)
+ val lobbyDTO = lobby.toDTO()
+ lobbyController.sendLobbyUpdateToPlayers(lobby)
return lobbyDTO
}
diff --git a/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/GameController.kt b/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/GameController.kt
index 0db7a21c..803cca78 100644
--- a/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/GameController.kt
+++ b/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/GameController.kt
@@ -66,7 +66,7 @@ class GameController @Autowired constructor(
val player = principal.player
val game = player.game
val preparedCardBack = game.prepareMove(player.index, action.move)
- val preparedCard = PreparedCard(player.toDTO(principal.name), preparedCardBack)
+ val preparedCard = PreparedCard(player.toDTO(), preparedCardBack)
logger.info("Game {}: player {} prepared move {}", game.id, principal.name, action.move)
sendPreparedCard(game.id, preparedCard)
diff --git a/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/HomeController.kt b/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/HomeController.kt
index a0d53f8b..c2619f8c 100644
--- a/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/HomeController.kt
+++ b/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/HomeController.kt
@@ -1,9 +1,9 @@
package org.luxons.sevenwonders.server.controllers
import org.hildan.livedoc.core.annotations.Api
+import org.luxons.sevenwonders.model.api.ConnectedPlayer
import org.luxons.sevenwonders.model.api.PlayerDTO
import org.luxons.sevenwonders.model.api.actions.ChooseNameAction
-import org.luxons.sevenwonders.server.api.toDTO
import org.luxons.sevenwonders.server.repositories.PlayerRepository
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
@@ -32,12 +32,12 @@ class HomeController @Autowired constructor(
*/
@MessageMapping("/chooseName")
@SendToUser("/queue/nameChoice")
- fun chooseName(@Validated action: ChooseNameAction, principal: Principal): PlayerDTO {
+ fun chooseName(@Validated action: ChooseNameAction, principal: Principal): ConnectedPlayer {
val username = principal.name
val player = playerRepository.createOrUpdate(username, action.playerName)
logger.info("Player '{}' chose the name '{}'", username, player.displayName)
- return player.toDTO(username)
+ return ConnectedPlayer(username, player.displayName)
}
companion object {
diff --git a/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/LobbyController.kt b/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/LobbyController.kt
index b74913cb..04fb2228 100644
--- a/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/LobbyController.kt
+++ b/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/LobbyController.kt
@@ -45,7 +45,7 @@ class LobbyController @Autowired constructor(
}
logger.info("Player {} left game '{}'", player, lobby.name)
- sendLobbyUpdateToPlayers(lobby, player)
+ sendLobbyUpdateToPlayers(lobby)
}
/**
@@ -62,7 +62,7 @@ class LobbyController @Autowired constructor(
lobby.reorderPlayers(action.orderedPlayers)
logger.info("Players in game '{}' reordered to {}", lobby.name, action.orderedPlayers)
- sendLobbyUpdateToPlayers(lobby, principal.player)
+ sendLobbyUpdateToPlayers(lobby)
}
/**
@@ -75,19 +75,18 @@ class LobbyController @Autowired constructor(
*/
@MessageMapping("/lobby/updateSettings")
fun updateSettings(@Validated action: UpdateSettingsAction, principal: Principal) {
- val player = principal.player
- val lobby = player.ownedLobby
+ val lobby = principal.player.ownedLobby
lobby.settings = action.settings
logger.info("Updated settings of game '{}'", lobby.name)
- sendLobbyUpdateToPlayers(lobby, player)
+ sendLobbyUpdateToPlayers(lobby)
}
- internal fun sendLobbyUpdateToPlayers(lobby: Lobby, player: Player) {
+ internal fun sendLobbyUpdateToPlayers(lobby: Lobby) {
lobby.getPlayers().forEach {
- template.convertAndSendToUser(it.username, "/queue/lobby/updated", lobby.toDTO(it))
+ template.convertAndSendToUser(it.username, "/queue/lobby/updated", lobby.toDTO())
}
- template.convertAndSend("/topic/games", listOf(lobby.toDTO(player)))
+ template.convertAndSend("/topic/games", listOf(lobby.toDTO()))
}
/**
diff --git a/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/lobby/Lobby.kt b/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/lobby/Lobby.kt
index 5368bedf..eadc1742 100644
--- a/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/lobby/Lobby.kt
+++ b/sw-server/src/main/kotlin/org/luxons/sevenwonders/server/lobby/Lobby.kt
@@ -3,7 +3,6 @@ package org.luxons.sevenwonders.server.lobby
import org.luxons.sevenwonders.engine.Game
import org.luxons.sevenwonders.engine.data.GameDefinition
import org.luxons.sevenwonders.model.CustomizableSettings
-import org.luxons.sevenwonders.model.api.Actionability
import org.luxons.sevenwonders.model.api.State
class Lobby(
@@ -14,8 +13,7 @@ class Lobby(
) {
private val players: MutableList<Player> = ArrayList(gameDefinition.maxPlayers)
- var settings: CustomizableSettings =
- CustomizableSettings()
+ var settings: CustomizableSettings = CustomizableSettings()
var state = State.LOBBY
private set
@@ -41,22 +39,9 @@ class Lobby(
players.add(player)
}
- fun joinability(userDisplayName: String): Actionability = when {
- hasStarted() -> Actionability(false, "Cannot join: the game has already started")
- maxPlayersReached() -> Actionability(
- false,
- "Cannot join: the game is full (${gameDefinition.maxPlayers} players max)"
- )
- playerNameAlreadyUsed(userDisplayName) -> Actionability(
- false,
- "Cannot join: already a player named '$userDisplayName' in this game"
- )
- else -> Actionability(true, "Join game")
- }
-
private fun hasStarted(): Boolean = state != State.LOBBY
- private fun maxPlayersReached(): Boolean = players.size >= gameDefinition.maxPlayers
+ fun maxPlayersReached(): Boolean = players.size >= gameDefinition.maxPlayers
private fun playerNameAlreadyUsed(name: String): Boolean = players.any { it.displayName == name }
@@ -71,14 +56,7 @@ class Lobby(
return game
}
- fun startability(username: String): Actionability = when {
- !hasEnoughPlayers() -> Actionability(false, "Cannot start: min ${gameDefinition.minPlayers} players required"
- )
- owner.username != username -> Actionability(false, "Cannot start the game: only the owner can")
- else -> Actionability(true, "Start game")
- }
-
- private fun hasEnoughPlayers(): Boolean = players.size >= gameDefinition.minPlayers
+ fun hasEnoughPlayers(): Boolean = players.size >= gameDefinition.minPlayers
@Synchronized
fun reorderPlayers(orderedUsernames: List<String>) {
diff --git a/sw-server/src/test/kotlin/org/luxons/sevenwonders/server/controllers/GameBrowserControllerTest.kt b/sw-server/src/test/kotlin/org/luxons/sevenwonders/server/controllers/GameBrowserControllerTest.kt
index 804b5f6e..88e04c14 100644
--- a/sw-server/src/test/kotlin/org/luxons/sevenwonders/server/controllers/GameBrowserControllerTest.kt
+++ b/sw-server/src/test/kotlin/org/luxons/sevenwonders/server/controllers/GameBrowserControllerTest.kt
@@ -52,7 +52,7 @@ class GameBrowserControllerTest {
assertFalse(games.isEmpty())
val lobby = games.iterator().next()
assertEquals(lobby, createdLobby)
- assertEquals(player.toDTO(principal.name), lobby.players[0])
+ assertEquals(player.toDTO(), lobby.players[0])
}
@Test
@@ -90,7 +90,7 @@ class GameBrowserControllerTest {
val createGameAction = CreateGameAction("Test Game")
val createdLobby = gameBrowserController.createGame(createGameAction, ownerPrincipal)
- assertEquals(owner.toDTO(ownerPrincipal.name), createdLobby.players[0])
+ assertEquals(owner.toDTO(), createdLobby.players[0])
val joiner = playerRepository.createOrUpdate("testjoiner", "Test User Joiner")
val joinerPrincipal = TestPrincipal("testjoiner")
@@ -98,8 +98,8 @@ class GameBrowserControllerTest {
val joinedLobby = gameBrowserController.joinGame(joinGameAction, joinerPrincipal)
- assertEquals(owner.toDTO(joinerPrincipal.name), joinedLobby.players[0])
- assertEquals(joiner.toDTO(joinerPrincipal.name), joinedLobby.players[1])
+ assertEquals(owner.toDTO(), joinedLobby.players[0])
+ assertEquals(joiner.toDTO(), joinedLobby.players[1])
}
@Test
diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt
index fc7e12d5..2f860ca7 100644
--- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt
+++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt
@@ -6,5 +6,5 @@ import react.dom.*
fun RBuilder.gameBrowser() = div {
h1 { +"Games" }
createGameForm {}
- gameList {}
+ gameList()
}
diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameList.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameList.kt
index 19cd961f..47c17da1 100644
--- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameList.kt
+++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameList.kt
@@ -15,6 +15,7 @@ import kotlinx.css.flexDirection
import kotlinx.css.verticalAlign
import kotlinx.html.classes
import kotlinx.html.title
+import org.luxons.sevenwonders.model.api.ConnectedPlayer
import org.luxons.sevenwonders.model.api.LobbyDTO
import org.luxons.sevenwonders.model.api.State
import org.luxons.sevenwonders.ui.redux.RequestJoinGame
@@ -30,6 +31,7 @@ import styled.styledSpan
import styled.styledTr
interface GameListStateProps : RProps {
+ var connectedPlayer: ConnectedPlayer
var games: List<LobbyDTO>
}
@@ -56,69 +58,73 @@ class GameListPresenter(props: GameListProps) : RComponent<GameListProps, RState
}
}
}
-}
-
-private fun RBuilder.gameListHeaderRow() = tr {
- th { +"Name" }
- th { +"Status" }
- th { +"Nb Players" }
- th { +"Join" }
-}
-private fun RBuilder.gameListItemRow(lobby: LobbyDTO, joinGame: (Long) -> Unit) = styledTr {
- css {
- verticalAlign = VerticalAlign.middle
+ private fun RBuilder.gameListHeaderRow() = tr {
+ th { +"Name" }
+ th { +"Status" }
+ th { +"Nb Players" }
+ th { +"Join" }
}
- attrs {
- key = lobby.id.toString()
- }
- td { +lobby.name }
- td { gameStatus(lobby.state) }
- td { playerCount(lobby.players.size) }
- td { joinButton(lobby, joinGame) }
-}
-private fun RBuilder.gameStatus(state: State) {
- val intent = when(state) {
- State.LOBBY -> Intent.SUCCESS
- State.PLAYING -> Intent.WARNING
- State.FINISHED -> Intent.DANGER
- }
- bpTag(minimal = true, intent = intent) {
- +state.toString()
- }
-}
-
-private fun RBuilder.playerCount(nPlayers: Int) {
- styledDiv {
+ private fun RBuilder.gameListItemRow(lobby: LobbyDTO, joinGame: (Long) -> Unit) = styledTr {
css {
- display = Display.flex
- flexDirection = FlexDirection.row
- alignItems = Align.center
+ verticalAlign = VerticalAlign.middle
}
attrs {
- title = "Number of players"
+ key = lobby.id.toString()
+ }
+ td { +lobby.name }
+ td { gameStatus(lobby.state) }
+ td { playerCount(lobby.players.size) }
+ td { joinButton(lobby) }
+ }
+
+ private fun RBuilder.gameStatus(state: State) {
+ val intent = when(state) {
+ State.LOBBY -> Intent.SUCCESS
+ State.PLAYING -> Intent.WARNING
+ State.FINISHED -> Intent.DANGER
}
- bpIcon(name = "people", title = null)
- styledSpan {
- +nPlayers.toString()
+ bpTag(minimal = true, intent = intent) {
+ +state.toString()
}
}
-}
-private fun RBuilder.joinButton(lobby: LobbyDTO, joinGame: (Long) -> Unit) {
- bpButton(
- minimal = true,
- title = lobby.joinAction.tooltip,
- icon = "arrow-right",
- disabled = !lobby.joinAction.canDo,
- onClick = { joinGame(lobby.id) }
- )
+ private fun RBuilder.playerCount(nPlayers: Int) {
+ styledDiv {
+ css {
+ display = Display.flex
+ flexDirection = FlexDirection.row
+ alignItems = Align.center
+ }
+ attrs {
+ title = "Number of players"
+ }
+ bpIcon(name = "people", title = null)
+ styledSpan {
+ +nPlayers.toString()
+ }
+ }
+ }
+
+ private fun RBuilder.joinButton(lobby: LobbyDTO) {
+ val joinability = lobby.joinability(props.connectedPlayer.displayName)
+ bpButton(
+ minimal = true,
+ title = joinability.tooltip,
+ icon = "arrow-right",
+ disabled = !joinability.canDo,
+ onClick = { props.joinGame(lobby.id) }
+ )
+ }
}
-val gameList = connectStateAndDispatch<GameListStateProps, GameListDispatchProps, GameListProps>(
+fun RBuilder.gameList() = gameList {}
+
+private val gameList = connectStateAndDispatch<GameListStateProps, GameListDispatchProps, GameListProps>(
clazz = GameListPresenter::class,
mapStateToProps = { state, _ ->
+ connectedPlayer = state.connectedPlayer ?: error("there should be a connected player")
games = state.games
},
mapDispatchToProps = { dispatch, _ ->
diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt
index 222d4329..b939dfe1 100644
--- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt
+++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt
@@ -1,6 +1,6 @@
package org.luxons.sevenwonders.ui.components.gameBrowser
-import org.luxons.sevenwonders.model.api.PlayerDTO
+import org.luxons.sevenwonders.model.api.ConnectedPlayer
import org.luxons.sevenwonders.ui.redux.connectState
import react.RBuilder
import react.RComponent
@@ -9,7 +9,7 @@ import react.RState
import react.dom.*
interface PlayerInfoProps : RProps {
- var currentPlayer: PlayerDTO?
+ var connectedPlayer: ConnectedPlayer?
}
class PlayerInfoPresenter(props: PlayerInfoProps) : RComponent<PlayerInfoProps, RState>(props) {
@@ -19,7 +19,7 @@ class PlayerInfoPresenter(props: PlayerInfoProps) : RComponent<PlayerInfoProps,
b {
+"Username:"
}
- props.currentPlayer?.let {
+ props.connectedPlayer?.let {
+ " ${it.displayName}"
}
}
@@ -31,6 +31,6 @@ fun RBuilder.playerInfo() = playerInfo {}
private val playerInfo = connectState(
clazz = PlayerInfoPresenter::class,
mapStateToProps = { state, _ ->
- currentPlayer = state.currentPlayer
+ connectedPlayer = state.connectedPlayer
}
)
diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/Lobby.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/Lobby.kt
index 45c9ca11..5b13d8b1 100644
--- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/Lobby.kt
+++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/Lobby.kt
@@ -34,14 +34,15 @@ class LobbyPresenter(props: LobbyProps) : RComponent<LobbyProps, RState>(props)
}
div {
h2 { +"${currentGame.name} — Lobby" }
- radialPlayerList(currentGame.players)
+ radialPlayerList(currentGame.players, currentPlayer)
if (currentPlayer.isGameOwner) {
+ val startability = currentGame.startability(currentPlayer.username)
bpButton(
large = true,
intent = Intent.PRIMARY,
icon = "play",
- title = currentGame.startAction.tooltip,
- disabled = !currentGame.startAction.canDo,
+ title = startability.tooltip,
+ disabled = !startability.canDo,
onClick = { props.startGame() }
) {
+ "START"
diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt
index 364a0dde..ff541696 100644
--- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt
+++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt
@@ -19,11 +19,11 @@ import styled.css
import styled.styledDiv
import styled.styledH5
-fun RBuilder.radialPlayerList(players: List<PlayerDTO>): ReactElement {
+fun RBuilder.radialPlayerList(players: List<PlayerDTO>, currentPlayer: PlayerDTO): ReactElement {
val playerItemBuilders = players
.growTo(targetSize = 3)
- .withUserFirst()
- .map { p -> p.elementBuilder() }
+ .withUserFirst(currentPlayer)
+ .map { p -> p.elementBuilder(p?.username == currentPlayer.username) }
val tableImgBuilder: ElementBuilder = { roundTableImg() }
@@ -48,35 +48,33 @@ private fun RBuilder.roundTableImg(): ReactElement = img {
}
}
-private fun List<PlayerDTO?>.withUserFirst(): List<PlayerDTO?> {
- val nonUsersBeginning = takeWhile { !it.isMe }
+private fun List<PlayerDTO?>.withUserFirst(me: PlayerDTO): List<PlayerDTO?> {
+ val nonUsersBeginning = takeWhile { it?.username != me.username }
val userToEnd = subList(nonUsersBeginning.size, size)
return userToEnd + nonUsersBeginning
}
-private val PlayerDTO?.isMe: Boolean get() = this?.isMe ?: false
-
private fun <T> List<T>.growTo(targetSize: Int): List<T?> {
if (size >= targetSize) return this
return this + List(targetSize - size) { null }
}
-private fun PlayerDTO?.elementBuilder(): ElementBuilder {
+private fun PlayerDTO?.elementBuilder(isMe: Boolean): ElementBuilder {
if (this == null) {
return { playerPlaceholder() }
} else {
- return { playerItem(this@elementBuilder) }
+ return { playerItem(this@elementBuilder, isMe) }
}
}
-private fun RBuilder.playerItem(player: PlayerDTO): ReactElement = styledDiv {
+private fun RBuilder.playerItem(player: PlayerDTO, isMe: Boolean): ReactElement = styledDiv {
css {
display = Display.flex
flexDirection = FlexDirection.column
alignItems = Align.center
}
val title = if (player.isGameOwner) "Game owner" else null
- userIcon(isMe = player.isMe, isOwner = player.isGameOwner, title = title)
+ userIcon(isMe = isMe, isOwner = player.isGameOwner, title = title)
styledH5 {
css {
margin = "0"
diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt
index 63fc26eb..4947fa9b 100644
--- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt
+++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt
@@ -1,12 +1,12 @@
package org.luxons.sevenwonders.ui.redux
import org.luxons.sevenwonders.model.PlayerTurnInfo
+import org.luxons.sevenwonders.model.api.ConnectedPlayer
import org.luxons.sevenwonders.model.api.LobbyDTO
-import org.luxons.sevenwonders.model.api.PlayerDTO
import org.luxons.sevenwonders.model.cards.PreparedCard
import redux.RAction
-data class SetCurrentPlayerAction(val player: PlayerDTO): RAction
+data class SetCurrentPlayerAction(val player: ConnectedPlayer): RAction
data class UpdateGameListAction(val games: List<LobbyDTO>): RAction
diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt
index f2a20cef..18d34d78 100644
--- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt
+++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt
@@ -1,25 +1,26 @@
package org.luxons.sevenwonders.ui.redux
import org.luxons.sevenwonders.model.PlayerTurnInfo
+import org.luxons.sevenwonders.model.api.ConnectedPlayer
import org.luxons.sevenwonders.model.api.LobbyDTO
import org.luxons.sevenwonders.model.api.PlayerDTO
import org.luxons.sevenwonders.model.api.State
import redux.RAction
data class SwState(
- val currentPlayer: PlayerDTO? = null,
+ val connectedPlayer: ConnectedPlayer? = null,
// they must be by ID to support updates to a sublist
val gamesById: Map<Long, LobbyDTO> = emptyMap(),
- val currentPlayerUsername: String? = null,
val currentLobby: LobbyDTO? = null,
val currentTurnInfo: PlayerTurnInfo? = null
) {
+ val currentPlayer: PlayerDTO? = currentLobby?.players?.first { it.username == connectedPlayer?.username }
val games: List<LobbyDTO> = gamesById.values.toList()
}
fun rootReducer(state: SwState, action: RAction): SwState = state.copy(
gamesById = gamesReducer(state.gamesById, action),
- currentPlayer = currentPlayerReducer(state.currentPlayer, action),
+ connectedPlayer = currentPlayerReducer(state.connectedPlayer, action),
currentLobby = currentLobbyReducer(state.currentLobby, action),
currentTurnInfo = currentTurnInfoReducer(state.currentTurnInfo, action)
)
@@ -29,7 +30,7 @@ private fun gamesReducer(games: Map<Long, LobbyDTO>, action: RAction): Map<Long,
else -> games
}
-private fun currentPlayerReducer(currentPlayer: PlayerDTO?, action: RAction): PlayerDTO? = when (action) {
+private fun currentPlayerReducer(currentPlayer: ConnectedPlayer?, action: RAction): ConnectedPlayer? = when (action) {
is SetCurrentPlayerAction -> action.player
else -> currentPlayer
}
bgstack15