cleintmessages logic

This commit is contained in:
Johannes Schmelz 2024-11-15 03:06:07 +01:00
parent 7a2ad1d31a
commit e59ab4a320
19 changed files with 484 additions and 87 deletions

View File

@ -230,12 +230,6 @@ public class ClientGameLogic implements ServerInterpreter, GameEventBroker {
throw new UnsupportedOperationException("Unimplemented method 'received'");
}
@Override
public void received(TradeRequest msg) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'received'");
}
@Override
public void received(UpdatePlayerAssets msg) {
// TODO Auto-generated method stub

View File

@ -46,6 +46,14 @@ public class Player implements FieldVisitor<Void>{
this.handler = handler;
}
public int getId() {
return id;
}
public int getFieldID() {
return fieldID;
}
public int move(int steps){
return fieldID = (fieldID+steps)%40;
}
@ -58,6 +66,11 @@ public class Player implements FieldVisitor<Void>{
this.rollResult = rollResult;
}
public List<PropertyField> getProperties() {
return properties;
}
public void buyProperty(PropertyField property) {
properties.add(property);
}
@ -66,6 +79,10 @@ public class Player implements FieldVisitor<Void>{
properties.remove(property);
}
public int getAccountBalance() {
return accountBalance;
}
public void payRent(int amount) {
accountBalance -= amount;
}
@ -78,6 +95,10 @@ public class Player implements FieldVisitor<Void>{
return name;
}
public int getNumJailCard() {
return getOutOfJailCard;
}
public void addJailCard() {
getOutOfJailCard++;
}

View File

@ -25,6 +25,15 @@ public class PlayerHandler {
players.addAll(players);
}
public int getPlayerCount() {
return players.size();
}
public boolean allPlayersReady() {
if (readyPlayers.size() == players.size()) return true;
return false;
}
void setPlayerReady(Player player, boolean ready) {
if (!players.contains(player)) {
throw new IllegalArgumentException("Player does not belong to this PlayerHandler");

View File

@ -1,30 +1,20 @@
////////////////////////////////////////
// Programming project code
// UniBw M, 2022, 2023, 2024
// www.unibw.de/inf2
// (c) Mark Minas (mark.minas@unibw.de)
////////////////////////////////////////
package pp.monopoly.game.server;
import pp.monopoly.MonopolyConfig;
import pp.monopoly.message.client.BuyPropertyRequest;
import pp.monopoly.message.client.ClientInterpreter;
import pp.monopoly.message.client.EndTurn;
import pp.monopoly.message.client.PlayerReady;
import pp.monopoly.message.client.RollDice;
import pp.monopoly.message.client.TradeOffer;
import pp.monopoly.message.client.TradeResponse;
import pp.monopoly.message.client.ViewAssetsRequest;
import pp.monopoly.message.client.*;
import pp.monopoly.message.server.ServerMessage;
import pp.monopoly.message.server.TradeReply;
import pp.monopoly.message.server.TradeRequest;
import pp.monopoly.message.server.ViewAssetsResponse;
import pp.monopoly.message.server.DiceResult;
import pp.monopoly.model.fields.BoardManager;
import pp.monopoly.model.fields.PropertyField;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.List;
import java.util.Random;
/**
* Controls the server-side game logic for Monopoly.
* Manages game states, player interactions, and message handling.
@ -36,11 +26,11 @@ public class ServerGameLogic implements ClientInterpreter {
private final PlayerHandler playerHandler = new PlayerHandler(this);
private final ServerSender serverSender;
private ServerState state = ServerState.CREATEGAME;
private Player hostPlayer;
private static final int MAX_PLAYERS = 6;
private BoardManager boardManager = new BoardManager();
/**
* Constructs a ServerGameLogic with the specified sender and configuration.
* Constructs a ServerGameLogic instance with the specified sender and configuration.
*
* @param serverSender the sender used to send messages to clients
* @param config the game configuration
@ -51,131 +41,251 @@ public class ServerGameLogic implements ClientInterpreter {
}
/**
* Class responsible for the Dice in Monopoly
* Inner class for dice functionality in the game.
* Rolls random dice values.
*/
private class Dice {
private static Random random = new Random();
/**
* Rolls a single die and returns a random value from 1 to 6.
*
* @return the result of a dice roll (1 to 6)
*/
private static int rollDice() {
return random.nextInt(6)+1;
return random.nextInt(6) + 1;
}
}
/**
* Throws the Dice.
* Generates a List with two random int in 1..6
*
* @return a List with the two rollResults of a Dice throw
* Rolls two dice and returns a list with the results.
*
* @return a List of two integers representing the dice roll results
*/
List<Integer> rollDice() {
return List.of(Dice.rollDice(), Dice.rollDice());
}
/**
* Returns the state of the game.
* Retrieves the current state of the game.
*
* @return the current ServerState
*/
ServerState getState() {
return state;
}
/**
* Sets the new state of the game and logs the state transition.
* Sets a new state for the game and logs the state transition.
*
* @param newState the new state to set
* @param newState the new ServerState to transition to
*/
void setState(ServerState newState) {
LOGGER.log(Level.DEBUG, "state transition {0} --> {1}", state, newState); //NON-NLS
LOGGER.log(Level.DEBUG, "State transition {0} --> {1}", state, newState);
state = newState;
}
/**
* Returns the player representing the client with the specified connection ID.
* Retrieves the player associated with the specified connection ID.
*
* @param id the ID of the client
* @return the player associated with the client ID, or null if not found
* @param id the connection ID of the client
* @return the Player associated with the given ID, or null if not found
*/
public Player getPlayerById(int id) {
return playerHandler.getPlayerAtIndex(id);
}
/**
* Sends a message to the specified player.
* Sends a message to a specified player.
*
* @param player the player to send the message to
* @param msg the message to send
* @param player the Player to whom the message is sent
* @param msg the ServerMessage to send
*/
void send(Player player, ServerMessage msg) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method");
if (player != null && msg != null) {
serverSender.send(player.getId(), msg);
LOGGER.log(Level.DEBUG, "Message sent to player {0}: {1}", player.getName(), msg.getClass().getSimpleName());
} else {
LOGGER.log(Level.WARNING, "Attempted to send a null message or to a null player");
}
}
/**
* Adds a new player to the game if there are less than six players.
*
* Adds a new player to the game if the game is in the CREATEGAME state and the maximum
* player limit has not been reached.
*
* @param id the connection ID of the new player
* @return the player added to the game, or null if the game is not in the right state
* @param player the Player to add to the game
* @return the added Player, or null if the player could not be added
*/
public Player addPlayer(Player player) {
if (state != ServerState.CREATEGAME) {
LOGGER.log(Level.WARNING, "Cannot add player; game is not in CREATEGAME state.");
return null;
}
if (playerHandler.getPlayerCount() >= MAX_PLAYERS) {
LOGGER.log(Level.WARNING, "Cannot add player; maximum player limit reached.");
return null;
}
playerHandler.addPlayer(player);
LOGGER.log(Level.DEBUG, "Player added: {0}", player.getName());
if (playerHandler.getPlayerCount() == MAX_PLAYERS) {
LOGGER.log(Level.INFO, "Maximum number of players reached. Starting game.");
setState(ServerState.INGAME);
}
return player;
}
/**
* Marks the player as ready
* Transitions the state to PLAY if both players are ready.
* Marks a player as ready and transitions the game state to PLAY if all players are ready.
*
* @param player the player who is ready
* @param player the Player to mark as ready
* @param status true if the player is ready, false otherwise
*/
void playerReady(Player player, boolean status) {
playerHandler.setPlayerReady(player, status);
LOGGER.log(Level.DEBUG, "Player {0} is now ready: {1}", player.getName(), status);
if (playerHandler.allPlayersReady() && playerHandler.getPlayerCount() > 1) {
setState(ServerState.INGAME);
LOGGER.log(Level.INFO, "All players are ready. Transitioning game state to PLAY.");
}
}
/**
* Handles a BuyPropertyRequest from a player, allowing the player to purchase a property
* if it is unowned and they have sufficient funds.
*
* @param msg the BuyPropertyRequest received from the player
* @param from the connection ID of the player who sent the request
*/
@Override
public void received(BuyPropertyRequest msg, int from) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'received'");
Player player = getPlayerById(from);
if (player != null && state == ServerState.INGAME) {
PropertyField property = (PropertyField) boardManager.getFieldAtIndex(player.move(0)); // Assuming player position for property
if (property.getOwner() == null && player.getAccountBalance() >= property.getPrice()) {
player.buyProperty(property);
property.setOwner(player);
player.earnMoney(-property.getPrice());
LOGGER.log(Level.INFO, "Player {0} bought property {1}", player.getName(), property.getName());
} else {
LOGGER.log(Level.WARNING, "Player {0} cannot buy property {1}", player.getName(), property.getName());
}
}
}
/**
* Handles an EndTurn request, ending the player's turn and advancing to the next player.
*
* @param msg the EndTurn message received from the player
* @param from the connection ID of the player who sent the request
*/
@Override
public void received(EndTurn msg, int from) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'received'");
Player player = getPlayerById(from);
if (player != null && state == ServerState.INGAME) {
LOGGER.log(Level.DEBUG, "Ending turn for player {0}", player.getName());
playerHandler.nextPlayer();
}
}
/**
* Handles a PlayerReady message, marking the player as ready.
*
* @param msg the PlayerReady message received from the player
* @param from the connection ID of the player who sent the request
*/
@Override
public void received(PlayerReady msg, int from) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'received'");
Player player = getPlayerById(from);
if (player != null) {
playerReady(player, true);
LOGGER.log(Level.DEBUG, "Player {0} is ready", player.getName());
}
}
/**
* Handles a RollDice message, rolling dice for the player and moving them on the board.
*
* @param msg the RollDice message received from the player
* @param from the connection ID of the player who sent the request
*/
@Override
public void received(RollDice msg, int from) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'received'");
Player player = getPlayerById(from);
if (player != null && state == ServerState.INGAME) {
List<Integer> rollResults = rollDice();
int rollSum = rollResults.get(0) + rollResults.get(1);
player.setRollResult(rollSum);
player.move(rollSum);
LOGGER.log(Level.INFO, "Player {0} rolled {1} and moved to position {2}", player.getName(), rollSum, player.getFieldID());
send(player, new DiceResult(rollResults));
}
}
/**
* Handles a TradeOffer message by forwarding the trade offer to the receiving player.
*
* @param msg the TradeOffer message received from the initiating player
* @param from the connection ID of the player who sent the offer
*/
@Override
public void received(TradeOffer msg, int from) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'received'");
Player sender = getPlayerById(from);
Player receiver = getPlayerById(msg.getReceiverId());
if (sender != null && receiver != null) {
LOGGER.log(Level.INFO, "Player {0} offers a trade to player {1}", sender.getName(), receiver.getName());
send(getPlayerById(msg.getReceiverId()), new TradeRequest(msg.getReceiverId(), msg.getTradeHandler()));
}
}
/**
* Handles a TradeResponse message by forwarding the response back to the initiating player.
*
* @param msg the TradeResponse message received from the receiving player
* @param from the connection ID of the player who sent the response
*/
@Override
public void received(TradeResponse msg, int from) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'received'");
Player responder = getPlayerById(from);
Player initiator = getPlayerById(msg.getInitiatorId());
if (responder != null && initiator != null) {
LOGGER.log(Level.INFO, "Player {0} responded to trade with player {1}", responder.getName(), initiator.getName());
send(initiator, new TradeReply(msg.getInitiatorId(), msg.getTradeHandler()));
}
}
/**
* Handles a ViewAssetsRequest message, sending the player a response containing their assets.
*
* @param msg the ViewAssetsRequest message received from the player
* @param from the connection ID of the player who sent the request
*/
@Override
public void received(ViewAssetsRequest msg, int from) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'received'");
Player player = getPlayerById(from);
if (player != null) {
LOGGER.log(Level.DEBUG, "Processing ViewAssetsRequest for player {0}", player.getName());
send(player, new ViewAssetsResponse(player.getProperties(), player.getAccountBalance(), player.getNumJailCard()));
}
}
/**
* Retrieves the board manager, which manages the game board.
*
* @return the BoardManager instance managing the game board
*/
public BoardManager getBoardManager() {
return boardManager;
}

