summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sw-client/src/commonMain/kotlin/org/luxons/sevenwonders/client/SevenWondersClient.kt34
-rw-r--r--sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/model/api/events/Events.kt30
-rw-r--r--sw-server/src/main/kotlin/org/luxons/sevenwonders/server/controllers/GameController.kt16
-rw-r--r--sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/RouteBasedSagas.kt13
4 files changed, 69 insertions, 24 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 50b9b70c..d14b07b7 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
@@ -1,9 +1,10 @@
package org.luxons.sevenwonders.client
-import kotlinx.coroutines.*
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.async
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.*
import kotlinx.serialization.builtins.serializer
import org.hildan.krossbow.stomp.StompClient
import org.hildan.krossbow.stomp.config.HeartBeat
@@ -19,7 +20,8 @@ import org.luxons.sevenwonders.model.Settings
import org.luxons.sevenwonders.model.api.*
import org.luxons.sevenwonders.model.api.actions.*
import org.luxons.sevenwonders.model.api.errors.ErrorDTO
-import org.luxons.sevenwonders.model.cards.PreparedCard
+import org.luxons.sevenwonders.model.api.events.GameEvent
+import org.luxons.sevenwonders.model.api.events.GameEventWrapper
import org.luxons.sevenwonders.model.wonders.AssignedWonder
class SevenWondersClient {
@@ -121,22 +123,23 @@ class SevenWondersSession(private val stompSession: StompSessionWithKxSerializat
stompSession.sendEmptyMsg("/app/lobby/startGame")
}
- suspend fun watchPlayerReady(gameId: Long): Flow<String> =
- stompSession.subscribe("/topic/game/$gameId/playerReady", String.serializer())
+ @OptIn(ExperimentalCoroutinesApi::class)
+ suspend fun watchGameEvents(gameId: Long): Flow<GameEvent> {
+ val private = watchPublicGameEvents()
+ val public = watchPrivateGameEvents(gameId)
+ return merge(private, public)
+ }
- suspend fun watchPreparedCards(gameId: Long): Flow<PreparedCard> =
- stompSession.subscribe("/topic/game/$gameId/prepared", PreparedCard.serializer())
+ private suspend fun watchPrivateGameEvents(gameId: Long) =
+ stompSession.subscribe("/topic/game/$gameId/events", GameEventWrapper.serializer()).map { it.event }
- suspend fun watchTurns(): Flow<PlayerTurnInfo> =
- stompSession.subscribe("/user/queue/game/turn", PlayerTurnInfo.serializer())
+ suspend fun watchPublicGameEvents() =
+ stompSession.subscribe("/user/queue/game/events", GameEventWrapper.serializer()).map { it.event }
suspend fun sayReady() {
stompSession.sendEmptyMsg("/app/game/sayReady")
}
- suspend fun watchOwnMoves(): Flow<PlayerMove> =
- stompSession.subscribe("/user/queue/game/preparedMove", PlayerMove.serializer())
-
suspend fun prepareMove(move: PlayerMove) {
stompSession.convertAndSend(
destination = "/app/game/prepareMove",
@@ -187,3 +190,6 @@ private suspend fun <T> doAndWaitForEvent(send: suspend () -> Unit, subscribe: s
send()
deferredFirstEvent.await()
}
+
+suspend fun SevenWondersSession.watchTurns() =
+ watchPublicGameEvents().filterIsInstance<GameEvent.NewTurnStarted>().map { it.turnInfo }
diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/model/api/events/Events.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/model/api/events/Events.kt
new file mode 100644
index 00000000..d8c05e91
--- /dev/null
+++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/model/api/events/Events.kt
@@ -0,0 +1,30 @@
+package org.luxons.sevenwonders.model.api.events
+
+import kotlinx.serialization.Serializable
+import org.luxons.sevenwonders.model.PlayerMove
+import org.luxons.sevenwonders.model.PlayerTurnInfo
+import org.luxons.sevenwonders.model.cards.PreparedCard
+
+// workaround for https://github.com/Kotlin/kotlinx.serialization/issues/1194
+@Serializable
+data class GameEventWrapper(
+ val event: GameEvent
+)
+
+fun GameEvent.wrap() = GameEventWrapper(this)
+
+@Serializable
+sealed class GameEvent {
+
+ @Serializable
+ data class NewTurnStarted(val turnInfo: PlayerTurnInfo) : GameEvent()
+
+ @Serializable
+ data class MovePrepared(val move: PlayerMove) : GameEvent()
+
+ @Serializable
+ data class CardPrepared(val preparedCard: PreparedCard) : GameEvent()
+
+ @Serializable
+ data class PlayerIsReady(val username: String) : GameEvent()
+}
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 e4c1b39a..70fb3220 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
@@ -4,6 +4,8 @@ import io.micrometer.core.instrument.MeterRegistry
import org.luxons.sevenwonders.engine.Game
import org.luxons.sevenwonders.model.api.GameListEvent
import org.luxons.sevenwonders.model.api.actions.PrepareMoveAction
+import org.luxons.sevenwonders.model.api.events.GameEvent
+import org.luxons.sevenwonders.model.api.events.wrap
import org.luxons.sevenwonders.model.api.wrap
import org.luxons.sevenwonders.model.cards.PreparedCard
import org.luxons.sevenwonders.model.hideHandsAndWaitForReadiness
@@ -102,7 +104,7 @@ class GameController(
handleEndOfGame(game, player, lobby)
}
} else {
- template.convertAndSendToUser(player.username, "/queue/game/preparedMove", action.move)
+ template.convertAndSendToUser(player.username, "/queue/game/events", GameEvent.MovePrepared(action.move).wrap())
}
}
}
@@ -130,18 +132,20 @@ class GameController(
}
}
- private fun sendPlayerReady(gameId: Long, player: Player) =
- template.convertAndSend("/topic/game/$gameId/playerReady", player.username)
+ private fun sendPlayerReady(gameId: Long, player: Player) {
+ template.convertAndSend("/topic/game/$gameId/events", GameEvent.PlayerIsReady(player.username).wrap())
+ }
- private fun sendPreparedCard(gameId: Long, preparedCard: PreparedCard) =
- template.convertAndSend("/topic/game/$gameId/prepared", preparedCard)
+ private fun sendPreparedCard(gameId: Long, preparedCard: PreparedCard) {
+ template.convertAndSend("/topic/game/$gameId/events", GameEvent.CardPrepared(preparedCard).wrap())
+ }
private fun sendTurnInfo(players: List<Player>, game: Game, hideHands: Boolean) {
val turns = game.getCurrentTurnInfo()
val turnsToSend = if (hideHands) turns.hideHandsAndWaitForReadiness() else turns
for (turnInfo in turnsToSend) {
val player = players[turnInfo.playerIndex]
- template.convertAndSendToUser(player.username, "/queue/game/turn", turnInfo)
+ template.convertAndSendToUser(player.username, "/queue/game/events", GameEvent.NewTurnStarted(turnInfo).wrap())
}
}
diff --git a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/RouteBasedSagas.kt b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/RouteBasedSagas.kt
index 06b33e13..af2624ec 100644
--- a/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/RouteBasedSagas.kt
+++ b/sw-ui/src/main/kotlin/org/luxons/sevenwonders/ui/redux/sagas/RouteBasedSagas.kt
@@ -3,6 +3,7 @@ package org.luxons.sevenwonders.ui.redux.sagas
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.map
import org.luxons.sevenwonders.client.SevenWondersSession
+import org.luxons.sevenwonders.model.api.events.GameEvent
import org.luxons.sevenwonders.ui.redux.*
import org.luxons.sevenwonders.ui.router.Navigate
import org.luxons.sevenwonders.ui.router.Route
@@ -49,10 +50,14 @@ suspend fun SwSagaContext.lobbySaga(session: SevenWondersSession) {
suspend fun SwSagaContext.gameSaga(session: SevenWondersSession) {
val game = reduxState.gameState ?: error("Game saga run without a current game")
coroutineScope {
- session.watchPlayerReady(game.id).map { PlayerReadyEvent(it) }.dispatchAllIn(this)
- session.watchPreparedCards(game.id).map { PreparedCardEvent(it) }.dispatchAllIn(this)
- session.watchOwnMoves().map { PreparedMoveEvent(it) }.dispatchAllIn(this)
- session.watchTurns().map { TurnInfoEvent(it) }.dispatchAllIn(this)
+ session.watchGameEvents(game.id).map {
+ when (it) {
+ is GameEvent.NewTurnStarted -> TurnInfoEvent(it.turnInfo)
+ is GameEvent.MovePrepared -> PreparedMoveEvent(it.move)
+ is GameEvent.CardPrepared -> PreparedCardEvent(it.preparedCard)
+ is GameEvent.PlayerIsReady -> PlayerReadyEvent(it.username)
+ }
+ }.dispatchAllIn(this)
session.sayReady()
}
console.log("End of game saga")
bgstack15