diff --git a/bruno/KnockOutWhist/Game/Get Game.bru b/bruno/KnockOutWhist/Game/Get Game.bru index 6b6d6af..8bc5076 100644 --- a/bruno/KnockOutWhist/Game/Get Game.bru +++ b/bruno/KnockOutWhist/Game/Get Game.bru @@ -11,7 +11,7 @@ get { } params:path { - id: uZDNZA + id: BZvtJ3 } settings { diff --git a/bruno/KnockOutWhist/Game/Start Game.bru b/bruno/KnockOutWhist/Game/Start Game.bru index cc231bf..fa798f6 100644 --- a/bruno/KnockOutWhist/Game/Start Game.bru +++ b/bruno/KnockOutWhist/Game/Start Game.bru @@ -11,7 +11,7 @@ post { } params:path { - id: uZDNZA + id: nR1o3n } settings { diff --git a/knockoutwhist b/knockoutwhist index e0e45c4..b9a7b0a 160000 --- a/knockoutwhist +++ b/knockoutwhist @@ -1 +1 @@ -Subproject commit e0e45c4b431fff6740e38a59906f5e217fcd801f +Subproject commit b9a7b0a2af7cef7225bf1a0388ebf58171a173f2 diff --git a/knockoutwhistweb/app/controllers/IngameController.scala b/knockoutwhistweb/app/controllers/IngameController.scala index ef588a8..8569b30 100644 --- a/knockoutwhistweb/app/controllers/IngameController.scala +++ b/knockoutwhistweb/app/controllers/IngameController.scala @@ -111,7 +111,10 @@ class IngameController @Inject()( cardIdOpt match { case Some(cardId) => val result = Try { - g.playCard(g.getUserSession(request.user.id), cardId.toInt) + val session = g.getUserSession(request.user.id) + session.lock.lock() + g.playCard(session, cardId.toInt) + session.lock.unlock() } if (result.isSuccess) { NoContent @@ -146,9 +149,15 @@ class IngameController @Inject()( val result = Try { cardIdOpt match { case Some(cardId) if cardId == "skip" => - g.playDogCard(g.getUserSession(request.user.id), -1) + val session = g.getUserSession(request.user.id) + session.lock.lock() + g.playDogCard(session, -1) + session.lock.unlock() case Some(cardId) => - g.playDogCard(g.getUserSession(request.user.id), cardId.toInt) + val session = g.getUserSession(request.user.id) + session.lock.lock() + g.playDogCard(session, cardId.toInt) + session.lock.unlock() case None => throw new IllegalArgumentException("cardId parameter is missing") } @@ -184,7 +193,10 @@ class IngameController @Inject()( trumpOpt match { case Some(trump) => val result = Try { - g.selectTrump(g.getUserSession(request.user.id), trump.toInt) + val session = g.getUserSession(request.user.id) + session.lock.lock() + g.selectTrump(session, trump.toInt) + session.lock.unlock() } if (result.isSuccess) { NoContent @@ -216,7 +228,10 @@ class IngameController @Inject()( tieOpt match { case Some(tie) => val result = Try { + val session = g.getUserSession(request.user.id) + session.lock.lock() g.selectTie(g.getUserSession(request.user.id), tie.toInt) + session.lock.unlock() } if (result.isSuccess) { NoContent diff --git a/knockoutwhistweb/app/controllers/MainMenuController.scala b/knockoutwhistweb/app/controllers/MainMenuController.scala index a7a1637..7032b52 100644 --- a/knockoutwhistweb/app/controllers/MainMenuController.scala +++ b/knockoutwhistweb/app/controllers/MainMenuController.scala @@ -21,7 +21,7 @@ class MainMenuController @Inject()( // Pass the request-handling function directly to authAction (no nested Action) def mainMenu(): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] => - Ok("Main Menu for user: " + request.user.name) + Ok(views.html.mainmenu.navbar(Some(request.user))) } def index(): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] => @@ -36,6 +36,22 @@ class MainMenuController @Inject()( ) Redirect(routes.IngameController.game(gameLobby.id)) } + + def joinGame(): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] => + val postData = request.body.asFormUrlEncoded + if (postData.isDefined) { + val gameId = postData.get.get("gameId").flatMap(_.headOption).getOrElse("") + val game = podManager.getGame(gameId) + game match { + case Some(g) => + Redirect(routes.IngameController.joinGame(gameId)) + case None => + NotFound("Game not found") + } + } else { + BadRequest("Invalid form submission") + } + } def rules(): Action[AnyContent] = { Action { implicit request => diff --git a/knockoutwhistweb/app/controllers/UserController.scala b/knockoutwhistweb/app/controllers/UserController.scala index 361826f..d3e5ebf 100644 --- a/knockoutwhistweb/app/controllers/UserController.scala +++ b/knockoutwhistweb/app/controllers/UserController.scala @@ -64,7 +64,7 @@ class UserController @Inject()( if (sessionCookie.isDefined) { sessionManager.invalidateSession(sessionCookie.get.value) } - NoContent.discardingCookies(DiscardingCookie("sessionId")) + Redirect(routes.UserController.login()).discardingCookies(DiscardingCookie("sessionId")) } } \ No newline at end of file diff --git a/knockoutwhistweb/app/logic/game/GameLobby.scala b/knockoutwhistweb/app/logic/game/GameLobby.scala index 7dadf4a..a43e41a 100644 --- a/knockoutwhistweb/app/logic/game/GameLobby.scala +++ b/knockoutwhistweb/app/logic/game/GameLobby.scala @@ -70,6 +70,9 @@ class GameLobby private( if (!sessionOpt.get.host) { throw new NotHostException("Only the host can start the game!") } + if (logic.getCurrentState != Lobby) { + throw new IllegalStateException("The game has already started!") + } val playerNamesList = ListBuffer[AbstractPlayer]() users.values.foreach { player => playerNamesList += PlayerFactory.createPlayer(player.name, player.id, HUMAN) @@ -108,6 +111,7 @@ class GameLobby private( if (!PlayerUtil.canPlayCard(card, getRound, getTrick, player)) { throw new CantPlayCardException("You can't play this card!") } + userSession.resetCanInteract() logic.playerInputLogic.receivedCard(card) } @@ -129,6 +133,7 @@ class GameLobby private( } val hand = getHand(player) val card = hand.cards(cardIndex) + userSession.resetCanInteract() logic.playerInputLogic.receivedDog(Some(card)) } @@ -141,6 +146,7 @@ class GameLobby private( val player = getPlayerInteractable(userSession, InteractionType.TrumpSuit) val trumpSuits = Suit.values.toList val selectedTrump = trumpSuits(trumpIndex) + userSession.resetCanInteract() logic.playerInputLogic.receivedTrumpSuit(selectedTrump) } @@ -151,6 +157,7 @@ class GameLobby private( */ def selectTie(userSession: UserSession, tieNumber: Int): Unit = { val player = getPlayerInteractable(userSession, InteractionType.TieChoice) + userSession.resetCanInteract() logic.playerTieLogic.receivedTieBreakerCard(tieNumber) } diff --git a/knockoutwhistweb/app/model/sessions/UserSession.scala b/knockoutwhistweb/app/model/sessions/UserSession.scala index df45464..148ed50 100644 --- a/knockoutwhistweb/app/model/sessions/UserSession.scala +++ b/knockoutwhistweb/app/model/sessions/UserSession.scala @@ -28,4 +28,8 @@ class UserSession(user: User, val host: Boolean) extends PlayerSession { override def name: String = user.name + def resetCanInteract(): Unit = { + canInteract = None + } + } diff --git a/knockoutwhistweb/app/views/ingame/ingame.scala.html b/knockoutwhistweb/app/views/ingame/ingame.scala.html index cb24ac0..f587dbc 100644 --- a/knockoutwhistweb/app/views/ingame/ingame.scala.html +++ b/knockoutwhistweb/app/views/ingame/ingame.scala.html @@ -17,7 +17,7 @@ @if(logic.getCurrentTrick.get.firstCard.isDefined) { @util.WebUIUtils.cardtoImage(logic.getCurrentTrick.get.firstCard.get) } else { - @views.html.render.card.apply("../../../public/images/cards/1B.png")("Blank Card") + @views.html.render.card.apply("images/cards/1B.png")("Blank Card") } diff --git a/knockoutwhistweb/app/views/mainmenu/navbar.scala.html b/knockoutwhistweb/app/views/mainmenu/navbar.scala.html new file mode 100644 index 0000000..a5f9cc4 --- /dev/null +++ b/knockoutwhistweb/app/views/mainmenu/navbar.scala.html @@ -0,0 +1,56 @@ +@(user: Option[model.users.User]) +@main("Knockout Whist - Main Menu") { + +} diff --git a/knockoutwhistweb/app/views/mainmenu/rules.scala.html b/knockoutwhistweb/app/views/mainmenu/rules.scala.html index a6a1b90..08a968d 100644 --- a/knockoutwhistweb/app/views/mainmenu/rules.scala.html +++ b/knockoutwhistweb/app/views/mainmenu/rules.scala.html @@ -1,7 +1,7 @@ @() @main("Rules") { -