View File

@ -1,11 +1,32 @@
package pp.monopoly.message.client;
/**
* Represents a request from a player to buy a property.
*/
public class BuyPropertyRequest extends ClientMessage{
private int propertyId;
/**
* Constructs a BuyPropertyRequest with the specified property ID.
*
* @param propertyId the ID of the property to buy
*/
public BuyPropertyRequest(int propertyId) {
this.propertyId = propertyId;
}
/**
* Gets the ID of the property to buy.
*
* @return the property ID
*/
public int getPropertyId() {
return propertyId;
}
@Override
public void accept(ClientInterpreter interpreter, int from) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'accept'");
}
}
}

View File

@ -1,5 +1,7 @@
package pp.monopoly.message.client;
/**
* Represents a message indicating the player wants to end their turn.
*/
public class EndTurn extends ClientMessage{
@Override

View File

@ -1,11 +1,32 @@
package pp.monopoly.message.client;
/**
* Represents a message indicating the player is ready to play.
*/
public class PlayerReady extends ClientMessage{
private boolean isReady;
/**
* Constructs a PlayerReady message.
*
* @param isReady true if the player is ready, false otherwise
*/
public PlayerReady(boolean isReady) {
this.isReady = isReady;
}
/**
* Checks if the player is ready.
*
* @return true if ready, false otherwise
*/
public boolean isReady() {
return isReady;
}
@Override
public void accept(ClientInterpreter interpreter, int from) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'accept'");
}
}
}

