diff --git a/src/main/java/de/towerdefence/server/match/Match.java b/src/main/java/de/towerdefence/server/match/Match.java index 7294b7f..c69b6c3 100644 --- a/src/main/java/de/towerdefence/server/match/Match.java +++ b/src/main/java/de/towerdefence/server/match/Match.java @@ -1,22 +1,37 @@ package de.towerdefence.server.match; import de.towerdefence.server.player.Player; +import de.towerdefence.server.server.channels.match.money.PlayerMoneyCallback; import de.towerdefence.server.server.channels.match.placing.InvalidPlacementReason; import de.towerdefence.server.server.channels.match.placing.Tower; import lombok.AllArgsConstructor; import lombok.Getter; -@AllArgsConstructor +import java.util.Optional; + @Getter public class Match { public final static int MAP_SIZE_X = 10; public final static int MAP_SIZE_Y = 20; + public final static int START_MONEY = 50; private final String matchId; private final Player player1; private final Player player2; + private int player1Money = START_MONEY; + private int player2Money = START_MONEY; + private PlayerMoneyCallback player1MoneyCallback; + private PlayerMoneyCallback player2MoneyCallback; private final Tower[][] player1Map = new Tower[MAP_SIZE_X][MAP_SIZE_Y]; private final Tower[][] player2Map = new Tower[MAP_SIZE_X][MAP_SIZE_Y]; + private boolean isPlayer1Connected = false; + private boolean isPlayer2Connected = false; + + public Match(String matchId, Player player1, Player player2) { + this.matchId = matchId; + this.player1 = player1; + this.player2 = player2; + } public Player getOpponent(Player player) { boolean isPlayer1 = player1.equals(player); @@ -53,4 +68,53 @@ public class Match { } return getOpponent(player); } + + // INFO: MoneyHandling + + public Optional getPlayerMoney(Player player) { + if (player != player1 && player != player2) { + return Optional.empty(); + } + if (player == player1) { + return Optional.of(player1Money); + } else { + return Optional.of(player2Money); + } + } + + public void addMoney(int money) { + player1Money += money; + player2Money += money; + } + + public void removeMoney(Player player, int money) { + if (player == player1) { + player1Money -= money; + } + if (player == player2) { + player2Money -= money; + } + } + + public void setPlayerMoneyCallback( Player player, PlayerMoneyCallback playerMoneyCallback) { + if (player == player1) { + this.player1MoneyCallback = playerMoneyCallback; + } + if (player == player2) { + this.player2MoneyCallback = playerMoneyCallback; + } + } + + /** + * @return true if both players are connected + */ + public boolean setPlayerConnected(Player player) { + if (player == player1) { + isPlayer1Connected = true; + } + if (player == player2) { + isPlayer2Connected = true; + } + return isPlayer1Connected && isPlayer2Connected; + } } diff --git a/src/main/java/de/towerdefence/server/match/MatchService.java b/src/main/java/de/towerdefence/server/match/MatchService.java index d547941..3f27222 100644 --- a/src/main/java/de/towerdefence/server/match/MatchService.java +++ b/src/main/java/de/towerdefence/server/match/MatchService.java @@ -1,15 +1,20 @@ package de.towerdefence.server.match; import de.towerdefence.server.player.Player; +import de.towerdefence.server.server.channels.match.money.PlayerMoneyCallback; import de.towerdefence.server.server.channels.match.placing.Tower; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.Map; +import java.util.Optional; +import java.util.concurrent.*; @Service public class MatchService { private final Map playerMatches = new HashMap<>(); + private final Map> moneyTasks = new HashMap<>(); + private static final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); public void createMatch(String matchId, Player player1, Player player2) { Match match = new Match(matchId, player1, player2); @@ -26,6 +31,31 @@ public class MatchService { */ public Player placeTower(Player player, int x, int y) throws InvalidPlacementException { return playerMatches.get(player).addTower(player, new Tower(), x, y); + } + + public void playerConnected(Player player, PlayerMoneyCallback callback) { + Match match = playerMatches.get(player); + Optional currentMoney = match.getPlayerMoney(player); + if (currentMoney.isEmpty()) { + return; + } + match.setPlayerMoneyCallback(player, callback); + callback.call(player, currentMoney.get()); + boolean matchStarted =match.setPlayerConnected(player); + if (!matchStarted) { + return; + } + ScheduledFuture moneyTask = scheduler.scheduleAtFixedRate( + () -> { + match.addMoney(3); + match.getPlayer1MoneyCallback().call(match.getPlayer1(), match.getPlayer1Money()); + match.getPlayer2MoneyCallback().call(match.getPlayer2(), match.getPlayer2Money()); + }, + 5, + 5, + TimeUnit.SECONDS + ); + moneyTasks.put(match, moneyTask); } } diff --git a/src/main/java/de/towerdefence/server/server/channels/match/MatchWebsocketHandler.java b/src/main/java/de/towerdefence/server/server/channels/match/MatchWebsocketHandler.java index aee3272..c02da6a 100644 --- a/src/main/java/de/towerdefence/server/server/channels/match/MatchWebsocketHandler.java +++ b/src/main/java/de/towerdefence/server/server/channels/match/MatchWebsocketHandler.java @@ -5,6 +5,7 @@ import de.towerdefence.server.match.InvalidPlacementException; import de.towerdefence.server.match.MatchService; import de.towerdefence.server.player.Player; import de.towerdefence.server.server.JsonWebsocketHandler; +import de.towerdefence.server.server.channels.match.money.PlayerMoneyMessage; import de.towerdefence.server.server.channels.match.placing.GamePlayerMap; import de.towerdefence.server.server.channels.match.placing.InvalidPlacementMessage; import de.towerdefence.server.server.channels.match.placing.RequestTowerPlacingMessage; @@ -35,6 +36,15 @@ public class MatchWebsocketHandler extends JsonWebsocketHandler { public void afterConnectionEstablished(WebSocketSession session) { super.afterConnectionEstablished(session); playerSessions.put(sessionPlayers.get(session), session); + matchService.playerConnected(sessionPlayers.get(session), this::onPlayerMoneyChanged); + } + + private void onPlayerMoneyChanged(Player player, int playerMoney) { + WebSocketSession session = playerSessions.get(player); + try { + new PlayerMoneyMessage(playerMoney).send(session); + } catch (IOException ignored) { + } } @Override diff --git a/src/main/java/de/towerdefence/server/server/channels/match/money/PlayerMoneyCallback.java b/src/main/java/de/towerdefence/server/server/channels/match/money/PlayerMoneyCallback.java new file mode 100644 index 0000000..dc1fb46 --- /dev/null +++ b/src/main/java/de/towerdefence/server/server/channels/match/money/PlayerMoneyCallback.java @@ -0,0 +1,8 @@ +package de.towerdefence.server.server.channels.match.money; + +import de.towerdefence.server.player.Player; + +@FunctionalInterface +public interface PlayerMoneyCallback { + void call(Player player, int playerMoney); +} diff --git a/src/main/java/de/towerdefence/server/server/channels/match/money/PlayerMoneyMessage.java b/src/main/java/de/towerdefence/server/server/channels/match/money/PlayerMoneyMessage.java new file mode 100644 index 0000000..d95b258 --- /dev/null +++ b/src/main/java/de/towerdefence/server/server/channels/match/money/PlayerMoneyMessage.java @@ -0,0 +1,26 @@ +package de.towerdefence.server.server.channels.match.money; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import de.towerdefence.server.server.JsonMessage; +import lombok.AllArgsConstructor; + +import java.util.Map; + +@AllArgsConstructor +public class PlayerMoneyMessage extends JsonMessage { + + private final int playerMoney; + + @Override + protected String getMessageId() { + return "PlayerMoney"; + } + + @Override + protected Map getData(JsonNodeFactory factory) { + return Map.of( + "playerMoney", factory.numberNode(this.playerMoney) + ); + } +} diff --git a/ws/ws.yml b/ws/ws.yml index cb56075..70fb9ea 100644 --- a/ws/ws.yml +++ b/ws/ws.yml @@ -241,6 +241,21 @@ channels: - x - y - reason + PlayerMoney: + description: Money a player currently has + payload: + type: object + additionalProperties: false + properties: + $id: + type: string + format: messageId + playerMoney: + type: integer + required: + - $id + - playerMoney + operations: requestConnectionToken: @@ -322,6 +337,13 @@ operations: $ref: "#/channels/match" messages: - $ref: "#/channels/match/messages/TowerPlaced" + playerMoney: + title: PlayerMoney + action: receive + channel: + $ref: "#/channels/match" + messages: + - $ref: "#/channels/match/messages/PlayerMoney"