From e0f16a224d17b6aa407b89dfb4d18222dcf2d609 Mon Sep 17 00:00:00 2001 From: LQ63 Date: Wed, 26 Nov 2025 01:35:46 +0100 Subject: [PATCH 01/11] feat(ui): Websocket Started implementing functionality to Websocket. --- build.sbt | 4 +- .../app/logic/game/GameLobby.scala | 6 +- .../app/model/sessions/UserSession.scala | 21 ++- knockoutwhistweb/app/model/users/User.scala | 6 +- .../app/util/WebsocketEventMapper.scala | 4 + .../mapper/GameStateChangeEventMapper.scala | 18 +++ .../app/util/mapper/NewRoundEventMapper.scala | 16 +++ .../app/util/mapper/NewTrickEventMapper.scala | 13 ++ .../util/mapper/RequestCardEventMapper.scala | 15 +++ .../app/util/mapper/TrickEndEventMapper.scala | 18 +++ .../app/views/lobby/lobby.scala.html | 4 +- .../app/views/mainmenu/creategame.scala.html | 2 +- knockoutwhistweb/public/javascripts/events.js | 126 ++++++++++++++++++ .../public/javascripts/interact.js | 13 ++ 14 files changed, 258 insertions(+), 8 deletions(-) create mode 100644 knockoutwhistweb/app/util/mapper/GameStateChangeEventMapper.scala create mode 100644 knockoutwhistweb/app/util/mapper/NewRoundEventMapper.scala create mode 100644 knockoutwhistweb/app/util/mapper/NewTrickEventMapper.scala create mode 100644 knockoutwhistweb/app/util/mapper/RequestCardEventMapper.scala create mode 100644 knockoutwhistweb/app/util/mapper/TrickEndEventMapper.scala diff --git a/build.sbt b/build.sbt index 53846e6..35210c3 100644 --- a/build.sbt +++ b/build.sbt @@ -40,8 +40,8 @@ lazy val knockoutwhistweb = project.in(file("knockoutwhistweb")) libraryDependencies += "de.mkammerer" % "argon2-jvm" % "2.12", libraryDependencies += "com.auth0" % "java-jwt" % "4.5.0", libraryDependencies += "com.github.ben-manes.caffeine" % "caffeine" % "3.2.3", - libraryDependencies += "tools.jackson.module" %% "jackson-module-scala" % "3.0.2", - JsEngineKeys.engineType := JsEngineKeys.EngineType.Node + libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.16.1", + //JsEngineKeys.engineType := JsEngineKeys.EngineType.Node ) lazy val root = (project in file(".")) diff --git a/knockoutwhistweb/app/logic/game/GameLobby.scala b/knockoutwhistweb/app/logic/game/GameLobby.scala index 0da9376..2bcdc7f 100644 --- a/knockoutwhistweb/app/logic/game/GameLobby.scala +++ b/knockoutwhistweb/app/logic/game/GameLobby.scala @@ -2,7 +2,7 @@ package logic.game import de.knockoutwhist.cards.{Hand, Suit} import de.knockoutwhist.control.GameLogic -import de.knockoutwhist.control.GameState.{Lobby, MainMenu} +import de.knockoutwhist.control.GameState.{InGame, Lobby, MainMenu} import de.knockoutwhist.control.controllerBaseImpl.sublogic.util.{MatchUtil, PlayerUtil} import de.knockoutwhist.events.global.{GameStateChangeEvent, SessionClosed} import de.knockoutwhist.events.player.PlayerEvent @@ -59,6 +59,9 @@ class GameLobby private( if (event.oldState == MainMenu && event.newState == Lobby) { return } + if (event.oldState == Lobby && event.newState == InGame) { + println("RECEIVED GAMESTATEEVENT") + } users.values.foreach(session => session.updatePlayer(event)) case event: SimpleEvent => users.values.foreach(session => session.updatePlayer(event)) @@ -71,6 +74,7 @@ class GameLobby private( * @param user the user who wants to start the game. */ def startGame(user: User): Unit = { + println("STARTED GAME IN LOGIC") val sessionOpt = users.get(user.id) if (sessionOpt.isEmpty) { throw new NotInThisGameException("You are not in this game!") diff --git a/knockoutwhistweb/app/model/sessions/UserSession.scala b/knockoutwhistweb/app/model/sessions/UserSession.scala index c98e384..f66e405 100644 --- a/knockoutwhistweb/app/model/sessions/UserSession.scala +++ b/knockoutwhistweb/app/model/sessions/UserSession.scala @@ -2,9 +2,11 @@ package model.sessions import de.knockoutwhist.events.player.{RequestCardEvent, RequestTieChoiceEvent, RequestTrumpSuitEvent} import de.knockoutwhist.utils.events.SimpleEvent +import logic.PodManager import logic.game.GameLobby import model.users.User -import play.api.libs.json.JsObject +import play.api.libs.json.Format.GenericFormat +import play.api.libs.json.{JsError, JsObject, JsResult, JsSuccess, JsValue} import java.util.UUID import java.util.concurrent.locks.ReentrantLock @@ -26,7 +28,7 @@ class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) e else canInteract = Some(InteractionType.Card) case _ => } - websocketActor.foreach(_.transmitEventToClient(event)) + websocketActor.foreach(_.transmitEventToClient(event, gameLobby)) } override def id: UUID = user.id @@ -44,6 +46,21 @@ class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) e case "Ping" => // No action needed for Ping () + case "Start Game" => + println("INSIDE HANDLE WEB RESPONSE" + data) + val gameId: String = (data \ "gameId").get.toString + val cleanGameId: String = gameId.replaceAll("^[\"']|[\"']$", "") + val user: JsObject = (data \ "user").asOpt[JsObject].get + val gameLobby: GameLobby = PodManager.getGame(cleanGameId).get + val realUser: JsResult[User] = user.validate[User] + val uu: User = realUser match { + case JsSuccess(extractedUser, _) => + extractedUser + case e: JsError => + println("FAILED" + JsError.toJson(e).toString()) + throw new Exception("Failed to deserialize User object: " + JsError.toJson(e).toString()) + } + gameLobby.startGame(uu) } } lock.unlock() diff --git a/knockoutwhistweb/app/model/users/User.scala b/knockoutwhistweb/app/model/users/User.scala index f418618..a07fd5b 100644 --- a/knockoutwhistweb/app/model/users/User.scala +++ b/knockoutwhistweb/app/model/users/User.scala @@ -1,5 +1,7 @@ package model.users +import play.api.libs.json.{Format, Json} + import java.util.UUID case class User( @@ -16,5 +18,7 @@ case class User( private def withPasswordHash(newPasswordHash: String): User = { this.copy(passwordHash = newPasswordHash) } - } +object User { + implicit val userFormat: Format[User] = Json.format[User] +} \ No newline at end of file diff --git a/knockoutwhistweb/app/util/WebsocketEventMapper.scala b/knockoutwhistweb/app/util/WebsocketEventMapper.scala index 50f8f3e..518b5d8 100644 --- a/knockoutwhistweb/app/util/WebsocketEventMapper.scala +++ b/knockoutwhistweb/app/util/WebsocketEventMapper.scala @@ -27,6 +27,10 @@ object WebsocketEventMapper { registerCustomMapper(ReceivedHandEventMapper) registerCustomMapper(GameStateEventMapper) registerCustomMapper(CardPlayedEventMapper) + registerCustomMapper(NewRoundEventMapper) + registerCustomMapper(NewTrickEventMapper) + registerCustomMapper(TrickEndEventMapper) + registerCustomMapper(RequestCardEventMapper) registerCustomMapper(LobbyUpdateEventMapper) registerCustomMapper(LeftEventMapper) registerCustomMapper(KickEventMapper) diff --git a/knockoutwhistweb/app/util/mapper/GameStateChangeEventMapper.scala b/knockoutwhistweb/app/util/mapper/GameStateChangeEventMapper.scala new file mode 100644 index 0000000..e42d4a2 --- /dev/null +++ b/knockoutwhistweb/app/util/mapper/GameStateChangeEventMapper.scala @@ -0,0 +1,18 @@ +package util.mapper + +import de.knockoutwhist.events.global.GameStateChangeEvent +import logic.game.GameLobby +import play.api.libs.json.{JsObject, Json} + +object GameStateChangeEventMapper extends SimpleEventMapper[GameStateChangeEvent]{ + override def id: String = "GameStateChangeEvent" + + override def toJson(event: GameStateChangeEvent, gameLobby: GameLobby): JsObject = { + println("CALLED toJSON FOR GAMESTATECHANGE") + Json.obj( + "oldState" -> event.oldState.toString, + "newState" -> event.newState.toString, + "gameLobby" -> gameLobby.id + ) + } +} diff --git a/knockoutwhistweb/app/util/mapper/NewRoundEventMapper.scala b/knockoutwhistweb/app/util/mapper/NewRoundEventMapper.scala new file mode 100644 index 0000000..b7be5ea --- /dev/null +++ b/knockoutwhistweb/app/util/mapper/NewRoundEventMapper.scala @@ -0,0 +1,16 @@ +package util.mapper + +import de.knockoutwhist.events.global.NewRoundEvent +import logic.game.GameLobby +import play.api.libs.json.{JsObject, Json} + +object NewRoundEventMapper extends SimpleEventMapper[NewRoundEvent]{ + override def id: String = "NewRoundEvent" + + override def toJson(event: NewRoundEvent, gameLobby: GameLobby): JsObject = { + Json.obj( + "trumpsuit" -> gameLobby.getLogic.getCurrentRound.get.trumpSuit.toString, + "players" -> gameLobby.getLogic.getCurrentMatch.get.playersIn.map(player => player.toString) + ) + } +} diff --git a/knockoutwhistweb/app/util/mapper/NewTrickEventMapper.scala b/knockoutwhistweb/app/util/mapper/NewTrickEventMapper.scala new file mode 100644 index 0000000..863c75d --- /dev/null +++ b/knockoutwhistweb/app/util/mapper/NewTrickEventMapper.scala @@ -0,0 +1,13 @@ +package util.mapper + +import de.knockoutwhist.events.global.NewTrickEvent +import logic.game.GameLobby +import play.api.libs.json.{JsObject, Json} + +object NewTrickEventMapper extends SimpleEventMapper[NewTrickEvent]{ + override def id: String = "NewTrickEvent" + + override def toJson(event: NewTrickEvent, gameLobby: GameLobby): JsObject = { + Json.obj() + } +} diff --git a/knockoutwhistweb/app/util/mapper/RequestCardEventMapper.scala b/knockoutwhistweb/app/util/mapper/RequestCardEventMapper.scala new file mode 100644 index 0000000..8b193cf --- /dev/null +++ b/knockoutwhistweb/app/util/mapper/RequestCardEventMapper.scala @@ -0,0 +1,15 @@ +package util.mapper + +import de.knockoutwhist.events.player.RequestCardEvent +import logic.game.GameLobby +import play.api.libs.json.{JsObject, Json} + +object RequestCardEventMapper extends SimpleEventMapper[RequestCardEvent]{ + override def id: String = "RequestCardEvent" + + override def toJson(event: RequestCardEvent, gameLobby: GameLobby): JsObject = { + Json.obj( + "player" -> event.player.name + ) + } +} diff --git a/knockoutwhistweb/app/util/mapper/TrickEndEventMapper.scala b/knockoutwhistweb/app/util/mapper/TrickEndEventMapper.scala new file mode 100644 index 0000000..9e6e1f7 --- /dev/null +++ b/knockoutwhistweb/app/util/mapper/TrickEndEventMapper.scala @@ -0,0 +1,18 @@ +package util.mapper + +import de.knockoutwhist.events.global.TrickEndEvent +import de.knockoutwhist.rounds.Trick +import logic.game.GameLobby +import play.api.libs.json.{JsObject, Json} + +object TrickEndEventMapper extends SimpleEventMapper[TrickEndEvent]{ + override def id: String = "TrickEndEvent" + + override def toJson(event: TrickEndEvent, gameLobby: GameLobby): JsObject = { + Json.obj( + "playerwon" -> event.winner.name, + "playersin" -> gameLobby.getLogic.getCurrentMatch.get.playersIn.map(player => player.name), + "tricklist" -> gameLobby.getLogic.getCurrentRound.get.tricklist.map(trick => trick.winner.map(player => player.name).getOrElse("Trick in Progress")) + ) + } +} diff --git a/knockoutwhistweb/app/views/lobby/lobby.scala.html b/knockoutwhistweb/app/views/lobby/lobby.scala.html index 66c4390..0d522b6 100644 --- a/knockoutwhistweb/app/views/lobby/lobby.scala.html +++ b/knockoutwhistweb/app/views/lobby/lobby.scala.html @@ -69,7 +69,7 @@ }
-
Start Game
+
Start Game
} else {
@@ -98,6 +98,7 @@
\ No newline at end of file diff --git a/knockoutwhistweb/app/views/mainmenu/creategame.scala.html b/knockoutwhistweb/app/views/mainmenu/creategame.scala.html index e521320..5ad2504 100644 --- a/knockoutwhistweb/app/views/mainmenu/creategame.scala.html +++ b/knockoutwhistweb/app/views/mainmenu/creategame.scala.html @@ -30,4 +30,4 @@ \ No newline at end of file + \ No newline at end of file diff --git a/knockoutwhistweb/public/javascripts/events.js b/knockoutwhistweb/public/javascripts/events.js index e23d4fe..bff1444 100644 --- a/knockoutwhistweb/public/javascripts/events.js +++ b/knockoutwhistweb/public/javascripts/events.js @@ -1,3 +1,30 @@ +function alertMessage(message) { + let newHtml = ''; + const alertId = `alert-${Date.now()}`; + const fadeTime = 500; + const duration = 5000; + newHtml += ` +
+ +
+ `; + $('#main-body').prepend(newHtml); + const $notice = $(`#${alertId}`); + $notice.fadeIn(fadeTime); + setTimeout(function() { + $notice.fadeOut(fadeTime, function() { + $(this).parent().remove(); + }); + }, duration); +} function receiveHandEvent(eventData) { //Data const dog = eventData.dog; @@ -38,6 +65,101 @@ function receiveHandEvent(eventData) { } handElement.html(newHtml); } +function newRoundEvent(eventData) { + const trumpsuit = eventData.trumpsuit; + const players = eventData.players; + + const tableElement = $('#score-table-body'); + + + let tablehtml = ` +

Tricks Won

+ +
+
PLAYER
+
TRICKS
+
+ `; + + players.forEach( + tablehtml += ` +
+
'${players}'
+
+ 0 +
+
+ ` + ); + tableElement.html(tablehtml); + + const trumpsuitClass = $('#trumpsuit'); + trumpsuitClass.html(trumpsuit); + +} +function trickEndEvent(eventData) { + const winner = eventData.playerwon; + const players = eventData.playersin; + const tricklist = eventData.tricklist; + + let newHtml = ''; + + let tricktable = $('#score-table-body'); + + newHtml += ` +

Tricks Won

+ +
+
PLAYER
+
TRICKS
+
+ `; + let playercounts = new Map(); + + players.forEach( player => { + playercounts.set(player, 0) + }); + tricklist.forEach( player => { + if ( player !== "Trick in Progress" && playercounts.has(player)) { + playercounts.set(player, playercounts.get(player) + 1) + } + } + ) + const playerorder = players.sort((playerA, playerB) => { + const countA = playercounts.get(playerA.name) || 0; + const countB = playercounts.get(playerB.name) || 0; + return countB - countA; + }); + playerorder.forEach( player => { + newHtml += ` +
+
'${player}'
+
+ '${playercounts.get(player)}' +
+
+ ` + }); + tricktable.html(newHtml); +} +function newTrickEvent() { + const firstCardContainer = $('first-card-container'); + + let newHtml = ''; + + newHtml += ` + Blank Card + `; + + firstCardContainer.html(newHtml); +} +function requestCardEvent(eventData) { + const player = eventData.player; + const handElement = $('#card-slide') + handElement.removeClass('inactive'); +} +//alertMessage("It worked!") + function receiveGameStateChange(eventData) { const content = eventData.content; @@ -218,6 +340,10 @@ function receiveTurnEvent(eventData) { onEvent("ReceivedHandEvent", receiveHandEvent) onEvent("GameStateChangeEvent", receiveGameStateChange) +onEvent("NewRoundEvent", newRoundEvent) +onEvent("TrickEndEvent", trickEndEvent) +onEvent("NewTrickEvent", newTrickEvent) +onEvent("RequestCardEvent", requestCardEvent) onEvent("CardPlayedEvent", receiveCardPlayedEvent) onEvent("LobbyUpdateEvent", receiveLobbyUpdateEvent) onEvent("LeftEvent", receiveGameStateChange) diff --git a/knockoutwhistweb/public/javascripts/interact.js b/knockoutwhistweb/public/javascripts/interact.js index 555634e..7e8ace5 100644 --- a/knockoutwhistweb/public/javascripts/interact.js +++ b/knockoutwhistweb/public/javascripts/interact.js @@ -5,6 +5,19 @@ function handlePlayCard(card, dog) { function handleSkipDogLife(button) { // TODO needs implementation } +function startGame(gameId, userId, username, userpasswordhash, userinternalid) { + const userpayload = { + internalId: userinternalid, + id: userId, + name: username, + passwordHash: userpasswordhash + } + const payload = { + gameId: gameId, + user: userpayload + }; + sendEvent("Start Game", payload) +} function handleKickPlayer(playerId) { // TODO needs implementation } -- 2.52.0 From 6402df43b1cb3b9c375de3be801597c7f96d4628 Mon Sep 17 00:00:00 2001 From: LQ63 Date: Wed, 26 Nov 2025 09:52:16 +0100 Subject: [PATCH 02/11] fix(ui): Websocket Fixed startGame to be correctly implemented --- build.sbt | 2 +- .../app/model/sessions/UserSession.scala | 16 ++-------------- .../app/model/sessions/UserWebsocketActor.scala | 2 +- knockoutwhistweb/app/model/users/User.scala | 3 --- knockoutwhistweb/public/javascripts/interact.js | 14 ++------------ 5 files changed, 6 insertions(+), 31 deletions(-) diff --git a/build.sbt b/build.sbt index 35210c3..487601e 100644 --- a/build.sbt +++ b/build.sbt @@ -41,7 +41,7 @@ lazy val knockoutwhistweb = project.in(file("knockoutwhistweb")) libraryDependencies += "com.auth0" % "java-jwt" % "4.5.0", libraryDependencies += "com.github.ben-manes.caffeine" % "caffeine" % "3.2.3", libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.16.1", - //JsEngineKeys.engineType := JsEngineKeys.EngineType.Node + JsEngineKeys.engineType := JsEngineKeys.EngineType.Node ) lazy val root = (project in file(".")) diff --git a/knockoutwhistweb/app/model/sessions/UserSession.scala b/knockoutwhistweb/app/model/sessions/UserSession.scala index f66e405..0f40c69 100644 --- a/knockoutwhistweb/app/model/sessions/UserSession.scala +++ b/knockoutwhistweb/app/model/sessions/UserSession.scala @@ -39,7 +39,7 @@ class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) e canInteract = None } - def handleWebResponse(eventType: String, data: JsObject): Unit = { + def handleWebResponse(eventType: String, data: JsObject, user: User, gameLobby: GameLobby): Unit = { lock.lock() Try { eventType match { @@ -48,19 +48,7 @@ class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) e () case "Start Game" => println("INSIDE HANDLE WEB RESPONSE" + data) - val gameId: String = (data \ "gameId").get.toString - val cleanGameId: String = gameId.replaceAll("^[\"']|[\"']$", "") - val user: JsObject = (data \ "user").asOpt[JsObject].get - val gameLobby: GameLobby = PodManager.getGame(cleanGameId).get - val realUser: JsResult[User] = user.validate[User] - val uu: User = realUser match { - case JsSuccess(extractedUser, _) => - extractedUser - case e: JsError => - println("FAILED" + JsError.toJson(e).toString()) - throw new Exception("Failed to deserialize User object: " + JsError.toJson(e).toString()) - } - gameLobby.startGame(uu) + gameLobby.startGame(user) } } lock.unlock() diff --git a/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala b/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala index b2b59c7..6c612d6 100644 --- a/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala +++ b/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala @@ -74,7 +74,7 @@ class UserWebsocketActor( val event = eventOpt.get val data = (json \ "data").asOpt[JsObject].getOrElse(Json.obj()) val result = Try { - session.handleWebResponse(event, data) + session.handleWebResponse(event, data, session.user, session.gameLobby) } if (result.isSuccess) { transmitJsonToClient(Json.obj( diff --git a/knockoutwhistweb/app/model/users/User.scala b/knockoutwhistweb/app/model/users/User.scala index a07fd5b..d9063f6 100644 --- a/knockoutwhistweb/app/model/users/User.scala +++ b/knockoutwhistweb/app/model/users/User.scala @@ -18,7 +18,4 @@ case class User( private def withPasswordHash(newPasswordHash: String): User = { this.copy(passwordHash = newPasswordHash) } -} -object User { - implicit val userFormat: Format[User] = Json.format[User] } \ No newline at end of file diff --git a/knockoutwhistweb/public/javascripts/interact.js b/knockoutwhistweb/public/javascripts/interact.js index 7e8ace5..ae476ea 100644 --- a/knockoutwhistweb/public/javascripts/interact.js +++ b/knockoutwhistweb/public/javascripts/interact.js @@ -5,18 +5,8 @@ function handlePlayCard(card, dog) { function handleSkipDogLife(button) { // TODO needs implementation } -function startGame(gameId, userId, username, userpasswordhash, userinternalid) { - const userpayload = { - internalId: userinternalid, - id: userId, - name: username, - passwordHash: userpasswordhash - } - const payload = { - gameId: gameId, - user: userpayload - }; - sendEvent("Start Game", payload) +function startGame() { + sendEvent("Start Game") } function handleKickPlayer(playerId) { // TODO needs implementation -- 2.52.0 From 6e76223c4a31fae7955d8c3e23d66b35150b7727 Mon Sep 17 00:00:00 2001 From: LQ63 Date: Wed, 26 Nov 2025 18:56:26 +0100 Subject: [PATCH 03/11] feat(ui): Websocket Started implementing functionality to the Websocket --- .../app/model/sessions/UserSession.scala | 27 +++++++++- .../model/sessions/UserWebsocketActor.scala | 6 ++- .../app/util/WebsocketEventMapper.scala | 1 + .../app/util/mapper/NewRoundEventMapper.scala | 4 +- .../app/util/mapper/NewTrickEventMapper.scala | 3 +- .../util/mapper/RequestCardEventMapper.scala | 3 +- .../app/util/mapper/TrickEndEventMapper.scala | 4 +- .../app/views/ingame/ingame.scala.html | 2 +- .../app/views/ingame/selecttrump.scala.html | 8 +-- knockoutwhistweb/public/javascripts/events.js | 46 +++-------------- .../public/javascripts/interact.js | 50 ++++++++++++++++++- .../public/javascripts/websocket.js | 2 +- 12 files changed, 102 insertions(+), 54 deletions(-) diff --git a/knockoutwhistweb/app/model/sessions/UserSession.scala b/knockoutwhistweb/app/model/sessions/UserSession.scala index 0f40c69..7067850 100644 --- a/knockoutwhistweb/app/model/sessions/UserSession.scala +++ b/knockoutwhistweb/app/model/sessions/UserSession.scala @@ -28,7 +28,7 @@ class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) e else canInteract = Some(InteractionType.Card) case _ => } - websocketActor.foreach(_.transmitEventToClient(event, gameLobby)) + websocketActor.foreach(_.transmitEventToClient(event, gameLobby, user)) } override def id: UUID = user.id @@ -41,7 +41,7 @@ class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) e def handleWebResponse(eventType: String, data: JsObject, user: User, gameLobby: GameLobby): Unit = { lock.lock() - Try { + val result = Try { eventType match { case "Ping" => // No action needed for Ping @@ -49,9 +49,32 @@ class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) e case "Start Game" => println("INSIDE HANDLE WEB RESPONSE" + data) gameLobby.startGame(user) + case "play Card" => + println("PLAYING CARD..." + data) + val maybeCardIndex: Option[Int] = (data \ "cardindex").asOpt[Int] + maybeCardIndex match { + case Some(index) => + val session = gameLobby.getUserSession(user.id) + gameLobby.playCard(session, index) + case None => + println("Card Index not found or is not a number.") + } + case "Picked Trumpsuit" => + val maybeSuitIndex: Option[Int] = (data \ "suitIndex").asOpt[Int] + maybeSuitIndex match { + case Some(index) => + val session = gameLobby.getUserSession(user.id) + gameLobby.selectTrump(session, index) + case None => + println("Card Index not found or is not a number.") + } } } lock.unlock() + if (result.isFailure) { + val throwable = result.failed.get + throw throwable + } } } diff --git a/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala b/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala index 6c612d6..ffb7c0a 100644 --- a/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala +++ b/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala @@ -1,6 +1,9 @@ package model.sessions import de.knockoutwhist.utils.events.SimpleEvent +import logic.PodManager +import logic.game.GameLobby +import model.users.User import org.apache.pekko.actor.{Actor, ActorRef} import play.api.libs.json.{JsObject, JsValue, Json} import util.WebsocketEventMapper @@ -96,7 +99,8 @@ class UserWebsocketActor( transmitTextToClient(jsonObj.toString()) } - def transmitEventToClient(event: SimpleEvent): Unit = { + def transmitEventToClient(event: SimpleEvent, gameLobby: GameLobby, user: User): Unit = { + val session = gameLobby.getUserSession(user.id) transmitJsonToClient(WebsocketEventMapper.toJson(event, session)) } diff --git a/knockoutwhistweb/app/util/WebsocketEventMapper.scala b/knockoutwhistweb/app/util/WebsocketEventMapper.scala index 518b5d8..cb8bb6f 100644 --- a/knockoutwhistweb/app/util/WebsocketEventMapper.scala +++ b/knockoutwhistweb/app/util/WebsocketEventMapper.scala @@ -7,6 +7,7 @@ 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, TurnEventMapper} +import util.mapper.{GameStateEventMapper, NewRoundEventMapper, NewTrickEventMapper, ReceivedHandEventMapper, RequestCardEventMapper, SimpleEventMapper, TrickEndEventMapper, CardPlayedEventMapper} object WebsocketEventMapper { diff --git a/knockoutwhistweb/app/util/mapper/NewRoundEventMapper.scala b/knockoutwhistweb/app/util/mapper/NewRoundEventMapper.scala index b7be5ea..2e63029 100644 --- a/knockoutwhistweb/app/util/mapper/NewRoundEventMapper.scala +++ b/knockoutwhistweb/app/util/mapper/NewRoundEventMapper.scala @@ -2,12 +2,14 @@ package util.mapper import de.knockoutwhist.events.global.NewRoundEvent import logic.game.GameLobby +import model.sessions.UserSession import play.api.libs.json.{JsObject, Json} object NewRoundEventMapper extends SimpleEventMapper[NewRoundEvent]{ override def id: String = "NewRoundEvent" - override def toJson(event: NewRoundEvent, gameLobby: GameLobby): JsObject = { + override def toJson(event: NewRoundEvent, session: UserSession): JsObject = { + val gameLobby = session.gameLobby Json.obj( "trumpsuit" -> gameLobby.getLogic.getCurrentRound.get.trumpSuit.toString, "players" -> gameLobby.getLogic.getCurrentMatch.get.playersIn.map(player => player.toString) diff --git a/knockoutwhistweb/app/util/mapper/NewTrickEventMapper.scala b/knockoutwhistweb/app/util/mapper/NewTrickEventMapper.scala index 863c75d..4861ae3 100644 --- a/knockoutwhistweb/app/util/mapper/NewTrickEventMapper.scala +++ b/knockoutwhistweb/app/util/mapper/NewTrickEventMapper.scala @@ -2,12 +2,13 @@ package util.mapper import de.knockoutwhist.events.global.NewTrickEvent import logic.game.GameLobby +import model.sessions.UserSession import play.api.libs.json.{JsObject, Json} object NewTrickEventMapper extends SimpleEventMapper[NewTrickEvent]{ override def id: String = "NewTrickEvent" - override def toJson(event: NewTrickEvent, gameLobby: GameLobby): JsObject = { + override def toJson(event: NewTrickEvent, session: UserSession): JsObject = { Json.obj() } } diff --git a/knockoutwhistweb/app/util/mapper/RequestCardEventMapper.scala b/knockoutwhistweb/app/util/mapper/RequestCardEventMapper.scala index 8b193cf..217f859 100644 --- a/knockoutwhistweb/app/util/mapper/RequestCardEventMapper.scala +++ b/knockoutwhistweb/app/util/mapper/RequestCardEventMapper.scala @@ -2,12 +2,13 @@ package util.mapper import de.knockoutwhist.events.player.RequestCardEvent import logic.game.GameLobby +import model.sessions.UserSession import play.api.libs.json.{JsObject, Json} object RequestCardEventMapper extends SimpleEventMapper[RequestCardEvent]{ override def id: String = "RequestCardEvent" - override def toJson(event: RequestCardEvent, gameLobby: GameLobby): JsObject = { + override def toJson(event: RequestCardEvent, session: UserSession): JsObject = { Json.obj( "player" -> event.player.name ) diff --git a/knockoutwhistweb/app/util/mapper/TrickEndEventMapper.scala b/knockoutwhistweb/app/util/mapper/TrickEndEventMapper.scala index 9e6e1f7..a133f9b 100644 --- a/knockoutwhistweb/app/util/mapper/TrickEndEventMapper.scala +++ b/knockoutwhistweb/app/util/mapper/TrickEndEventMapper.scala @@ -3,12 +3,14 @@ package util.mapper import de.knockoutwhist.events.global.TrickEndEvent import de.knockoutwhist.rounds.Trick import logic.game.GameLobby +import model.sessions.UserSession import play.api.libs.json.{JsObject, Json} object TrickEndEventMapper extends SimpleEventMapper[TrickEndEvent]{ override def id: String = "TrickEndEvent" - override def toJson(event: TrickEndEvent, gameLobby: GameLobby): JsObject = { + override def toJson(event: TrickEndEvent, session: UserSession): JsObject = { + val gameLobby = session.gameLobby Json.obj( "playerwon" -> event.winner.name, "playersin" -> gameLobby.getLogic.getCurrentMatch.get.playersIn.map(player => player.name), diff --git a/knockoutwhistweb/app/views/ingame/ingame.scala.html b/knockoutwhistweb/app/views/ingame/ingame.scala.html index e4f1382..8d437e7 100644 --- a/knockoutwhistweb/app/views/ingame/ingame.scala.html +++ b/knockoutwhistweb/app/views/ingame/ingame.scala.html @@ -107,7 +107,7 @@ } else { @for(i <- player.currentHand().get.cards.indices) {
-
+
@util.WebUIUtils.cardtoImage(player.currentHand().get.cards(i)) width="120px" style="border-radius: 6px"/>
@if(player.isInDogLife) { diff --git a/knockoutwhistweb/app/views/ingame/selecttrump.scala.html b/knockoutwhistweb/app/views/ingame/selecttrump.scala.html index 8700adc..92ff345 100644 --- a/knockoutwhistweb/app/views/ingame/selecttrump.scala.html +++ b/knockoutwhistweb/app/views/ingame/selecttrump.scala.html @@ -18,25 +18,25 @@
-
+
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Spades)) width="120px" style="border-radius: 6px"/>
-
+
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Hearts)) width="120px" style="border-radius: 6px"/>
-
+
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Diamonds)) width="120px" style="border-radius: 6px"/>
-
+
@util.WebUIUtils.cardtoImage(de.knockoutwhist.cards.Card(de.knockoutwhist.cards.CardValue.Ace, de.knockoutwhist.cards.Suit.Clubs)) width="120px" style="border-radius: 6px"/>
diff --git a/knockoutwhistweb/public/javascripts/events.js b/knockoutwhistweb/public/javascripts/events.js index bff1444..803bd38 100644 --- a/knockoutwhistweb/public/javascripts/events.js +++ b/knockoutwhistweb/public/javascripts/events.js @@ -133,9 +133,9 @@ function trickEndEvent(eventData) { playerorder.forEach( player => { newHtml += `
-
'${player}'
+
${player}
- '${playercounts.get(player)}' + ${playercounts.get(player)}
` @@ -143,14 +143,12 @@ function trickEndEvent(eventData) { tricktable.html(newHtml); } function newTrickEvent() { - const firstCardContainer = $('first-card-container'); + const firstCardContainer = $('#first-card-container'); let newHtml = ''; - newHtml += ` - Blank Card + Blank Card `; - firstCardContainer.html(newHtml); } function requestCardEvent(eventData) { @@ -158,7 +156,6 @@ function requestCardEvent(eventData) { const handElement = $('#card-slide') handElement.removeClass('inactive'); } -//alertMessage("It worked!") function receiveGameStateChange(eventData) { @@ -207,37 +204,6 @@ 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; @@ -349,4 +315,6 @@ onEvent("LobbyUpdateEvent", receiveLobbyUpdateEvent) onEvent("LeftEvent", receiveGameStateChange) onEvent("KickEvent", receiveKickEvent) onEvent("SessionClosed", receiveSessionClosedEvent) -onEvent("TurnEvent", receiveTurnEvent) \ No newline at end of file +onEvent("TurnEvent", receiveTurnEvent) + +globalThis.alertMessage = alertMessage \ No newline at end of file diff --git a/knockoutwhistweb/public/javascripts/interact.js b/knockoutwhistweb/public/javascripts/interact.js index ae476ea..af04ab5 100644 --- a/knockoutwhistweb/public/javascripts/interact.js +++ b/knockoutwhistweb/public/javascripts/interact.js @@ -1,5 +1,40 @@ -function handlePlayCard(card, dog) { - // TODO needs implementation +function handlePlayCard(cardIndex, dog) { + const cardslide = $('#card-slide') + cardslide.addClass("inactive") + + const payload = { + cardindex: cardIndex, + isDog: dog + } + sendEventAndWait("play Card", payload).then( + () => { + console.debug("play card successful") + const datacardid = $(`#${cardIndex}`) + datacardid.parent('.handcard').remove(); + cardslide.find('.handcard').each(function(newIndex) { + + const $innerButton = $(this).find('.btn'); + + $innerButton.attr('id', newIndex); + $innerButton.attr('data-card-id', newIndex); + + const isInDogLife = $innerButton.attr('onclick').includes("'true'") ? 'true' : 'false'; + $innerButton.attr('onclick', `handlePlayCard(${newIndex}, '${isInDogLife}')`); + + console.debug(`Re-indexed card: Old index was ${$innerButton.attr('data-card-id')}, New index is ${newIndex}`); + }); + } + ).catch( + (err) => { + const cardslide = $('#card-slide') + console.log("EERROOOORRR PLAYING CARD" + (err.toString() === "You can't play this card!") + err.message) + console.warn("play card was not successful") + if (err.message === "You can't play this card!") { + cardslide.removeClass("inactive") + } + alertMessage("You aren't allowed to play this card") + } + ) } function handleSkipDogLife(button) { @@ -8,6 +43,17 @@ function handleSkipDogLife(button) { function startGame() { sendEvent("Start Game") } + +function handleTrumpSelection(object) { + const $button = $(object); + const trumpIndex = parseInt($button.data('trump')); + const payload = { + suitIndex: trumpIndex + } + console.log("SENDING TRUMP SUIT SELECTION:", payload); + sendEvent("Picked Trumpsuit", payload) + +} function handleKickPlayer(playerId) { // TODO needs implementation } diff --git a/knockoutwhistweb/public/javascripts/websocket.js b/knockoutwhistweb/public/javascripts/websocket.js index fcd1c92..9008c6b 100644 --- a/knockoutwhistweb/public/javascripts/websocket.js +++ b/knockoutwhistweb/public/javascripts/websocket.js @@ -31,7 +31,7 @@ function setupSocketHandlers(socket) { if (status === "success") { entry.resolve(data === undefined ? {} : data); } else { - entry.reject(new Error(msg.error || "Server returned error")); + entry.reject(new Error(msg.error || "Server returned error")); } return; } -- 2.52.0 From 352cd751406732576a9431bfc80fe2fa05ef306d Mon Sep 17 00:00:00 2001 From: Janis Date: Wed, 26 Nov 2025 19:12:02 +0100 Subject: [PATCH 04/11] chore: rebasing --- build.sbt | 2 +- knockoutwhist | 2 +- .../app/util/WebsocketEventMapper.scala | 1 + .../mapper/GameStateChangeEventMapper.scala | 18 ------------------ 4 files changed, 3 insertions(+), 20 deletions(-) delete mode 100644 knockoutwhistweb/app/util/mapper/GameStateChangeEventMapper.scala diff --git a/build.sbt b/build.sbt index 487601e..53846e6 100644 --- a/build.sbt +++ b/build.sbt @@ -40,7 +40,7 @@ lazy val knockoutwhistweb = project.in(file("knockoutwhistweb")) libraryDependencies += "de.mkammerer" % "argon2-jvm" % "2.12", libraryDependencies += "com.auth0" % "java-jwt" % "4.5.0", libraryDependencies += "com.github.ben-manes.caffeine" % "caffeine" % "3.2.3", - libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.16.1", + libraryDependencies += "tools.jackson.module" %% "jackson-module-scala" % "3.0.2", JsEngineKeys.engineType := JsEngineKeys.EngineType.Node ) diff --git a/knockoutwhist b/knockoutwhist index c5dd02a..b34066d 160000 --- a/knockoutwhist +++ b/knockoutwhist @@ -1 +1 @@ -Subproject commit c5dd02a5e826eaa6a6fa07c0847f94f9868709a6 +Subproject commit b34066d920fdde174a11807d38c1398a45b3e7ad diff --git a/knockoutwhistweb/app/util/WebsocketEventMapper.scala b/knockoutwhistweb/app/util/WebsocketEventMapper.scala index cb8bb6f..e2c71e5 100644 --- a/knockoutwhistweb/app/util/WebsocketEventMapper.scala +++ b/knockoutwhistweb/app/util/WebsocketEventMapper.scala @@ -6,6 +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, NewRoundEventMapper, NewTrickEventMapper, ReceivedHandEventMapper, RequestCardEventMapper, SessionClosedMapper, SimpleEventMapper, TrickEndEventMapper} import util.mapper.{CardPlayedEventMapper, GameStateEventMapper, KickEventMapper, LeftEventMapper, LobbyUpdateEventMapper, ReceivedHandEventMapper, SessionClosedMapper, SimpleEventMapper, TurnEventMapper} import util.mapper.{GameStateEventMapper, NewRoundEventMapper, NewTrickEventMapper, ReceivedHandEventMapper, RequestCardEventMapper, SimpleEventMapper, TrickEndEventMapper, CardPlayedEventMapper} diff --git a/knockoutwhistweb/app/util/mapper/GameStateChangeEventMapper.scala b/knockoutwhistweb/app/util/mapper/GameStateChangeEventMapper.scala deleted file mode 100644 index e42d4a2..0000000 --- a/knockoutwhistweb/app/util/mapper/GameStateChangeEventMapper.scala +++ /dev/null @@ -1,18 +0,0 @@ -package util.mapper - -import de.knockoutwhist.events.global.GameStateChangeEvent -import logic.game.GameLobby -import play.api.libs.json.{JsObject, Json} - -object GameStateChangeEventMapper extends SimpleEventMapper[GameStateChangeEvent]{ - override def id: String = "GameStateChangeEvent" - - override def toJson(event: GameStateChangeEvent, gameLobby: GameLobby): JsObject = { - println("CALLED toJSON FOR GAMESTATECHANGE") - Json.obj( - "oldState" -> event.oldState.toString, - "newState" -> event.newState.toString, - "gameLobby" -> gameLobby.id - ) - } -} -- 2.52.0 From 182131f4dc349f4587634c0e1f3df4fd0f230d6f Mon Sep 17 00:00:00 2001 From: Janis Date: Thu, 27 Nov 2025 08:02:48 +0100 Subject: [PATCH 05/11] chore(api): Simplified imports in WebsocketEventMapper and WebUIUtils --- knockoutwhist | 2 +- knockoutwhistweb/app/util/WebUIUtils.scala | 2 +- knockoutwhistweb/app/util/WebsocketEventMapper.scala | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/knockoutwhist b/knockoutwhist index b34066d..c5dd02a 160000 --- a/knockoutwhist +++ b/knockoutwhist @@ -1 +1 @@ -Subproject commit b34066d920fdde174a11807d38c1398a45b3e7ad +Subproject commit c5dd02a5e826eaa6a6fa07c0847f94f9868709a6 diff --git a/knockoutwhistweb/app/util/WebUIUtils.scala b/knockoutwhistweb/app/util/WebUIUtils.scala index 625303d..03f33b8 100644 --- a/knockoutwhistweb/app/util/WebUIUtils.scala +++ b/knockoutwhistweb/app/util/WebUIUtils.scala @@ -1,8 +1,8 @@ package util -import de.knockoutwhist.cards.{Card, Hand} import de.knockoutwhist.cards.CardValue.* import de.knockoutwhist.cards.Suit.{Clubs, Diamonds, Hearts, Spades} +import de.knockoutwhist.cards.{Card, Hand} import play.api.libs.json.{JsArray, Json} import play.twirl.api.Html import scalafx.scene.image.Image diff --git a/knockoutwhistweb/app/util/WebsocketEventMapper.scala b/knockoutwhistweb/app/util/WebsocketEventMapper.scala index e2c71e5..bdb9dfa 100644 --- a/knockoutwhistweb/app/util/WebsocketEventMapper.scala +++ b/knockoutwhistweb/app/util/WebsocketEventMapper.scala @@ -6,9 +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, NewRoundEventMapper, NewTrickEventMapper, ReceivedHandEventMapper, RequestCardEventMapper, SessionClosedMapper, SimpleEventMapper, TrickEndEventMapper} -import util.mapper.{CardPlayedEventMapper, GameStateEventMapper, KickEventMapper, LeftEventMapper, LobbyUpdateEventMapper, ReceivedHandEventMapper, SessionClosedMapper, SimpleEventMapper, TurnEventMapper} -import util.mapper.{GameStateEventMapper, NewRoundEventMapper, NewTrickEventMapper, ReceivedHandEventMapper, RequestCardEventMapper, SimpleEventMapper, TrickEndEventMapper, CardPlayedEventMapper} +import util.mapper.* object WebsocketEventMapper { -- 2.52.0 From 998308d14082bccf3894b467ee55582b7468d9c7 Mon Sep 17 00:00:00 2001 From: LQ63 Date: Thu, 27 Nov 2025 08:21:23 +0100 Subject: [PATCH 06/11] fix(ui): Websocket Removed debug messages, reformatted method --- knockoutwhistweb/app/logic/game/GameLobby.scala | 4 ---- knockoutwhistweb/app/model/sessions/UserSession.scala | 3 +-- knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala | 3 +-- knockoutwhistweb/app/views/lobby/lobby.scala.html | 2 +- knockoutwhistweb/public/javascripts/interact.js | 1 - 5 files changed, 3 insertions(+), 10 deletions(-) diff --git a/knockoutwhistweb/app/logic/game/GameLobby.scala b/knockoutwhistweb/app/logic/game/GameLobby.scala index 2bcdc7f..d998ea3 100644 --- a/knockoutwhistweb/app/logic/game/GameLobby.scala +++ b/knockoutwhistweb/app/logic/game/GameLobby.scala @@ -59,9 +59,6 @@ class GameLobby private( if (event.oldState == MainMenu && event.newState == Lobby) { return } - if (event.oldState == Lobby && event.newState == InGame) { - println("RECEIVED GAMESTATEEVENT") - } users.values.foreach(session => session.updatePlayer(event)) case event: SimpleEvent => users.values.foreach(session => session.updatePlayer(event)) @@ -74,7 +71,6 @@ class GameLobby private( * @param user the user who wants to start the game. */ def startGame(user: User): Unit = { - println("STARTED GAME IN LOGIC") val sessionOpt = users.get(user.id) if (sessionOpt.isEmpty) { throw new NotInThisGameException("You are not in this game!") diff --git a/knockoutwhistweb/app/model/sessions/UserSession.scala b/knockoutwhistweb/app/model/sessions/UserSession.scala index 7067850..4be8f15 100644 --- a/knockoutwhistweb/app/model/sessions/UserSession.scala +++ b/knockoutwhistweb/app/model/sessions/UserSession.scala @@ -28,7 +28,7 @@ class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) e else canInteract = Some(InteractionType.Card) case _ => } - websocketActor.foreach(_.transmitEventToClient(event, gameLobby, user)) + websocketActor.foreach(_.transmitEventToClient(event)) } override def id: UUID = user.id @@ -47,7 +47,6 @@ class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) e // No action needed for Ping () case "Start Game" => - println("INSIDE HANDLE WEB RESPONSE" + data) gameLobby.startGame(user) case "play Card" => println("PLAYING CARD..." + data) diff --git a/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala b/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala index ffb7c0a..0ea5002 100644 --- a/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala +++ b/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala @@ -99,8 +99,7 @@ class UserWebsocketActor( transmitTextToClient(jsonObj.toString()) } - def transmitEventToClient(event: SimpleEvent, gameLobby: GameLobby, user: User): Unit = { - val session = gameLobby.getUserSession(user.id) + def transmitEventToClient(event: SimpleEvent): Unit = { transmitJsonToClient(WebsocketEventMapper.toJson(event, session)) } diff --git a/knockoutwhistweb/app/views/lobby/lobby.scala.html b/knockoutwhistweb/app/views/lobby/lobby.scala.html index 0d522b6..32b7fbc 100644 --- a/knockoutwhistweb/app/views/lobby/lobby.scala.html +++ b/knockoutwhistweb/app/views/lobby/lobby.scala.html @@ -69,7 +69,7 @@ }
-
Start Game
+
Start Game
} else {
diff --git a/knockoutwhistweb/public/javascripts/interact.js b/knockoutwhistweb/public/javascripts/interact.js index af04ab5..84ec6aa 100644 --- a/knockoutwhistweb/public/javascripts/interact.js +++ b/knockoutwhistweb/public/javascripts/interact.js @@ -27,7 +27,6 @@ function handlePlayCard(cardIndex, dog) { ).catch( (err) => { const cardslide = $('#card-slide') - console.log("EERROOOORRR PLAYING CARD" + (err.toString() === "You can't play this card!") + err.message) console.warn("play card was not successful") if (err.message === "You can't play this card!") { cardslide.removeClass("inactive") -- 2.52.0 From efda2961c8ae0052d95b630e9b4ac8f2abad0810 Mon Sep 17 00:00:00 2001 From: LQ63 Date: Thu, 27 Nov 2025 08:27:40 +0100 Subject: [PATCH 07/11] fix(ui): Websocket Removed debug messages, reformatted methods --- knockoutwhistweb/app/logic/game/GameLobby.scala | 2 +- knockoutwhistweb/app/model/sessions/UserSession.scala | 2 +- knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/knockoutwhistweb/app/logic/game/GameLobby.scala b/knockoutwhistweb/app/logic/game/GameLobby.scala index d998ea3..0da9376 100644 --- a/knockoutwhistweb/app/logic/game/GameLobby.scala +++ b/knockoutwhistweb/app/logic/game/GameLobby.scala @@ -2,7 +2,7 @@ package logic.game import de.knockoutwhist.cards.{Hand, Suit} import de.knockoutwhist.control.GameLogic -import de.knockoutwhist.control.GameState.{InGame, Lobby, MainMenu} +import de.knockoutwhist.control.GameState.{Lobby, MainMenu} import de.knockoutwhist.control.controllerBaseImpl.sublogic.util.{MatchUtil, PlayerUtil} import de.knockoutwhist.events.global.{GameStateChangeEvent, SessionClosed} import de.knockoutwhist.events.player.PlayerEvent diff --git a/knockoutwhistweb/app/model/sessions/UserSession.scala b/knockoutwhistweb/app/model/sessions/UserSession.scala index 4be8f15..e59936e 100644 --- a/knockoutwhistweb/app/model/sessions/UserSession.scala +++ b/knockoutwhistweb/app/model/sessions/UserSession.scala @@ -39,7 +39,7 @@ class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) e canInteract = None } - def handleWebResponse(eventType: String, data: JsObject, user: User, gameLobby: GameLobby): Unit = { + def handleWebResponse(eventType: String, data: JsObject): Unit = { lock.lock() val result = Try { eventType match { diff --git a/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala b/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala index 0ea5002..57fa511 100644 --- a/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala +++ b/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala @@ -77,7 +77,7 @@ class UserWebsocketActor( val event = eventOpt.get val data = (json \ "data").asOpt[JsObject].getOrElse(Json.obj()) val result = Try { - session.handleWebResponse(event, data, session.user, session.gameLobby) + session.handleWebResponse(event, data) } if (result.isSuccess) { transmitJsonToClient(Json.obj( -- 2.52.0 From c0d872f581db58d38c8e1d85446359a7f09e8d9f Mon Sep 17 00:00:00 2001 From: LQ63 Date: Thu, 27 Nov 2025 08:28:16 +0100 Subject: [PATCH 08/11] fix(ui): Websocket Removed print --- knockoutwhistweb/app/model/sessions/UserSession.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/knockoutwhistweb/app/model/sessions/UserSession.scala b/knockoutwhistweb/app/model/sessions/UserSession.scala index e59936e..e3e774e 100644 --- a/knockoutwhistweb/app/model/sessions/UserSession.scala +++ b/knockoutwhistweb/app/model/sessions/UserSession.scala @@ -49,7 +49,6 @@ class UserSession(val user: User, val host: Boolean, val gameLobby: GameLobby) e case "Start Game" => gameLobby.startGame(user) case "play Card" => - println("PLAYING CARD..." + data) val maybeCardIndex: Option[Int] = (data \ "cardindex").asOpt[Int] maybeCardIndex match { case Some(index) => -- 2.52.0 From 1ca410bc4ba87a9294fb7e7645de9e9e6bb7f7a2 Mon Sep 17 00:00:00 2001 From: LQ63 Date: Thu, 27 Nov 2025 08:43:20 +0100 Subject: [PATCH 09/11] fix(ui): Websocket Fixed imports, removed playedCards at trickstart --- knockoutwhistweb/app/model/sessions/UserSession.scala | 3 +-- knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala | 3 --- knockoutwhistweb/app/model/users/User.scala | 1 - knockoutwhistweb/public/javascripts/events.js | 4 +++- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/knockoutwhistweb/app/model/sessions/UserSession.scala b/knockoutwhistweb/app/model/sessions/UserSession.scala index e3e774e..91333dd 100644 --- a/knockoutwhistweb/app/model/sessions/UserSession.scala +++ b/knockoutwhistweb/app/model/sessions/UserSession.scala @@ -2,11 +2,10 @@ package model.sessions import de.knockoutwhist.events.player.{RequestCardEvent, RequestTieChoiceEvent, RequestTrumpSuitEvent} import de.knockoutwhist.utils.events.SimpleEvent -import logic.PodManager import logic.game.GameLobby import model.users.User import play.api.libs.json.Format.GenericFormat -import play.api.libs.json.{JsError, JsObject, JsResult, JsSuccess, JsValue} +import play.api.libs.json.{JsObject, JsValue} import java.util.UUID import java.util.concurrent.locks.ReentrantLock diff --git a/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala b/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala index 57fa511..b2b59c7 100644 --- a/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala +++ b/knockoutwhistweb/app/model/sessions/UserWebsocketActor.scala @@ -1,9 +1,6 @@ package model.sessions import de.knockoutwhist.utils.events.SimpleEvent -import logic.PodManager -import logic.game.GameLobby -import model.users.User import org.apache.pekko.actor.{Actor, ActorRef} import play.api.libs.json.{JsObject, JsValue, Json} import util.WebsocketEventMapper diff --git a/knockoutwhistweb/app/model/users/User.scala b/knockoutwhistweb/app/model/users/User.scala index d9063f6..92b20b5 100644 --- a/knockoutwhistweb/app/model/users/User.scala +++ b/knockoutwhistweb/app/model/users/User.scala @@ -1,6 +1,5 @@ package model.users -import play.api.libs.json.{Format, Json} import java.util.UUID diff --git a/knockoutwhistweb/public/javascripts/events.js b/knockoutwhistweb/public/javascripts/events.js index 803bd38..19a0658 100644 --- a/knockoutwhistweb/public/javascripts/events.js +++ b/knockoutwhistweb/public/javascripts/events.js @@ -144,12 +144,14 @@ function trickEndEvent(eventData) { } function newTrickEvent() { const firstCardContainer = $('#first-card-container'); - + const emptyHtml = ''; let newHtml = ''; newHtml += ` Blank Card `; firstCardContainer.html(newHtml); + const playedCardsContainer = $('#trick-cards-container') + playedCardsContainer.html(emptyHtml) } function requestCardEvent(eventData) { const player = eventData.player; -- 2.52.0 From 47bcd3eb364da1d4469bf085b8c52119c4c70cca Mon Sep 17 00:00:00 2001 From: LQ63 Date: Thu, 27 Nov 2025 08:48:19 +0100 Subject: [PATCH 10/11] fix(ui): Websocket Removed whitespace --- knockoutwhistweb/public/javascripts/websocket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/knockoutwhistweb/public/javascripts/websocket.js b/knockoutwhistweb/public/javascripts/websocket.js index 9008c6b..fcd1c92 100644 --- a/knockoutwhistweb/public/javascripts/websocket.js +++ b/knockoutwhistweb/public/javascripts/websocket.js @@ -31,7 +31,7 @@ function setupSocketHandlers(socket) { if (status === "success") { entry.resolve(data === undefined ? {} : data); } else { - entry.reject(new Error(msg.error || "Server returned error")); + entry.reject(new Error(msg.error || "Server returned error")); } return; } -- 2.52.0 From daeb86cd8241f1a3eb8b70f930f892918cf79363 Mon Sep 17 00:00:00 2001 From: Janis Date: Thu, 27 Nov 2025 08:53:27 +0100 Subject: [PATCH 11/11] chore(api): Removed unused imports --- knockoutwhistweb/app/model/sessions/UserSession.scala | 1 - knockoutwhistweb/app/util/WebsocketEventMapper.scala | 1 - 2 files changed, 2 deletions(-) diff --git a/knockoutwhistweb/app/model/sessions/UserSession.scala b/knockoutwhistweb/app/model/sessions/UserSession.scala index 91333dd..1547826 100644 --- a/knockoutwhistweb/app/model/sessions/UserSession.scala +++ b/knockoutwhistweb/app/model/sessions/UserSession.scala @@ -4,7 +4,6 @@ import de.knockoutwhist.events.player.{RequestCardEvent, RequestTieChoiceEvent, import de.knockoutwhist.utils.events.SimpleEvent import logic.game.GameLobby import model.users.User -import play.api.libs.json.Format.GenericFormat import play.api.libs.json.{JsObject, JsValue} import java.util.UUID diff --git a/knockoutwhistweb/app/util/WebsocketEventMapper.scala b/knockoutwhistweb/app/util/WebsocketEventMapper.scala index bdb9dfa..e8883bd 100644 --- a/knockoutwhistweb/app/util/WebsocketEventMapper.scala +++ b/knockoutwhistweb/app/util/WebsocketEventMapper.scala @@ -1,7 +1,6 @@ package util import de.knockoutwhist.utils.events.SimpleEvent -import logic.game.GameLobby import model.sessions.UserSession import play.api.libs.json.{JsValue, Json} import tools.jackson.databind.json.JsonMapper -- 2.52.0