View File

@ -1,5 +1,7 @@
package pp.monopoly.message.client;
/**
* Represents a message requesting to roll the dice.
*/
public class RollDice extends ClientMessage{
@Override

View File

@ -1,6 +1,28 @@
package pp.monopoly.message.client;
import pp.monopoly.model.TradeHandler;
/**
* Represents a trade Request message from one player to another.
*/
public class TradeOffer extends ClientMessage{
private int receiverId;
private TradeHandler tradehandler;
/**
* Constructs a TradeOffer with the specified details.
*
* @param receiverId the ID of the player receiving the Request
* @param tradehandler the tradehandler
*/
public TradeOffer(int receiverId, TradeHandler tradehandler) {
this.receiverId = receiverId;
this.tradehandler = tradehandler;
}
public int getReceiverId() { return receiverId; }
public TradeHandler getTradeHandler() { return tradehandler; }
@Override
public void accept(ClientInterpreter interpreter, int from) {
@ -8,4 +30,4 @@ public class TradeOffer extends ClientMessage{
throw new UnsupportedOperationException("Unimplemented method 'accept'");
}
}
}

View File

@ -1,11 +1,33 @@
package pp.monopoly.message.client;
import pp.monopoly.model.TradeHandler;
/**
* Represents a response to a trade offer.
*/
public class TradeResponse extends ClientMessage{
private int initiatorId;
private TradeHandler tradeHandler;
/**
* Constructs a TradeResponse with the specified response details.
*
* @param initiatorId the ID of the player who initiated the trade
* @param accepted true if the offer is accepted, false if declined
*/
public TradeResponse(int initiatorId, TradeHandler tradeHandler) {
this.initiatorId = initiatorId;
this.tradeHandler = tradeHandler;
}
public int getInitiatorId() { return initiatorId; }
public TradeHandler getTradeHandler() {
return tradeHandler;
}
@Override
public void accept(ClientInterpreter interpreter, int from) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'accept'");
}
}
}

