added server-side and client-side validation for JSON files
- added the client-side validation in the EditorState class - added the server-side validation in the WaitState and ServerGameLogic class - added Getter in the ShipMapDTO - added the 'map.invalid' in the properties
This commit is contained in:
@@ -10,12 +10,14 @@
|
|||||||
import pp.battleship.message.client.MapMessage;
|
import pp.battleship.message.client.MapMessage;
|
||||||
import pp.battleship.model.Battleship;
|
import pp.battleship.model.Battleship;
|
||||||
import pp.battleship.model.IntPoint;
|
import pp.battleship.model.IntPoint;
|
||||||
|
import pp.battleship.model.Rotation;
|
||||||
import pp.battleship.model.ShipMap;
|
import pp.battleship.model.ShipMap;
|
||||||
import pp.battleship.model.dto.ShipMapDTO;
|
import pp.battleship.model.dto.ShipMapDTO;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.System.Logger.Level;
|
import java.lang.System.Logger.Level;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static pp.battleship.Resources.lookup;
|
import static pp.battleship.Resources.lookup;
|
||||||
import static pp.battleship.model.Battleship.Status.INVALID_PREVIEW;
|
import static pp.battleship.model.Battleship.Status.INVALID_PREVIEW;
|
||||||
@@ -238,6 +240,8 @@ public void loadMap(File file) throws IOException {
|
|||||||
final ShipMapDTO dto = ShipMapDTO.loadFrom(file);
|
final ShipMapDTO dto = ShipMapDTO.loadFrom(file);
|
||||||
if (!dto.fits(logic.getDetails()))
|
if (!dto.fits(logic.getDetails()))
|
||||||
throw new IOException(lookup("map.doesnt.fit"));
|
throw new IOException(lookup("map.doesnt.fit"));
|
||||||
|
if (!validMap(dto))
|
||||||
|
throw new IOException(lookup("map.invalid"));
|
||||||
ownMap().clear();
|
ownMap().clear();
|
||||||
dto.getShips().forEach(ownMap()::add);
|
dto.getShips().forEach(ownMap()::add);
|
||||||
harbor().clear();
|
harbor().clear();
|
||||||
@@ -264,4 +268,70 @@ public boolean mayLoadMap() {
|
|||||||
public boolean maySaveMap() {
|
public boolean maySaveMap() {
|
||||||
return harbor().getItems().isEmpty();
|
return harbor().getItems().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the given ShipMapDTO by checking if all ships are within bounds
|
||||||
|
* and do not overlap with each other.
|
||||||
|
*
|
||||||
|
* @param dto the ShipMapDTO to validate
|
||||||
|
* @return true if the map is valid, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean validMap(ShipMapDTO dto) {
|
||||||
|
return inBounds(dto) && !overlaps(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if all ships in the given ShipMapDTO are within the bounds of the map.
|
||||||
|
*
|
||||||
|
* @param dto the ShipMapDTO to validate
|
||||||
|
* @return true if all ships are within bounds, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean inBounds(ShipMapDTO dto) {
|
||||||
|
List<Battleship> ships = dto.getShips();
|
||||||
|
for (Battleship ship : ships) {
|
||||||
|
if (!isWithinBounds(ship, dto.getWidth(), dto.getHeight())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given ship is within the bounds of the map.
|
||||||
|
*
|
||||||
|
* @param ship the Battleship to check
|
||||||
|
* @param width the width of the map
|
||||||
|
* @param height the height of the map
|
||||||
|
* @return true if the ship is within bounds, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean isWithinBounds(Battleship ship, int width, int height) {
|
||||||
|
int x1 = ship.getX();
|
||||||
|
int y1 = ship.getY();
|
||||||
|
Rotation r = ship.getRot();
|
||||||
|
int x2 = x1 + ship.getLength() * r.dx();
|
||||||
|
int y2 = y1 + ship.getLength() * r.dy();
|
||||||
|
|
||||||
|
return x1 >= 0 && y1 >= 0 && x1 <= width && y1 <= height &&
|
||||||
|
x2 >= 0 && y2 >= 0 && x2 <= width && y2 <= height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if any ships in the given ShipMapDTO overlap with each other.
|
||||||
|
*
|
||||||
|
* @param dto the ShipMapDTO to validate
|
||||||
|
* @return true if any ships overlap, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean overlaps(ShipMapDTO dto) {
|
||||||
|
List<Battleship> ships = dto.getShips();
|
||||||
|
for (int i = 0; i < ships.size(); i++) {
|
||||||
|
Battleship ship1 = ships.get(i);
|
||||||
|
for (int j = i + 1; j < ships.size(); j++) {
|
||||||
|
Battleship ship2 = ships.get(j);
|
||||||
|
if (ship1.collidesWith(ship2)) {
|
||||||
|
return true; // Collision detected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
package pp.battleship.game.client;
|
package pp.battleship.game.client;
|
||||||
|
|
||||||
|
import pp.battleship.message.server.GameDetails;
|
||||||
import pp.battleship.message.server.StartBattleMessage;
|
import pp.battleship.message.server.StartBattleMessage;
|
||||||
|
|
||||||
import java.lang.System.Logger.Level;
|
import java.lang.System.Logger.Level;
|
||||||
@@ -38,4 +39,17 @@ public void receivedStartBattle(StartBattleMessage msg) {
|
|||||||
logic.setInfoText(msg.getInfoTextKey());
|
logic.setInfoText(msg.getInfoTextKey());
|
||||||
logic.setState(new BattleState(logic, msg.isMyTurn()));
|
logic.setState(new BattleState(logic, msg.isMyTurn()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the GameDetails message received from the server.
|
||||||
|
* If the map is invalid, the editor state is set.
|
||||||
|
*
|
||||||
|
* @param msg the GameDetails message received
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void receivedGameDetails(GameDetails msg) {
|
||||||
|
ClientGameLogic.LOGGER.log(Level.WARNING, "Invalid Map"); //NON-NLS
|
||||||
|
logic.setInfoText("map.invalid");
|
||||||
|
logic.setState(new EditorState(logic));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
import pp.battleship.message.server.StartBattleMessage;
|
import pp.battleship.message.server.StartBattleMessage;
|
||||||
import pp.battleship.model.Battleship;
|
import pp.battleship.model.Battleship;
|
||||||
import pp.battleship.model.IntPoint;
|
import pp.battleship.model.IntPoint;
|
||||||
|
import pp.battleship.model.Rotation;
|
||||||
|
|
||||||
import java.lang.System.Logger;
|
import java.lang.System.Logger;
|
||||||
import java.lang.System.Logger.Level;
|
import java.lang.System.Logger.Level;
|
||||||
@@ -142,8 +143,75 @@ public Player addPlayer(int id) {
|
|||||||
public void received(MapMessage msg, int from) {
|
public void received(MapMessage msg, int from) {
|
||||||
if (state != ServerState.SET_UP)
|
if (state != ServerState.SET_UP)
|
||||||
LOGGER.log(Level.ERROR, "playerReady not allowed in {0}", state); //NON-NLS
|
LOGGER.log(Level.ERROR, "playerReady not allowed in {0}", state); //NON-NLS
|
||||||
else
|
else if (validMap(msg))
|
||||||
playerReady(getPlayerById(from), msg.getShips());
|
playerReady(getPlayerById(from), msg.getShips());
|
||||||
|
else {
|
||||||
|
LOGGER.log(Level.ERROR, "map does not fit game details"); //NON-NLS
|
||||||
|
send(getPlayerById(from), new GameDetails(config));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the received map message by checking if all ships are within bounds
|
||||||
|
* and do not overlap with each other.
|
||||||
|
*
|
||||||
|
* @param msg the received MapMessage containing the ships
|
||||||
|
* @return true if the map is valid, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean validMap(MapMessage msg) {
|
||||||
|
List<Battleship> ships = msg.getShips();
|
||||||
|
return inBounds(ships) && !overlaps(ships);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if all ships in the given list are within the bounds of the map.
|
||||||
|
*
|
||||||
|
* @param ships the list of Battleships to validate
|
||||||
|
* @return true if all ships are within bounds, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean inBounds(List<Battleship> ships) {
|
||||||
|
for (Battleship ship : ships) {
|
||||||
|
if (!isWithinBounds(ship)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given ship is within the bounds of the map.
|
||||||
|
*
|
||||||
|
* @param ship the Battleship to check
|
||||||
|
* @return true if the ship is within bounds, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean isWithinBounds(Battleship ship) {
|
||||||
|
int x1 = ship.getX();
|
||||||
|
int y1 = ship.getY();
|
||||||
|
Rotation r = ship.getRot();
|
||||||
|
int x2 = x1 + ship.getLength() * r.dx();
|
||||||
|
int y2 = y1 + ship.getLength() * r.dy();
|
||||||
|
|
||||||
|
return x1 >= 0 && y1 >= 0 && x1 <= config.getMapWidth() && y1 <= config.getMapHeight() &&
|
||||||
|
x2 >= 0 && y2 >= 0 && x2 <= config.getMapWidth() && y2 <= config.getMapHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if any ships in the given list overlap with each other.
|
||||||
|
*
|
||||||
|
* @param ships the list of Battleships to validate
|
||||||
|
* @return true if any ships overlap, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean overlaps(List<Battleship> ships) {
|
||||||
|
for (int i = 0; i < ships.size(); i++) {
|
||||||
|
Battleship ship1 = ships.get(i);
|
||||||
|
for (int j = i + 1; j < ships.size(); j++) {
|
||||||
|
Battleship ship2 = ships.get(j);
|
||||||
|
if (ship1.collidesWith(ship2)) {
|
||||||
|
return true; // Collision detected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -114,4 +114,22 @@ public static ShipMapDTO loadFrom(File file) throws IOException {
|
|||||||
throw new IOException(e.getLocalizedMessage());
|
throw new IOException(e.getLocalizedMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the width of the ship map.
|
||||||
|
*
|
||||||
|
* @return the width of the ship map
|
||||||
|
*/
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the height of the ship map.
|
||||||
|
*
|
||||||
|
* @return the height of the ship map
|
||||||
|
*/
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,3 +37,4 @@ dialog.error=Error
|
|||||||
dialog.question=Question
|
dialog.question=Question
|
||||||
port.must.be.integer=Port must be an integer number
|
port.must.be.integer=Port must be an integer number
|
||||||
map.doesnt.fit=The map doesn't fit to this game
|
map.doesnt.fit=The map doesn't fit to this game
|
||||||
|
map.invalid=The map is invalid
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ host.name=Host
|
|||||||
port.number=Port
|
port.number=Port
|
||||||
wait.its.not.your.turn=Warte, Du bist nicht dran!!
|
wait.its.not.your.turn=Warte, Du bist nicht dran!!
|
||||||
menu.quit=Spiel beenden
|
menu.quit=Spiel beenden
|
||||||
menu.return-to-game=Zurück zum Spiel
|
menu.return-to-game=Zur<EFBFBD>ck zum Spiel
|
||||||
menu.sound-enabled=Sound eingeschaltet
|
menu.sound-enabled=Sound eingeschaltet
|
||||||
menu.map.load=Karte von Datei laden...
|
menu.map.load=Karte von Datei laden...
|
||||||
menu.map.save=Karte in Datei speichern...
|
menu.map.save=Karte in Datei speichern...
|
||||||
@@ -37,3 +37,4 @@ dialog.error=Fehler
|
|||||||
dialog.question=Frage
|
dialog.question=Frage
|
||||||
port.must.be.integer=Der Port muss eine ganze Zahl sein
|
port.must.be.integer=Der Port muss eine ganze Zahl sein
|
||||||
map.doesnt.fit=Diese Karte passt nicht zu diesem Spiel
|
map.doesnt.fit=Diese Karte passt nicht zu diesem Spiel
|
||||||
|
map.invalid=Die Karte ist ung<6E>ltig
|
||||||
|
|||||||
Reference in New Issue
Block a user