diff --git a/.idea/.gitignore b/.idea/.gitignore index 13566b81b018ad684f3a35fee301741b2734c8f4..2fd2e631a061da0fd9d009491ab696e69f18960a 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -6,3 +6,5 @@ # Datasource local storage ignored files /dataSources/ /dataSources.local.xml +/misc.xml + diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000000000000000000000000000000000000..f07edf43fd5a289e4b6ae3c41e745c07417fb94b --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="DataSourceManagerImpl" format="xml" multifile-model="true"> + <data-source source="LOCAL" name="battleArena@battlearena.database.windows.net" uuid="7b1fc391-14cb-46cf-a8a0-29c091f02047"> + <driver-ref>azure.ms</driver-ref> + <synchronize>true</synchronize> + <jdbc-driver>com.microsoft.sqlserver.jdbc.SQLServerDriver</jdbc-driver> + <jdbc-url>jdbc:sqlserver://battlearena.database.windows.net:1433;database=battleArena;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30;</jdbc-url> + <working-dir>$ProjectFileDir$</working-dir> + </data-source> + </component> +</project> \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index e7a7ee4e1a8bb936f74453926c8d1206f86e405b..f33e38f0f5d3f09852522d1e2b2b2325f91a3785 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -7,7 +7,7 @@ </list> </option> </component> - <component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="openjdk-21" project-jdk-type="JavaSDK"> + <component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="21" project-jdk-type="JavaSDK"> <output url="file://$PROJECT_DIR$/out" /> </component> </project> \ No newline at end of file diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 0000000000000000000000000000000000000000..8641bbfdf2e2a8e1ae8a5ddca2037e037e9e7899 --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="SqlDialectMappings"> + <file url="file://$PROJECT_DIR$/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Scripts/DDL_Script_Oracle.sql" dialect="AZURE" /> + <file url="PROJECT" dialect="AZURE" /> + </component> +</project> \ No newline at end of file diff --git a/pom.xml b/pom.xml index 231758b8295c2602c5156431d7eec666619df078..4f37f2aaef6c006c1cdabb857ae7787128d71766 100644 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,13 @@ <scope>test</scope> </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-params</artifactId> + <version>5.10.0</version> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> @@ -51,6 +58,24 @@ <version>19.0.2.1</version> </dependency> + <dependency> + <groupId>com.oracle.database.jdbc</groupId> + <artifactId>ojdbc11</artifactId> + <version>23.3.0.23.09</version> + </dependency> + + <dependency> + <groupId>com.microsoft.sqlserver</groupId> + <artifactId>mssql-jdbc</artifactId> + <version>12.4.2.jre11</version> + </dependency> + + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.10.1</version> + </dependency> + </dependencies> <build> diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/GameSceneController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/GameSceneController.java index 513c8c606c6b4883bc6cb67f99b187c09332bf27..2d90bb00e2c3503261084d7acf6b1dfd98593c61 100644 --- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/GameSceneController.java +++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/GameSceneController.java @@ -108,4 +108,4 @@ public class GameSceneController implements Initializable { public int getScaledTileSize() { return scaledTileSize; } -} \ No newline at end of file +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/AccountType.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/AccountType.java new file mode 100644 index 0000000000000000000000000000000000000000..145d7a4f6f54bad787231fc80b276a2abaae261b --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/AccountType.java @@ -0,0 +1,9 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +public enum AccountType { + + NONE, + LOCAL, + ONLINE + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/AppSettings.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/AppSettings.java new file mode 100644 index 0000000000000000000000000000000000000000..24d7de8bba503c2d58df72b95d3de8901cd7a91b --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/AppSettings.java @@ -0,0 +1,22 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +public class AppSettings { + + private Double sfxVolume; + private int musicVolume; + + + public AppSettings(Double sfxVolume, int musicVolume) { + this.sfxVolume = sfxVolume; + this.musicVolume = musicVolume; + } + + public Double getSfxVolume() { + return sfxVolume; + } + + public int getMusicVolume() { + return musicVolume; + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/AzureDB.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/AzureDB.java new file mode 100644 index 0000000000000000000000000000000000000000..b138e76967b758555477fbde0c736ff98e2f7690 --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/AzureDB.java @@ -0,0 +1,258 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.CryptoException; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.SQLException; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities.CryptoUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.ArrayList; + +public class AzureDB implements ISQLDataBase { + + /*this class is only here for showcasing the interchangeability of the DBMS*/ + + private static String user=""; + private static String password=""; + private static String[] parts= new String[2]; + + static File encryptedFile = new File("src\\main\\resources\\database\\AzureDB_logindetails"); + + private static final Logger log = LogManager.getLogger(OracleDB.class); + + public static void getLoginData() throws CryptoException { + parts = CryptoUtils.decrypt(encryptedFile); + user = parts[0]; + password = parts[1]; + log.info("AzureDB_logindetails: user: " + user + " password: " + password); + } + + @Override + public Connection connect() throws SQLException { + try { + getLoginData(); + String url = "jdbc:sqlserver://battlearena.database.windows.net;encrypt=true;user=" + user + ";password=" + password + ";databaseName=battleArena;"; + + log.info("Connecting to the database!"); + Connection connection = DriverManager.getConnection(url); + log.info("Database connection test" + connection.getCatalog()); + + connection.setAutoCommit(true); + + return connection; + } + catch(Exception e){ + log.error(e); + throw new SQLException("SQL Connection Error! " + e.getMessage()); + } + } + + @Override + public ArrayList<MapData> getCoreMaps() throws SQLException { + try(Connection connection = connect()) { + ArrayList<MapData> newMaps = new ArrayList<MapData>(); + String sql = "SELECT * FROM CoreMaps"; + PreparedStatement stmt = connection.prepareStatement(sql); + + log.info("Sending SQL statement"); + ResultSet rs = stmt.executeQuery(); + + while(rs.next()){ + newMaps.add(new MapData(rs.getString("map_id"), rs.getString("map_name"), rs.getInt("map_width"), rs.getInt("map_height"), rs.getString("map_data"))); + } + log.info("SQL query successful"); + rs.close(); + stmt.close(); + return newMaps; + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error retrieving Coremaps! " + e.getMessage()); + } + } + + @Override + public ArrayList<MapInfo> getCommunityMapsList() throws SQLException { + try(Connection connection = connect()) { + ArrayList<MapInfo> tempList = new ArrayList<MapInfo>(); + String sql = "SELECT map_id, map_name, map_width, map_height, map_downloads FROM communitymaps"; + PreparedStatement stmt = connection.prepareStatement(sql); + + log.info("Sending SQL statement"); + ResultSet rs = stmt.executeQuery(); + + while(rs.next()){ + tempList.add(new MapInfo(rs.getString("map_id"), rs.getString("map_name"), rs.getInt("map_width"), rs.getInt("map_height"), rs.getInt("map_downloads"))); + } + rs.close(); + stmt.close(); + log.info("Community map names retrieved successfully"); + return tempList; + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error retrieving community map names! " + e.getMessage()); + } + } + + @Override + public MapData getCommunityMapByID(String mapID) throws SQLException { + try(Connection connection = connect()) { + String sql = "SELECT * FROM communitymaps WHERE map_ID = ?"; + PreparedStatement stmt = connection.prepareStatement(sql); + stmt.setString(1, mapID); + + log.info("Sending SQL statement"); + ResultSet rs = stmt.executeQuery(); + MapData mapChosen = new MapData("", "",0,0, ""); + if(rs.next() == false){ //if no data matches + throw new SQLException("No match on Database"); + } + while(rs.next()) { + mapChosen = new MapData(rs.getString("map_id"), rs.getString("map_name"), rs.getInt("map_width"), rs.getInt("map_height"), rs.getString("map_data")); + } + rs.close(); + stmt.close(); + log.info("Community map retrieved successfully"); + + String sql2 = "UPDATE communitymaps SET map_downloads = map_downloads + 1 WHERE map_id = ?"; + PreparedStatement stmt2 = connection.prepareStatement(sql2); + stmt2.setString(1, mapID); + stmt2.executeQuery(); + log.info("Sending SQL statement to update Download-Counter"); + stmt2.close(); + + return mapChosen; + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error retrieving community map! " + e.getMessage()); + } + } + + @Override + public void uploadCommunityMap(MapData map) throws SQLException { + try(Connection connection = connect()) { + String sql = "INSERT INTO communitymaps (map_id, map_name, map_width, map_height, map_data) VALUES (?, ?, ?, ?, ?)"; + PreparedStatement stmt = connection.prepareStatement(sql); + stmt.setString(1, map.getMapID()); + stmt.setString(2, map.getMapName()); + stmt.setInt(3, map.getMapWidth()); + stmt.setInt(4, map.getMapHeight()); + stmt.setString(5, map.getMapData()); + + log.info("Sending SQL statement"); + stmt.executeQuery(); + + stmt.close(); + log.info("Community Map uploaded successfully"); + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error uploading created community map! " + e.getMessage()); + } + } + + @Override + public void createPlayer(String playerName, String playerPW) throws SQLException { + try(Connection connection = connect()) { + String sql = "INSERT INTO players (player_name, player_pw, games_won, games_lost, kills, deaths, blocks_destroyed, ingame_time) VALUES (?, ?, 0, 0, 0, 0, 0, 0)"; + PreparedStatement stmt = connection.prepareStatement(sql); + stmt.setString(1, playerName); + stmt.setString(2, playerPW); + + log.info("Sending SQL statement"); + stmt.executeQuery(); + + stmt.close(); + log.info("Online account created successfully"); + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error creating online account! " + e.getMessage()); + } + } + + @Override + public String checkCredentials(String playerName) throws SQLException { + try(Connection connection = connect()) { + String sql = "SELECT player_pw FROM players WHERE player_name = ?"; + PreparedStatement stmt = connection.prepareStatement(sql); + stmt.setString(1, playerName); + + log.info("Sending SQL statement"); + ResultSet rs = stmt.executeQuery(); + + String password = ""; + while(rs.next()) { + password = rs.getString("player_pw"); + } + rs.close(); + stmt.close(); + log.info("Player credentials retrieved successfully"); + return password; + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error retrieving retrieving player credentials! " + e.getMessage()); + } + } + + @Override + public PlayerStatistics getStatistics(String playerName) throws SQLException { + try(Connection connection = connect()) { + String sql = "SELECT games_won, games_lost, kills, deaths, blocks_destroyed, ingame_time FROM players WHERE player_name = ?"; + PreparedStatement stmt = connection.prepareStatement(sql); + stmt.setString(1, playerName); + + log.info("Sending SQL statement"); + ResultSet rs = stmt.executeQuery(); + if(rs.next() == false){ //if no data matches + throw new SQLException("No match on Database"); + } + PlayerStatistics stats = new PlayerStatistics(0, 0, 0, 0, 0, 0); + while(rs.next()) { + stats = new PlayerStatistics(rs.getInt("games_won"), rs.getInt("games_lost"), rs.getInt("kills"), rs.getInt("deaths"), rs.getInt("blocks_destroyed"), rs.getInt("ingame_time")); + } + rs.close(); + stmt.close(); + log.info("Player statistics retrieved successfully"); + return stats; + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error retrieving player statistics! " + e.getMessage()); + } + } + + @Override + public void updatePlayerStats(PlayerStatistics stats, PlayerAccount account) throws SQLException { + try(Connection connection = connect()) { + String sql = "UPDATE players SET games_won = ?, games_lost = ?, kills = ?, deaths = ?, blocks_destroyed = ?, ingame_time = ? WHERE player_name = ?"; + PreparedStatement stmt = connection.prepareStatement(sql); + stmt.setInt(1, stats.getGamesWon()); + stmt.setInt(2, stats.getGamesLost()); + stmt.setInt(3, stats.getKills()); + stmt.setInt(4, stats.getDeaths()); + stmt.setInt(5, stats.getBlocksDestroyed()); + stmt.setInt(6, stats.getGameTime()); + stmt.setString(7, account.getPlayerName()); + + log.info("Sending SQL statement"); + stmt.executeQuery(); + + stmt.close(); + log.info("Player statistics updated successfully"); + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error updating player statistics! " + e.getMessage()); + } + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/CryptoException.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/CryptoException.java new file mode 100644 index 0000000000000000000000000000000000000000..1bb0c30885d3d243bf25ff82449b3c33fc7dc72b --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/CryptoException.java @@ -0,0 +1,7 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions; + +public class CryptoException extends Exception{ + public CryptoException(String message, Throwable throwable) { + super(message, throwable); + } +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/DatabaseException.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/DatabaseException.java new file mode 100644 index 0000000000000000000000000000000000000000..57a4b7f978103f55a4a83525db1353be7b1fe4fb --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/DatabaseException.java @@ -0,0 +1,12 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions; + +public class DatabaseException extends Exception{ + + public DatabaseException() {} + + public DatabaseException(String message2) + { + super(message2); + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/GSONException.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/GSONException.java new file mode 100644 index 0000000000000000000000000000000000000000..f16aa2d2831903fca6ccbd1555c798b53132f872 --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/GSONException.java @@ -0,0 +1,12 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions; + +public class GSONException extends Exception{ + + public GSONException() {} + + public GSONException(String message2) + { + super(message2); + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/ParserException.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/ParserException.java new file mode 100644 index 0000000000000000000000000000000000000000..27bd887ed9a7b5cb604d63e2194c818c91cae56a --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/ParserException.java @@ -0,0 +1,12 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions; + +public class ParserException extends Exception{ + + public ParserException() {} + + public ParserException(String message2) + { + super(message2); + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/SQLException.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/SQLException.java new file mode 100644 index 0000000000000000000000000000000000000000..adbdfa7fac0321fd39687bd957c7f05f542aaaa9 --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Exceptions/SQLException.java @@ -0,0 +1,12 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions; + +public class SQLException extends Exception{ + + public SQLException() {} + + public SQLException(String message2) + { + super(message2); + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/GsonHandler.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/GsonHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..b330be1f110d65125e9dfb9b413adcac5c90a10e --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/GsonHandler.java @@ -0,0 +1,137 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.GSONException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.FileReader; +import java.io.FileWriter; +import java.lang.reflect.Type; +import java.util.ArrayList; + +public class GsonHandler { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + private static final Logger log = LogManager.getLogger(GsonHandler.class); + Type mapDataType = new TypeToken<ArrayList<MapData>>(){}.getType(); + Type playerStatsType = new TypeToken<PlayerStatistics>(){}.getType(); + Type settingsType = new TypeToken<AppSettings>(){}.getType(); + Type accountType = new TypeToken<PlayerAccount>(){}.getType(); + + private final String filePathCoreMaps = "src/main/resources/maps/coreMaps.json"; + private final String filePathCommunityMaps = "src/main/resources/maps/communityMaps.json"; + private final String filePathPlayerStats = "src/main/resources/player/playerStatsLocal.json"; + private final String filePathPlayerAccount = "src/main/resources/player/playerAccount.json"; + private final String filePathSettings = "src/main/resources/player/appSettings.json"; + + public ArrayList<MapData> loadMaps(MapType type) throws GSONException { + String filePath; + if(type == MapType.COREMAP){ + filePath = filePathCoreMaps; + } + else{ + filePath = filePathCommunityMaps; + } + try (FileReader reader = new FileReader(filePath)) { + ArrayList<MapData> maps = gson.fromJson(reader, mapDataType); + log.info("GSON - Maps successfully loaded from JSON"); + return maps; + } catch (Exception e) { + log.info(e); + log.info("GSON - Loading maps from JSON failed"); + throw new GSONException("Error loading maps!"); + } + } + + public void saveMaps(ArrayList<MapData> maps, MapType type) throws GSONException { + String filePath; + if(type == MapType.COREMAP){ + filePath = filePathCoreMaps; + } + else{ + filePath = filePathCommunityMaps; + } + try (FileWriter writer = new FileWriter(filePath)) { + gson.toJson(maps, writer); + log.info("GSON - Maps successfully saved to JSON"); + } catch (Exception e) { + log.info(e); + log.info("GSON - Saving maps to JSON failed"); + throw new GSONException("Error saving maps!"); + } + } + + public PlayerStatistics loadStats() throws GSONException { + try (FileReader reader = new FileReader(filePathPlayerStats)) { + PlayerStatistics stats = gson.fromJson(reader, playerStatsType); + log.info("GSON - Player statistics successfully loaded from JSON"); + return stats; + } catch (Exception e) { + log.info(e); + log.info("GSON - Loading player statistics from JSON failed"); + throw new GSONException("Error loading player statistics!"); + } + } + + public void saveStats(PlayerStatistics stats) throws GSONException { + try (FileWriter writer = new FileWriter(filePathPlayerStats)) { + gson.toJson(stats, writer); + log.info("GSON - Player statistics successfully saved to JSON"); + } catch (Exception e) { + log.info(e); + log.info("GSON - Saving player statistics to JSON failed"); + throw new GSONException("Error saving player statistics!"); + } + } + + public AppSettings loadSettings() throws GSONException { + try (FileReader reader = new FileReader(filePathSettings)) { + AppSettings settings = gson.fromJson(reader, settingsType); + log.info("GSON - Settings successfully loaded from JSON"); + return settings; + } catch (Exception e) { + log.info(e); + log.info("GSON - Loading settings from JSON failed"); + throw new GSONException("Error Loading settings!"); + } + } + + public void saveSettings(AppSettings settings) throws GSONException { + try (FileWriter writer = new FileWriter(filePathSettings)) { + gson.toJson(settings, writer); + log.info("GSON - Settings successfully saved to JSON"); + } catch (Exception e) { + log.info(e); + log.info("GSON - Saving settings to JSON failed"); + throw new GSONException("Error saving settings!"); + } + } + + public PlayerAccount loadAccount() throws GSONException { + try (FileReader reader = new FileReader(filePathPlayerAccount)) { + PlayerAccount account = gson.fromJson(reader, accountType); + log.info("GSON - Player account information successfully loaded from JSON"); + return account; + } catch (Exception e) { + log.info(e); + log.info("GSON - Loading player account information from JSON failed"); + throw new GSONException("Error loading player account information!"); + } + } + + public void saveAccount(PlayerAccount account) throws GSONException { + try (FileWriter writer = new FileWriter(filePathPlayerAccount)) { + gson.toJson(account, writer); + log.info("GSON - Player account information successfully saved to JSON"); + } catch (Exception e) { + log.info(e); + log.info("GSON - Saving player account information to JSON failed"); + throw new GSONException("Error loading player account information!"); + } + } + + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ISQLDataBase.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ISQLDataBase.java new file mode 100644 index 0000000000000000000000000000000000000000..dd7bb2f0eb72ddd6eac0a59ce72e0654f522a3ab --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ISQLDataBase.java @@ -0,0 +1,23 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.SQLException; + +import java.sql.Connection; +import java.util.ArrayList; + +public interface ISQLDataBase { + + //Establish Connection + Connection connect() throws SQLException; + + //CRUD Operations in SQL + ArrayList<MapData> getCoreMaps() throws SQLException; + ArrayList<MapInfo> getCommunityMapsList() throws SQLException; + MapData getCommunityMapByID(String mapID) throws SQLException; + void uploadCommunityMap(MapData map) throws SQLException; + void createPlayer(String playerName, String playerPW) throws SQLException; + String checkCredentials(String playerName) throws SQLException; + PlayerStatistics getStatistics(String playerName) throws SQLException; + void updatePlayerStats(PlayerStatistics stats, PlayerAccount account) throws SQLException; + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/MapData.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/MapData.java new file mode 100644 index 0000000000000000000000000000000000000000..2a88a714ec211cc081dfb511673568de0d2ba6fd --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/MapData.java @@ -0,0 +1,38 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +public class MapData { + private String mapID; + private String mapName; + private int mapWidth; //included for future use (to allow maps of different size) + private int mapHeight; //included for future use (to allow maps of different size) + private String mapData; + + protected MapData(String mapID, String mapName, int mapWidth, int mapHeight, String mapData) { + this.mapID = mapID; + this.mapName = mapName; + this.mapWidth = mapWidth; + this.mapHeight = mapHeight; + this.mapData = mapData; + } + + public String getMapID() { + return mapID; + } + + public String getMapName() { + return mapName; + } + + public int getMapWidth() { + return mapWidth; + } + + public int getMapHeight() { + return mapHeight; + } + + public String getMapData() { + return mapData; + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/MapInfo.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/MapInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..17fcfdfc65a8777e255f3501ed59e103bfb13f3b --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/MapInfo.java @@ -0,0 +1,40 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +public class MapInfo { + + private String mapID; + private String mapName; + private int mapWidth; //included for future use (to allow maps of different size) + private int mapHeight; //included for future use (to allow maps of different size) + private int mapDownloads; //only used for communityMapsList + + protected MapInfo(String mapID, String mapName, int mapWidth, int mapHeight, int mapDownloads) { + this.mapID = mapID; + this.mapName = mapName; + this.mapWidth = mapWidth; + this.mapHeight = mapHeight; + this.mapDownloads = mapDownloads; + } + + public String getMapID() { + return mapID; + } + + public String getMapName() { + return mapName; + } + + public int getMapWidth() { + return mapWidth; + } + + public int getMapHeight() { + return mapHeight; + } + + public int getMapDownloads() { + return mapDownloads; + } + +} + diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/MapType.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/MapType.java new file mode 100644 index 0000000000000000000000000000000000000000..d7738b3c5205d4f217e2a27f0e88578cc34f6fa1 --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/MapType.java @@ -0,0 +1,8 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +public enum MapType { + + COREMAP, + COMMUNITYMAP + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/OracleDB.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/OracleDB.java new file mode 100644 index 0000000000000000000000000000000000000000..070e42d3bbd2fcbed93881fea80a7e5aac077733 --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/OracleDB.java @@ -0,0 +1,257 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities.CryptoUtils; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.CryptoException; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.SQLException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.sql.*; +import java.util.ArrayList; + +import oracle.jdbc.pool.OracleDataSource; + + +public class OracleDB implements ISQLDataBase { + private static String user=""; + private static String password=""; + private static String[] parts= new String[2]; + + static File encryptedFile = new File("src\\main\\resources\\database\\OracleDB_logindetails"); + + //static File encryptedFile = new File("src\\main\\resources\\database\\document.encrypted"); + //static File decryptedFile = new File("src\\main\\resources\\database\\document.decrypted"); + + private static final Logger log = LogManager.getLogger(OracleDB.class); + public static void getLoginData() throws CryptoException { + parts = CryptoUtils.decrypt(encryptedFile); + user = parts[0]; + password = parts[1]; + //log.info("OracleDB_logindetails: user: " + user + " password: " + password); + } + + @Override + public Connection connect() throws SQLException { + try { + getLoginData(); + OracleDataSource ods = new OracleDataSource(); + ods.setURL("jdbc:oracle:thin:@(description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1521)(host=adb.eu-frankfurt-1.oraclecloud.com))(connect_data=(service_name=g093caf2cf1fea4_battlearena_high.adb.oraclecloud.com))(security=(ssl_server_dn_match=yes)))"); + ods.setUser(user); + ods.setPassword(password); + Connection conn = ods.getConnection(); + + log.info("Connecting to the database!"); + + return conn; + } + catch(Exception e){ + log.error(e); + throw new SQLException("SQL connection error! " + e.getMessage()); + } + } + + @Override + public ArrayList<MapData> getCoreMaps() throws SQLException { + try(Connection connection = connect()) { + ArrayList<MapData> newMaps = new ArrayList<MapData>(); + String sql = "SELECT * FROM battlearenadata.coremaps"; + PreparedStatement stmt = connection.prepareStatement(sql); + + log.info("Sending SQL statement"); + ResultSet rs = stmt.executeQuery(); + + while(rs.next()){ + newMaps.add(new MapData(rs.getString("map_id"), rs.getString("map_name"), rs.getInt("map_width"), rs.getInt("map_height"), rs.getString("map_data"))); + } + rs.close(); + stmt.close(); + log.info("Coremaps retrieved successfully"); + return newMaps; + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error retrieving coremaps! " + e.getMessage()); + } + } + + @Override + public ArrayList<MapInfo> getCommunityMapsList() throws SQLException { + try(Connection connection = connect()) { + ArrayList<MapInfo> tempList = new ArrayList<MapInfo>(); + String sql = "SELECT map_id, map_name, map_width, map_height, map_downloads FROM battlearenadata.communitymaps"; + PreparedStatement stmt = connection.prepareStatement(sql); + + log.info("Sending SQL statement"); + ResultSet rs = stmt.executeQuery(); + + while(rs.next()){ + tempList.add(new MapInfo(rs.getString("map_id"), rs.getString("map_name"), rs.getInt("map_width"), rs.getInt("map_height"), rs.getInt("map_downloads"))); + } + rs.close(); + stmt.close(); + log.info("Community map names retrieved successfully"); + return tempList; + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error retrieving community map names! " + e.getMessage()); + } + } + + @Override + public MapData getCommunityMapByID(String mapID) throws SQLException { + try(Connection connection = connect()) { + String sql = "SELECT * FROM battlearenadata.communitymaps WHERE map_ID = ?"; + PreparedStatement stmt = connection.prepareStatement(sql); + stmt.setString(1, mapID); + + log.info("Sending SQL statement"); + ResultSet rs = stmt.executeQuery(); + MapData mapChosen = new MapData("", "",0,0, ""); + if(rs.next() == false){ //if no data matches + throw new SQLException("No match on Database"); + } + while(rs.next()) { + mapChosen = new MapData(rs.getString("map_id"), rs.getString("map_name"), rs.getInt("map_width"), rs.getInt("map_height"), rs.getString("map_data")); + } + rs.close(); + stmt.close(); + log.info("Community map retrieved successfully"); + + String sql2 = "UPDATE battlearenadata.communitymaps SET map_downloads = map_downloads + 1 WHERE map_id = ?"; + PreparedStatement stmt2 = connection.prepareStatement(sql2); + stmt2.setString(1, mapID); + stmt2.executeQuery(); + log.info("Sending SQL statement to update Download-Counter"); + stmt2.close(); + + return mapChosen; + } + catch(Exception e){ + log.error(e.getMessage()); + throw new SQLException("Error retrieving community map! " + e.getMessage()); + } + } + + @Override + public void uploadCommunityMap(MapData map) throws SQLException { + try(Connection connection = connect()) { + String sql = "INSERT INTO battlearenadata.communitymaps (map_id, map_name, map_width, map_height, map_data) VALUES (?, ?, ?, ?, ?)"; + PreparedStatement stmt = connection.prepareStatement(sql); + stmt.setString(1, map.getMapID()); + stmt.setString(2, map.getMapName()); + stmt.setInt(3, map.getMapWidth()); + stmt.setInt(4, map.getMapHeight()); + stmt.setString(5, map.getMapData()); + + log.info("Sending SQL statement"); + stmt.executeQuery(); + + stmt.close(); + log.info("Community Map uploaded successfully"); + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error uploading created community map! " + e.getMessage()); + } + } + + @Override + public void createPlayer(String playerName, String playerPW) throws SQLException { + try(Connection connection = connect()) { + String sql = "INSERT INTO battlearenadata.players (player_name, player_pw, games_won, games_lost, kills, deaths, blocks_destroyed, ingame_time) VALUES (?, ?, 0, 0, 0, 0, 0, 0)"; + PreparedStatement stmt = connection.prepareStatement(sql); + stmt.setString(1, playerName); + stmt.setString(2, playerPW); + + log.info("Sending SQL statement"); + stmt.executeQuery(); + + stmt.close(); + log.info("Online account created successfully"); + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error creating online account! " + e.getMessage()); + } + } + + @Override + public String checkCredentials(String playerName) throws SQLException { + try(Connection connection = connect()) { + String sql = "SELECT player_pw FROM battlearenadata.players WHERE player_name = ?"; + PreparedStatement stmt = connection.prepareStatement(sql); + stmt.setString(1, playerName); + + log.info("Sending SQL statement"); + ResultSet rs = stmt.executeQuery(); + + String password = ""; + while(rs.next()) { + password = rs.getString("player_pw"); + } + rs.close(); + stmt.close(); + log.info("Player credentials retrieved successfully"); + return password; + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error retrieving retrieving player credentials! " + e.getMessage()); + } + } + + @Override + public PlayerStatistics getStatistics(String playerName) throws SQLException { + try(Connection connection = connect()) { + String sql = "SELECT games_won, games_lost, kills, deaths, blocks_destroyed, ingame_time FROM battlearenadata.players WHERE player_name = ?"; + PreparedStatement stmt = connection.prepareStatement(sql); + stmt.setString(1, playerName); + + log.info("Sending SQL statement"); + ResultSet rs = stmt.executeQuery(); + if(rs.next() == false){ //if no data matches + throw new SQLException("No match on database"); + } + PlayerStatistics stats = new PlayerStatistics(0, 0, 0, 0, 0, 0); + while(rs.next()) { + stats = new PlayerStatistics(rs.getInt("games_won"), rs.getInt("games_lost"), rs.getInt("kills"), rs.getInt("deaths"), rs.getInt("blocks_destroyed"), rs.getInt("ingame_time")); + } + rs.close(); + stmt.close(); + log.info("Player statistics retrieved successfully"); + return stats; + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error retrieving player statistics! " + e.getMessage()); + } + } + + @Override + public void updatePlayerStats(PlayerStatistics stats, PlayerAccount account) throws SQLException { + try(Connection connection = connect()) { + String sql = "UPDATE battlearenadata.players SET games_won = ?, games_lost = ?, kills = ?, deaths = ?, blocks_destroyed = ?, ingame_time = ? WHERE player_name = ?"; + PreparedStatement stmt = connection.prepareStatement(sql); + stmt.setInt(1, stats.getGamesWon()); + stmt.setInt(2, stats.getGamesLost()); + stmt.setInt(3, stats.getKills()); + stmt.setInt(4, stats.getDeaths()); + stmt.setInt(5, stats.getBlocksDestroyed()); + stmt.setInt(6, stats.getGameTime()); + stmt.setString(7, account.getPlayerName()); + + log.info("Sending SQL statement"); + stmt.executeQuery(); + + stmt.close(); + log.info("Player statistics updated successfully"); + } + catch(Exception e){ + log.error(e); + throw new SQLException("Error updating player statistics! " + e.getMessage()); + } + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Persistence.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Persistence.java new file mode 100644 index 0000000000000000000000000000000000000000..d8dd5bf0303003f3ab525b04a8b2ea6db4588403 --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Persistence.java @@ -0,0 +1,286 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.GSONException; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.ParserException; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.SQLException; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities.HashGenerator; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.DatabaseException; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities.Parser; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; + +import java.util.ArrayList; + +public class Persistence { + + private static final Logger log = LogManager.getLogger(Persistence.class); + private static final Persistence persistenceSingleton = new Persistence(); + private final GsonHandler gsonHandler = new GsonHandler(); + protected OracleDB db = new OracleDB(); //evtl. Methoden von OracleDB static machen und von GSON Handler + protected ArrayList<MapData> coreMaps; + protected ArrayList<MapData> communityMaps; + protected PlayerStatistics statistics; + protected PlayerAccount account; + private AppSettings settings; + + + + private Persistence (){} + + public static Persistence getInstance(){ + return persistenceSingleton; + } + + public void loadCoreMaps() throws DatabaseException { + try { + coreMaps = gsonHandler.loadMaps(MapType.COREMAP); + log.info("Core-Maps successfully loaded from file"); + } + catch(Exception e){ + log.error(e); + throw new DatabaseException("Loading core maps from local storage failed!"); + } + } + + public void loadCommunityMaps() throws DatabaseException { + try { + communityMaps = gsonHandler.loadMaps(MapType.COMMUNITYMAP); + log.info("Community-Maps successfully loaded from file"); + } + catch(Exception e){ + log.error(e); + throw new DatabaseException("Loading community maps from local storage failed!"); + } + } + + public void updateCoreMaps() throws DatabaseException { + try { + coreMaps = db.getCoreMaps(); + gsonHandler.saveMaps(coreMaps, MapType.COREMAP); + log.info("Maps successfully updated from SQL-Server"); + } + catch(Exception e){ + log.error(e); + if(e.getMessage().contains("ORA-17868") | e.getMessage().contains("ORA-01017")){ + throw new DatabaseException("No connection to SQL server!"); + } + else{ + throw new DatabaseException("Unknown Database Error. Retrieving Core-Map update failed!"); + } + } + } + + public void getCommunityMap(String mapID) throws DatabaseException { + for(int i = 0; communityMaps.size() > i; i++){ + if(communityMaps.get(i).getMapID().equals(mapID)){ + throw new DatabaseException("Identical map already saved locally. See map name: " + communityMaps.get(i).getMapID()); + } + } + try { + communityMaps.add(db.getCommunityMapByID(mapID)); + gsonHandler.saveMaps(communityMaps, MapType.COMMUNITYMAP); + log.info("Community Map successfully retrieved from SQL-Server!"); + } + catch(Exception e){ + log.error(e); + if(e.getMessage().contains("ORA-17868") | e.getMessage().contains("ORA-01017")){ + throw new DatabaseException("No connection to SQL server!"); + } + else if(e.getMessage().equals("No match on Database")){ + throw new DatabaseException("No map existing for mapID: " + mapID); + } + else{ + throw new DatabaseException("Unknown Database Error. Retrieving Community-Map failed!"); + } + } + } + + public void saveCreatedMapLocally(MapData map) throws DatabaseException { + try { + for(int i = 0; communityMaps.size() > i; i++){ + if(communityMaps.get(i).getMapID().equals(map.getMapID())){ + throw new DatabaseException("Identical map already saved locally. See map name: " + communityMaps.get(i).getMapID()); + } + } + communityMaps.add(map); + gsonHandler.saveMaps(communityMaps, MapType.COMMUNITYMAP); + log.info("Newly created map stored successfully in JSON"); + } + catch(Exception e){ + log.error(e); + if(e.getMessage().contains("Identical map already saved") | e.getMessage().contains("ORA-01017")){ + throw new DatabaseException(e.getMessage()); + } + else{ + throw new DatabaseException("Unknown Database Error. Saving newly created Community-Map locally failed!"); + } + } + } + + public void uploadCreatedMap(MapData map) throws DatabaseException { + try { + db.uploadCommunityMap(map); + log.info("Newly created Community-Map successfully published!"); + } + catch(Exception e){ + log.error(e); + if(e.getMessage().contains("ORA-17868") | e.getMessage().contains("ORA-01017")){ + throw new DatabaseException("No connection to SQL server!"); + } + else if(e.getMessage().contains("ORA-00001")){ + throw new DatabaseException("Map already existing on communityMaps server!\n Look for mapID: " + map.getMapID()); + } + else{ + throw new DatabaseException("Unknown Database Error. Saving to SQL communityMap server failed!"); + } + } + } + + public void loadSettings() throws DatabaseException { + try { + settings = gsonHandler.loadSettings(); + log.info("Application settings successfully loaded from file"); + } + catch(Exception e){ + log.error(e); + throw new DatabaseException("Loading settings from local storage failed!"); + } + } + + public void createAccount(String playerName, String password, AccountType type) throws DatabaseException { + try { + Parser.usernameValid(playerName); + if(type == AccountType.LOCAL) { + account = new PlayerAccount(playerName, "", type); + } + else if(type == AccountType.ONLINE) { + Parser.passwordValid(password); + String hashedPassword = HashGenerator.hashAndHex(password); + db.createPlayer(playerName, hashedPassword); + account = new PlayerAccount(playerName, hashedPassword, type); + } + else{ + throw new DatabaseException("Corrupted Account-Type. Please restart game."); + } + gsonHandler.saveAccount(account); + } + catch(ParserException e){ + log.error(e); + throw new DatabaseException(e.getMessage()); + } + catch(SQLException e){ + log.error(e); + if(e.getMessage().contains("ORA-17868") | e.getMessage().contains("ORA-01017")){ + throw new DatabaseException("No connection to SQL server! Do you want to create a local account?"); + } + else if(e.getMessage().equals("ORA-00001")){ + throw new DatabaseException("Player name already taken. Please change name, use local account or login with existing account!"); + } + else{ + throw new DatabaseException("Connection to SQL server failed! Do you want to create a local account?"); + } + } + catch(Exception e){ + log.error(e); + throw new DatabaseException("Error creating account. Please restart game or download game files again."); + } + } + + public void loadPlayerAccount() throws DatabaseException { + try { + gsonHandler.loadAccount(); + } + catch(Exception e){ + log.error(e); + throw new DatabaseException("Loading player account data from local storage failed!"); + } + } + + public void verifyPlayerAccount() throws DatabaseException { + try { + if (account.getAccountType() == AccountType.NONE) { + throw new DatabaseException("Must create playerAccount first"); + } else if (account.getAccountType() == AccountType.LOCAL) { + Parser.usernameValid(account.getPlayerName()); + } else if (account.getAccountType() == AccountType.ONLINE) { + Parser.usernameValid(account.getPlayerName()); + Parser.sha1HashValid(account.getAccountPassword()); + if (!(account.getAccountPassword().equals(db.checkCredentials(account.getPlayerName())))){ + throw new DatabaseException("Locally stored password does not match online password. Please reenter credentials!"); + } + } + else{ + throw new DatabaseException("AccountType invalid - accountData corrupted! Please create new Account or login with existing!"); + } + } + catch(ParserException e){ + log.error(e); + throw new DatabaseException(e.getMessage()); + } + catch(SQLException e){ + log.error(e); + if(e.getMessage().contains("ORA-17868") | e.getMessage().contains("ORA-01017")){ + throw new DatabaseException("No connection to SQL server! Do you want to continue without tracking statistics?"); + } + else if(e.getMessage().contains("No match on Database")){ + throw new DatabaseException("No entry for player name " + account.getPlayerName() + " on SQL server. Please create account or login with different username!"); + } + else{ + throw new DatabaseException("Connection to SQL server failed! Do you want to continue without tracking statistics"); + } + } + catch(Exception e){ + log.error(e); + throw new DatabaseException("Loading player account data from local storage failed! Please create new account!"); + } + } + + public void loadPlayerStatistics() throws DatabaseException { + try { + if (account.getAccountType() == AccountType.LOCAL) { + statistics = gsonHandler.loadStats(); + } else { + statistics = db.getStatistics(account.getPlayerName()); + } + } + catch(SQLException e){ + log.error(e); + if(e.getMessage().contains("ORA-17868") | e.getMessage().contains("ORA-01017")){ + throw new DatabaseException("No connection to SQL server!"); + } + else{ + throw new DatabaseException("Unknown Database Error. Retrieving statistics from SQL server failed!"); + } + } + catch(GSONException e){ + log.error(e); + throw new DatabaseException(e.getMessage()); + } + } + + public void updatePlayerStatistics(int kills, int deaths, int gameTime, boolean gameWon){ //after game round + statistics.setKills(statistics.getKills() + kills); + statistics.setDeaths(statistics.getDeaths() + deaths); + statistics.setGameTime(statistics.getGameTime() + gameTime); + if(gameWon){ + statistics.setGamesWon(statistics.getGamesWon() + 1); + } + else{ + statistics.setGamesWon(statistics.getGamesLost() + 1); + } + } + + public void savePlayerStatistics(){ //on shutdown of game + try { + if (account.getAccountType() == AccountType.LOCAL) { + gsonHandler.saveStats(statistics); + } else if (account.getAccountType() == AccountType.ONLINE) { + db.updatePlayerStats(statistics, account); + } + } + catch(Exception e){ + log.error(e); + } + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/PlayerAccount.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/PlayerAccount.java new file mode 100644 index 0000000000000000000000000000000000000000..a028edd30e66fc1116615efb7764503e3746469a --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/PlayerAccount.java @@ -0,0 +1,28 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +public class PlayerAccount { + + private String playerName; + private String accountPassword; //only used for Online-Account; "" for local account + private AccountType accountType; + + + public PlayerAccount(String playerName, String accountPassword, AccountType accountType) { + this.playerName = playerName; + this.accountPassword = accountPassword; + this.accountType = accountType; + } + + public String getPlayerName() { + return playerName; + } + + public String getAccountPassword() { + return accountPassword; + } + + public AccountType getAccountType() { + return accountType; + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/PlayerStatistics.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/PlayerStatistics.java new file mode 100644 index 0000000000000000000000000000000000000000..532324238dd5b1b7a19c8de5a0555bc3e2c83fba --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/PlayerStatistics.java @@ -0,0 +1,74 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; + +public class PlayerStatistics { + private static final Logger log = LogManager.getLogger(PlayerStatistics.class); + + private int gamesLost = 0; + private int gamesWon = 0; + private int kills = 0; + private int deaths = 0; + private int blocksDestroyed = 0; + private int gameTime = 0; + + public PlayerStatistics(int gamesLost, int gamesWon, int kills, int deaths, int blocksDestroyed, int gameTime) { + this.gamesLost = gamesLost; + this.gamesWon = gamesWon; + this.kills = kills; + this.deaths = deaths; + this.blocksDestroyed = blocksDestroyed; + this.gameTime = gameTime; + } + + + public int getGamesLost() { + return gamesLost; + } + + public void setGamesLost(int gamesLost) { + this.gamesLost = gamesLost; + } + + public int getGamesWon() { + return gamesWon; + } + + public void setGamesWon(int gamesWon) { + this.gamesWon = gamesWon; + } + + public int getKills() { + return kills; + } + + public void setKills(int kills) { + this.kills = kills; + } + + public int getDeaths() { + return deaths; + } + + public void setDeaths(int deaths) { + this.deaths = deaths; + } + + public int getBlocksDestroyed() { + return blocksDestroyed; + } + + public void setBlocksDestroyed(int blocksDestroyed) { + this.blocksDestroyed = blocksDestroyed; + } + + public int getGameTime() { + return gameTime; + } + + public void setGameTime(int gameTime) { + this.gameTime = gameTime; + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/RuntimeInfo.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/RuntimeInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..641449a5164e3aaa72e5aef97324569ec1c7b3c2 --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/RuntimeInfo.java @@ -0,0 +1,89 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes; + +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.ParserException; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities.HashGenerator; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities.Parser; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; + +public class RuntimeInfo { + + private static final Logger log = LogManager.getLogger(RuntimeInfo.class); + private static final RuntimeInfo runtimeInfoSingleton = new RuntimeInfo(); + private final Persistence persistenceInst = Persistence.getInstance(); + protected ArrayList<String> coreMapsListLocal; //for drop-down list + protected ArrayList<String> communityMapsListLocal; //for drop-down list + protected ArrayList<MapInfo> communityMapsListRemote; //for community map browser + protected String mapDataGame; + protected boolean offlineMode; //if Account-Type is online but no SQL connection: start game without stats tracking + + + private RuntimeInfo(){}; + + public static RuntimeInfo getInstance(){ + return runtimeInfoSingleton; + } + + public String getMapDataGame() { + return mapDataGame; + } + + public MapData createMap(String mapName, String mapData) throws ParserException { + try { + Parser.mapDataValid(mapData); + Parser.mapNameValid(mapName); + return new MapData(HashGenerator.hashAndHex(mapData), mapName, 18, 18, mapData); + } + catch(Exception e){ + log.error(e); + throw new ParserException(e.getMessage()); + } + } + + public void setGameMap(String mapSelected, boolean choseCoremaps){ + String mapID = mapSelected.substring(mapSelected.indexOf("(") + 1, mapSelected.length() - 1); + + if(choseCoremaps) { + for (int index = 0; index < persistenceInst.coreMaps.size(); index++) { + if (persistenceInst.coreMaps.get(index).getMapID().equals(mapID)) { + mapDataGame = persistenceInst.coreMaps.get(index).getMapID(); + } + } + } + else { + for (int index = 0; index < persistenceInst.communityMaps.size(); index++) { + if (persistenceInst.communityMaps.get(index).getMapID().equals(mapID)) { + mapDataGame = persistenceInst.coreMaps.get(index).getMapID(); + } + } + } + } + + public void createCoreMapsList(){ //for dropdown list in "create" scene + coreMapsListLocal = new ArrayList<String>(); + for(int i = 0; i < persistenceInst.coreMaps.size(); i++){ + coreMapsListLocal.add(persistenceInst.coreMaps.get(i).getMapName() + " (" + persistenceInst.coreMaps.get(i).getMapID() + ")"); + } + } + + public void createLocalCommunityMapsList(){ //for dropdown list in "create" scene + communityMapsListLocal = new ArrayList<String>(); + for (int i = 0; i < persistenceInst.communityMaps.size(); i++) { + communityMapsListLocal.add(persistenceInst.communityMaps.get(i).getMapName() + " (" + persistenceInst.communityMaps.get(i).getMapID() + ")"); + } + } + + public void createRemoteCommunityMapsList(){ //for Map-Browser + try { + communityMapsListRemote = persistenceInst.db.getCommunityMapsList(); + log.info("MapList successfully retrieved from server!"); + //log.info(communityMapsListRemote.get(0).getMapName()); //for testing purposes + } + catch(Exception e){ + log.error(e); + } + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/CryptoUtils.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/CryptoUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..757543af9f7227b44495bed77f991b06ca34716a --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/CryptoUtils.java @@ -0,0 +1,159 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities; +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.CryptoException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.*; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.SecretKeySpec; + +import java.nio.charset.StandardCharsets; + + +public class CryptoUtils{ + private static String parts[] = new String[2]; + private static final String ALGORITHM = "AES"; + private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding"; + private static String key = "Peters Olivenöl"; + private static String encrypted_as_word = "encrypted;"; + private static boolean alreadyencrypted = false; + private static boolean multipleencryptions = false; + private static int encryptionreturn; + + private static final Logger log = LogManager.getLogger(CryptoUtils.class); + + + public static int encrypt(File inputFile, boolean multipleencryptions) throws CryptoException { + alreadyencrypted = check_if_file_already_encrypted(inputFile); + if(multipleencryptions){ + doCrypto(Cipher.ENCRYPT_MODE, key, inputFile); + log.info("This File can be encrypted multiple times"); + return encryptionreturn = 0; + } + else if(!alreadyencrypted && !multipleencryptions){ + doCrypto(Cipher.ENCRYPT_MODE, key, inputFile); + log.info("This File can only be encryptet once and this is now!"); + return encryptionreturn = 1; + }else { + log.info("This file is already encrypted and doesnt need to be encrypted anymore! " + inputFile); + return encryptionreturn = 2; + } + } + + public static String[] decrypt(File inputFile) throws CryptoException { + doCrypto(Cipher.DECRYPT_MODE, key, inputFile); + return parts; + } + + private static String[] doCrypto(int cipherMode, String key, File inputFile) throws CryptoException { + try { + Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM); + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + cipher.init(cipherMode, secretKey); + + FileInputStream inputStream = new FileInputStream(inputFile); + byte[] inputBytes = new byte[(int) inputFile.length()]; + inputStream.read(inputBytes); //liest from inputstream into BufferArray + + byte[] outputBytes = cipher.doFinal(inputBytes); + + String completeString = new String(outputBytes, StandardCharsets.UTF_8); + //log.info("completeString/outputBytes: " + completeString); + parts = completeString.split(";"); + + if(cipherMode == Cipher.ENCRYPT_MODE){ + FileOutputStream outputStream = new FileOutputStream(inputFile); + outputStream.write(outputBytes);//outputBytes + outputStream.close(); + multipleencryptions = true; + } + inputStream.close(); + + } catch (NoSuchPaddingException | NoSuchAlgorithmException + | InvalidKeyException | BadPaddingException + | IllegalBlockSizeException | IOException ex) { + throw new CryptoException("Error encrypting/decrypting file", ex); + } + return parts; + } + public static boolean check_if_file_already_encrypted(File inputFile){ + String filename = inputFile.getName(); + //log.info("filename: " + filename); + if(filename.contains(encrypted_as_word)){ + return alreadyencrypted =true; + } + inputFile.renameTo(new File("src\\main\\resources\\database\\" + encrypted_as_word + filename)); + return alreadyencrypted = false; + } + + /*public static String[] doCrypto(int cipherMode, String key, File inputFile) throws CryptoException { + try { + + String filename = inputFile.getName(); + //String encrypted_as_word = "encrypted;"; + byte[] encryptet_as_word_as_bytes = encrypted_as_word.getBytes(); + + Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM); + Cipher cipher = Cipher.getInstance(TRANSFORMATION); + cipher.init(cipherMode, secretKey); + + FileInputStream inputStream = new FileInputStream(inputFile); + byte[] inputBytes = new byte[(int) inputFile.length()]; + inputStream.read(inputBytes); //liest from inputstream into BufferArray + + String inputbytes = new String(inputBytes, StandardCharsets.UTF_8); + String[] wellencrypted = inputbytes.split(";"); + + log.info("encrypted_as_word.substring(0,encrypted_as_word.length()-1): " + encrypted_as_word.substring(0,encrypted_as_word.length()-1)); + + if(wellencrypted[0].equals(encrypted_as_word.substring(0,encrypted_as_word.length()-1))){ + wellencrypted = Arrays.copyOfRange(wellencrypted,1,wellencrypted.length); + inputBytes = wellencrypted[0].getBytes(); + log.info("Das Wort encrypted ist enthalten!"); + log.info("inputBytes: " + new String(inputBytes, StandardCharsets.UTF_8)); + + } + log.info("wellencrypted[0]: " +wellencrypted[0]); + log.info("wel[0]: " + wel[0]); + log.info("inputbytes: " + inputbytes); + log.info("inputBytes: " + new String(inputBytes, StandardCharsets.UTF_8)); + + byte[] outputBytes = cipher.doFinal(inputBytes); + + + String completeString = new String(outputBytes, StandardCharsets.UTF_8); + log.info("completeString/outputBytes: " + completeString); + parts = completeString.split(";"); + + if(cipherMode == Cipher.ENCRYPT_MODE){ + FileOutputStream outputStream = new FileOutputStream(inputFile); + ByteArrayOutputStream outputStream12 = new ByteArrayOutputStream( ); + outputStream12.write(encryptet_as_word_as_bytes); + outputStream12.write(outputBytes); + byte combined[] = outputStream12.toByteArray( ); + String combinedbytes = new String(combined, StandardCharsets.UTF_8); + log.info("combined: " + combinedbytes); + + + outputStream.write(combined);//outputBytes + + outputStream.close(); + } + + inputStream.close(); + + } catch (NoSuchPaddingException | NoSuchAlgorithmException + | InvalidKeyException | BadPaddingException + | IllegalBlockSizeException | IOException ex) { + throw new CryptoException("Error encrypting/decrypting file", ex); + } + return parts; + }*/ +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/HashGenerator.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/HashGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..b6bead225f6a2d53dd83766c6af73a6204be0afc --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/HashGenerator.java @@ -0,0 +1,26 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class HashGenerator { + + private static final Logger log = LogManager.getLogger(HashGenerator.class); + + public static String hashAndHex(String input) throws NoSuchAlgorithmException { + //Generates SHA1 Hash from input string and converts bytes from hash to hexadecimal resulting in hexadecimal String + MessageDigest sha1 = MessageDigest.getInstance("SHA1"); + byte[] sha1Hash = sha1.digest((input).getBytes()); + String result = ""; + for (int i=0; i < sha1Hash.length; i++) { + result += + Integer.toString( ( sha1Hash[i] & 0xff ) + 0x100, 16).substring( 1 ); + } + return result; + } + + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/Parser.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/Parser.java new file mode 100644 index 0000000000000000000000000000000000000000..4ccec6fc0d9eb8956792cdcc5290cbc1455dae10 --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/Parser.java @@ -0,0 +1,194 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities; + +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.ParserException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Parser { + + /* + Includes public static Parser methods for: + -username + password fields when creating account or logging in with existing credentials + -map name, when creating map + -IP-address field when joining game + -Map-name or map-ID, when searching for a map + -Parser for mapData from newly created map (length, formatting (spaces), tile-types, border-tiles etc.) + */ + + public static void usernameValid(String username) throws ParserException { + + if(username.length() < 4){ + throw new ParserException("Username too short! Min length is 4 characters."); + } + if(username.length() > 40){ + throw new ParserException("Username too long! Max length is 40 characters."); + } + + Pattern pat = Pattern.compile("[^a-z0-9_-]", Pattern.CASE_INSENSITIVE); + Matcher mat = pat.matcher(username); + boolean result = mat.find(); + if(result){ + throw new ParserException("Forbidden characters used! Only user letters A-Z or numbers 0-9 or symbols '-' or '_' !"); + } + } + + public static void passwordValid(String password) throws ParserException { + + if(password.length() < 4){ + throw new ParserException("Password too short! Min length is 4 characters."); + } + if(password.length() > 40){ + throw new ParserException("Password too long! Max length is 40 characters."); + } + + Pattern pat = Pattern.compile("[^a-z0-9_-]", Pattern.CASE_INSENSITIVE); + Matcher mat = pat.matcher(password); + boolean result = mat.find(); + if(result){ + throw new ParserException("Forbidden characters used! Only user letters A-Z or numbers 0-9 or symbols '-' or '_' !"); + } + } + + public static void mapNameValid(String mapName) throws ParserException { + + if(mapName.length() < 4){ + throw new ParserException("Map-Name too short! Min length is 4 characters."); + } + if(mapName.length() > 30){ + throw new ParserException("Map-Name too long! Max length is 30 characters."); + } + + Pattern pat = Pattern.compile("[^a-z0-9_-]", Pattern.CASE_INSENSITIVE); + Matcher mat = pat.matcher(mapName); + boolean result = mat.find(); + if(result){ + throw new ParserException("Forbidden characters used! Only user letters A-Z or numbers 0-9 or symbols '-' or '_' !"); + } + } + + public static void sha1HashValid(String mapID) throws ParserException { + + if(!(mapID.length() == 40)){ + throw new ParserException("Map-ID length not correct. Must have length of 40 characters!"); + } + + Pattern pat = Pattern.compile("[^a-f0-9]"); //maybe make case-insensitive -> letters can be uppercase and still be valid hex number + Matcher mat = pat.matcher(mapID); + boolean result = mat.find(); + if(result){ + throw new ParserException("Forbidden characters used! Map ID only consists out of letters a-f and/or numbers 0-9!"); + } + } + + public static void ipAddressValid(String address) throws ParserException { + + if(address.equals("localhost")){ + return; + } + + if(address.length() > 15){ + throw new ParserException("IP-Address too long. Must have length of 15 characters including octet dividers (.) !"); + } + + if(address.length() < 7){ + throw new ParserException("IP-Address too short. Must have length of 7 characters including octet dividers (.) !"); + } + + if(address.charAt(0) == '.' | address.charAt(address.length()-1) == '.'){ + throw new ParserException("IP-Address must not start nor end with octet dividers (.) !"); + } + + int counter = 0; + for(int i = 0; address.length() > i ; i++){ + if(address.charAt(i) == '.'){ + counter++; + } + } + if(!(counter == 3)){ + throw new ParserException("IP-Address must contain exactly 3 octet dividers (.) !"); + } + + Pattern pat = Pattern.compile("[^0-9]"); + for(int i = 0; address.length() > i ; i++){ + if(!(address.charAt(i) == '.')){ + Matcher mat = pat.matcher(address.substring(i, i+1)); + boolean result = mat.find(); + if(result){ + throw new ParserException("IP address does not consist out of numbers 0-9 and separators (.))!"); + } + } + } + + counter = 0; + int[] positions = new int[5]; + positions[0] = 0; + positions[4] = address.length(); + for(int i = 0; address.length() > i ; i++){ + if(address.charAt(i) == '.'){ + counter++; + positions[counter] = i; + } + } + for(int i = 0; 4 > i; i++){ + if(Integer.parseInt(address.substring(positions[i], positions[i+1])) > 255){ + throw new ParserException("Octets of IP-address must not exceed 255!"); + } + if(i < 3) { + positions[i + 1] = positions[i + 1] + 1; + } + } + } + + public static void mapDataValid(String mapData) throws ParserException { + + if(!(mapData.length() == 647)){ + throw new ParserException("Map-Data corrupted - must have length of 647 chars including spaces!"); + } + + for(int i = 1; i < 647; i = i + 2){ + if(!(mapData.charAt(i) == ' ')){ + throw new ParserException("Map-Data corrupted - must use space every other character!"); + } + } + + for(int i = 0; i < 647; i = i + 2){ + if((Integer.parseInt(mapData.substring(i, i+1)) > 4) | (Integer.parseInt(mapData.substring(i, i+1)) <= 0)){ + throw new ParserException("Map-Data corrupted - Tile number must be between 1 and 4!"); + } + } + + for(int i = 0; i < 18; i = i + 2){ + if(!(Integer.parseInt(mapData.substring(i, i+1)) == 3)){ + throw new ParserException("Map-Data corrupted - Top-Line must be border tiles!"); + } + } + + for(int i = 628; i < 647; i = i + 2){ + if(!(Integer.parseInt(mapData.substring(i, i+1)) == 3)){ + throw new ParserException("Map-Data corrupted - Bottom-Line must be border tiles!"); + } + } + + for(int i = 0; i < 647; i = i + 2){ + if(i % 36 == 0 && !(Integer.parseInt(mapData.substring(i, i+1)) == 3)){ + throw new ParserException("Map-Data corrupted - Left Edge must be border tiles!"); + } + } + + for(int i = 2; i < 647; i = i + 2){ + if(i % 36 == 0 && !(Integer.parseInt(mapData.substring(i-2, i-1)) == 3)){ + throw new ParserException("Map-Data corrupted - Right Edge must be border tiles!"); + } + } + + if(!(Integer.parseInt(mapData.substring(38, 39)) == 1) | !(Integer.parseInt(mapData.substring(68, 69)) == 1)){ + throw new ParserException("Map-Data corrupted - Player spawn must use walkable tile!"); + } + + if(!(Integer.parseInt(mapData.substring(578, 579)) == 1) | !(Integer.parseInt(mapData.substring(608, 609)) == 1)){ + throw new ParserException("Map-Data corrupted - Player spawn must use walkable tile!"); + } + } + +} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Scripts/DDL_Script_AzureDB.sql b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Scripts/DDL_Script_AzureDB.sql new file mode 100644 index 0000000000000000000000000000000000000000..64e90f19dee42b333ff193b2041cbe3e29723604 --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Scripts/DDL_Script_AzureDB.sql @@ -0,0 +1,75 @@ +--Note: DDL to be run as admin on MsSQL (AzureDB); +--Backup SQL only for CoreMaps Download + + +DROP TABLE coremaps; +DROP TABLE communitymaps; +DROP TABLE players; + +CREATE TABLE coremaps( + map_id CHAR(40) NOT NULL UNIQUE, --SHA1 hash is 40 chars length in hex + map_name VARCHAR(30) NOT NULL, + map_width INTEGER NOT NULL, + map_height INTEGER NOT NULL, + map_data VARCHAR(1682) NOT NULL UNIQUE); --allows for map size up to 29x29 + +CREATE TABLE communitymaps( + map_id CHAR(40) NOT NULL UNIQUE, --SHA1 hash is 40 chars length in hex + map_name VARCHAR(30) NOT NULL, + map_width INTEGER NOT NULL, + map_height INTEGER NOT NULL, + map_data VARCHAR(1682) NOT NULL UNIQUE, --allows for map size up to 29x29 + map_downloads INTEGER NOT NULL); + +CREATE TABLE players( + player_name VARCHAR(40) NOT NULL UNIQUE, --Player name is PlayerID + player_pw VARCHAR(40) NOT NULL, + games_won INTEGER NOT NULL, + games_lost INTEGER NOT NULL, + kills INTEGER NOT NULL, + deaths INTEGER NOT NULL, + blocks_destroyed INTEGER NOT NULL, + ingame_time INTEGER NOT NULL); + + +INSERT INTO coremaps (map_id, map_name, map_width, map_height, map_data) +VALUES ('72e1c81687463ab159b4cb8d935e347a26d7fe40', + 'Arena1', + 18, + 18, + '3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3'); + +INSERT INTO coremaps (map_id, map_name, map_width, map_height, map_data) +VALUES ('f7e1fc56cefbacacb9ba403220476f3ac258de06', + 'Arena2', + 18, + 18, + '3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 1 1 1 1 1 1 1 3 1 1 3 3 1 1 1 1 1 3 1 3 3 3 1 1 1 3 1 1 3 3 1 1 1 1 1 3 1 1 1 1 1 1 1 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3'); + +INSERT INTO communitymaps (map_id, map_name, map_width, map_height, map_data, map_downloads) +VALUES ('c8ce8e85e4a9b99e4fa956e2486e55df73b2cf08', + 'Arena1', + 18, + 18, + '3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 3 3 3 3 1 1 1 1 1 1 1 3 3 1 1 1 1 1 3 3 3 3 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3', + 0); + +INSERT INTO players (player_name, player_pw, games_won, games_lost, kills, deaths, blocks_destroyed, ingame_time) +VALUES ('Player1', + 'password', + 18, + 0, + 80, + 0, + 140, + 5000); + +INSERT INTO players (player_name, player_pw, games_won, games_lost, kills, deaths, blocks_destroyed, ingame_time) +VALUES ('Player2', + 'password', + 15, + 3, + 50, + 5, + 110, + 6000); \ No newline at end of file diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Scripts/DDL_Script_Oracle.sql b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Scripts/DDL_Script_Oracle.sql new file mode 100644 index 0000000000000000000000000000000000000000..af8c0ca3e9ee71ca652b85f47c5ad018fa79725e --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Scripts/DDL_Script_Oracle.sql @@ -0,0 +1,92 @@ +--Note: DDL to be run as admin on OracleDB; Passwords for user accounts are not included and must be inserted before execution + +DROP TABLE battlearenadata.coremaps; +DROP TABLE battlearenadata.communitymaps; +DROP TABLE battlearenadata.players; + +DROP USER battlearenaplayer; +DROP USER battlearenadata; + +CREATE USER battlearenaplayer IDENTIFIED BY "insertPasswordHere"; +CREATE USER battlearenadata IDENTIFIED BY "insertPasswordHere"; + +GRANT CONNECT TO battlearenaplayer; + +CREATE TABLE battlearenadata.coremaps( + map_id CHAR(40) NOT NULL UNIQUE, --SHA1 hash is 40 chars length in hex + map_name VARCHAR(30) NOT NULL, + map_width INTEGER NOT NULL, + map_height INTEGER NOT NULL, + map_data VARCHAR(1682) NOT NULL UNIQUE); --allows for map size up to 29x29 + +CREATE TABLE battlearenadata.communitymaps( + map_id CHAR(40) NOT NULL UNIQUE, --SHA1 hash is 40 chars length in hex + map_name VARCHAR(30) NOT NULL, + map_width INTEGER NOT NULL, + map_height INTEGER NOT NULL, + map_data VARCHAR(1682) NOT NULL UNIQUE, --allows for map size up to 29x29 + map_downloads INTEGER NOT NULL); + +CREATE TABLE battlearenadata.players( + player_name VARCHAR(40) NOT NULL UNIQUE, --Player name is PlayerID + player_pw VARCHAR(40) NOT NULL, + games_won INTEGER NOT NULL, + games_lost INTEGER NOT NULL, + kills INTEGER NOT NULL, + deaths INTEGER NOT NULL, + blocks_destroyed INTEGER NOT NULL, + ingame_time INTEGER NOT NULL); + +ALTER USER battlearenadata QUOTA 500M ON coremaps; +ALTER USER battlearenadata QUOTA 500M ON communitymaps; +ALTER USER battlearenadata QUOTA 500M ON players; + +INSERT INTO battlearenadata.coremaps (map_id, map_name, map_width, map_height, map_data) +VALUES ('72e1c81687463ab159b4cb8d935e347a26d7fe40', + 'Arena1', + 18, + 18, + '3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3'); + +INSERT INTO battlearenadata.coremaps (map_id, map_name, map_width, map_height, map_data) +VALUES ('f7e1fc56cefbacacb9ba403220476f3ac258de06', + 'Arena2', + 18, + 18, + '3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 1 1 1 1 1 1 1 3 1 1 3 3 1 1 1 1 1 3 1 3 3 3 1 1 1 3 1 1 3 3 1 1 1 1 1 3 1 1 1 1 1 1 1 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3'); + +INSERT INTO battlearenadata.communitymaps (map_id, map_name, map_width, map_height, map_data, map_downloads) +VALUES ('c8ce8e85e4a9b99e4fa956e2486e55df73b2cf08', + 'Arena1', + 18, + 18, + '3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 3 3 3 3 1 1 1 1 1 1 1 3 3 1 1 1 1 1 3 3 3 3 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3', + 0); + +INSERT INTO battlearenadata.players (player_name, player_pw, games_won, games_lost, kills, deaths, blocks_destroyed, ingame_time) +VALUES ('Player1', + 'password', + 18, + 0, + 80, + 0, + 140, + 5000); + +INSERT INTO battlearenadata.players (player_name, player_pw, games_won, games_lost, kills, deaths, blocks_destroyed, ingame_time) +VALUES ('Player2', + 'password', + 15, + 3, + 50, + 5, + 110, + 6000); + +GRANT SELECT ON battlearenadata.coremaps TO battlearenaplayer; + +GRANT SELECT, INSERT ON battlearenadata.communitymaps TO battlearenaplayer; + +GRANT SELECT, INSERT, UPDATE ON battlearenadata.players TO battlearenaplayer; + +GRANT UPDATE (map_downloads) ON battlearenadata.communitymaps TO battlearenaplayer; \ No newline at end of file diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/Client.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/Client.java index 87189a54b8a83db73c96f74eee8e46702322b5f4..23b1c65ccd218152576cc9c7d366e68c65d1c591 100644 --- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/Client.java +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/Client.java @@ -12,7 +12,6 @@ public class Client { private PrintWriter out; private BufferedReader in; - private static final Logger log = LogManager.getLogger(Client.class); public void startConnection(String ip, int port) throws IOException { @@ -24,7 +23,7 @@ public class Client { public int[] sendcords(int[] cords) throws IOException { String message = String.join(",", Arrays.stream(cords).mapToObj(String::valueOf).toArray(String[]::new)); out.println(message); - log.info("Sent coordinates: " + message); + // log.info("Sent coordinates: " + message); String resp = in.readLine(); return convertStringToArray(resp); } @@ -42,7 +41,6 @@ public class Client { return result; } - public void stopConnection() throws IOException { in.close(); out.close(); diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/ConnectionHandler.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/ConnectionHandler.java index 67529ff1e0e3eb4cc9f2b0f01ef637a2190415e7..b47419daa11eea14e292ecab5dac7e0ae483f2b6 100644 --- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/ConnectionHandler.java +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/ConnectionHandler.java @@ -11,48 +11,57 @@ public class ConnectionHandler { private static int pX = 0; private static int pY = 0; - private int enemyX; - private int enemyY; + private static int enemyX = 0; + private static int enemyY = 0; private static int playerID = 0; private static int[] coordinates = {pX,pY,playerID}; - + private static String ipaddress = "localhost"; private static final Logger log = LogManager.getLogger(ConnectionHandler.class); - public static void main(String[] args) throws IOException, InterruptedException { + public void startHandler() throws IOException, InterruptedException { Client client = new Client(); - client.startConnection("localhost", 4444); - while (true){ - int[] cords = client.sendcords(coordinates); - System.out.println("Enemy X: " + cords[0]); - System.out.println("Enemy Y: " + cords[1]); - System.out.println("Your PlayerID is " + cords[2]); - pX++; - pY++; - playerID = cords[2]; - //Assign the Values to the message to send: - coordinates[0] = pX; - coordinates[1] = pY; - coordinates[2] = playerID; - - TimeUnit.SECONDS.sleep(1); - } + client.startConnection(ipaddress, 4444); + + ConnectionThread connectionthread = new ConnectionThread(client); + connectionthread.start(); - //stop the connection: - //client.stopConnection(); } - class ConnectionThread implements Runnable { - public void run() { + private static class ConnectionThread extends Thread { + private final Client client; + + public ConnectionThread(Client client) { + this.client = client; + } + public void run() { try { - Thread.sleep(250); - } catch (InterruptedException e){ - log.error("Error in Thread.sleep()"); + while (!Thread.interrupted()) { + int[] cords = client.sendcords(coordinates); + enemyX = cords[0]; + enemyY = cords[1]; + // System.out.println("Enemy X: " + enemyX); + // System.out.println("Enemy Y: " + enemyY); + // System.out.println("Your PlayerID is " + cords[2]); + playerID = cords[2]; + // Assign the Values to the message to send: + coordinates[0] = pX; + coordinates[1] = pY; + coordinates[2] = playerID; + + Thread.sleep(16); + } + } catch (InterruptedException | IOException e) { + e.printStackTrace(); // Handle the exception as needed } } } + public int getPlayerID() { + return playerID; + } + public int getpX() { return pX; } @@ -72,17 +81,12 @@ public class ConnectionHandler { public int getEnemyX() { return enemyX; } - - public void setEnemyX(int enemyX) { - this.enemyX = enemyX; - } - public int getEnemyY() { return enemyY; } - public void setEnemyY(int enemyY) { - this.enemyY = enemyY; + public static void setIpaddress(String ipaddress) { + ConnectionHandler.ipaddress = ipaddress; } } diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/Server.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/Server.java index e9226a37ba2b57a3d708a2f022e243b8f66d68da..fddc2fae68590bac4fc51d13f466b7bd8684012c 100644 --- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/Server.java +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/Server.java @@ -23,18 +23,28 @@ public class Server { private static int playerID; private static int playercount = 0; private static int[] cords; - private static int[] returncords = {enemyx,enemyy,playerID}; + private boolean started = false; + private static String ipaddress = "localhost"; + +//Uncomment these lines to test the server starting manually: + /* public static void main(String[] args) throws IOException { //main method for testing purposes + Server server = new Server(); + log.info("server starting..."); + server.start(ipaddress, 4444); + } */ - public static void main(String[] args) throws IOException { + //use this method to start the server from another class + public void startServer() throws IOException { Server server = new Server(); log.info("server starting..."); - server.start("localhost",4444); + server.start(ipaddress,4444); } - public void start(String localhost, int port) throws IOException { + public void start(String host_ip, int port) throws IOException { serverSocket = new ServerSocket(port); log.info("server started!"); + started = true; while (true){ new ServerHandler(serverSocket.accept()).start(); } @@ -132,7 +142,7 @@ public class Server { } catch (IOException e) { throw new RuntimeException(e); } - }, 0, 250, TimeUnit.MILLISECONDS); + }, 0, 50, TimeUnit.MILLISECONDS); } } @@ -145,4 +155,10 @@ public class Server { } } + public boolean isStarted() { + return started; + } + public static void setIpaddress(String ipaddress) { + Server.ipaddress = ipaddress; + } } diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/TestMap.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/TestMap.java new file mode 100644 index 0000000000000000000000000000000000000000..f6d7fdf0800d787b23fb6df532afdb898733d53c --- /dev/null +++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Multiplayer/TestMap.java @@ -0,0 +1,113 @@ +package de.hdm_stuttgart.battlearena.Model.Multiplayer; + +import javafx.application.Application; +import javafx.scene.Scene; +import javafx.scene.input.KeyCode; +import javafx.scene.layout.Pane; +import javafx.scene.paint.Color; +import javafx.scene.shape.Rectangle; +import javafx.stage.Stage; +import java.util.concurrent.TimeUnit; + +import java.io.IOException; + +public class TestMap extends Application { + private static final int SQUARE_SIZE = 50; + private static Rectangle square; + private static Rectangle enemy; + private Color color = Color.BLACK; + + @Override + public void start(Stage primaryStage) throws IOException, InterruptedException { + + ConnectionHandler handler = new ConnectionHandler(); + handler.startHandler(); + + TimeUnit.SECONDS.sleep(1); + + square = new Rectangle(SQUARE_SIZE, SQUARE_SIZE, color); + enemy = new Rectangle(SQUARE_SIZE, SQUARE_SIZE, color); + + Pane root = new Pane(); + root.getChildren().add(square); + root.getChildren().add(enemy); + + Scene scene = new Scene(root, 400, 400); + + scene.setOnKeyPressed(event -> handleKeyPress(event.getCode(), handler)); + + primaryStage.setTitle("Player #" + handler.getPlayerID()); + primaryStage.setScene(scene); + primaryStage.show(); + + if(handler.getPlayerID() == 1){ + square.setX(50); + square.setY(50); + enemy.setX(200); + enemy.setY(50); + } else if(handler.getPlayerID() == 2){ + square.setX(200); + square.setY(50); + enemy.setX(50); + enemy.setY(50); + } + + UpdateThread update = new UpdateThread(handler); + update.start(); + + } + + private void handleKeyPress(KeyCode code, ConnectionHandler handler) { + switch (code) { + case UP: + square.setY(square.getY() - 20); + handler.setpY(handler.getpY() - 20); + break; + case DOWN: + square.setY(square.getY() + 20); + handler.setpY(handler.getpY() + 20); + break; + case LEFT: + square.setX(square.getX() - 20); + handler.setpX(handler.getpX() - 20); + break; + case RIGHT: + square.setX(square.getX() + 20); + handler.setpX(handler.getpX() + 20); + break; + } + } + + private static class UpdateThread extends Thread { + private final ConnectionHandler handler; + + private UpdateThread(ConnectionHandler handler) { + this.handler = handler; + } + + public void run() { + while (true){ + + handler.setpX((int) square.getX()); + handler.setpY((int) square.getY()); + + //receive cords + enemy.setX(handler.getEnemyX()); + enemy.setY(handler.getEnemyY()); + + + try { + Thread.sleep(16); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + + } + } + + public static void main(String[] args) throws IOException { + launch(args); + } +} \ No newline at end of file diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Persistance/DataBase.java b/src/main/java/de/hdm_stuttgart/battlearena/Persistance/DataBase.java deleted file mode 100644 index e766e18264ef67496e300c52199eae616e794db6..0000000000000000000000000000000000000000 --- a/src/main/java/de/hdm_stuttgart/battlearena/Persistance/DataBase.java +++ /dev/null @@ -1,10 +0,0 @@ -package de.hdm_stuttgart.battlearena.Persistance; - -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.LogManager; - -public class DataBase implements IDataBase{ - - private static final Logger log = LogManager.getLogger(DataBase.class); - -} diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Persistance/IDataBase.java b/src/main/java/de/hdm_stuttgart/battlearena/Persistance/IDataBase.java deleted file mode 100644 index 17187e8f1400a7d8e1af04e9e33392998a38246c..0000000000000000000000000000000000000000 --- a/src/main/java/de/hdm_stuttgart/battlearena/Persistance/IDataBase.java +++ /dev/null @@ -1,4 +0,0 @@ -package de.hdm_stuttgart.battlearena.Persistance; - -public interface IDataBase { -} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index e154cc0323db15ac6a2b92f324888773b82f03e6..2350a517d6af6b0318a876694b89460514fc8e56 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -3,10 +3,16 @@ module gui { requires javafx.fxml; requires javafx.media; requires org.apache.logging.log4j; + requires java.sql; + requires com.google.gson; + requires com.oracle.database.jdbc; + requires java.naming; opens de.hdm_stuttgart.battlearena to javafx.fxml; - opens de.hdm_stuttgart.battlearena.Controller to javafx.fxml; + opens de.hdm_stuttgart.battlearena.Model.DataStorage.Classes to com.google.gson; + opens de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions to com.google.gson; + opens de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities to com.google.gson; exports de.hdm_stuttgart.battlearena.Main; exports de.hdm_stuttgart.battlearena.Controller; exports de.hdm_stuttgart.battlearena.Model.Entity; diff --git a/src/main/resources/database/AzureDB_logindetails b/src/main/resources/database/AzureDB_logindetails new file mode 100644 index 0000000000000000000000000000000000000000..88e4927a50d6dbc1bdf561cf31ab96067cc6286c --- /dev/null +++ b/src/main/resources/database/AzureDB_logindetails @@ -0,0 +1 @@ +��z����%�\<��$�d<iA�pA5��ś]\&q<��#����ߤVr \ No newline at end of file diff --git a/src/main/resources/database/OracleDB_logindetails b/src/main/resources/database/OracleDB_logindetails new file mode 100644 index 0000000000000000000000000000000000000000..231cb64d34a6d7c284298e353721a36b706e58d5 Binary files /dev/null and b/src/main/resources/database/OracleDB_logindetails differ diff --git a/src/main/resources/database/document.encrypted b/src/main/resources/database/document.encrypted new file mode 100644 index 0000000000000000000000000000000000000000..837a9fbcf781d32fe5ecb8608ad6a314235ba395 Binary files /dev/null and b/src/main/resources/database/document.encrypted differ diff --git a/src/main/resources/database/encrypted;encryptiondecryptiontestFile.txt b/src/main/resources/database/encrypted;encryptiondecryptiontestFile.txt new file mode 100644 index 0000000000000000000000000000000000000000..575b3c72b847f7e1e6e83c5d02a75fe9c5906c67 --- /dev/null +++ b/src/main/resources/database/encrypted;encryptiondecryptiontestFile.txt @@ -0,0 +1 @@ +Hier steht ein Testtext. \ No newline at end of file diff --git a/src/main/resources/database/encryptiondecryptiontestFile.txt b/src/main/resources/database/encryptiondecryptiontestFile.txt new file mode 100644 index 0000000000000000000000000000000000000000..4b7d67bb3df7989061607a0fd4a1869f4fbdda21 --- /dev/null +++ b/src/main/resources/database/encryptiondecryptiontestFile.txt @@ -0,0 +1 @@ +èkæÝ9z"²œÓF'ÙøŒ®[4]ÙqŠð(/ \ No newline at end of file diff --git a/src/main/resources/de/hdm_stuttgart/battlearena/config.properties b/src/main/resources/de/hdm_stuttgart/battlearena/config.properties index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..dbd084cebdb997732b0b641b24d6d1d4a64c1c55 100644 --- a/src/main/resources/de/hdm_stuttgart/battlearena/config.properties +++ b/src/main/resources/de/hdm_stuttgart/battlearena/config.properties @@ -0,0 +1,3 @@ +url=jdbc:sqlserver://battlearena.database.windows.net:1433;database=battleArena;encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30; +user=battleArenaAdmin@battlearena; +password=krassesRPGGame23# diff --git a/src/main/resources/maps/communityMaps.json b/src/main/resources/maps/communityMaps.json new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/main/resources/maps/coreMaps.json b/src/main/resources/maps/coreMaps.json new file mode 100644 index 0000000000000000000000000000000000000000..84828ae2b407d2ff4b089fdb479656a518e3a688 --- /dev/null +++ b/src/main/resources/maps/coreMaps.json @@ -0,0 +1,16 @@ +[ + { + "mapID": "a593cafd1d061f0f463a2d2051bf4718aaaf5c48", + "mapName": "Arena1", + "mapWidth": 18, + "mapHeight": 18, + "mapData": "4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 1 2 1 1 1 1 2 2 2 1 1 1 1 1 1 1 3 4 2 1 1 1 1 1 2 2 2 1 1 1 1 2 1 1 3 4 1 1 1 2 2 4 3 3 1 4 3 3 3 3 2 2 3 4 1 1 1 2 2 4 1 1 1 1 1 1 1 3 1 2 3 4 1 1 1 2 2 4 1 3 3 3 1 1 1 3 2 2 3 4 1 1 1 2 2 4 1 1 1 1 1 1 1 3 2 1 3 4 1 1 1 2 2 4 3 3 1 4 3 3 3 3 2 1 3 4 1 1 1 1 1 1 2 2 2 1 1 1 1 1 1 1 3 4 1 1 1 2 2 4 3 3 1 3 3 3 3 3 2 1 3 4 1 1 1 1 2 4 3 3 1 3 3 3 3 3 1 1 3 4 1 1 1 1 2 4 3 3 1 3 3 3 3 3 2 2 3 4 1 1 1 1 1 4 3 3 1 3 3 3 3 3 1 2 3 4 1 2 1 1 1 1 2 2 2 1 1 1 1 1 1 1 3 4 1 1 2 1 1 1 2 2 2 1 1 1 1 1 1 1 3 4 1 1 1 2 2 4 3 3 1 3 3 3 3 3 2 2 3 4 1 1 1 2 2 4 3 3 1 3 3 3 3 3 2 2 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3" + }, + { + "mapID": "e559d8fbb53b333f5839cb3c6c0c515395afe344", + "mapName": "Arena2", + "mapWidth": 18, + "mapHeight": 18, + "mapData": "4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 1 2 1 1 1 1 2 2 2 1 1 1 1 1 1 1 2 4 2 1 1 1 1 1 2 2 2 1 1 1 1 2 3 1 3 4 1 1 1 2 2 4 3 3 1 4 3 3 3 3 2 2 3 4 1 1 1 2 2 4 1 1 1 1 1 1 1 3 1 2 3 4 1 1 1 2 2 4 1 3 3 3 1 1 1 3 2 2 3 4 1 1 1 2 2 4 1 1 1 1 1 1 1 3 2 1 3 4 1 1 1 2 2 4 3 3 1 4 3 3 3 3 2 1 3 4 1 1 1 1 1 1 2 2 2 1 1 1 1 1 1 1 3 4 1 1 1 2 2 4 3 3 1 3 3 3 3 3 2 1 3 4 1 1 1 1 2 4 3 3 1 3 3 3 3 3 1 1 3 4 1 1 1 1 2 4 3 3 1 3 3 3 3 3 2 2 3 4 1 1 1 1 1 4 3 3 1 3 3 3 3 3 1 2 3 4 1 2 1 1 1 1 2 2 2 1 1 1 1 1 1 1 3 4 1 1 2 1 1 1 2 2 2 1 1 1 1 1 1 1 3 4 1 1 1 2 2 4 3 3 1 3 3 3 3 3 2 2 3 4 1 1 1 2 2 4 3 3 1 3 3 3 3 3 2 2 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3" + } +] \ No newline at end of file diff --git a/src/main/resources/player/appSettings.json b/src/main/resources/player/appSettings.json new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/main/resources/player/playerAccount.json b/src/main/resources/player/playerAccount.json new file mode 100644 index 0000000000000000000000000000000000000000..1cecf8373c050f15e816dae79f50e4b326d4f090 --- /dev/null +++ b/src/main/resources/player/playerAccount.json @@ -0,0 +1,5 @@ +{ + "playerName": "Player1", + "accountPassword": "7c4a8d09ca3762af61e59520943dc26494f8941b", + "accountType": "ONLINE" +} \ No newline at end of file diff --git a/src/main/resources/player/playerStatsLocal.json b/src/main/resources/player/playerStatsLocal.json new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/test/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/CryptoUtilsTest.java b/src/test/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/CryptoUtilsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6fe7a78190c6e19cc745d4aaec49d281970665cf --- /dev/null +++ b/src/test/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/CryptoUtilsTest.java @@ -0,0 +1,101 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities; + +//import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.CryptoException; + +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.CryptoException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.jupiter.api.*; + +import java.io.*; + +import static org.junit.jupiter.api.Assertions.*; + +public class CryptoUtilsTest { + private static File encryptiondecryptiontestFile = new File("src\\main\\resources\\database\\encryptiondecryptiontestFile.txt"); + private static File encryptedtestFile = new File("src\\main\\resources\\database\\encrypted;encryptedtestFile.txt"); + private static boolean alreadyencrypted; + private static int encryptionreturn; + private static String text=""; + private static String[] parts; + private static String testtext = "Hier steht ein Testtext."; + private static boolean multipleencryptions = false; + private static final Logger log = LogManager.getLogger(CryptoUtilsTest.class); + + @BeforeEach + void beforeEachTest(TestInfo testInfo) { + log.info(() -> String.format("About to execute [%s]", + testInfo.getDisplayName())); + } + @AfterEach + void afterEachTest(TestInfo testInfo) { + log.info(() -> String.format("Finished executing [%s]", + testInfo.getDisplayName())); + } + @Test + void encryptDecryptiontest() throws IOException { + BufferedWriter writer = new BufferedWriter(new FileWriter(encryptiondecryptiontestFile)); + writer.write(testtext); + writer.close(); + try { + CryptoUtils.encrypt(encryptiondecryptiontestFile, true); + parts = CryptoUtils.decrypt(encryptiondecryptiontestFile); + text = parts[0]; + System.out.println(text); + } catch (CryptoException ex) { + System.out.println(ex.getMessage()); + ex.printStackTrace(); + } + assertEquals(testtext,text); + } + @RepeatedTest(3) + void repeatedCheckFileEncryptingMultipleTimes() throws IOException { + BufferedWriter writer = new BufferedWriter(new FileWriter(encryptiondecryptiontestFile)); + writer.write(testtext); + writer.close(); + try { + encryptionreturn = CryptoUtils.encrypt(encryptiondecryptiontestFile, true); + parts = CryptoUtils.decrypt(encryptiondecryptiontestFile); + text = parts[0]; + System.out.println(text); + } catch (CryptoException ex) { + System.out.println(ex.getMessage()); + ex.printStackTrace(); + } + assertEquals(encryptionreturn, 0); + assertEquals(testtext,text); //Change + } + @Test + void checkFileEncryptingOnce() throws IOException { + BufferedWriter writer = new BufferedWriter(new FileWriter(encryptiondecryptiontestFile)); + writer.write(testtext); + writer.close(); + try { + encryptionreturn = CryptoUtils.encrypt(encryptiondecryptiontestFile, false); + parts = CryptoUtils.decrypt(encryptiondecryptiontestFile); + text = parts[0]; + System.out.println(text); + } catch (CryptoException ex) { + System.out.println(ex.getMessage()); + ex.printStackTrace(); + } + assertEquals(encryptionreturn, 1); + assertEquals(testtext,text); //Change + } + @Test + void checkIfFileAlreadyEncrypted(){ + alreadyencrypted = CryptoUtils.check_if_file_already_encrypted(encryptedtestFile); + assertTrue(alreadyencrypted); + } + @Test + void checkIfFileNotYetEncrypted(){ + alreadyencrypted = CryptoUtils.check_if_file_already_encrypted(encryptiondecryptiontestFile); + assertFalse(alreadyencrypted); + } + @Test + void exceptionTestingFileNotFound() { + CryptoException exception = assertThrows(CryptoException.class, () -> + CryptoUtils.decrypt(new File("src/main/resources/database/thisFileShouldn'tExist"))); + assertEquals("Error encrypting/decrypting file", exception.getMessage()); + } +} diff --git a/src/test/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/ParserTest.java b/src/test/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/ParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..62f0b705af1053613a39adfe2a296fc69099dd98 --- /dev/null +++ b/src/test/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/ParserTest.java @@ -0,0 +1,166 @@ +package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities; + +import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.ParserException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.*; +class ParserTest { + + + @ParameterizedTest + @ValueSource(strings = {"Player1", + "Player2", + "HelloWorld"}) + void usernameValid(String test){ + assertDoesNotThrow(() -> Parser.usernameValid(test)); + } + + @Test + void usernameValidException() { + ParserException testMe = assertThrows(ParserException.class, () -> Parser.usernameValid("hi")); + assertTrue(testMe.getMessage().contains("Username too short! Min length is 4 characters.")); + + testMe = assertThrows(ParserException.class, () -> Parser.usernameValid("jiaodjidsfjoisjdiofjsiofjidosfijsodfjisdfjoi")); + assertTrue(testMe.getMessage().contains("Username too long! Max length is 40 characters.")); + + testMe = assertThrows(ParserException.class, () -> Parser.usernameValid("SELECT * FROM")); + assertTrue(testMe.getMessage().contains("Forbidden characters used! Only user letters A-Z or numbers 0-9 or symbols '-' or '_' !")); + } + + @ParameterizedTest + @ValueSource(strings = {"pw123456", + "Passwort", + "lololol"}) + void passwordValid(String test){ + assertDoesNotThrow(() -> Parser.passwordValid(test)); + } + + @Test + void passwordValidException() { + ParserException testMe = assertThrows(ParserException.class, () -> Parser.passwordValid("hi")); + assertTrue(testMe.getMessage().contains("Password too short! Min length is 4 characters.")); + + testMe = assertThrows(ParserException.class, () -> Parser.passwordValid("jiaodjidsfjoisjdiofjsiofjidosfijsodfjisdfjoi")); + assertTrue(testMe.getMessage().contains("Password too long! Max length is 40 characters.")); + + testMe = assertThrows(ParserException.class, () -> Parser.passwordValid("SELECT * FROM")); + assertTrue(testMe.getMessage().contains("Forbidden characters used! Only user letters A-Z or numbers 0-9 or symbols '-' or '_' !")); + } + + @ParameterizedTest + @ValueSource(strings = {"Map_1", + "de_dust", + "Ziba-Tower"}) + void mapNameValid(String test){ + assertDoesNotThrow(() -> Parser.mapNameValid(test)); + } + + @Test + void mapNameValidException() { + ParserException testMe = assertThrows(ParserException.class, () -> Parser.mapNameValid("hi")); + assertTrue(testMe.getMessage().contains("Map-Name too short! Min length is 4 characters.")); + + testMe = assertThrows(ParserException.class, () -> Parser.mapNameValid("jiaodjidsfjoisjdiofjsiofjidosfijsodfjisdfjoi")); + assertTrue(testMe.getMessage().contains("Map-Name too long! Max length is 30 characters.")); + + testMe = assertThrows(ParserException.class, () -> Parser.mapNameValid("SELECT * FROM")); + assertTrue(testMe.getMessage().contains("Forbidden characters used! Only user letters A-Z or numbers 0-9 or symbols '-' or '_' !")); + } + + @ParameterizedTest + @ValueSource(strings = {"a593cafd1d061f0f463a2d2051bf4718aaaf5c48", + "e559d8fbb53b333f5839cb3c6c0c515395afe344", + "a593cafd1d061f0f463a2d2051bf4718aaaf5c48"}) + void mapIDValid(String test){ + assertDoesNotThrow(() -> Parser.sha1HashValid(test)); + } + + @Test + void mapIDValidException() { + + ParserException testMe = assertThrows(ParserException.class, () -> Parser.sha1HashValid("jiaodjidsfjoisjdiofjsiofjidosfijsodfjisdfjoi")); + assertTrue(testMe.getMessage().contains("Map-ID length not correct. Must have length of 40 characters!")); + + testMe = assertThrows(ParserException.class, () -> Parser.sha1HashValid("XYZ3cafd1d061f0f463a2d2051bf4718aaaf5c48")); + assertTrue(testMe.getMessage().contains("Forbidden characters used! Map ID only consists out of letters a-f and/or numbers 0-9!")); + } + + @ParameterizedTest + @ValueSource(strings = {"255.255.255.255", + "0.0.0.0", + "12.12.12.1", + "localhost"}) + void ipAddressValid(String test){ + assertDoesNotThrow(() -> Parser.ipAddressValid(test)); + } + + @Test + void ipAddressValidException() { + + ParserException testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("255.255.255.255.255.255")); + assertTrue(testMe.getMessage().contains("IP-Address too long. Must have length of 15 characters including octet dividers (.) !")); + + testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("0.0.0")); + assertTrue(testMe.getMessage().contains("IP-Address too short. Must have length of 7 characters including octet dividers (.) !")); + + testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid(".25.255.25.")); + assertTrue(testMe.getMessage().contains("IP-Address must not start nor end with octet dividers (.) !")); + + testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("12.3.0.12.12")); + assertTrue(testMe.getMessage().contains("IP-Address must contain exactly 3 octet dividers (.) !")); + + testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("255.ff.12.12")); + assertTrue(testMe.getMessage().contains("IP address does not consist out of numbers 0-9 and separators (.))!")); + + testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("2555.800.12.12")); + assertTrue(testMe.getMessage().contains("Octets of IP-address must not exceed 255!")); + } + + @ParameterizedTest + @ValueSource(strings = {"3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3", + "3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 1 1 1 1 1 1 1 3 1 1 3 3 1 1 1 1 1 3 1 3 3 3 1 1 1 3 1 1 3 3 1 1 1 1 1 3 1 1 1 1 1 1 1 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 1 1 1 1 1 3 3 3 1 3 3 3 3 3 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3", + "3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 3 3 3 3 1 1 1 1 1 1 1 3 3 1 1 1 1 1 3 3 3 3 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3"}) + void mapDataValid(String test){ + assertDoesNotThrow(() -> Parser.mapDataValid(test)); + } + + @Test + void mapDataValidException() { + ParserException testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("hi")); + assertTrue(testMe.getMessage().contains("Map-Data corrupted - must have length of 647 chars including spaces!")); + + testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("3 3 3 3 3a3a3a3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3")); + assertTrue(testMe.getMessage().contains("Map-Data corrupted - must use space every other character!")); + + testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("3 3 3 8 9 7 7 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3")); + assertTrue(testMe.getMessage().contains("Map-Data corrupted - Tile number must be between 1 and 4!")); + + testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("3 3 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3")); + assertTrue(testMe.getMessage().contains("Map-Data corrupted - Top-Line must be border tiles!")); + + testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 1 1 1 1 1 3 3 3 3 3 3")); + assertTrue(testMe.getMessage().contains("Map-Data corrupted - Bottom-Line must be border tiles!")); + + testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3")); + assertTrue(testMe.getMessage().contains("Map-Data corrupted - Left Edge must be border tiles!")); + + testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3")); + assertTrue(testMe.getMessage().contains("Map-Data corrupted - Right Edge must be border tiles!")); + + testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3")); + assertTrue(testMe.getMessage().contains("Map-Data corrupted - Player spawn must use walkable tile!")); + + testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3")); + assertTrue(testMe.getMessage().contains("Map-Data corrupted - Player spawn must use walkable tile!")); + + testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3")); + assertTrue(testMe.getMessage().contains("Map-Data corrupted - Player spawn must use walkable tile!")); + + testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3")); + assertTrue(testMe.getMessage().contains("Map-Data corrupted - Player spawn must use walkable tile!")); + + } + +} \ No newline at end of file