From 2aee79bb6887008397aa0780d1d74ce96af1c202 Mon Sep 17 00:00:00 2001 From: Janis Date: Thu, 27 Nov 2025 07:57:37 +0100 Subject: [PATCH] feat(api): Implemented turn event via websocket (#86) Co-authored-by: TeamCity Reviewed-on: https://git.janis-eccarius.de/KnockOutWhist/KnockOutWhist-Web/pulls/86 Reviewed-by: lq64 --- .../app/util/WebsocketEventMapper.scala | 5 +- .../app/util/mapper/TurnEventMapper.scala | 35 +++++++++++ .../app/views/ingame/ingame.scala.html | 14 +++-- knockoutwhistweb/public/javascripts/events.js | 63 +++++++++++++++++++ 4 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 knockoutwhistweb/app/util/mapper/TurnEventMapper.scala diff --git a/knockoutwhistweb/app/util/WebsocketEventMapper.scala b/knockoutwhistweb/app/util/WebsocketEventMapper.scala index aa237ed..50f8f3e 100644 --- a/knockoutwhistweb/app/util/WebsocketEventMapper.scala +++ b/knockoutwhistweb/app/util/WebsocketEventMapper.scala @@ -6,7 +6,7 @@ import model.sessions.UserSession import play.api.libs.json.{JsValue, Json} import tools.jackson.databind.json.JsonMapper import tools.jackson.module.scala.ScalaModule -import util.mapper.{CardPlayedEventMapper, GameStateEventMapper, KickEventMapper, LeftEventMapper, LobbyUpdateEventMapper, ReceivedHandEventMapper, SessionClosedMapper, SimpleEventMapper} +import util.mapper.{CardPlayedEventMapper, GameStateEventMapper, KickEventMapper, LeftEventMapper, LobbyUpdateEventMapper, ReceivedHandEventMapper, SessionClosedMapper, SimpleEventMapper, TurnEventMapper} object WebsocketEventMapper { @@ -31,7 +31,8 @@ object WebsocketEventMapper { registerCustomMapper(LeftEventMapper) registerCustomMapper(KickEventMapper) registerCustomMapper(SessionClosedMapper) - + registerCustomMapper(TurnEventMapper) + def toJson(obj: SimpleEvent, session: UserSession): JsValue = { val data: Option[JsValue] = if (customMappers.contains(obj.id)) { Some(customMappers(obj.id).toJson(obj, session)) diff --git a/knockoutwhistweb/app/util/mapper/TurnEventMapper.scala b/knockoutwhistweb/app/util/mapper/TurnEventMapper.scala new file mode 100644 index 0000000..88880d7 --- /dev/null +++ b/knockoutwhistweb/app/util/mapper/TurnEventMapper.scala @@ -0,0 +1,35 @@ +package util.mapper + +import de.knockoutwhist.events.global.TurnEvent +import de.knockoutwhist.player.AbstractPlayer +import model.sessions.UserSession +import play.api.libs.json.{JsArray, JsObject, Json} + +object TurnEventMapper extends SimpleEventMapper[TurnEvent] { + + override def id: String = "TurnEvent" + + override def toJson(event: TurnEvent, session: UserSession): JsObject = { + val nextPlayers = if (session.gameLobby.logic.getPlayerQueue.isEmpty) { + Json.arr() + } else { + val queue = session.gameLobby.logic.getPlayerQueue.get + JsArray( + queue.duplicate().map(player => mapPlayer(player)).toList + ) + } + + Json.obj( + "currentPlayer" -> mapPlayer(event.player), + "nextPlayers" -> nextPlayers + ) + } + + private def mapPlayer(player: AbstractPlayer): JsObject = { + Json.obj( + "name" -> player.name, + "dog" -> player.isInDogLife + ) + } + +} diff --git a/knockoutwhistweb/app/views/ingame/ingame.scala.html b/knockoutwhistweb/app/views/ingame/ingame.scala.html index c22a21b..e4f1382 100644 --- a/knockoutwhistweb/app/views/ingame/ingame.scala.html +++ b/knockoutwhistweb/app/views/ingame/ingame.scala.html @@ -15,12 +15,16 @@ }else {

---

} - @if(gamelobby.getLogic.getPlayerQueue.isDefined && gamelobby.getLogic.getCurrentMatch && !TrickUtil.isOver(gamelobby.getLogic.getCurrentMatch.get, gamelobby.getLogic.getPlayerQueue.get)) { -

Next Player

- @for(nextplayer <- gamelobby.getLogic.getPlayerQueue.get.duplicate()) { -

@nextplayer

+ +
+ @if(gamelobby.getLogic.getPlayerQueue.isDefined && gamelobby.getLogic.getCurrentMatch && !TrickUtil.isOver(gamelobby.getLogic.getCurrentMatch.get, gamelobby.getLogic.getPlayerQueue.get)) { + @for(nextplayer <- gamelobby.getLogic.getPlayerQueue.get.duplicate()) { +

@nextplayer @if(nextplayer.isInDogLife) { + 🐶 + }

+ } } - } +
diff --git a/knockoutwhistweb/public/javascripts/events.js b/knockoutwhistweb/public/javascripts/events.js index ad4d2f7..e23d4fe 100644 --- a/knockoutwhistweb/public/javascripts/events.js +++ b/knockoutwhistweb/public/javascripts/events.js @@ -85,6 +85,37 @@ function receiveCardPlayedEvent(eventData) { `; firstCardContainer.html(newFirstCardHTML); } +function receiveTurnEvent(eventData) { + const currentPlayer = eventData.currentPlayer; + const nextPlayers = eventData.nextPlayers; + + const currentPlayerNameContainer = $('#current-player-name'); + const nextPlayersContainer = $('#next-players-container'); + const nextPlayerText = $('#next-players-section'); + + let currentPlayerName = currentPlayer.name; + if (currentPlayer.dog) { + currentPlayerName += " 🐶"; + } + currentPlayerNameContainer.text(currentPlayerName); + + if (nextPlayers.length === 0) { + nextPlayerText.hide(); + nextPlayersContainer.html(''); + } else { + nextPlayerText.show(); + let nextPlayersHtml = ''; + nextPlayers.forEach((player) => { + let playerName = player.name; + if (player.dog) { + playerName += " 🐶"; + } + nextPlayersHtml += `

${playerName}

`; + }); + nextPlayersContainer.html(nextPlayersHtml); + } +} + function receiveLobbyUpdateEvent(eventData) { const host = eventData.host; const maxPlayers = eventData.maxPlayers; @@ -154,6 +185,37 @@ function receiveSessionClosedEvent(eventData) { } +function receiveTurnEvent(eventData) { + const currentPlayer = eventData.currentPlayer; + const nextPlayers = eventData.nextPlayers; + + const currentPlayerNameContainer = $('#current-player-name'); + const nextPlayersContainer = $('#next-players-container'); + const nextPlayerText = $('#next-players-section'); + + let currentPlayerName = currentPlayer.name; + if (currentPlayer.dog) { + currentPlayerName += " 🐶"; + } + currentPlayerNameContainer.text(currentPlayerName); + + if (nextPlayers.length === 0) { + nextPlayerText.hide(); + nextPlayersContainer.html(''); + } else { + nextPlayerText.show(); + let nextPlayersHtml = ''; + nextPlayers.forEach((player) => { + let playerName = player.name; + if (player.dog) { + playerName += " 🐶"; + } + nextPlayersHtml += `

${playerName}

`; + }); + nextPlayersContainer.html(nextPlayersHtml); + } +} + onEvent("ReceivedHandEvent", receiveHandEvent) onEvent("GameStateChangeEvent", receiveGameStateChange) onEvent("CardPlayedEvent", receiveCardPlayedEvent) @@ -161,3 +223,4 @@ onEvent("LobbyUpdateEvent", receiveLobbyUpdateEvent) onEvent("LeftEvent", receiveGameStateChange) onEvent("KickEvent", receiveKickEvent) onEvent("SessionClosed", receiveSessionClosedEvent) +onEvent("TurnEvent", receiveTurnEvent) \ No newline at end of file