WIP: [Feature]: Enemy Waves Part1 #17

Draft
snoweuph wants to merge 4 commits from story/td-5-gegnerwellen into trunk
11 changed files with 97 additions and 81 deletions
Showing only changes of commit eff9ea139a - Show all commits

View file

@ -44,7 +44,8 @@ public class GameSession {
Player player, Player player,
PlayerMoneyCallback moneyCallback, PlayerMoneyCallback moneyCallback,
PlayerHitpointsCallback hitpointsCallback, PlayerHitpointsCallback hitpointsCallback,
EnemiesChangedCallback enemyCallback) { EnemiesChangedCallback enemyCallback
) {
this.player = player; this.player = player;
this.moneyCallback = moneyCallback; this.moneyCallback = moneyCallback;
this.hitpointsCallback = hitpointsCallback; this.hitpointsCallback = hitpointsCallback;
@ -75,7 +76,8 @@ public class GameSession {
enemyCallback.call( enemyCallback.call(
player, player,
newEnemies.toArray(new Enemy[newEnemies.size()]), newEnemies.toArray(new Enemy[newEnemies.size()]),
changedEnemies.toArray(new Enemy[changedEnemies.size()])); changedEnemies.toArray(new Enemy[changedEnemies.size()])
);
} }
} }
@ -118,11 +120,11 @@ public class GameSession {
return changedEnemies; return changedEnemies;
} }
public void placeTower(Tower tower, int x, int y) throws InvalidPlacementException { public void placeTower(Tower tower, Vector2i pos) throws InvalidPlacementException {
if (x < 0 || y < 0 || x + 1 > MAP_SIZE.x || y + 1 > MAP_SIZE.y) { if (pos.x < 0 || pos.y < 0 || pos.x + 1 > MAP_SIZE.x || pos.y + 1 > MAP_SIZE.y) {
throw new InvalidPlacementException(InvalidPlacementReason.OUT_OF_BOUNDS); throw new InvalidPlacementException(InvalidPlacementReason.OUT_OF_BOUNDS);
} }
if (towers[x][y] != null) { if (towers[pos.x][pos.y] != null) {
throw new InvalidPlacementException(InvalidPlacementReason.LOCATION_USED); throw new InvalidPlacementException(InvalidPlacementReason.LOCATION_USED);
} }
if (money < Tower.COST) { if (money < Tower.COST) {
@ -133,9 +135,8 @@ public class GameSession {
money -= Tower.COST; money -= Tower.COST;
moneyCallback.call(player, money); moneyCallback.call(player, money);
tower.x = x; tower.pos = pos;
tower.y = y; towers[pos.x][pos.y] = tower;
towers[x][y] = tower;
} }
public void addMoney(int amount) { public void addMoney(int amount) {

View file

@ -1,12 +1,13 @@
package de.towerdefence.server.game; package de.towerdefence.server.game;
import org.joml.Vector2i;
import lombok.Getter; import lombok.Getter;
@Getter @Getter
public class Tower { public class Tower {
public static final int COST = 20; public static final int COST = 20;
protected int x; protected Vector2i pos;
protected int y;
public Tower() { public Tower() {
} }

View file

@ -92,9 +92,12 @@ public class AStar {
if (!walkable.call(pos)) { if (!walkable.call(pos)) {
return; return;
} }
accumulator.add(new PathNode( accumulator.add(
new PathNode(
right, right,
nextCost, nextCost,
right.gridDistance(target) + nextCost)); right.gridDistance(target) + nextCost
)
);
} }
} }

View file

@ -6,7 +6,7 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
final class PathNode { final class PathNode {
protected final Vector2i pos; final Vector2i pos;
protected final long cost; // This is the cost to this Node final long cost; // This is the cost to this Node
protected final long estimate; // This is the estimated remaining cost to the Target final long estimate; // This is the estimated remaining cost to the Target
} }

View file

@ -55,7 +55,8 @@ public class Match {
Player player, Player player,
PlayerMoneyCallback moneyCallback, PlayerMoneyCallback moneyCallback,
PlayerHitpointsCallback hitpointsCallback, PlayerHitpointsCallback hitpointsCallback,
EnemiesChangedCallback enemyCallback) { EnemiesChangedCallback enemyCallback
) {
boolean isPlayer1 = player1.equals(player); boolean isPlayer1 = player1.equals(player);
boolean isPlayer2 = player2.equals(player); boolean isPlayer2 = player2.equals(player);
if (!isPlayer1 && !isPlayer2) { if (!isPlayer1 && !isPlayer2) {

View file

@ -5,6 +5,8 @@ import de.towerdefence.server.game.callbacks.PlayerMoneyCallback;
import de.towerdefence.server.game.exeptions.InvalidPlacementException; import de.towerdefence.server.game.exeptions.InvalidPlacementException;
import de.towerdefence.server.game.exeptions.InvalidPlacementReason; import de.towerdefence.server.game.exeptions.InvalidPlacementReason;
import de.towerdefence.server.player.Player; import de.towerdefence.server.player.Player;
import org.joml.Vector2i;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.HashMap; import java.util.HashMap;
@ -51,7 +53,7 @@ public class MatchService {
if (opponent.isEmpty()) { if (opponent.isEmpty()) {
throw new NotInMatchException(); throw new NotInMatchException();
} }
playerSession.get().placeTower(new Tower(), x, y); playerSession.get().placeTower(new Tower(), new Vector2i(x, y));
return opponent.get(); return opponent.get();
} }
@ -59,7 +61,8 @@ public class MatchService {
Player player, Player player,
PlayerMoneyCallback moneyCallback, PlayerMoneyCallback moneyCallback,
PlayerHitpointsCallback hitpointsCallback, PlayerHitpointsCallback hitpointsCallback,
EnemiesChangedCallback enemyCallback) { EnemiesChangedCallback enemyCallback
) {
Match match = playerMatches.get(player); Match match = playerMatches.get(player);
match.connectPlayer(player, moneyCallback, hitpointsCallback, enemyCallback); match.connectPlayer(player, moneyCallback, hitpointsCallback, enemyCallback);
Optional<GameSession> optionalPlayerSession = match.getPlayerGameSession(player); Optional<GameSession> optionalPlayerSession = match.getPlayerGameSession(player);

View file

@ -1,22 +1,13 @@
package de.towerdefence.server.server.channels.match; package de.towerdefence.server.server.channels.match;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import de.towerdefence.server.game.Enemy; import de.towerdefence.server.game.Enemy;
import de.towerdefence.server.game.exeptions.InvalidPlacementException; import de.towerdefence.server.game.exeptions.InvalidPlacementException;
import de.towerdefence.server.match.MatchService; import de.towerdefence.server.match.MatchService;
import de.towerdefence.server.match.NotInMatchException; import de.towerdefence.server.match.NotInMatchException;
import de.towerdefence.server.player.Player; import de.towerdefence.server.player.Player;
import de.towerdefence.server.server.JsonWebsocketHandler; import de.towerdefence.server.server.JsonWebsocketHandler;
import de.towerdefence.server.server.channels.match.enemy.EnemyUpdateMessage;
import de.towerdefence.server.server.channels.match.hitpoints.PlayerHitpointsMessage; import de.towerdefence.server.server.channels.match.hitpoints.PlayerHitpointsMessage;
import de.towerdefence.server.server.channels.match.money.PlayerMoneyMessage; 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.GamePlayerMap;
@ -25,6 +16,13 @@ import de.towerdefence.server.server.channels.match.placing.RequestTowerPlacingM
import de.towerdefence.server.server.channels.match.placing.TowerPlacedMessage; import de.towerdefence.server.server.channels.match.placing.TowerPlacedMessage;
import de.towerdefence.server.session.Channel; import de.towerdefence.server.session.Channel;
import de.towerdefence.server.session.SessionsService; import de.towerdefence.server.session.SessionsService;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
public class MatchWebsocketHandler extends JsonWebsocketHandler { public class MatchWebsocketHandler extends JsonWebsocketHandler {
@ -73,7 +71,11 @@ public class MatchWebsocketHandler extends JsonWebsocketHandler {
} }
private void onEnemiesChanged(Player player, Enemy[] newEnemies, Enemy[] changedEnemies) { private void onEnemiesChanged(Player player, Enemy[] newEnemies, Enemy[] changedEnemies) {
WebSocketSession session = playerSessions.get(player);
try {
new EnemyUpdateMessage(newEnemies, changedEnemies).send(session);
} catch (IOException ignored) {
}
} }
@Override @Override
@ -82,7 +84,8 @@ public class MatchWebsocketHandler extends JsonWebsocketHandler {
String payload = message.getPayload(); String payload = message.getPayload();
if (!Objects.equals( if (!Objects.equals(
objectMapper.readTree(payload).get("$id").asText(), objectMapper.readTree(payload).get("$id").asText(),
RequestTowerPlacingMessage.MESSAGE_ID)) { RequestTowerPlacingMessage.MESSAGE_ID
)) {
this.closeSession(session, CloseStatus.BAD_DATA); this.closeSession(session, CloseStatus.BAD_DATA);
return; return;
} }
@ -90,16 +93,15 @@ public class MatchWebsocketHandler extends JsonWebsocketHandler {
} catch (IOException ignored) { } catch (IOException ignored) {
this.closeSession(session, CloseStatus.BAD_DATA); this.closeSession(session, CloseStatus.BAD_DATA);
} }
} }
private void handleRequestTowerPlacingMessage( private void handleRequestTowerPlacingMessage(WebSocketSession session, String payload)
WebSocketSession session, throws IOException {
String payload) throws IOException { RequestTowerPlacingMessage msg =
RequestTowerPlacingMessage msg = objectMapper.readValue(payload, RequestTowerPlacingMessage.class); objectMapper.readValue(payload, RequestTowerPlacingMessage.class);
Player opponent; Player opponent;
try { try {
opponent = this.matchService.placeTower( opponent =this.matchService.placeTower(
this.sessionPlayers.get(session), this.sessionPlayers.get(session),
msg.getX(), msg.getX(),
msg.getY() msg.getY()

View file

@ -12,8 +12,6 @@ import lombok.AllArgsConstructor;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collector;
import java.util.stream.Collectors;
@AllArgsConstructor @AllArgsConstructor
public class EnemyUpdateMessage extends JsonMessage { public class EnemyUpdateMessage extends JsonMessage {
@ -34,8 +32,8 @@ public class EnemyUpdateMessage extends JsonMessage {
.map((Enemy enemy) -> { .map((Enemy enemy) -> {
ObjectNode o = factory.objectNode(); ObjectNode o = factory.objectNode();
o.set("id", factory.numberNode(enemy.getId())); o.set("id", factory.numberNode(enemy.getId()));
o.set("x", factory.numberNode(enemy.getX())); o.set("x", factory.numberNode(enemy.getPos().x));
o.set("y", factory.numberNode(enemy.getY())); o.set("y", factory.numberNode(enemy.getPos().y));
return o; return o;
}) })
.map(JsonNode.class::cast) .map(JsonNode.class::cast)
@ -46,8 +44,8 @@ public class EnemyUpdateMessage extends JsonMessage {
.map((Enemy enemy) -> { .map((Enemy enemy) -> {
ObjectNode o = factory.objectNode(); ObjectNode o = factory.objectNode();
o.set("id", factory.numberNode(enemy.getId())); o.set("id", factory.numberNode(enemy.getId()));
o.set("x", factory.numberNode(enemy.getX())); o.set("x", factory.numberNode(enemy.getPos().x));
o.set("y", factory.numberNode(enemy.getY())); o.set("y", factory.numberNode(enemy.getPos().y));
return o; return o;
}) })
.map(JsonNode.class::cast) .map(JsonNode.class::cast)

View file

@ -26,6 +26,7 @@ public class InvalidPlacementMessage extends JsonMessage {
return Map.of( return Map.of(
"x", factory.numberNode(this.x), "x", factory.numberNode(this.x),
"y", factory.numberNode(this.y), "y", factory.numberNode(this.y),
"reason", factory.textNode(this.reason.getJsonName())); "reason", factory.textNode(this.reason.getJsonName())
);
} }
} }

View file

@ -25,4 +25,10 @@
<Method name="placeTower"/> <Method name="placeTower"/>
<Bug code="L,B,ISC"/> <Bug code="L,B,ISC"/>
</Match> </Match>
<Match>
<!-- This will be used soon -->
<Class name="de.towerdefence.server.game.GameSession"/>
<Field name="hitpointsCallback"/>
<Bug code="L,P,UrF"/>
</Match>
</FindBugsFilter> </FindBugsFilter>