feat(user-sessions): add custom exceptions for game logic and enhance user session interaction
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
package exceptions;
|
||||||
|
|
||||||
|
public class CantPlayCardException extends GameException {
|
||||||
|
public CantPlayCardException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
7
knockoutwhistweb/app/exceptions/GameException.java
Normal file
7
knockoutwhistweb/app/exceptions/GameException.java
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package exceptions;
|
||||||
|
|
||||||
|
public abstract class GameException extends RuntimeException {
|
||||||
|
public GameException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package exceptions;
|
package exceptions;
|
||||||
|
|
||||||
public class NotHostException extends RuntimeException {
|
public class NotHostException extends GameException {
|
||||||
public NotHostException(String message) {
|
public NotHostException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package exceptions;
|
package exceptions;
|
||||||
|
|
||||||
public class NotInThisGameException extends RuntimeException {
|
public class NotInThisGameException extends GameException {
|
||||||
public NotInThisGameException(String message) {
|
public NotInThisGameException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package exceptions;
|
package exceptions;
|
||||||
|
|
||||||
public class NotInteractableException extends RuntimeException {
|
public class NotInteractableException extends GameException {
|
||||||
public NotInteractableException(String message) {
|
public NotInteractableException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
package logic.game
|
package logic.game
|
||||||
|
|
||||||
|
import de.knockoutwhist.cards.{Hand, Suit}
|
||||||
import de.knockoutwhist.control.GameLogic
|
import de.knockoutwhist.control.GameLogic
|
||||||
|
import de.knockoutwhist.control.controllerBaseImpl.sublogic.util.{MatchUtil, PlayerUtil, RoundUtil}
|
||||||
import de.knockoutwhist.events.player.PlayerEvent
|
import de.knockoutwhist.events.player.PlayerEvent
|
||||||
import de.knockoutwhist.player.Playertype.HUMAN
|
import de.knockoutwhist.player.Playertype.HUMAN
|
||||||
import de.knockoutwhist.player.{AbstractPlayer, PlayerFactory}
|
import de.knockoutwhist.player.{AbstractPlayer, PlayerFactory}
|
||||||
import de.knockoutwhist.rounds.Match
|
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||||
import de.knockoutwhist.utils.events.{EventListener, SimpleEvent}
|
import de.knockoutwhist.utils.events.{EventListener, SimpleEvent}
|
||||||
import exceptions.{NotHostException, NotInThisGameException, NotInteractableException}
|
import exceptions.{CantPlayCardException, NotHostException, NotInThisGameException, NotInteractableException}
|
||||||
import model.sessions.UserSession
|
import model.sessions.{InteractionType, UserSession}
|
||||||
import model.users.User
|
import model.users.User
|
||||||
|
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
@@ -44,20 +46,92 @@ class GameLobby(val logic: GameLogic, val id: String, internalId: UUID) extends
|
|||||||
logic.controlMatch()
|
logic.controlMatch()
|
||||||
}
|
}
|
||||||
|
|
||||||
def playCard(user: User, card: Int): Unit = {
|
/**
|
||||||
val sessionOpt = users.get(user.id)
|
* Play a card from the player's hand.
|
||||||
if (sessionOpt.isEmpty) {
|
* @param userSession the user session of the player.
|
||||||
throw new NotInThisGameException("You are not in this game!")
|
* @param cardIndex the index of the card in the player's hand.
|
||||||
|
*/
|
||||||
|
def playCard(userSession: UserSession, cardIndex: Int): Unit = {
|
||||||
|
val player = getPlayer(userSession, InteractionType.Card)
|
||||||
|
if (player.isInDogLife) {
|
||||||
|
throw new CantPlayCardException("You are in dog life!")
|
||||||
}
|
}
|
||||||
if (!sessionOpt.get.canInteract) {
|
val hand = getHand(player)
|
||||||
throw new NotInteractableException("You can't play a card!")
|
val card = hand.cards(cardIndex)
|
||||||
|
if (!PlayerUtil.canPlayCard(card, getRound, getTrick, player)) {
|
||||||
|
throw new CantPlayCardException("You can't play this card!")
|
||||||
|
}
|
||||||
|
logic.playerInputLogic.receivedCard(card)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play a card from the player's hand while in dog life or skip the round.
|
||||||
|
* @param userSession the user session of the player.
|
||||||
|
* @param cardIndex the index of the card in the player's hand or -1 if the player wants to skip the round.
|
||||||
|
*/
|
||||||
|
def playDogCard(userSession: UserSession, cardIndex: Int): Unit = {
|
||||||
|
val player = getPlayer(userSession, InteractionType.DogCard)
|
||||||
|
if (!player.isInDogLife) {
|
||||||
|
throw new CantPlayCardException("You are not in dog life!")
|
||||||
|
}
|
||||||
|
if (cardIndex == -1) {
|
||||||
|
if (!MatchUtil.dogNeedsToPlay(getMatch, getRound)) {
|
||||||
|
throw new CantPlayCardException("You can't skip this round!")
|
||||||
|
}
|
||||||
|
logic.playerInputLogic.receivedDog(None)
|
||||||
|
}
|
||||||
|
val hand = getHand(player)
|
||||||
|
val card = hand.cards(cardIndex)
|
||||||
|
logic.playerInputLogic.receivedDog(Some(card))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select the trump suit for the round.
|
||||||
|
* @param userSession the user session of the player.
|
||||||
|
* @param trumpIndex the index of the trump suit.
|
||||||
|
*/
|
||||||
|
def selectTrump(userSession: UserSession, trumpIndex: Int): Unit = {
|
||||||
|
val player = getPlayer(userSession, InteractionType.TrumpSuit)
|
||||||
|
val trumpSuits = Suit.values.toList
|
||||||
|
val selectedTrump = trumpSuits(trumpIndex)
|
||||||
|
logic.playerInputLogic.receivedTrumpSuit(selectedTrump)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param userSession
|
||||||
|
* @param tieNumber
|
||||||
|
*/
|
||||||
|
def selectTie(userSession: UserSession, tieNumber: Int): Unit = {
|
||||||
|
val player = getPlayer(userSession, InteractionType.TieChoice)
|
||||||
|
logic.playerTieLogic.receivedTieBreakerCard(tieNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------
|
//-------------------
|
||||||
|
|
||||||
|
private def getPlayer(userSession: UserSession, iType: InteractionType): AbstractPlayer = {
|
||||||
|
if (!Thread.holdsLock(userSession.lock)) {
|
||||||
|
throw new IllegalStateException("The user session is not locked!")
|
||||||
|
}
|
||||||
|
if (userSession.canInteract.isEmpty || userSession.canInteract.get != iType) {
|
||||||
|
throw new NotInteractableException("You can't play a card!")
|
||||||
|
}
|
||||||
|
val playerOption = getMatch.totalplayers.find(_.id == userSession.id)
|
||||||
|
if (playerOption.isEmpty) {
|
||||||
|
throw new NotInThisGameException("You are not in this game!")
|
||||||
|
}
|
||||||
|
playerOption.get
|
||||||
|
}
|
||||||
|
|
||||||
|
private def getHand(player: AbstractPlayer): Hand = {
|
||||||
|
val handOption = player.currentHand()
|
||||||
|
if (handOption.isEmpty) {
|
||||||
|
throw new IllegalStateException("You have no cards!")
|
||||||
|
}
|
||||||
|
handOption.get
|
||||||
|
}
|
||||||
|
|
||||||
private def getMatch: Match = {
|
private def getMatch: Match = {
|
||||||
val matchOpt = logic.getCurrentMatch
|
val matchOpt = logic.getCurrentMatch
|
||||||
if (matchOpt.isEmpty) {
|
if (matchOpt.isEmpty) {
|
||||||
@@ -66,4 +140,20 @@ class GameLobby(val logic: GameLogic, val id: String, internalId: UUID) extends
|
|||||||
matchOpt.get
|
matchOpt.get
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def getRound: Round = {
|
||||||
|
val roundOpt = logic.getCurrentRound
|
||||||
|
if (roundOpt.isEmpty) {
|
||||||
|
throw new IllegalStateException("No round is currently running!")
|
||||||
|
}
|
||||||
|
roundOpt.get
|
||||||
|
}
|
||||||
|
|
||||||
|
private def getTrick: Trick = {
|
||||||
|
val trickOpt = logic.getCurrentTrick
|
||||||
|
if (trickOpt.isEmpty) {
|
||||||
|
throw new IllegalStateException("No trick is currently running!")
|
||||||
|
}
|
||||||
|
trickOpt.get
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
10
knockoutwhistweb/app/model/sessions/InteractionType.scala
Normal file
10
knockoutwhistweb/app/model/sessions/InteractionType.scala
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package model.sessions
|
||||||
|
|
||||||
|
enum InteractionType {
|
||||||
|
|
||||||
|
case TrumpSuit
|
||||||
|
case Card
|
||||||
|
case DogCard
|
||||||
|
case TieChoice
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,18 +5,21 @@ import de.knockoutwhist.utils.events.SimpleEvent
|
|||||||
import model.users.User
|
import model.users.User
|
||||||
|
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
import java.util.concurrent.locks.{Lock, ReentrantLock}
|
||||||
|
|
||||||
class UserSession(user: User, val host: Boolean) extends PlayerSession {
|
class UserSession(user: User, val host: Boolean) extends PlayerSession {
|
||||||
var canInteract: Boolean = false
|
var canInteract: Option[InteractionType] = None
|
||||||
|
val lock: Lock = ReentrantLock()
|
||||||
|
|
||||||
override def updatePlayer(event: SimpleEvent): Unit = {
|
override def updatePlayer(event: SimpleEvent): Unit = {
|
||||||
event match {
|
event match {
|
||||||
case event: RequestTrumpSuitEvent =>
|
case event: RequestTrumpSuitEvent =>
|
||||||
canInteract = true
|
canInteract = Some(InteractionType.TrumpSuit)
|
||||||
case event: RequestTieChoiceEvent =>
|
case event: RequestTieChoiceEvent =>
|
||||||
canInteract = true
|
canInteract = Some(InteractionType.TieChoice)
|
||||||
case event: RequestCardEvent =>
|
case event: RequestCardEvent =>
|
||||||
canInteract = true
|
if (event.player.isInDogLife) canInteract = Some(InteractionType.DogCard)
|
||||||
|
else canInteract = Some(InteractionType.Card)
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user