View File

@ -1,5 +1,7 @@
package pp.monopoly.message.client;
/**
* Represents a request from a player to view their assets.
*/
public class ViewAssetsRequest extends ClientMessage{
@Override

View File

@ -1,7 +1,19 @@
package pp.monopoly.message.server;
import java.util.List;
public class DiceResult extends ServerMessage{
private List<Integer> rollResult;
public DiceResult(List<Integer> rollResult) {
this.rollResult = rollResult;
}
public List<Integer> getRollResult() {
return rollResult;
}
@Override
public void accept(ServerInterpreter interpreter) {
// TODO Auto-generated method stub

View File

@ -69,13 +69,6 @@ public interface ServerInterpreter {
*/
void received(TimeOutWarning msg);
/**
* Handles a TradeRequest message received from the server.
*
* @param msg the TradeRequest message received
*/
void received(TradeRequest msg);
/**
* Handles a UpdatePlayerAssets message received from the server.
*

View File

@ -0,0 +1,40 @@
package pp.monopoly.message.server;
import pp.monopoly.model.TradeHandler;
/**
* Represents a response to a trade offer.
*/
public class TradeReply extends ServerMessage{
private int initiatorId;
private TradeHandler tradeHandler;
/**
* Constructs a TradeResponse with the specified response details.
*
* @param initiatorId the ID of the player who initiated the trade
* @param accepted true if the offer is accepted, false if declined
*/
public TradeReply(int initiatorId, TradeHandler tradeHandler) {
this.initiatorId = initiatorId;
this.tradeHandler = tradeHandler;
}
public int getInitiatorId() { return initiatorId; }
public TradeHandler getTradeHandler() {
return tradeHandler;
}
@Override
public void accept(ServerInterpreter interpreter) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'accept'");
}
@Override
public String getInfoTextKey() {
// TODO Auto-generated method stub
throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
}
}

View File

@ -1,6 +1,29 @@
package pp.monopoly.message.server;
import pp.monopoly.model.TradeHandler;
/**
* Represents a trade Request message from one player to another.
*/
public class TradeRequest extends ServerMessage{
private int receiverId;
private TradeHandler tradehandler;
/**
* Constructs a TradeRequest with the specified details.
*
* @param receiverId the ID of the player receiving the Request
* @param tradehandler the tradehandler
*/
public TradeRequest(int receiverId, TradeHandler tradehandler) {
this.receiverId = receiverId;
this.tradehandler = tradehandler;
}
public int getReceiverId() { return receiverId; }
public TradeHandler getTradeHandler() { return tradehandler; }
@Override
public void accept(ServerInterpreter interpreter) {

View File

@ -1,7 +1,29 @@
package pp.monopoly.message.server;
import java.util.List;
import pp.monopoly.model.fields.PropertyField;
/**
* Represents a response containing the player's assets.
*/
public class ViewAssetsResponse extends ServerMessage{
private List<PropertyField> properties;
private int accountBalance;
private int jailCards;
/**
* Constructs a ViewAssetsResponse with the specified properties and account balance.
*
* @param properties a List of PropertyField objects representing the player's properties
* @param accountBalance the player's current account balance
*/
public ViewAssetsResponse(List<PropertyField> properties, int accountBalance, int jailCards) {
this.properties = properties;
this.accountBalance = accountBalance;
this.jailCards = jailCards;
}
@Override
public void accept(ServerInterpreter interpreter) {
// TODO Auto-generated method stub
@ -14,4 +36,16 @@ public class ViewAssetsResponse extends ServerMessage{
throw new UnsupportedOperationException("Unimplemented method 'getInfoTextKey'");
}
public List<PropertyField> getProperties() {
return properties;
}
public int getAccountBalance() {
return accountBalance;
}
public int getJailCards() {
return jailCards;
}
}

View File

@ -0,0 +1,5 @@
package pp.monopoly.model;
public class TradeHandler {
}

View File

@ -16,4 +16,8 @@ abstract class Field {
public int getId() {
return id;
}
public String getName() {
return name;
}
}

View File

@ -2,31 +2,91 @@ package pp.monopoly.model.fields;
import pp.monopoly.game.server.Player;
/**
* Represents an abstract property field in the Monopoly game.
* Contains attributes related to ownership, price, rent, and mortgage status.
*/
public abstract class PropertyField extends Field {
private final int price;
protected final int rent;
private Player owner;
private boolean mortaged = false;
private boolean mortgaged = false;
/**
* Constructs a PropertyField with the specified name, ID, price, and rent.
*
* @param name the name of the property
* @param id the unique identifier for the property
* @param price the purchase price of the property
* @param rent the base rent for the property
*/
protected PropertyField(String name, int id, int price, int rent) {
super(name, id);
this.price = price;
this.rent = rent;
}
/**
* Calculates the rent for this property.
* The calculation may depend on various factors specific to property type.
*
* @return the calculated rent for this property
*/
public abstract int calcRent();
/**
* Gets the purchase price of the property.
*
* @return the price of the property
*/
public int getPrice() {
return price;
}
/**
* Gets the mortgage value (hypothecary value) of the property.
* Typically, this is half of the property price.
*
* @return the mortgage value of the property
*/
public int getHypo() {
return price/2;
return price / 2;
}
/**
* Gets the owner of the property.
*
* @return the Player who owns the property, or null if the property is unowned
*/
public Player getOwner() {
return owner;
}
/**
* Sets the owner of the property.
*
* @param player the Player who will own this property
*/
public void setOwner(Player player) {
owner = player;
}
/**
* Checks if the property is currently mortgaged.
*
* @return true if the property is mortgaged, false otherwise
*/
public boolean isMortgaged() {
return mortgaged;
}
/**
* Sets the mortgage status of the property.
*
* @param mortgaged true to mark the property as mortgaged, false to unmark it
*/
public void setMortgaged(boolean mortgaged) {
this.mortgaged = mortgaged;
}
}