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/README.md b/README.md
index 69625de7934d607289e90646606803cc8faefb41..36649891de9120708f42d1e77509733f2abd6a23 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,5 @@
 ## Hier könnte ihre Werbung stehn
+
+### Known issues:
+ - Videos sometimes don't load in Windows 11 especially on weaker systems
+ - SQL server is very slow (thanks Oracle)
diff --git a/pom.xml b/pom.xml
index 231758b8295c2602c5156431d7eec666619df078..00cecae4b603bb2ef7a769e8effa5db5010b47d5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,6 +39,20 @@
             <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.mockito</groupId>
+            <artifactId>mockito-junit-jupiter</artifactId>
+            <version>5.8.0</version>
+            <scope>test</scope>
+        </dependency>
+
         <dependency>
             <groupId>org.apache.logging.log4j</groupId>
             <artifactId>log4j-core</artifactId>
@@ -51,6 +65,43 @@
             <version>19.0.2.1</version>
         </dependency>
 
+        <dependency>
+            <groupId>com.jtransc</groupId>
+            <artifactId>jtransc-rt</artifactId>
+            <version>0.5.0-ALPHA4</version>
+        </dependency>
+
+        <!--<dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-core</artifactId>
+            <version>4.3.24.RELEASE</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>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>RELEASE</version>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
     <build>
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/CommunityMapController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/CommunityMapController.java
index 3dc79401a4a89941e5bcffa4b07dacbb45c14817..be1256f441fa09604694e890557db0bd53131531 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/CommunityMapController.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/CommunityMapController.java
@@ -49,7 +49,7 @@ public class CommunityMapController implements Initializable {
 //    TODO: create map preview
 
     @FXML
-    private void backButton() {   // for some reason compiler doesn't recognize method usage when 'back' is used as method name. Any other method name works however
+    private void backButton() {
         parent.getChildren().clear();
         parent.getChildren().add(new SceneLoader().loadScene("MapForge"));
     }
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/CreateAccountController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/CreateAccountController.java
new file mode 100644
index 0000000000000000000000000000000000000000..826cb76c7ba083c1cd0608fe5d6d83e28ef68733
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/CreateAccountController.java
@@ -0,0 +1,86 @@
+package de.hdm_stuttgart.battlearena.Controller;
+
+import de.hdm_stuttgart.battlearena.Controller.Utilities.SceneLoader;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.AccountType;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.DatabaseException;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Persistence;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.Label;
+import javafx.scene.control.RadioButton;
+import javafx.scene.control.TextField;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.layout.VBox;
+
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class CreateAccountController implements Initializable {
+    @FXML
+    private VBox parent;
+    @FXML
+    private RadioButton local;
+    @FXML
+    private ToggleGroup statistics;
+    @FXML
+    private TextField playerName, password;
+    @FXML
+    private Label errorMessage, passwordLabel;
+
+    String selectedButton;
+    SceneLoader sceneLoader = new SceneLoader();
+    Persistence persistence = Persistence.getInstance();
+
+    @Override
+    public void initialize(URL url, ResourceBundle resourceBundle) {
+        getSelected();
+    }
+
+    private void getSelected() {
+        statistics.selectedToggleProperty().addListener((observableValue, toggle, t1) -> {
+            if (statistics.getSelectedToggle() != null) {
+                RadioButton selectedToggle = (RadioButton) statistics.getSelectedToggle();
+                selectedButton = selectedToggle.getText();
+                System.out.println(selectedButton);
+            }
+            if (local.isSelected()) {
+                password.setEditable(false);
+                password.setText("");
+                passwordLabel.setStyle("-fx-text-fill: rgba(0, 0, 0, 0.3)");
+                password.setStyle("-fx-border-color: rgba(0, 0, 0, 0.3)");
+            } else {
+                passwordLabel.setStyle("-fx-text-fill: black");
+                password.setEditable(true);
+                password.setStyle("-fx-border-color: black");
+            }
+        });
+    }
+
+    private void switchScene(String name) {
+        parent.getChildren().clear();
+        parent.getChildren().add(sceneLoader.loadScene(name));
+    }
+
+    @FXML
+    private void create() {
+        AccountType accountType;
+        if (selectedButton.equals("Local")) {
+            accountType = AccountType.LOCAL;
+        } else {
+            accountType = AccountType.ONLINE;
+        }
+        try {
+            persistence.createAccount(playerName.getText(), password.getText(), accountType);
+            persistence.resetPlayerStatistics();
+            persistence.loadPlayerStatistics();
+            switchScene("MainMenu");
+        } catch (DatabaseException e) {
+            errorMessage.setText(e.getMessage());
+        }
+    }
+
+    @FXML
+    private void back() {
+        switchScene("PlayerCreateScene");
+    }
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/Enum/GameMode.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/Enum/GameMode.java
new file mode 100644
index 0000000000000000000000000000000000000000..1979fc24fa3fbaf955b93b4b53942edfd080080c
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/Enum/GameMode.java
@@ -0,0 +1,6 @@
+package de.hdm_stuttgart.battlearena.Controller.Enum;
+
+public enum GameMode {
+    LOCAL,
+    NETWORK
+}
\ No newline at end of file
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/Enum/GameState.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/Enum/GameState.java
new file mode 100644
index 0000000000000000000000000000000000000000..1ea713b41a90fa593348760d6a6be8c9f0ed1a62
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/Enum/GameState.java
@@ -0,0 +1,9 @@
+package de.hdm_stuttgart.battlearena.Controller.Enum;
+
+public enum GameState {
+    MENU,
+    PAUSE,
+    PLAYING,
+    LOST,
+    WON
+}
\ No newline at end of file
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/Enum/PlayerMode.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/Enum/PlayerMode.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb864e26dcdce0777bc7301cfeb51007063ba46f
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/Enum/PlayerMode.java
@@ -0,0 +1,6 @@
+package de.hdm_stuttgart.battlearena.Controller.Enum;
+
+public enum PlayerMode {
+    PLAYER_ONE,
+    PLAYER_TWO
+}
\ No newline at end of file
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 1743c0963b8d10d5aaaba03cfc159bb23a31553f..96304c946ce51211f11fec18c3d44e508d751931 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/GameSceneController.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/GameSceneController.java
@@ -2,6 +2,10 @@ package de.hdm_stuttgart.battlearena.Controller;
 
 import de.hdm_stuttgart.battlearena.Controller.Utilities.ScreenClasses;
 import de.hdm_stuttgart.battlearena.Controller.Utilities.ScreenDimensionCalculator;
+import de.hdm_stuttgart.battlearena.Controller.Enum.GameMode;
+import de.hdm_stuttgart.battlearena.Controller.Enum.GameState;
+import de.hdm_stuttgart.battlearena.Controller.Enum.PlayerMode;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.RuntimeInfo;
 import de.hdm_stuttgart.battlearena.Model.Entity.EntityClass;
 import de.hdm_stuttgart.battlearena.Model.Entity.EntityFactory;
 import de.hdm_stuttgart.battlearena.Model.Entity.EntityType;
@@ -56,11 +60,15 @@ public class GameSceneController implements Initializable {
 
     InputHandler inputHandler = InputHandler.getInstance();
 
+    RuntimeInfo runtimeInfo = RuntimeInfo.getInstance();
+
+    GameMode gameMode = runtimeInfo.getGameMode();
+
     IEntity player;
     IEntity enemy;
 
-    EntityClass playerClass = EntityClass.HUMAN;
-    EntityClass enemyClass = EntityClass.HUMAN;
+    EntityClass playerOneClass = runtimeInfo.getPlayerOneClass();
+    EntityClass playerTwoClass = runtimeInfo.getPlayerTwoClass();
 
     TileManager tileManager;
 
@@ -72,7 +80,7 @@ public class GameSceneController implements Initializable {
                         "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 5 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 " +
@@ -85,7 +93,7 @@ public class GameSceneController implements Initializable {
                         "4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3";
     int horizontalTileCount = 18;
     int verticalTileCount = 18;
-    int diffTileCount = 5;
+    int diffTileCount = 6;
     int scaledTileSize = 48;
 
 
@@ -139,11 +147,20 @@ public class GameSceneController implements Initializable {
         graphicsContext2D = canvas2D.getGraphicsContext2D();
         graphicsContext2D.setImageSmoothing(false);
 
-        player = EntityFactory.createEntity(EntityType.PLAYER, graphicsContext2D, inputHandler, playerClass, this);
-        enemy = EntityFactory.createEntity(EntityType.ENEMY_PLAYER, graphicsContext2D, inputHandler, enemyClass, this);
+        player = EntityFactory.createEntity(EntityType.PLAYER, graphicsContext2D, inputHandler,
+                playerOneClass, this, PlayerMode.PLAYER_ONE);
+        if (gameMode == GameMode.NETWORK) {
+            enemy = EntityFactory.createEntity(EntityType.NETWORK_PLAYER_TWO, graphicsContext2D, inputHandler,
+                    playerTwoClass, this, PlayerMode.PLAYER_TWO);
+        } else {
+            enemy = EntityFactory.createEntity(EntityType.PLAYER, graphicsContext2D, inputHandler,
+                    playerTwoClass, this, PlayerMode.PLAYER_TWO);
+        }
 
         tileManager = new TileManager(graphicsContext2D, diffTileCount, horizontalTileCount, verticalTileCount, mapString);
 
+        runtimeInfo.setGameState(GameState.PLAYING);
+
         AnimationTimer gameLoop = new AnimationTimer() {
             @Override
             public void handle(long l) {
@@ -160,18 +177,25 @@ public class GameSceneController implements Initializable {
         player.updateEntityMovement(this);
         enemy.updateEntityMovement(this);
         player.attack(enemy, graphicsContext2D);
+        enemy.attack(player, graphicsContext2D);
     }
 
     private void renderContent(GraphicsContext graphicsContext) {
         tileManager.renderMap();
         player.renderEntity(graphicsContext);
         enemy.renderEntity(graphicsContext);
+        player.checkHealTile(player, graphicsContext2D);
+        enemy.checkHealTile(enemy, graphicsContext2D);
     }
 
     public IEntity getEnemy() {
         return enemy;
     }
 
+    public IEntity getPlayer() {
+        return player;
+    }
+
     public TileManager getTileManager() {
         return tileManager;
     }
@@ -179,4 +203,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/Controller/IntroController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/IntroController.java
index 2c4472104e35751cedb56601d0b5f6b13f72e278..6a99c538617e193578e4a80332c60baa7c0bcf5e 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/IntroController.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/IntroController.java
@@ -1,6 +1,7 @@
 package de.hdm_stuttgart.battlearena.Controller;
 
 import de.hdm_stuttgart.battlearena.Controller.Utilities.CreateMediaPlayer;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Persistence;
 import javafx.fxml.FXML;
 import javafx.fxml.FXMLLoader;
 import javafx.fxml.Initializable;
@@ -8,6 +9,8 @@ import javafx.scene.Cursor;
 import javafx.scene.layout.BorderPane;
 import javafx.scene.media.MediaPlayer;
 import javafx.scene.media.MediaView;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 import java.io.File;
 import java.io.IOException;
@@ -27,6 +30,8 @@ public class IntroController implements Initializable {
     private File file = new File(fileName + videos[0]);
     private int counter = 0;
     private MediaPlayer mediaPlayer;
+    private final Persistence persistence = Persistence.getInstance();
+    private static final Logger log = LogManager.getLogger(Persistence.class);
 
     @Override
     public void initialize(URL url, ResourceBundle resourceBundle) {
@@ -59,10 +64,9 @@ public class IntroController implements Initializable {
     }
 
     private void videoEnd() {
-//        TODO: check if player exists
         try {
             mediaPlayer.dispose();
-            introParent.getScene().setRoot(FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/fxml/PlayerCreateScene.fxml"))));
+            introParent.getScene().setRoot(FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/fxml/LoadingScreen.fxml"))));
         } catch (IOException e) {
             throw new RuntimeException();
         }
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/LoadingScreenController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/LoadingScreenController.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7aa8a685f37286da95ba3edda224fc8c78f30d4
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/LoadingScreenController.java
@@ -0,0 +1,143 @@
+package de.hdm_stuttgart.battlearena.Controller;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.AccountType;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.DatabaseException;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Persistence;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ThreadStartup1;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ThreadStartup2;
+import javafx.application.Platform;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.geometry.Rectangle2D;
+import javafx.scene.control.Label;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.BorderPane;
+import javafx.stage.Screen;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.*;
+
+public class LoadingScreenController implements Initializable {
+    @FXML
+    private Label tips;
+    @FXML
+    private BorderPane parent;
+    @FXML
+    private ImageView logo, throbber;
+
+    boolean isReady = false;
+    private int counter = 0;
+    private boolean statsLoaded = false;
+    private final String[] loadingTips = {
+            "Did you know, that since 2009, Martin isn't on the FBI list?",
+            "BattleArena is actually derived from the combination of the words 'Battle' and 'Arena'.",
+            "Yannik ist over 1,80m tall.",
+            "Electricity is a vital part to play this game.",
+            "There is a typo in one of the tips.",
+            "Over 1000 people play games every day.",
+            "A lot of people believe Nikola Tesla was the first to invent electricity but some clouds beat him to it.",
+            "Monkeys usually don't have keys.",
+            "While you're reading this, you've wasted 2 seconds.",
+            "If you die, you're dead.",
+            "If you take damage, you loose hp.",
+            "Did you know that Java is also an Island?",
+            "This loading screen might never end.",
+            "Get the BattleArena Ultimate-Edition for only 420,69€.",
+            "To move left, press one of the keys on your keyboard.",
+            "To use the gravity-gun, close the game and start Half Life 2.",
+            "Buying this game was a good decision! (no refunds)."
+    };
+
+    private final List<String> shuffledTips = Arrays.asList(loadingTips);
+    private static final Logger log = LogManager.getLogger(Persistence.class);
+    Rectangle2D screen = Screen.getPrimary().getVisualBounds();
+    ThreadStartup1 thread1 = new ThreadStartup1();
+    ThreadStartup2 thread2 = new ThreadStartup2();
+    Persistence persistence = Persistence.getInstance();
+
+    Thread tipsThread = new Thread(() -> {
+        try {
+            setLoadingTips();
+        } catch (InterruptedException e) {
+            log.info("Data finished loading");
+        }
+    });
+
+    Thread loadingDataThread = new Thread(() -> {
+        try {
+            Thread.sleep(4000);
+            loadData();
+        } catch (IOException e) {
+            throw new RuntimeException();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    });
+
+    @Override
+    public void initialize(URL url, ResourceBundle resourceBundle) {
+        Collections.shuffle(shuffledTips);
+        setImages();
+
+        tipsThread.start();
+        thread1.start();
+
+        boolean threadOneIsRunning = true, threadTwoIsRunning = false;
+        while (!isReady) {
+            if (!thread1.isAlive() && threadOneIsRunning) {
+                thread2.start();
+                threadTwoIsRunning = true;
+                threadOneIsRunning = false;
+            }
+            if (!thread2.isAlive() && threadTwoIsRunning) {
+                isReady = true;
+            }
+        }
+        loadingDataThread.start();
+    }
+
+    private void setImages() {
+        logo.setTranslateY(screen.getHeight() * 0.08);
+        System.out.println(screen.getHeight());
+        logo.setFitWidth(screen.getWidth() * 0.3);
+        throbber.setFitWidth(screen.getWidth() * 0.07);
+        logo.setPreserveRatio(true);
+        throbber.setPreserveRatio(true);
+    }
+
+    private void setLoadingTips() throws InterruptedException {
+        while (!statsLoaded && counter < loadingTips.length) {
+            String nextTip = shuffledTips.get(counter);
+            Platform.runLater(() -> tips.setText(nextTip)); // JavaFX method to queue a task that needs to be executed on the JavaFX application thread (update ui components)
+            counter++;
+
+//            check if statsLoaded is still false before sleeping
+            if (!statsLoaded) {
+                if (nextTip.length() > 60) {
+                    Thread.sleep(6000);
+                } else {
+                    Thread.sleep(3500);
+                }
+                setLoadingTips();
+            }
+        }
+    }
+
+    private void loadData() throws IOException {
+        if (persistence.getAccount().getAccountType() != AccountType.NONE) {
+            try {
+                persistence.loadPlayerStatistics();
+                statsLoaded = true;
+            } catch (DatabaseException e) {
+                log.error(e);
+            }
+        }
+
+        Platform.runLater(tipsThread::interrupt);
+        parent.getScene().setRoot(FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/fxml/MenuBorderPane.fxml"))));
+    }
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/LoginController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/LoginController.java
new file mode 100644
index 0000000000000000000000000000000000000000..6e3fd79dd026c1b1db894041b1782058cd819ab8
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/LoginController.java
@@ -0,0 +1,55 @@
+package de.hdm_stuttgart.battlearena.Controller;
+
+import de.hdm_stuttgart.battlearena.Controller.Utilities.SceneLoader;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.DatabaseException;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.ParserException;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Persistence;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities.Parser;
+import javafx.application.Platform;
+import javafx.fxml.FXML;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.VBox;
+
+import java.security.NoSuchAlgorithmException;
+
+public class LoginController {
+    @FXML
+    private VBox parent;
+    @FXML
+    private TextField playerName, password;
+    @FXML
+    private Label errorMessage;
+
+    SceneLoader sceneLoader = new SceneLoader();
+    Persistence persistence = Persistence.getInstance();
+
+    private void switchScene(String name) {
+        parent.getChildren().clear();
+        parent.getChildren().add(sceneLoader.loadScene(name));
+    }
+
+    @FXML
+    private void login() {
+        errorMessage.setText("Loading an eternity because of slow SQL server...");
+        thread.start();
+    }
+
+    Thread thread = new Thread(() -> {
+        try {
+            persistence.login(playerName.getText(), password.getText());
+            persistence.loadPlayerStatistics();
+            Platform.runLater(() -> switchScene("MainMenu"));
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        } catch (DatabaseException e) {
+            Platform.runLater(() -> errorMessage.setText(e.getMessage()));
+        }
+    });
+
+    @FXML
+    private void back() {
+        thread.interrupt();
+        switchScene("PlayerCreateScene");
+    }
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/MainMenuController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/MainMenuController.java
index c71e7fc4804f06df9f0249a24e102b057c55ba7a..83a6d92e8b0dbe60af7cbbbe09a263afdb51a6b5 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/MainMenuController.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/MainMenuController.java
@@ -1,6 +1,8 @@
 package de.hdm_stuttgart.battlearena.Controller;
 
 import de.hdm_stuttgart.battlearena.Controller.Utilities.SceneLoader;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.DatabaseException;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Persistence;
 import javafx.fxml.FXML;
 import javafx.fxml.Initializable;
 import javafx.scene.control.Button;
@@ -17,6 +19,7 @@ public class MainMenuController implements Initializable {
     @FXML
     private Button exitButton;
     private final SceneLoader sceneLoader = new SceneLoader();
+    private final Persistence persistence = Persistence.getInstance();
 
     private void switchScene(String name) {
         parent.getChildren().clear();
@@ -44,7 +47,9 @@ public class MainMenuController implements Initializable {
     }
 
     @FXML
-    private void exit() {
+    private void exit() throws DatabaseException {
+        persistence.savePlayerStatistics();
+        persistence.saveSettings();
         Stage stage = (Stage) exitButton.getScene().getWindow();
         stage.close();
     }
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/MapForgeController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/MapForgeController.java
index 7f57a6dd566a493f12e2c9ffdea4772df823f130..784361391329dab062e1c64e5aee944381861ff1 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/MapForgeController.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/MapForgeController.java
@@ -2,6 +2,8 @@ package de.hdm_stuttgart.battlearena.Controller;
 
 import de.hdm_stuttgart.battlearena.Controller.Utilities.MusicPlayerSingleton;
 import de.hdm_stuttgart.battlearena.Controller.Utilities.SceneLoader;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.DatabaseException;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Persistence;
 import javafx.fxml.FXML;
 import javafx.fxml.FXMLLoader;
 import javafx.scene.layout.VBox;
@@ -13,6 +15,7 @@ public class MapForgeController {
     @FXML
     private VBox parent;
     SceneLoader sceneLoader = new SceneLoader();
+    private final Persistence persistence = Persistence.getInstance();
 
     @FXML
     private void mapEditorScene() {
@@ -30,13 +33,9 @@ public class MapForgeController {
     }
 
     @FXML
-    private void updateMapScene() {
-        try {
-            parent.getScene().setRoot(FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/fxml/PlayerCreateScene.fxml"))));
-            MusicPlayerSingleton.getInstance().getMediaPlayer().dispose();
-        } catch (IOException e) {
-            throw new RuntimeException();
-        }
+    private void updateMapScene() throws DatabaseException {
+        persistence.updateCoreMaps();
+//        TODO: set message label if update was successful or not
     }
 
     @FXML
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/MapSelectionController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/MapSelectionController.java
new file mode 100644
index 0000000000000000000000000000000000000000..d821334354bd487632d52077ffa4a3c21f6a1914
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/MapSelectionController.java
@@ -0,0 +1,72 @@
+package de.hdm_stuttgart.battlearena.Controller;
+
+import de.hdm_stuttgart.battlearena.Controller.Utilities.MusicPlayerSingleton;
+import de.hdm_stuttgart.battlearena.Controller.Utilities.SceneLoader;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.MapData;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Persistence;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.RuntimeInfo;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.scene.control.ToggleButton;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.ResourceBundle;
+
+public class MapSelectionController implements Initializable {
+    @FXML
+    private VBox boxBox, parent;
+    @FXML
+    private Text selectedMapText;
+
+    private int selectedMap;
+
+    private final SceneLoader sceneLoader = new SceneLoader();
+
+    private final ArrayList<MapData> coreMaps = Persistence.getInstance().getCoreMaps();
+
+    @Override
+    public void initialize(URL url, ResourceBundle resourceBundle) {
+        ToggleGroup group = new ToggleGroup();
+
+        for (int i = 0; i < coreMaps.size(); i++) {
+            ToggleButton toggleButton = new ToggleButton(coreMaps.get(i).getMapName());
+            toggleButton.setToggleGroup(group);
+            boxBox.getChildren().add(toggleButton);
+        }
+
+        group.selectedToggleProperty().addListener((observableValue, oldToggle, newToggle) -> {
+            if (group.getSelectedToggle() != null) {
+                ToggleButton selected = (ToggleButton) group.getSelectedToggle();
+                selectedMap = boxBox.getChildren().indexOf(selected);
+                System.out.println(selectedMap);
+                String value = selected.getText();
+                selectedMapText.setText(value);
+                System.out.println(value);
+            }
+        });
+    }
+
+    @FXML
+    private void gameScene() {
+        try {
+            RuntimeInfo.getInstance().setGameMap(coreMaps.get(selectedMap));
+            MusicPlayerSingleton.getInstance().getMediaPlayer().dispose();
+            parent.getScene().setRoot(FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/fxml/GameScene.fxml"))));
+        } catch (IOException e) {
+            throw new RuntimeException();
+        }
+    }
+
+    @FXML
+    private void backButton() {
+        parent.getChildren().clear();
+        parent.getChildren().add(sceneLoader.loadScene("SkinSelection"));
+    }
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/MenuBorderPaneController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/MenuBorderPaneController.java
index 47fa1988d8563ef57198d22de1ddc62e8a73ce27..7ae68807db90c91640c155306f900445949eb5ca 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/MenuBorderPaneController.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/MenuBorderPaneController.java
@@ -3,6 +3,8 @@ package de.hdm_stuttgart.battlearena.Controller;
 import de.hdm_stuttgart.battlearena.Controller.Utilities.CreateMediaPlayer;
 import de.hdm_stuttgart.battlearena.Controller.Utilities.MusicPlayerSingleton;
 import de.hdm_stuttgart.battlearena.Controller.Utilities.SceneLoader;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.AccountType;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Persistence;
 import javafx.fxml.FXML;
 import javafx.fxml.Initializable;
 import javafx.geometry.Rectangle2D;
@@ -32,17 +34,22 @@ public class MenuBorderPaneController implements Initializable {
     private final SceneLoader sceneLoader = new SceneLoader();
     private MediaPlayer musicPlayer, mediaPlayer;
     private MediaView mediaView;
-    private final String[] videoFiles = {"allMyFellas", "wooOOoo", "myMind", "dogCheese", "gta", "cat", "bobama", "roomba", "firework", "cheezburger",
-            "kangaroo", "lifeCouldBeMonke", "imNotYou", "parkingTickets", "russianKid", "rejectHumanity", "horse", "catSitting", "pablo", "holyCrap",
-            "lessGoo", "sadCat", "basketball", "msPuff", "=D", "banana", "chaCha", "async", "sadHorse", "minecraftCat", "muecke", "top10Cats", "dog",
-            "pot", "mineCraftCat2", "bear", "pancake", "frog", "gtfo", "carl", "dog2", "slippery", "wolf", "legCat", "sad", "waaahhh"};
+    private final String[] videoFiles = {"depression", "allMyFellas", "wooOOoo", "myMind", "dogCheese", "gta", "cat", "bobama", "roomba", "firework", "cheezburger",
+            "kangaroo", "lifeCouldBeMonke", "seal", "rolling", "imNotYou", "parkingTickets", "russianKid", "rejectHumanity", "horse", "catSitting", "pablo", "holyCrap",
+            "lessGoo", "sadCat", "basketball", "yoinkySploinky", "msPuff", "=D", "banana", "chaCha", "async", "sadHorse", "minecraftCat", "muecke", "top10Cats", "dog",
+            "pot", "mineCraftCat2", "catEating", "catJump", "bear", "pancake", "frog", "gtfo", "carl", "dog2", "slippery", "wolf", "legCat", "sad", "waaahhh"};
 
     List<String> shuffledVideos = Arrays.asList(videoFiles);
 
     Rectangle2D screen = Screen.getPrimary().getVisualBounds();
+
     @Override
     public void initialize(URL url, ResourceBundle resourceBundle) {
-        center.getChildren().add(sceneLoader.loadScene("MainMenu"));
+        if (Persistence.getInstance().getAccount().getAccountType() == AccountType.NONE) {
+            center.getChildren().add(sceneLoader.loadScene("PlayerCreateScene"));
+        } else {
+            center.getChildren().add(sceneLoader.loadScene("MainMenu"));
+        }
 //        set size for rusty gear image depending on screen resolution
         final double imageWidth = screen.getWidth() / 6;
         imgRight.setFitWidth(imageWidth);
@@ -107,6 +114,7 @@ public class MenuBorderPaneController implements Initializable {
     private void backgroundMusic(String file) {
         Media media = new Media(new File("src/main/resources/sound/music/" + file).toURI().toString());
         musicPlayer = new MediaPlayer(media);
+        musicPlayer.setVolume((double) Persistence.getInstance().getSettings().getMusicVolume() / 100);
         musicPlayer.setCycleCount(MediaPlayer.INDEFINITE);
         musicPlayer.play();
         MusicPlayerSingleton.getInstance().setMediaPlayer(musicPlayer);
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/PlaceholderController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/PlaceholderController.java
new file mode 100644
index 0000000000000000000000000000000000000000..a018d9e82ae12e61b22762484397f479597ff0c1
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/PlaceholderController.java
@@ -0,0 +1,51 @@
+package de.hdm_stuttgart.battlearena.Controller;
+
+import de.hdm_stuttgart.battlearena.Controller.Utilities.CreateMediaPlayer;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.fxml.Initializable;
+import javafx.scene.control.Button;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.media.Media;
+import javafx.scene.media.MediaPlayer;
+import javafx.scene.media.MediaView;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Objects;
+import java.util.ResourceBundle;
+
+public class PlaceholderController implements Initializable {
+    @FXML
+    private BorderPane parent;
+    @FXML
+    private MediaView mediaView;
+    @FXML
+    private Button button;
+    private MediaPlayer mediaPlayer, musicPlayer;
+
+    @Override
+    public void initialize(URL url, ResourceBundle resourceBundle) {
+        File file = new File("src/main/resources/videos/construction.mp4");
+        mediaPlayer = new CreateMediaPlayer().getMediaPlayer(mediaView, file, true, parent);
+        mediaView.setMediaPlayer(mediaPlayer);
+        mediaPlayer.setCycleCount(MediaPlayer.INDEFINITE);
+        parent.setStyle("-fx-font-size: 50; -fx-text-fill: white; -fx-font-family: 'Arial Black'");
+
+        Media musicMedia = new Media(new File("src/main/resources/sound/music/constructionJazz.mp3").toURI().toString());
+        musicPlayer = new MediaPlayer(musicMedia);
+        musicPlayer.setCycleCount(MediaPlayer.INDEFINITE);
+        musicPlayer.setAutoPlay(true);
+
+        button.setOnMouseClicked(mouseEvent -> {
+            try {
+                mediaPlayer.dispose();
+                musicPlayer.dispose();
+                parent.getScene().setRoot(FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/fxml/MenuBorderPane.fxml"))));
+            } catch (IOException e) {
+                throw new RuntimeException();
+            }
+        });
+    }
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/PlayerCreateController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/PlayerCreateController.java
index 68dfd4029aad7452c5d19d82fdfcaec3f0e8435e..56f73045145a2c36b567f177e7423cd86f0bcd07 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/PlayerCreateController.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/PlayerCreateController.java
@@ -1,51 +1,34 @@
 package de.hdm_stuttgart.battlearena.Controller;
 
-import de.hdm_stuttgart.battlearena.Controller.Utilities.CreateMediaPlayer;
+import de.hdm_stuttgart.battlearena.Controller.Utilities.SceneLoader;
 import javafx.fxml.FXML;
-import javafx.fxml.FXMLLoader;
-import javafx.fxml.Initializable;
-import javafx.scene.control.Button;
-import javafx.scene.layout.BorderPane;
-import javafx.scene.media.Media;
-import javafx.scene.media.MediaPlayer;
-import javafx.scene.media.MediaView;
+import javafx.scene.layout.VBox;
+import javafx.stage.Stage;
 
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Objects;
-import java.util.ResourceBundle;
-
-public class PlayerCreateController implements Initializable {
-    @FXML
-    private BorderPane parent;
-    @FXML
-    private MediaView mediaView;
+public class PlayerCreateController {
     @FXML
-    private Button button;
-    private MediaPlayer mediaPlayer, musicPlayer;
+    private VBox parent;
 
-    @Override
-    public void initialize(URL url, ResourceBundle resourceBundle) {
-        File file = new File("src/main/resources/videos/construction.mp4");
-        mediaPlayer = new CreateMediaPlayer().getMediaPlayer(mediaView, file, true, parent);
-        mediaView.setMediaPlayer(mediaPlayer);
-        mediaPlayer.setCycleCount(MediaPlayer.INDEFINITE);
-        parent.setStyle("-fx-font-size: 50; -fx-text-fill: white; -fx-font-family: 'Arial Black'");
+    SceneLoader sceneLoader = new SceneLoader();
 
-        Media musicMedia = new Media(new File("src/main/resources/sound/music/constructionJazz.mp3").toURI().toString());
-        musicPlayer = new MediaPlayer(musicMedia);
-        musicPlayer.setCycleCount(MediaPlayer.INDEFINITE);
-        musicPlayer.setAutoPlay(true);
+    private void switchScene(String name) {
+        parent.getChildren().clear();
+        parent.getChildren().add(sceneLoader.loadScene(name));
+    }
 
-        button.setOnMouseClicked(mouseEvent -> {
-            try {
-                mediaPlayer.dispose();
-                musicPlayer.dispose();
-                parent.getScene().setRoot(FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/fxml/MenuBorderPane.fxml"))));
-            } catch (IOException e) {
-                throw new RuntimeException();
-            }
-        });
+    @FXML
+    private void createScene() {
+        switchScene("CreateAccount");
+    }
+
+    @FXML
+    private void loginScene() {
+        switchScene("Login");
+    }
+
+    @FXML
+    private void exit() {
+        Stage stage = (Stage) parent.getScene().getWindow();
+        stage.close();
     }
 }
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/SettingsController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/SettingsController.java
index a3c7526665111d073af465d5c74599952442b63b..836c9cf9df4f8f17b7633fac1c0867d9b00bac02 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/SettingsController.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/SettingsController.java
@@ -2,6 +2,7 @@ package de.hdm_stuttgart.battlearena.Controller;
 
 import de.hdm_stuttgart.battlearena.Controller.Utilities.MusicPlayerSingleton;
 import de.hdm_stuttgart.battlearena.Controller.Utilities.SceneLoader;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Persistence;
 import javafx.fxml.FXML;
 import javafx.fxml.FXMLLoader;
 import javafx.fxml.Initializable;
@@ -17,14 +18,16 @@ public class SettingsController implements Initializable {
     @FXML
     private VBox parent;
     @FXML
-    private Slider musicVolume, sfxVolume;
+    private Slider musicSlider, sfxSlider;
     SceneLoader sceneLoader = new SceneLoader();
-    public double music;
+    private int musicVolume, sfxVolume;
     MusicPlayerSingleton musicPlayer = MusicPlayerSingleton.getInstance();
+    Persistence persistence = Persistence.getInstance();
 
     @Override
     public void initialize(URL url, ResourceBundle resourceBundle) {
         setMusicVolume();
+        setSfxVolume();
     }
 
     @FXML
@@ -35,22 +38,34 @@ public class SettingsController implements Initializable {
 
     @FXML
     private void backButton() {
+        switchScene("MainMenu");
+    }
+
+    @FXML
+    private void account() {
+        switchScene("PlayerCreateScene");
+    }
+
+    private void switchScene(String name) {
         parent.getChildren().clear();
-        parent.getChildren().add(sceneLoader.loadScene("MainMenu"));
+        parent.getChildren().add(sceneLoader.loadScene(name));
     }
 
     private void setMusicVolume() {
-//        need a runtime database to save volume
-        musicVolume.valueProperty().addListener((observableValue, oldValue, newValue) -> {
-            setMusic(musicVolume);
-            System.out.println(music);
+        musicSlider.setValue(persistence.getSettings().getMusicVolume());
+        musicSlider.valueProperty().addListener((observableValue, oldValue, newValue) -> {
+            musicVolume = newValue.intValue();
+            persistence.getSettings().setMusicVolume(musicVolume);
+            musicPlayer.getMediaPlayer().setVolume((double) musicVolume / 100);
         });
     }
 
-    private void setMusic(Slider slider) {
-        slider.valueProperty().addListener(((observableValue, oldValue, newValue) -> {
-            music = newValue.doubleValue() / 100;
-            musicPlayer.getMediaPlayer().setVolume(music);
+    private void setSfxVolume(){
+        sfxSlider.setValue(persistence.getSettings().getSfxVolume());
+        sfxSlider.valueProperty().addListener(((observableValue, oldValue, newValue) -> {
+            sfxVolume = newValue.intValue();
+            persistence.getSettings().setSfxVolume(sfxVolume);
+//            sfxPlayer.getMediaPlayer().setVolume((double) sfxVolume / 100);
         }));
     }
 }
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/SkinSelectionController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/SkinSelectionController.java
index 226c55739e694653d84fc674d240ff5667a5e980..5276d92651d747ed1ad42b757b0d3c3fde9c241a 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/SkinSelectionController.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/SkinSelectionController.java
@@ -1,5 +1,6 @@
 package de.hdm_stuttgart.battlearena.Controller;
 
+import de.hdm_stuttgart.battlearena.Controller.Utilities.MusicPlayerSingleton;
 import de.hdm_stuttgart.battlearena.Controller.Utilities.SceneLoader;
 import javafx.fxml.FXML;
 import javafx.fxml.FXMLLoader;
@@ -53,11 +54,7 @@ public class SkinSelectionController implements Initializable {
 
     @FXML
     private void gameScene() {
-        try {
-//            MusicPlayerSingleton.getInstance().getMediaPlayer().dispose();
-            parent.getScene().setRoot(FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/fxml/GameScene.fxml"))));
-        } catch (IOException e) {
-            throw new RuntimeException();
-        }
+        parent.getChildren().clear();
+        parent.getChildren().add(new SceneLoader().loadScene("MapSelection"));
     }
 }
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/StatisticsController.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/StatisticsController.java
index 009c8a94b5f4a68c3c1b21ddcf194621be698a9c..ee8ccd517fc9c48f3178e792d136dba3f20783e8 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/StatisticsController.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/StatisticsController.java
@@ -1,6 +1,7 @@
 package de.hdm_stuttgart.battlearena.Controller;
 
 import de.hdm_stuttgart.battlearena.Controller.Utilities.SceneLoader;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Persistence;
 import javafx.beans.binding.Bindings;
 import javafx.collections.FXCollections;
 import javafx.collections.ObservableList;
@@ -23,6 +24,8 @@ public class StatisticsController implements Initializable {
     private PieChart kd, wl;
     SceneLoader sceneLoader = new SceneLoader();
 
+    Persistence persistence = Persistence.getInstance();
+
     public void mainMenuScene() {
         parent.getChildren().clear();
         parent.getChildren().add(sceneLoader.loadScene("MainMenu"));
@@ -30,17 +33,27 @@ public class StatisticsController implements Initializable {
 
     @Override
     public void initialize(URL url, ResourceBundle resourceBundle) {
-        iniPieChartkd();
-        iniPieChartwl();
+        iniPieChartKD();
+        iniPieChartWL();
         kd.setLegendVisible(false);
         wl.setLegendVisible(false);
+        setLabels();
+    }
+
+    private void setLabels() {
+        kills.setText(String.valueOf(persistence.getStatistics().getKills()));
+        gamesWon.setText(Integer.toString(persistence.getStatistics().getGamesWon()));
+        gamesLost.setText(String.valueOf(persistence.getStatistics().getGamesLost()));
+        gameTime.setText(Integer.toString(persistence.getStatistics().getGameTimeInHours()));
+        deaths.setText(String.valueOf(persistence.getStatistics().getDeaths()));
+        blocks.setText(Integer.toString(persistence.getStatistics().getBlocksDestroyed()));
     }
 
-    public void iniPieChartkd() {
+    public void iniPieChartKD() {
         ObservableList<PieChart.Data> pieChartData =
                 FXCollections.observableArrayList(
-                        new PieChart.Data("Kills", 20),
-                        new PieChart.Data("Deaths", 12));
+                        new PieChart.Data("Kills", persistence.getStatistics().getKills()),
+                        new PieChart.Data("Deaths", persistence.getStatistics().getDeaths()));
 
         pieChartData.forEach(data ->
                 data.nameProperty().bind(
@@ -52,11 +65,11 @@ public class StatisticsController implements Initializable {
         kd.getData().addAll(pieChartData);
     }
 
-    public void iniPieChartwl() {
+    public void iniPieChartWL() {
         ObservableList<PieChart.Data> pieChartData =
                 FXCollections.observableArrayList(
-                        new PieChart.Data("Wins", 3),
-                        new PieChart.Data("Losses", 5));
+                        new PieChart.Data("Wins", persistence.getStatistics().getGamesWon()),
+                        new PieChart.Data("Losses", persistence.getStatistics().getGamesLost()));
 
         pieChartData.forEach(data ->
                 data.nameProperty().bind(
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Controller/Utilities/ButtonTransition.java b/src/main/java/de/hdm_stuttgart/battlearena/Controller/Utilities/ButtonTransition.java
index b129d469320cdd8549e234a3a5d6fae8901187ea..8e59516428834ab48bf7a9b2cfebb1760ad63308 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Controller/Utilities/ButtonTransition.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Controller/Utilities/ButtonTransition.java
@@ -1,6 +1,7 @@
 package de.hdm_stuttgart.battlearena.Controller.Utilities;
 
 import javafx.animation.ScaleTransition;
+import javafx.application.Platform;
 import javafx.scene.control.Button;
 import javafx.scene.control.skin.ButtonSkin;
 import javafx.util.Duration;
@@ -13,14 +14,20 @@ public class ButtonTransition extends ButtonSkin {
         fadeIn.setNode(button);
         fadeIn.setToX(1.1);
         fadeIn.setToY(1.1);
-        button.setOnMouseEntered(e -> fadeIn.playFromStart());
+
+//        this ensures that any JavaFX related code is run on the JavaFX application thread
+        button.setOnMouseEntered(e -> {
+            Platform.runLater(fadeIn::playFromStart);
+        });
 
 //        set transition for mouse exiting buttonButtonTransitionScale
         final ScaleTransition fadeOut = new ScaleTransition(Duration.millis(150));
         fadeOut.setNode(button);
         fadeOut.setToX(1.0);
         fadeOut.setToY(1.0);
-        button.setOnMouseExited(e -> fadeOut.playFromStart());
+        button.setOnMouseExited(e -> {
+            Platform.runLater(fadeOut::playFromStart);
+        });
 
         button.setScaleX(1.0);
         button.setScaleY(1.0);
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Main/Driver.java b/src/main/java/de/hdm_stuttgart/battlearena/Main/Driver.java
new file mode 100644
index 0000000000000000000000000000000000000000..66f93ada9d0e18cccb86262356517c4f79d881e3
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Main/Driver.java
@@ -0,0 +1,75 @@
+package de.hdm_stuttgart.battlearena.Main;
+
+
+import de.hdm_stuttgart.battlearena.Model.Sound.SoundManager;
+import de.hdm_stuttgart.battlearena.Model.Inputs.InputHandler;
+
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.geometry.Rectangle2D;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.image.Image;
+import javafx.scene.text.Font;
+import javafx.stage.Screen;
+import javafx.stage.Stage;
+
+import javafx.stage.StageStyle;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.util.Objects;
+
+public class Driver extends Application {
+
+    private static final Logger log = LogManager.getLogger(Driver.class);
+    Rectangle2D screen = Screen.getPrimary().getVisualBounds();
+
+    InputHandler inputHandler = InputHandler.getInstance();
+
+    SoundManager soundManager = new SoundManager();
+
+    @Override
+    public void start(Stage stage) throws Exception {
+
+//        loading font in start() because CSS can't handle whitespace in folder names
+        Font.loadFont(getClass().getResourceAsStream("/fonts/StarshipShadow.ttf"), 50);
+        Font.loadFont(getClass().getResourceAsStream("/fonts/AmaticSC-Bold.ttf"), 50);
+        Font.loadFont(getClass().getResourceAsStream("/fonts/Arthemis-mLA22.ttf"), 50);
+        Font.loadFont(getClass().getResourceAsStream("/fonts/ShadowsIntoLight-Regular.ttf"), 50);
+
+        Parent root =  FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/fxml/LoadingScreen.fxml")));
+
+        Scene scene = new Scene(root);
+
+        scene.setOnKeyPressed(inputHandler::handleKeyPress);
+        scene.setOnKeyReleased(inputHandler::handleKeyRelease);
+
+        stage.setTitle("BattleArena");
+        stage.getIcons().add(new Image("file:src/main/resources/textures/images/icon.png"));
+        stage.setScene(scene);
+        stage.minHeightProperty().setValue(400);
+        stage.minWidthProperty().setValue(600);
+        stage.setMaximized(true);
+        stage.setWidth(screen.getWidth());
+        stage.setHeight(screen.getHeight());
+        stage.initStyle(StageStyle.UNDECORATED);
+        scene.getStylesheets().add(Objects.requireNonNull(this.getClass().getResource("/styles/style.css")).toExternalForm());
+        stage.setScene(scene);
+
+        stage.setOnCloseRequest(event -> {
+            if (soundManager != null) {
+                soundManager.stopMusic();
+            }
+        });
+
+        stage.show();
+        log.debug("Project started successfully!");
+
+//        Exiting program if an exception occurs
+//        Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
+//            log.error(throwable.getMessage());
+//            System.exit(1);
+//        });
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Main/Main.java b/src/main/java/de/hdm_stuttgart/battlearena/Main/Main.java
index 1925554e2b86d0efcb4b469b1ca2d799c6ecaec0..77261800125e391620b0facc16c47a6ee3217f79 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Main/Main.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Main/Main.java
@@ -1,59 +1,9 @@
 package de.hdm_stuttgart.battlearena.Main;
 
-import de.hdm_stuttgart.battlearena.Model.Inputs.InputHandler;
 import javafx.application.Application;
-import javafx.fxml.FXMLLoader;
-import javafx.geometry.Rectangle2D;
-import javafx.scene.Parent;
-import javafx.scene.Scene;
-import javafx.scene.image.Image;
-import javafx.scene.text.Font;
-import javafx.stage.Screen;
-import javafx.stage.Stage;
-
-import javafx.stage.StageStyle;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import java.util.Objects;
-
-public class Main extends Application {
-
-    private static final Logger log = LogManager.getLogger(Main.class);
-    Rectangle2D screen = Screen.getPrimary().getVisualBounds();
-
-    InputHandler inputHandler = InputHandler.getInstance();
 
+public class Main {
     public static void main(String[] args) {
-        launch(args);
-    }
-
-    @Override
-    public void start(Stage stage) throws Exception {
-//        loading font in start() because CSS can't handle whitespace in folder names
-        Font.loadFont(getClass().getResourceAsStream("/fonts/StarshipShadow.ttf"), 50);
-
-//        TODO: revert back to intro scene
-        Parent root =  FXMLLoader.load(Objects.requireNonNull(getClass().getResource("/fxml/MenuBorderPane.fxml")));
-
-        Scene scene = new Scene(root);
-
-        scene.setOnKeyPressed(inputHandler::handleKeyPress);
-        scene.setOnKeyReleased(inputHandler::handleKeyRelease);
-
-        stage.setTitle("BattleArena");
-        stage.getIcons().add(new Image("file:src/main/resources/textures/images/icon.png"));
-        stage.setScene(scene);
-        stage.minHeightProperty().setValue(400);
-        stage.minWidthProperty().setValue(600);
-        stage.setMaximized(true);
-        stage.setWidth(screen.getWidth());
-        stage.setHeight(screen.getHeight());
-        stage.initStyle(StageStyle.UNDECORATED);
-        scene.getStylesheets().add(Objects.requireNonNull(this.getClass().getResource("/styles/style.css")).toExternalForm());
-        stage.setScene(scene);
-
-        stage.show();
-        log.debug("Project started successfully!");
+        Application.launch(Driver.class, args);
     }
-}
\ No newline at end of file
+}
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..710cf9ca3be97bbf21ff8aa00304dff1f8c19b87
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/AppSettings.java
@@ -0,0 +1,30 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+public class AppSettings {
+
+    private int sfxVolume;      //values from 0 to 100 (volume in percent)
+    private int musicVolume;    //values from 0 to 100 (volume in percent)
+
+
+    public AppSettings(int sfxVolume, int musicVolume) {
+        this.sfxVolume = sfxVolume;
+        this.musicVolume = musicVolume;
+    }
+
+    public void setSfxVolume(int sfxVolume) {
+        this.sfxVolume = sfxVolume;
+    }
+
+    public int getSfxVolume() {
+        return sfxVolume;
+    }
+
+    public void setMusicVolume(int musicVolume) {
+        this.musicVolume = musicVolume;
+    }
+
+    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..f75e8d1d4f322ef6b6c6302549337ea8b2a550b4
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/AzureDB.java
@@ -0,0 +1,271 @@
+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;
+
+/*this class is only here for showcasing the interchangeability of the DBMS. AzureDB could be used as fallback database when primary database is unreachable*/
+
+public class AzureDB 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\\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;";
+            Connection connection = DriverManager.getConnection(url);
+            //log.info("Database connection test" + connection.getCatalog());
+            connection.setAutoCommit(true);
+
+            log.info("Connecting to SQL database ...");
+
+            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")));
+            }
+            rs.close();
+            stmt.close();
+            log.info("Core-Maps retrieved successfully from SQL server!");
+            return newMaps;
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error retrieving Core-Maps from SQL server! " + 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 from SQL server!");
+            return tempList;
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error retrieving Community-Map names from SQL server! " + 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 SQL 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 from SQL server!");
+            return stats;
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error retrieving player statistics from SQL server! " + 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 SQL 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 from SQL server!");
+
+            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 for downloaded map.");
+            stmt2.close();
+
+            return mapChosen;
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error retrieving Community-Map from SQL server! " + 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 from SQL server!");
+            return password;
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error retrieving retrieving player credentials from SQL server! " + 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, map_downloads) VALUES (?, ?, ?, ?, ?, 0)";
+            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 to SQL server!");
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error uploading created Community-Map to SQL server! " + 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 on SQL server!");
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error creating online account on SQL server! " + 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 on SQL server!");
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error updating player statistics on SQL server! " + e.getMessage());
+        }
+    }
+
+    @Override
+    public void resetPlayerStats(PlayerAccount account) throws SQLException{        //verification of player credentials necessary beforehand (use methode "verifyAccountData" in "Persistence.java)
+        try(Connection connection = connect()) {
+            String sql = "UPDATE players SET games_won = 0, games_lost = 0, kills = 0, deaths = 0, blocks_destroyed = 0, ingame_time = 0 WHERE player_name = ?";
+            PreparedStatement stmt = connection.prepareStatement(sql);
+            stmt.setString(1, account.getPlayerName());
+
+            log.info("Sending SQL statement.");
+            stmt.executeQuery();
+
+            stmt.close();
+            log.info("Player statistics reset successfully on SQL server!");
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error resetting player statistics on SQL server! " + e.getMessage());
+        }
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ENUMs/AccountType.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ENUMs/AccountType.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ddb26cd2de6356b40b45af16dad0b9dfeb7f4d8
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ENUMs/AccountType.java
@@ -0,0 +1,9 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs;
+
+public enum AccountType {
+
+    NONE,
+    LOCAL,
+    ONLINE
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ENUMs/MapType.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ENUMs/MapType.java
new file mode 100644
index 0000000000000000000000000000000000000000..8403ea2c46b21e5b8349917316f7414eb1a74710
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ENUMs/MapType.java
@@ -0,0 +1,8 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs;
+
+public enum MapType {
+
+    COREMAP,
+    COMMUNITYMAP
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ENUMs/ThreadStatus.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ENUMs/ThreadStatus.java
new file mode 100644
index 0000000000000000000000000000000000000000..48ef20b9c36ce3e1758460adb489b643a7175c8e
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ENUMs/ThreadStatus.java
@@ -0,0 +1,10 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs;
+
+public enum ThreadStatus {
+
+    RUNNING,
+    FAILED,
+    FINISHED,
+    NONE
+
+}
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..0b6bb2a2974338947bbbd2a7f299ef52077dfd59
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/GsonHandler.java
@@ -0,0 +1,149 @@
+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.ENUMs.MapType;
+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);
+            if(type == MapType.COREMAP){
+                log.info("GSON - Loading Core-Maps from JSON failed!");
+                throw new GSONException("Loading Core-Maps from JSON failed!");
+            }
+            else{
+                log.info("GSON - Loading Community-Maps from JSON failed!");
+                throw new GSONException("Loading Community-Maps from JSON failed!");
+            }
+        }
+    }
+
+    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);
+            if(type == MapType.COREMAP){
+                log.info("GSON - Saving Core-Maps to JSON failed!");
+                throw new GSONException("Saving Core-Maps to JSON failed!");
+            }
+            else{
+                log.info("GSON - Saving Community-Maps to JSON failed!");
+                throw new GSONException("Saving Community-Maps to JSON failed!");
+            }
+        }
+    }
+
+    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("Loading player statistics from JSON failed!");
+        }
+    }
+
+    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("Saving player statistics to JSON failed!");
+        }
+    }
+
+    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("Loading settings from JSON failed!");
+        }
+    }
+
+    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("Saving settings to JSON failed!");
+        }
+    }
+
+    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("Loading player account information from JSON failed!");
+        }
+    }
+
+    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("Saving player account information to JSON failed!");
+        }
+    }
+
+}
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..7a169c9b21d76b2a7eba64b8899dbb5e397b22cb
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ISQLDataBase.java
@@ -0,0 +1,24 @@
+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;
+    void resetPlayerStats(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/OracleDB.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/OracleDB.java
new file mode 100644
index 0000000000000000000000000000000000000000..856fe24df247e972c4ed074ddddce4fd1f71a1ce
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/OracleDB.java
@@ -0,0 +1,272 @@
+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");
+    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 SQL 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("Core-Maps retrieved successfully from SQL server!");
+            return newMaps;
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error retrieving Core-Maps from SQL server! " + 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 from SQL server!");
+            return tempList;
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error retrieving Community-Map names from SQL server! " + 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 SQL 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 from SQL server!");
+            return stats;
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error retrieving player statistics from SQL server! " + 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 SQL 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 from SQL server!");
+
+            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 for downloaded map!");
+            stmt2.close();
+
+            return mapChosen;
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error retrieving Community-Map from SQL server! " + 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 from SQL server!");
+            return password;
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error retrieving retrieving player credentials from SQL server! " + 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, map_downloads) VALUES (?, ?, ?, ?, ?, 0)";
+            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 to SQL server!");
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error uploading created Community-Map to SQL server! " + 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 on SQL server!");
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error creating online account on SQL server! " + 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 on SQL server!");
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error updating player statistics on SQL server! " + e.getMessage());
+        }
+    }
+
+    @Override
+    public void resetPlayerStats(PlayerAccount account) throws SQLException{        //verification of player credentials necessary beforehand (use methode "verifyAccountData" in "Persistence.java)
+        try(Connection connection = connect()) {
+            String sql = "UPDATE battlearenadata.players SET games_won = 0, games_lost = 0, kills = 0, deaths = 0, blocks_destroyed = 0, ingame_time = 0 WHERE player_name = ?";
+            PreparedStatement stmt = connection.prepareStatement(sql);
+            stmt.setString(1, account.getPlayerName());
+
+            log.info("Sending SQL statement.");
+            stmt.executeQuery();
+
+            stmt.close();
+            log.info("Player statistics reset successfully on SQL server!");
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new SQLException("Error resetting player statistics on SQL server! " + 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..9291ee84f4f5721980c84957f9e7f58532f46e8c
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Persistence.java
@@ -0,0 +1,480 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.AccountType;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.MapType;
+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.security.NoSuchAlgorithmException;
+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" for testing purposes to showcase Mockito tests
+    private ArrayList<MapData> coreMaps;
+    private ArrayList<MapData> communityMaps;
+    private PlayerStatistics statistics;
+    private PlayerAccount account;
+    private AppSettings settings;
+    private ArrayList<MapInfo> communityMapsListRemote;  //for community map browser
+
+
+
+    private Persistence (){}
+
+    public static Persistence getInstance(){
+        return persistenceSingleton;
+    }
+
+    public ArrayList<MapData> getCoreMaps() {
+        return coreMaps;
+    }
+
+    public ArrayList<MapData> getCommunityMaps() {
+        return communityMaps;
+    }
+
+    public PlayerStatistics getStatistics() {
+        return statistics;
+    }
+
+    public PlayerAccount getAccount() {
+        return account;
+    }
+
+    public AppSettings getSettings() {
+        return settings;
+    }
+
+    public ArrayList<MapInfo> getCommunityMapsListRemote() {
+        return communityMapsListRemote;
+    }
+
+    public void loadPlayerAccount() throws DatabaseException {
+        try {
+            account = gsonHandler.loadAccount();
+            log.info("Player account successfully loaded!");
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new DatabaseException("Loading player account data from local storage failed!");
+        }
+    }
+
+    public void loadPlayerStatistics() throws DatabaseException {
+        try {
+            if (account.getAccountType() == AccountType.LOCAL) {
+                statistics = gsonHandler.loadStats();
+                Parser.playerStatsValid(statistics);
+            } else {
+                statistics = db.getStatistics(account.getPlayerName());
+                Parser.playerStatsValid(statistics);
+            }
+            log.info("Player statistics successfully loaded!");
+        }
+        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());
+        }
+        catch (ParserException e) {
+            throw new RuntimeException("Player statistics data corrupted!");
+        }
+    }
+
+    public void loadCoreMaps() throws DatabaseException {
+        try {
+            coreMaps = gsonHandler.loadMaps(MapType.COREMAP);
+            log.info("Core-Maps successfully loaded from file!");
+            //createCoreMapsList();
+        }
+        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!");
+            //createLocalCommunityMapsList();
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new DatabaseException("Loading community maps from local storage 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 updateCoreMaps() throws DatabaseException {
+        try {
+            coreMaps = db.getCoreMaps();
+            gsonHandler.saveMaps(coreMaps, MapType.COREMAP);
+            //createCoreMapsList();
+            log.info("Core-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);
+            //createLocalCommunityMapsList();
+            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 saveSettings(){
+        try{
+        gsonHandler.saveSettings(settings);
+        }
+        catch(Exception e){
+            log.error(e);
+        }
+    }
+
+    public void savePlayerStatistics() throws DatabaseException{     //on shutdown of game
+        try {
+            Parser.playerStatsValid(statistics);
+            if (account.getAccountType() == AccountType.LOCAL) {
+                gsonHandler.saveStats(statistics);
+            } else if (account.getAccountType() == AccountType.ONLINE) {
+                db.updatePlayerStats(statistics, account);
+            }
+            log.info("Statistics successfully saved!");
+        }
+        catch(Exception e){
+            log.error(e);
+        }
+    }
+
+    public void saveCreatedMap(MapData map, boolean doUpload) throws DatabaseException {
+        String part1 = "";
+        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")){
+                part1 = e.getMessage();
+            }
+        }
+        if(doUpload) {
+            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(part1 + "\nNo connection to SQL server! Saving to SQL communityMap server failed!");
+                } else if (e.getMessage().contains("ORA-00001")) {
+                    throw new DatabaseException(part1 + "\nMap already existing on communityMaps server!\n Look for mapID: " + map.getMapID());
+                } else {
+                    throw new DatabaseException(part1 + "\nUnknown Database Error. Saving to SQL communityMap server failed!");
+                }
+            }
+        }
+    }
+
+    public void updatePlayerStatistics(int kills, int deaths, int gameTime, int blocksDestroyed, boolean gameWon) throws DatabaseException{  //after game round; only update stats in RAM, not in persistence (run savePlayerStatistics() method at end of program to save stats to persistence)
+        try {
+            Parser.playerStatsValid(new PlayerStatistics(0, 0, kills, deaths, blocksDestroyed, gameTime)); //temp instance of PLayerStatistics to validate new values
+            statistics.addKills(kills);
+            statistics.addDeaths(deaths);
+            statistics.addGameTime(gameTime);
+            statistics.addBlocksDestroyed(blocksDestroyed);
+            if(gameWon){
+                statistics.addGamesWon();
+            }
+            else{
+                statistics.addGamesLost();
+            }
+            log.info("Statistics successfully updated!");
+        }
+        catch(Exception e){
+            log.error(e);
+        }
+    }
+
+    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);
+            log.info("Player account successfully created!");
+        }
+        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 createRemoteCommunityMapsList(){        //for Map-Browser
+        try {
+            communityMapsListRemote = db.getCommunityMapsList();
+            log.info("MapList successfully retrieved from server!");
+            //log.info(communityMapsListRemote.get(0).getMapName());                 //for testing purposes
+        }
+        catch(Exception e){
+            log.error(e);
+        }
+    }
+
+    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.sha1HexHashValid(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{   //eigentlich überflüssig, da GSON schon beim Laden der Daten meckern würde, wenn er den Accounttype nicht finden kann
+                throw new DatabaseException("AccountType invalid - accountData corrupted! Please create new Account or login with existing!");
+            }
+            log.info("Player account successfully verified!");
+        }
+        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 SQL 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 verifyCoreMaps() throws DatabaseException{
+        try {
+            for (int i = 0; coreMaps.size() > i; i++) {
+                Parser.mapDataValid(coreMaps.get(i).getMapData());
+                Parser.mapNameValid(coreMaps.get(i).getMapName());
+                Parser.sha1HexHashValid(coreMaps.get(i).getMapID());
+                if(!HashGenerator.hashAndHex(coreMaps.get(i).getMapData()).equals(coreMaps.get(i).getMapID())){
+                    throw new DatabaseException("mapData Hash does not match mapID!");
+                }
+            }
+            log.info("Core-Maps data is valid!");
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new DatabaseException(e.getMessage());
+        }
+    }
+
+    public void verifyCommunityMaps() throws DatabaseException{
+        try {
+            for (int i = 0; communityMaps.size() > i; i++) {
+                Parser.mapDataValid(communityMaps.get(i).getMapData());
+                Parser.mapNameValid(communityMaps.get(i).getMapName());
+                Parser.sha1HexHashValid(communityMaps.get(i).getMapID());
+                if(!HashGenerator.hashAndHex(communityMaps.get(i).getMapData()).equals(communityMaps.get(i).getMapID())){
+                    throw new DatabaseException("mapData Hash does not match mapID!");
+                }
+            }
+            log.info("Community-Maps data is valid!");
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new DatabaseException(e.getMessage());
+        }
+    }
+
+    public void verifyAppSettings() throws DatabaseException{
+        try {
+            Parser.volumeValid(settings.getSfxVolume());
+            Parser.volumeValid(settings.getMusicVolume());
+            log.info("Settings data is valid!");
+        }
+        catch(Exception e){
+            log.error(e);
+            throw new DatabaseException(e.getMessage());
+        }
+    }
+
+    public void resetPlayerAccount() throws DatabaseException{
+        try{
+            account = new PlayerAccount("", "", AccountType.NONE);
+            gsonHandler.saveAccount(account);
+            log.info("Player account successfully reset!");
+        }
+        catch(Exception e){
+            log.error(e);
+        }
+    }
+
+    public void resetPlayerStatistics() throws DatabaseException{
+        try {
+            if (account.getAccountType() == AccountType.LOCAL) {
+                statistics = new PlayerStatistics(0, 0, 0, 0, 0, 0);
+                gsonHandler.saveStats(statistics);
+            } else if (account.getAccountType() == AccountType.ONLINE) {
+                verifyPlayerAccount();
+                db.resetPlayerStats(account);
+                statistics = new PlayerStatistics(0, 0, 0, 0, 0, 0);
+            }
+            log.info("Player statistics successfully reset on local storage!");
+        }
+        catch(Exception e){
+            log.error(e);
+        }
+    }
+
+    public void resetSettings(){
+        try {
+            settings = new AppSettings(50, 50);
+            gsonHandler.saveSettings(settings);
+        }
+        catch(Exception e){
+            log.error(e);
+        }
+    }
+
+    public void resetCoreMaps(){
+        try {
+            coreMaps = new ArrayList<MapData>();
+            coreMaps.add(new MapData("09a02b54d05b5b7ebc29a4383ca12d3dda846b72", "Arena1", 18, 18, "12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+            coreMaps.add(new MapData("0ab15557ab6dc4be60dfe6a9b0288bac3036bd97", "Arena2", 18, 18, "12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 5 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+            gsonHandler.saveMaps(coreMaps, MapType.COREMAP);
+            log.info("Core maps successfully reset on local storage!");
+        }
+        catch(Exception e){
+            log.error(e);
+        }
+    }
+
+    public void resetCommunityMaps(){
+        try {
+            communityMaps = new ArrayList<MapData>();
+            communityMaps.add(new MapData("fbf44184867512faecc195ae75ca55d5ab7bad2d", "Arena3", 18, 18, "12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 8 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+            communityMaps.add(new MapData("1c23b362fd666c5fb7ed60ca611b17246424e49f", "Arena4", 18, 18, "12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 8 4 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+            gsonHandler.saveMaps(communityMaps, MapType.COMMUNITYMAP);
+            log.info("Community maps successfully reset on local storage!");
+        }
+        catch(Exception e){
+            log.error(e);
+        }
+    }
+
+    public void login(String userName, String password) throws NoSuchAlgorithmException, RuntimeException, DatabaseException {
+        try {
+            String hash = HashGenerator.hashAndHex(password);
+            if (hash.equals(db.checkCredentials(userName))) {
+                account = new PlayerAccount(userName, hash, AccountType.ONLINE);
+                gsonHandler.saveAccount(account);
+                log.info("Login successful!");
+            } else {
+                throw new DatabaseException("Wrong password!");
+            }
+        }
+        catch (GSONException | SQLException e) {
+            throw new RuntimeException(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..ae1e60649de3d31e4a1b99e70de92a9bfbfe0c53
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/PlayerAccount.java
@@ -0,0 +1,30 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.AccountType;
+
+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..4f8783f2ee9afb7e50e038047615d63f4eaa8d20
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/PlayerStatistics.java
@@ -0,0 +1,78 @@
+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;   //in seconds
+
+    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;
+    }
+
+    protected void addGamesLost() {
+        gamesLost = gamesLost + 1;
+    }
+
+    public int getGamesWon() {
+        return gamesWon;
+    }
+
+    protected void addGamesWon() {
+        gamesWon = gamesWon + 1;
+    }
+
+    public int getKills() {
+        return kills;
+    }
+
+    protected void addKills(int kills) {
+        this.kills = this.kills + kills;
+    }
+
+    public int getDeaths() {
+        return deaths;
+    }
+
+    protected void addDeaths(int deaths) {
+        this.deaths = this.deaths + deaths;
+    }
+
+    public int getBlocksDestroyed() {
+        return blocksDestroyed;
+    }
+
+    protected void addBlocksDestroyed(int blocksDestroyed) {
+        this.blocksDestroyed = this.blocksDestroyed + blocksDestroyed;
+    }
+
+    public int getGameTime() {
+        return gameTime;
+    }
+
+    public int getGameTimeInHours(){
+        return gameTime / 3600;
+    }
+
+    protected void addGameTime(int gameTime) {
+        this.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..38ae10a6052607adc5c2279eb8058f1da8107551
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/RuntimeInfo.java
@@ -0,0 +1,159 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Controller.Enum.GameMode;
+import de.hdm_stuttgart.battlearena.Controller.Enum.GameState;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+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 de.hdm_stuttgart.battlearena.Model.Entity.EntityClass;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class RuntimeInfo {
+
+    private static final Logger log = LogManager.getLogger(RuntimeInfo.class);
+    private static final RuntimeInfo runtimeInfoSingleton = new RuntimeInfo();
+    private String mapDataGame;
+    private MapData mapGame;
+    private boolean offlineMode;  //if Account-Type is online but no SQL connection: start game without stats tracking
+    private GameState gameState = GameState.MENU; //Default value: MENU
+    private GameMode gameMode = GameMode.LOCAL; //Default value: LOCAL
+
+    //Default value: HUMAN
+    private EntityClass playerOneClass = EntityClass.HUMAN;
+    private EntityClass playerTwoClass = EntityClass.HUMAN;
+
+    //Stats Tracking during Gameplay
+    private int kills;
+    private int deaths;
+    private int blocksDestroyed;
+    private int gameTime;
+    private boolean gameWon;
+
+
+
+
+
+
+    private RuntimeInfo(){};
+
+    public static RuntimeInfo getInstance(){
+        return runtimeInfoSingleton;
+    }
+
+    public MapData generateMap(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(MapData mapSelected){    //Create Game Scene Dropdown list directly gives reference to selected map
+        try {
+            mapGame = mapSelected;
+            mapDataGame = mapSelected.getMapData();
+        }
+        catch(Exception e){
+            log.error(e);
+        }
+    }
+
+    public GameState getGameState() {
+        return gameState;
+    }
+
+    public void setGameState(GameState gameState) {
+        this.gameState = gameState;
+    }
+
+    public GameMode getGameMode() {
+        return gameMode;
+    }
+
+    public void setGameMode(GameMode gameMode) {
+        this.gameMode = gameMode;
+    }
+
+    public EntityClass getPlayerOneClass() {
+        return playerOneClass;
+    }
+
+    public void setPlayerOneClass(EntityClass playerOneClass) {
+        this.playerOneClass = playerOneClass;
+    }
+
+    public EntityClass getPlayerTwoClass() {
+        return playerTwoClass;
+    }
+
+    public void setPlayerTwoClass(EntityClass playerTwoClass) {
+        this.playerTwoClass = playerTwoClass;
+    }
+
+    public String getMapDataGame() {
+        return mapDataGame;
+    }
+
+    public int getKills() {
+        return kills;
+    }
+
+    public void setKills(int kills) {
+        this.kills = kills;
+    }
+
+    public void addKill() {
+        kills = kills + 1;
+    }
+
+    public int getDeaths() {
+        return deaths;
+    }
+
+    public void setDeaths(int deaths) {
+        this.deaths = deaths;
+    }
+
+    public void addDeath() {
+        deaths = deaths + 1;
+    }
+
+    public int getBlocksDestroyed() {
+        return blocksDestroyed;
+    }
+
+    public void setBlocksDestroyed(int blocksDestroyed) {
+        this.blocksDestroyed = blocksDestroyed;
+    }
+
+    public void addBlockDestroyed() {
+        blocksDestroyed = blocksDestroyed + 1;
+    }
+
+    public int getGameTime() {
+        return gameTime;
+    }
+
+    public void setGameTime(int gameTime) {
+        this.gameTime = gameTime;
+    }
+
+    public void addGameTime() {
+        gameTime = gameTime + 1;
+    }
+
+    public boolean isGameWon() {
+        return gameWon;
+    }
+
+    public void setGameWon(boolean gameWon) {
+        this.gameWon = gameWon;
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadCreateAcc.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadCreateAcc.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7f37c6deec9db193b2f3ac8410cf28cbf44b202
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadCreateAcc.java
@@ -0,0 +1,42 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.AccountType;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ThreadCreateAcc extends Thread{
+
+    private static final Logger log = LogManager.getLogger(ThreadCreateAcc.class);
+    private String playerName;
+    private String password;
+    private AccountType type;
+
+    @Override
+    public void run() {
+
+        Persistence persistenceInst = Persistence.getInstance();
+        Threads threadsInstance = Threads.getInstance();
+
+        try {
+            threadsInstance.setThreadCreateAccMsg("");
+            threadsInstance.setThreadCreateAcc(ThreadStatus.RUNNING);
+            persistenceInst.createAccount(playerName, password, type);
+            log.info("Create account thread finished successfully!");
+            threadsInstance.setThreadCreateAcc(ThreadStatus.FINISHED);
+        } catch (Exception e) {
+            log.error(e);
+            threadsInstance.setThreadCreateAccMsg(e.getMessage());
+            log.info("Create account thread failed!");
+            threadsInstance.setThreadCreateAcc(ThreadStatus.FAILED);
+        }
+    }
+
+    public void startThread(String playerName, String password, AccountType type){
+        this.playerName = playerName;
+        this.password = password;
+        this.type = type;
+        start();
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadDLCommMap.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadDLCommMap.java
new file mode 100644
index 0000000000000000000000000000000000000000..76bf3c0ebcc16150b3e34d907faaf0b5c33794e7
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadDLCommMap.java
@@ -0,0 +1,37 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ThreadDLCommMap extends Thread{
+
+    private static final Logger log = LogManager.getLogger(ThreadDLCommMap.class);
+    private String mapID;
+
+    @Override
+    public void run() {
+
+        Persistence persistenceInst = Persistence.getInstance();
+        Threads threadsInstance = Threads.getInstance();
+
+        try {
+            threadsInstance.setThreadDLCommMapMsg("");
+            threadsInstance.setThreadDLCommMap(ThreadStatus.RUNNING);
+            persistenceInst.getCommunityMap(mapID);
+            log.info("Download Community-Map thread finished successfully!");
+            threadsInstance.setThreadDLCommMap(ThreadStatus.FINISHED);
+        } catch (Exception e) {
+            log.error(e);
+            threadsInstance.setThreadDLCommMapMsg(e.getMessage());
+            log.info("Download Community-Map thread failed!");
+            threadsInstance.setThreadDLCommMap(ThreadStatus.FAILED);
+        }
+    }
+
+    public void startThread(String mapID){
+        this.mapID = mapID;
+        start();
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadGetMapList.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadGetMapList.java
new file mode 100644
index 0000000000000000000000000000000000000000..0062eaf71c227ed5aa6614307e6024357f691560
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadGetMapList.java
@@ -0,0 +1,31 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ThreadGetMapList extends Thread {
+
+    private static final Logger log = LogManager.getLogger(ThreadGetMapList.class);
+
+    @Override
+    public void run() {
+
+        Persistence persistenceInst = Persistence.getInstance();
+        Threads threadsInstance = Threads.getInstance();
+
+        try {
+            threadsInstance.setThreadCommMapListMsg("");
+            threadsInstance.setThreadCommMapList(ThreadStatus.RUNNING);
+            persistenceInst.createRemoteCommunityMapsList();
+            log.info("Retrieving Community-Map-List thread finished successfully!");
+            threadsInstance.setThreadCommMapList(ThreadStatus.FINISHED);
+        } catch (Exception e) {
+            log.error(e);
+            threadsInstance.setThreadCommMapListMsg(e.getMessage());
+            log.info("Retrieving Community-Map-List thread failed!");
+            threadsInstance.setThreadCommMapList(ThreadStatus.FAILED);
+        }
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadLogin.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadLogin.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6bb5e6c7c647dfe372702933672eead65c56b02
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadLogin.java
@@ -0,0 +1,39 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ThreadLogin extends Thread{
+
+    private static final Logger log = LogManager.getLogger(ThreadLogin.class);
+    private String userName;
+    private String password;
+
+    @Override
+    public void run() {
+
+        Persistence persistenceInst = Persistence.getInstance();
+        Threads threadsInstance = Threads.getInstance();
+
+        try {
+            threadsInstance.setThreadLoginMsg("");
+            threadsInstance.setThreadLogin(ThreadStatus.RUNNING);
+            persistenceInst.login(userName, password);
+            log.info("Login thread finished successfully!");
+            threadsInstance.setThreadLogin(ThreadStatus.FINISHED);
+        } catch (Exception e) {
+            log.error(e);
+            threadsInstance.setThreadLoginMsg(e.getMessage());
+            log.info("Login thread failed!");
+            threadsInstance.setThreadLogin(ThreadStatus.FAILED);
+        }
+    }
+
+    public void startThread(String userName, String password){
+        this.userName = userName;
+        this.password = password;
+        start();
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadRstStats.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadRstStats.java
new file mode 100644
index 0000000000000000000000000000000000000000..c815c70fc73043c305ddad9e575ac662207a50ac
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadRstStats.java
@@ -0,0 +1,31 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ThreadRstStats extends Thread {
+
+    private static final Logger log = LogManager.getLogger(ThreadRstStats.class);
+
+    @Override
+    public void run() {
+
+        Persistence persistenceInst = Persistence.getInstance();
+        Threads threadsInstance = Threads.getInstance();
+
+        try {
+            threadsInstance.setThreadRstStatsMsg("");
+            threadsInstance.setThreadRstStats(ThreadStatus.RUNNING);
+            persistenceInst.resetPlayerStatistics();
+            log.info("Reset Player-Statistics thread finished successfully!");
+            threadsInstance.setThreadRstStats(ThreadStatus.FINISHED);
+        } catch (Exception e) {
+            log.error(e);
+            threadsInstance.setThreadRstStatsMsg(e.getMessage());
+            log.info("Reset Player-Statistics thread failed!");
+            threadsInstance.setThreadRstStats(ThreadStatus.FAILED);
+        }
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadSaveCommMap.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadSaveCommMap.java
new file mode 100644
index 0000000000000000000000000000000000000000..47877f48acc768333279887fd1a899bdb046ac65
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadSaveCommMap.java
@@ -0,0 +1,39 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ThreadSaveCommMap extends Thread{
+
+    private static final Logger log = LogManager.getLogger(ThreadSaveCommMap.class);
+    private MapData map;
+    private boolean doUpload;
+
+    @Override
+    public void run() {
+
+        Persistence persistenceInst = Persistence.getInstance();
+        Threads threadsInstance = Threads.getInstance();
+
+        try {
+            threadsInstance.setThreadSaveCommMapMsg("");
+            threadsInstance.setThreadSaveCommMap(ThreadStatus.RUNNING);
+            persistenceInst.saveCreatedMap(map, doUpload);
+            log.info("Uploading Community-Map thread finished successfully!");
+            threadsInstance.setThreadSaveCommMap(ThreadStatus.FINISHED);
+        } catch (Exception e) {
+            log.error(e);
+            threadsInstance.setThreadSaveCommMapMsg(e.getMessage());
+            log.info("Uploading Community-Map thread failed!");
+            threadsInstance.setThreadSaveCommMap(ThreadStatus.FAILED);
+        }
+    }
+
+    public void startThread(MapData map, boolean doUpload){     //user can check box to optionally publish map on SQL server
+        this.map = map;
+        this.doUpload = doUpload;
+        start();
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadSaveStats.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadSaveStats.java
new file mode 100644
index 0000000000000000000000000000000000000000..3b6c425300db7c7790908c47e36e2282e788b33e
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadSaveStats.java
@@ -0,0 +1,31 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ThreadSaveStats extends Thread{
+
+    private static final Logger log = LogManager.getLogger(ThreadSaveStats.class);
+
+    @Override
+    public void run() {
+
+        Persistence persistenceInst = Persistence.getInstance();
+        Threads threadsInstance = Threads.getInstance();
+
+        try {
+            threadsInstance.setThreadSaveStatsMsg("");
+            threadsInstance.setThreadSaveStats(ThreadStatus.RUNNING);
+            persistenceInst.savePlayerStatistics();
+            log.info("Save Player-Statistics thread finished successfully!");
+            threadsInstance.setThreadSaveStats(ThreadStatus.FINISHED);
+        } catch (Exception e) {
+            log.error(e);
+            threadsInstance.setThreadSaveStatsMsg(e.getMessage());
+            log.info("Save Player-Statistics thread failed!");
+            threadsInstance.setThreadSaveStats(ThreadStatus.FAILED);
+        }
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadStartup1.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadStartup1.java
new file mode 100644
index 0000000000000000000000000000000000000000..3b8016b8ed5629b16ef2d949f6fc9a0376f51ad1
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadStartup1.java
@@ -0,0 +1,36 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ThreadStartup1 extends Thread{
+
+    private static final Logger log = LogManager.getLogger(ThreadStartup1.class);
+
+    @Override
+    public void run() {
+
+        Persistence persistenceInst = Persistence.getInstance();
+        Threads threadsInstance = Threads.getInstance();
+
+        try {
+            threadsInstance.setThreadStartup1Msg("");
+            threadsInstance.setThreadStartup1(ThreadStatus.RUNNING);
+            persistenceInst.loadSettings();
+            persistenceInst.loadCoreMaps();
+            persistenceInst.loadCommunityMaps();
+            persistenceInst.verifyAppSettings();
+            persistenceInst.verifyCoreMaps();
+            persistenceInst.verifyCommunityMaps();
+            log.info("Startup routine part1 complete!");
+            threadsInstance.setThreadStartup1(ThreadStatus.FINISHED);
+        } catch (Exception e) {
+            log.error(e);
+            threadsInstance.setThreadStartup1Msg(e.getMessage());
+            log.info("Startup routine part1 failed!");
+            threadsInstance.setThreadStartup1(ThreadStatus.FAILED);
+        }
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadStartup2.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadStartup2.java
new file mode 100644
index 0000000000000000000000000000000000000000..50ba60bf4edc9c10f56ed27e7833a65ae3e808d6
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadStartup2.java
@@ -0,0 +1,35 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.AccountType;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ThreadStartup2 extends Thread{
+
+    private static final Logger log = LogManager.getLogger(ThreadStartup2.class);
+
+    @Override
+    public void run() {
+
+        Persistence persistenceInst = Persistence.getInstance();
+        Threads threadsInstance = Threads.getInstance();
+
+        try {
+            threadsInstance.setThreadStartup2Msg("");
+            threadsInstance.setThreadStartup2(ThreadStatus.RUNNING);
+            persistenceInst.loadPlayerAccount();
+            if(persistenceInst.getAccount().getAccountType() != AccountType.NONE){
+                persistenceInst.verifyPlayerAccount();
+            }
+            log.info("Startup routine part2 complete!");
+            threadsInstance.setThreadStartup2(ThreadStatus.FINISHED);
+        } catch (Exception e) {
+            log.error(e);
+            threadsInstance.setThreadStartup2Msg(e.getMessage());
+            log.info("Startup routine part2 failed!");
+            threadsInstance.setThreadStartup2(ThreadStatus.FAILED);
+        }
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadStartup3.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadStartup3.java
new file mode 100644
index 0000000000000000000000000000000000000000..738c4add7276cc2706a23204b0b7daef94e51975
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadStartup3.java
@@ -0,0 +1,35 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.AccountType;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ThreadStartup3 extends Thread{
+
+    private static final Logger log = LogManager.getLogger(ThreadStartup3.class);
+
+    @Override
+    public void run() {
+
+        Persistence persistenceInst = Persistence.getInstance();
+        Threads threadsInstance = Threads.getInstance();
+
+        try {
+            threadsInstance.setThreadStartup3Msg("");
+            threadsInstance.setThreadStartup3(ThreadStatus.RUNNING);
+            persistenceInst.loadPlayerStatistics();
+            if(persistenceInst.getAccount().getAccountType() != AccountType.NONE){
+                persistenceInst.verifyPlayerAccount();
+            }
+            log.info("Startup routine part3 complete!");
+            threadsInstance.setThreadStartup3(ThreadStatus.FINISHED);
+        } catch (Exception e) {
+            log.error(e);
+            threadsInstance.setThreadStartup3Msg(e.getMessage());
+            log.info("Startup routine part3 failed!");
+            threadsInstance.setThreadStartup3(ThreadStatus.FAILED);
+        }
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadUpdateMaps.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadUpdateMaps.java
new file mode 100644
index 0000000000000000000000000000000000000000..f0bc303975da0e08d54330a3331e9dca7bee1577
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadUpdateMaps.java
@@ -0,0 +1,31 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ThreadUpdateMaps extends Thread{
+
+    private static final Logger log = LogManager.getLogger(ThreadUpdateMaps.class);
+
+    @Override
+    public void run() {
+
+        Persistence persistenceInst = Persistence.getInstance();
+        Threads threadsInstance = Threads.getInstance();
+
+        try {
+            threadsInstance.setThreadUpdateMapsMsg("");
+            threadsInstance.setThreadUpdateMaps(ThreadStatus.RUNNING);
+            persistenceInst.updateCoreMaps();
+            log.info("Update Core-Maps thread finished successfully!");
+            threadsInstance.setThreadUpdateMaps(ThreadStatus.FINISHED);
+        } catch (Exception e) {
+            log.error(e);
+            threadsInstance.setThreadUpdateMapsMsg(e.getMessage());
+            log.info("Update Core-Maps thread failed!");
+            threadsInstance.setThreadUpdateMaps(ThreadStatus.FAILED);
+        }
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadUpdateStats.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadUpdateStats.java
new file mode 100644
index 0000000000000000000000000000000000000000..44ae6fe13e20f599800784e95dc6b0bd9a8ca9b7
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/ThreadUpdateStats.java
@@ -0,0 +1,37 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ThreadUpdateStats extends Thread{
+
+    private static final Logger log = LogManager.getLogger(ThreadUpdateStats.class);
+
+    @Override
+    public void run() {
+
+        Persistence persistenceInst = Persistence.getInstance();
+        RuntimeInfo runtimeInfoInst = RuntimeInfo.getInstance();
+        Threads threadsInstance = Threads.getInstance();
+
+        try {
+            threadsInstance.setThreadUpdateStatsMsg("");
+            threadsInstance.setThreadUpdateStats(ThreadStatus.RUNNING);
+            persistenceInst.updatePlayerStatistics(runtimeInfoInst.getKills(), runtimeInfoInst.getDeaths(), runtimeInfoInst.getGameTime(), runtimeInfoInst.getBlocksDestroyed(), runtimeInfoInst.isGameWon());
+            runtimeInfoInst.setKills(0);
+            runtimeInfoInst.setDeaths(0);
+            runtimeInfoInst.setGameTime(0);
+            runtimeInfoInst.setBlocksDestroyed(0);
+            runtimeInfoInst.setGameWon(false);
+            log.info("Update statistics thread finished successfully!");
+            threadsInstance.setThreadUpdateStats(ThreadStatus.FINISHED);
+        } catch (Exception e) {
+            log.error(e);
+            threadsInstance.setThreadUpdateStatsMsg(e.getMessage());
+            log.info("Update statistics thread failed!");
+            threadsInstance.setThreadUpdateStats(ThreadStatus.FAILED);
+        }
+    }
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Threads.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Threads.java
new file mode 100644
index 0000000000000000000000000000000000000000..ebf4876b70d047545985366e5983fdd7438a97ec
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Threads.java
@@ -0,0 +1,237 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs.ThreadStatus;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class Threads {
+
+    private static final Logger log = LogManager.getLogger(Threads.class);
+    private static final Threads threadsSingleton = new Threads();
+
+    //Thread Status-Updates
+    private ThreadStatus threadStartup1;
+    private String threadStartup1Msg;
+    private ThreadStatus threadStartup2;
+    private String threadStartup2Msg;
+    private ThreadStatus threadStartup3;
+    private String threadStartup3Msg;
+    private ThreadStatus threadUpdateMaps;
+    private String threadUpdateMapsMsg;
+    private ThreadStatus threadUpdateStats;
+    private String threadUpdateStatsMsg;
+    private ThreadStatus threadDLCommMap;
+    private String threadDLCommMapMsg;
+    private ThreadStatus threadSaveCommMap;
+    private String threadSaveCommMapMsg;
+    private ThreadStatus threadCommMapList;
+    private String threadCommMapListMsg;
+    private ThreadStatus threadRstStats;
+    private String threadRstStatsMsg;
+    private ThreadStatus threadSaveStats;
+    private String threadSaveStatsMsg;
+    private ThreadStatus threadCreateAcc;
+    private String threadCreateAccMsg;
+    private ThreadStatus threadLogin;
+    private String threadLoginMsg;
+
+
+
+    private Threads(){};
+    public static Threads getInstance(){
+        return threadsSingleton;
+    }
+
+    public ThreadStatus getThreadStartup1() {
+        return threadStartup1;
+    }
+
+    public void setThreadStartup1(ThreadStatus threadStartup1) {
+        this.threadStartup1 = threadStartup1;
+    }
+
+    public String getThreadStartup1Msg() {
+        return threadStartup1Msg;
+    }
+
+    public void setThreadStartup1Msg(String threadStartup1Msg) {
+        this.threadStartup1Msg = threadStartup1Msg;
+    }
+
+    public ThreadStatus getThreadStartup2() {
+        return threadStartup2;
+    }
+
+    public void setThreadStartup2(ThreadStatus threadStartup2) {
+        this.threadStartup2 = threadStartup2;
+    }
+
+    public String getThreadStartup2Msg() {
+        return threadStartup2Msg;
+    }
+
+    public void setThreadStartup2Msg(String threadStartup2Msg) {
+        this.threadStartup2Msg = threadStartup2Msg;
+    }
+
+    public ThreadStatus getThreadUpdateMaps() {
+        return threadUpdateMaps;
+    }
+
+    public ThreadStatus getThreadStartup3() {
+        return threadStartup3;
+    }
+
+    public void setThreadStartup3(ThreadStatus threadStartup3) {
+        this.threadStartup3 = threadStartup3;
+    }
+
+    public String getThreadStartup3Msg() {
+        return threadStartup3Msg;
+    }
+
+    public void setThreadStartup3Msg(String threadStartup3Msg) {
+        this.threadStartup3Msg = threadStartup3Msg;
+    }
+
+    public void setThreadUpdateMaps(ThreadStatus threadUpdateMaps) {
+        this.threadUpdateMaps = threadUpdateMaps;
+    }
+
+    public String getThreadUpdateMapsMsg() {
+        return threadUpdateMapsMsg;
+    }
+
+    public void setThreadUpdateMapsMsg(String threadUpdateMapsMsg) {
+        this.threadUpdateMapsMsg = threadUpdateMapsMsg;
+    }
+
+    public ThreadStatus getThreadUpdateStats() {
+        return threadUpdateStats;
+    }
+
+    public void setThreadUpdateStats(ThreadStatus threadUpdateStats) {
+        this.threadUpdateStats = threadUpdateStats;
+    }
+
+    public String getThreadUpdateStatsMsg() {
+        return threadUpdateStatsMsg;
+    }
+
+    public void setThreadUpdateStatsMsg(String threadUpdateStatsMsg) {
+        this.threadUpdateStatsMsg = threadUpdateStatsMsg;
+    }
+
+    public ThreadStatus getThreadDLCommMap() {
+        return threadDLCommMap;
+    }
+
+    public void setThreadDLCommMap(ThreadStatus threadDLCommMap) {
+        this.threadDLCommMap = threadDLCommMap;
+    }
+
+    public String getThreadDLCommMapMsg() {
+        return threadDLCommMapMsg;
+    }
+
+    public void setThreadDLCommMapMsg(String threadDLCommMapMsg) {
+        this.threadDLCommMapMsg = threadDLCommMapMsg;
+    }
+
+    public ThreadStatus getThreadSaveCommMap() {
+        return threadSaveCommMap;
+    }
+
+    public void setThreadSaveCommMap(ThreadStatus threadSaveCommMap) {
+        this.threadSaveCommMap = threadSaveCommMap;
+    }
+
+    public String getThreadSaveCommMapMsg() {
+        return threadSaveCommMapMsg;
+    }
+
+    public void setThreadSaveCommMapMsg(String threadSaveCommMapMsg) {
+        this.threadSaveCommMapMsg = threadSaveCommMapMsg;
+    }
+
+    public ThreadStatus getThreadCommMapList() {
+        return threadCommMapList;
+    }
+
+    public void setThreadCommMapList(ThreadStatus threadCommMapList) {
+        this.threadCommMapList = threadCommMapList;
+    }
+
+    public String getThreadCommMapListMsg() {
+        return threadCommMapListMsg;
+    }
+
+    public void setThreadCommMapListMsg(String threadCommMapListMsg) {
+        this.threadCommMapListMsg = threadCommMapListMsg;
+    }
+
+    public ThreadStatus getThreadRstStats() {
+        return threadRstStats;
+    }
+
+    public void setThreadRstStats(ThreadStatus threadRstStats) {
+        this.threadRstStats = threadRstStats;
+    }
+
+    public String getThreadRstStatsMsg() {
+        return threadRstStatsMsg;
+    }
+
+    public void setThreadRstStatsMsg(String threadRstStatsMsg) {
+        this.threadRstStatsMsg = threadRstStatsMsg;
+    }
+
+    public ThreadStatus getThreadSaveStats() {
+        return threadSaveStats;
+    }
+
+    public void setThreadSaveStats(ThreadStatus threadSaveStats) {
+        this.threadSaveStats = threadSaveStats;
+    }
+
+    public String getThreadSaveStatsMsg() {
+        return threadSaveStatsMsg;
+    }
+
+    public void setThreadSaveStatsMsg(String threadSaveStatsMsg) {
+        this.threadSaveStatsMsg = threadSaveStatsMsg;
+    }
+
+    public ThreadStatus getThreadCreateAcc() {
+        return threadCreateAcc;
+    }
+
+    public void setThreadCreateAcc(ThreadStatus threadCreateAcc) {
+        this.threadCreateAcc = threadCreateAcc;
+    }
+
+    public String getThreadCreateAccMsg() {
+        return threadCreateAccMsg;
+    }
+
+    public void setThreadCreateAccMsg(String threadCreateAccMsg) {
+        this.threadCreateAccMsg = threadCreateAccMsg;
+    }
+
+    public ThreadStatus getThreadLogin() {
+        return threadLogin;
+    }
+
+    public void setThreadLogin(ThreadStatus threadLogin) {
+        this.threadLogin = threadLogin;
+    }
+
+    public String getThreadLoginMsg() {
+        return threadLoginMsg;
+    }
+
+    public void setThreadLoginMsg(String threadLoginMsg) {
+        this.threadLoginMsg = threadLoginMsg;
+    }
+
+}
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..b7a04381a3f69ba1c3083c64986b73794d6ac51c
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/Parser.java
@@ -0,0 +1,361 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.ParserException;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.PlayerStatistics;
+
+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 {
+        int minUsernameLength = 4;
+        int maxUsernameLength = 40;
+
+        if(username.length() < minUsernameLength){
+            throw new ParserException("Username too short! Min length is " + minUsernameLength + " characters.");
+        }
+        if(username.length() > maxUsernameLength){
+            throw new ParserException("Username too long! Max length is " + maxUsernameLength + " 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 {
+        int minPasswordLength = 4;
+        int maxPasswordLength = 40;
+
+        if(password.length() < minPasswordLength){
+            throw new ParserException("Password too short! Min length is " + minPasswordLength + " characters.");
+        }
+        if(password.length() > maxPasswordLength){
+            throw new ParserException("Password too long! Max length is " + maxPasswordLength + " 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 {
+        int minMapNameLength = 4;
+        int maxMapNameLength = 30;
+
+        if(mapName.length() < minMapNameLength){
+            throw new ParserException("Map-Name too short! Min length is " + minMapNameLength + " characters.");
+        }
+        if(mapName.length() > maxMapNameLength){
+            throw new ParserException("Map-Name too long! Max length is " + maxMapNameLength + " 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 sha1HexHashValid(String mapID) throws ParserException {
+        int hashLength = 40;
+
+        if(mapID.length() != hashLength){
+            throw new ParserException("SHA1 hash length not correct. Must have length of " + hashLength + " 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! SHA1 hash only consists out of letters a-f and/or numbers 0-9!");
+        }
+    }
+
+    public static void ipAddressValid(String address) throws ParserException {
+
+        int addressMinLength = 7;
+        int addressMaxLength = 15;
+        int addressLength = address.length();
+        int octetMinDecValue = 0;
+        int octetMaxDecValue = 255;
+
+        if(address.equals("localhost")){
+            return;
+        }
+
+        if(addressLength > addressMaxLength){
+            throw new ParserException("IP-Address too long. Must have maximum length of " + addressMaxLength + " characters including octet dividers (.) !");
+        }
+
+        if(addressLength < addressMinLength){
+            throw new ParserException("IP-Address too short. Must have minimum length of " + addressMinLength + " characters including octet dividers (.) !");
+        }
+
+        if(address.charAt(0) == '.' | address.charAt(addressLength - 1) == '.'){
+            throw new ParserException("IP-Address must not start nor end with octet dividers (.) !");
+        }
+
+        int counter = 0;
+        for(int i = 0; addressLength > i ; i++){
+            if(address.charAt(i) == '.'){
+                counter++;
+            }
+        }
+        if(counter != 3){
+            throw new ParserException("IP-Address must contain exactly 3 octet dividers (.) !");
+        }
+
+        for(int i = 0; addressLength > i ; i++){
+            if(address.charAt(i) == '.' && address.charAt(i + 1) == '.'){
+                throw new ParserException("IP-Address must not contain two or more consecutive dividers (.) without number in between!");
+            }
+        }
+
+        Pattern pat = Pattern.compile("[^0-9.]");
+        for(int i = 0; addressLength > i ; i++){
+            Matcher mat = pat.matcher(address.substring(i, i+1));
+            boolean result = mat.find();
+            if(result){
+                throw new ParserException("IP address must consist out of numbers 0-9 and separators (.) !");
+            }
+        }
+
+        counter = 0;
+        int[] positions = new int[4];
+        positions[0] = 0;
+        for(int i = 0; addressLength > i ; i++){
+            if(address.charAt(i) == '.'){
+                counter++;
+                positions[counter] = i + 1;
+            }
+        }
+        for(int i = 0; positions.length > i; i++){
+            if(positions.length - 1 > i) {
+                if (Integer.parseInt(address.substring(positions[i], positions[i + 1] - 1)) > octetMaxDecValue) {
+                    throw new ParserException("Octets of IP-address must not exceed 255!");
+                }
+            }
+            else{
+                if (Integer.parseInt(address.substring(positions[i], addressLength)) > octetMaxDecValue) {
+                    throw new ParserException("Octets of IP-address must not exceed 255!");
+                }
+            }
+        }
+    }
+
+    public static void mapDataValid(String mapData) throws ParserException {
+
+        //values could be handed to method (Instance of MapData Class)
+        int actualMapDataLength = mapData.length();
+        int mapWidth = 18;         //Tiles
+        int mapHeight = 18;        //Tiles
+        int spacesAmount = (mapHeight * mapWidth) - 1;      //space used as separator
+        int totalTilesAmount = mapHeight * mapWidth;
+        int borderTilesAmount = (2 * mapWidth) + (2 * (mapHeight - 2));
+        int spawnTilesAmount = 4;
+        int fieldTilesAmount = totalTilesAmount - borderTilesAmount - spawnTilesAmount;
+        int maxTileNumberDigits = 2;  //Tile-Numbers are max 2 digits: 10 to 29
+        int minTileNumberDigits = 1; //Tile-Numbers are min 1 digit: 0 to 9
+        int minTileNumber = 0;
+        int maxTileNumber = 29;
+        int walkableTileMinNumber = 0;
+        int walkableTileMaxNumber = 9;
+        int indestructibleTileMinNumber = 10;
+        int indestructibleTileMaxNumber = 19;
+        int destructibleTileMinNumber = 20;
+        int destructibleTileMaxNumber = 29;
+        int maxMapDataLength = spacesAmount + borderTilesAmount * Integer.toString(indestructibleTileMaxNumber).length() + spawnTilesAmount * Integer.toString(walkableTileMaxNumber).length() + fieldTilesAmount * Integer.toString(destructibleTileMaxNumber).length();           //"Integer.toString(destructibleTileMaxNumber).length()" results in number of digits of destructibleTileMaxNumber
+        int minMapDataLength = spacesAmount + borderTilesAmount * Integer.toString(indestructibleTileMinNumber).length() + spawnTilesAmount * Integer.toString(walkableTileMinNumber).length() + fieldTilesAmount * Integer.toString(walkableTileMinNumber).length();
+
+        if(actualMapDataLength > maxMapDataLength){
+            throw new ParserException("Map-Data corrupted - mapData String must not exceed length of " + maxMapDataLength + " chars including spaces for " + mapWidth + "x" + mapHeight + " Tiles map!");
+        }
+
+        if(actualMapDataLength < minMapDataLength){
+            throw new ParserException("Map-Data corrupted - minimum length of mapData String must be " + minMapDataLength + " chars including spaces for " + mapWidth + "x" + mapHeight + " Tiles map!");
+        }
+
+        if(mapData.charAt(0) == ' ' | mapData.charAt(actualMapDataLength - 1) == ' '){
+            throw new ParserException("Map-Data corrupted - must not start nor end with space!");
+        }
+
+        for(int i = 0; actualMapDataLength > i ; i++){
+            if(mapData.charAt(i) == ' ' && mapData.charAt(i + 1) == ' '){
+                throw new ParserException("Map-Data corrupted - must not contain two or more consecutive spaces without number in between!");
+            }
+        }
+
+        int counter = 0;
+        for(int i = 0; i < actualMapDataLength; i++){
+            if((mapData.charAt(i) == ' ')){
+                counter++;
+            }
+        }
+        if(counter != spacesAmount){
+            throw new ParserException("Map-Data corrupted - number of spaces must be " + spacesAmount + "!");
+        }
+
+        Pattern pat = Pattern.compile("[^0-9 ]");
+        for(int i = 0; actualMapDataLength > i ; i++){
+            Matcher mat = pat.matcher(mapData.substring(i, i+1));
+            boolean result = mat.find();
+            if(result){
+                throw new ParserException("Map-Data corrupted - must consist out of numbers 0-9 and space as separator!");
+            }
+        }
+
+        counter = 0;
+        int[] positions = new int[totalTilesAmount];
+        positions[0] = 0;
+        for(int i = 0; actualMapDataLength > i ; i++){
+            if(mapData.charAt(i) == ' '){
+                counter++;
+                positions[counter] = i + 1;
+            }
+        }
+        for(int i = 0; positions.length > i; i++){
+            if(positions.length - 1 > i) {
+                if (Integer.parseInt(mapData.substring(positions[i], positions[i + 1] - 1)) > maxTileNumber | Integer.parseInt(mapData.substring(positions[i], positions[i + 1] - 1)) < minTileNumber) {
+                    throw new ParserException("Map-Data corrupted - Tile number must be between " + minTileNumber + " and " + maxTileNumber + "!");
+                }
+            }
+            else{
+                if (Integer.parseInt(mapData.substring(positions[i], actualMapDataLength)) > maxTileNumber | Integer.parseInt(mapData.substring(positions[i], actualMapDataLength)) < minTileNumber) {
+                    throw new ParserException("Map-Data corrupted - Tile number must be between " + minTileNumber + " and " + maxTileNumber + "!");
+                }
+            }
+        }
+
+        //Alternative code for checking if tile number is between minTileNumber and maxTileNumber:
+
+        /*
+        String combinedNumbers = "";
+        for(int i = 0; i < actualMapDataLength - 1; i++){
+            if(mapData.charAt(i+1) == ' '){
+                combinedNumbers = combinedNumbers + mapData.charAt(i);
+                if((Integer.parseInt(combinedNumbers) > maxTileNumber) | (Integer.parseInt(combinedNumbers) < minTileNumber)){
+                    throw new ParserException("Map-Data corrupted - Tile number must be between " + minTileNumber + " and " + maxTileNumber + "!");
+                }
+                combinedNumbers = "";
+                if(i < actualMapDataLength - 1){
+                    i++;
+                }
+            }
+            else if(i >= actualMapDataLength - 2){
+                combinedNumbers = combinedNumbers + mapData.charAt(i) + mapData.charAt(i+1);
+                if((Integer.parseInt(combinedNumbers) > maxTileNumber) | (Integer.parseInt(combinedNumbers) < minTileNumber)){
+                    throw new ParserException("Map-Data corrupted - Tile number must be between " + minTileNumber + " and " + maxTileNumber + "!");
+                }
+            }
+            else{
+                combinedNumbers = combinedNumbers + mapData.charAt(i);
+            }
+        }
+        */
+
+        //corner Tiles included
+        for(int i = 0; i < mapWidth; i++){
+            if(Integer.parseInt(mapData.substring(positions[i], positions[i+1] - 1)) > indestructibleTileMaxNumber | Integer.parseInt(mapData.substring(positions[i], positions[i+1] - 1)) < indestructibleTileMinNumber){
+                throw new ParserException("Map-Data corrupted - Top-Line must be border tiles!");
+            }
+        }
+
+        //corner Tiles included
+        for(int i = positions.length - mapWidth; i < positions.length; i++){
+            if(positions.length - 1 > i) {
+                if (Integer.parseInt(mapData.substring(positions[i], positions[i + 1] - 1)) > indestructibleTileMaxNumber | Integer.parseInt(mapData.substring(positions[i], positions[i + 1] - 1)) < indestructibleTileMinNumber) {
+                    throw new ParserException("Map-Data corrupted - Bottom-Line must be border tiles!");
+                }
+            }
+            else{
+                if (Integer.parseInt(mapData.substring(positions[i], actualMapDataLength)) > indestructibleTileMaxNumber | Integer.parseInt(mapData.substring(positions[i], actualMapDataLength)) < indestructibleTileMinNumber) {
+                    throw new ParserException("Map-Data corrupted - Bottom-Line must be border tiles!");
+                }
+            }
+        }
+
+        //corner Tiles excluded
+        for(int i = mapWidth; i < positions.length - mapWidth; i = i + mapWidth){
+            if(i % mapWidth == 0 && Integer.parseInt(mapData.substring(positions[i], positions[i + 1] - 1)) > indestructibleTileMaxNumber | Integer.parseInt(mapData.substring(positions[i], positions[i + 1] - 1)) < indestructibleTileMinNumber){
+                throw new ParserException("Map-Data corrupted - Left Edge must be border tiles!");
+            }
+        }
+
+        //corner Tiles excluded
+        for(int i = mapWidth - 1; i < positions.length - mapWidth; i = i + mapWidth){
+            if((i + 1) % mapWidth == 0 && Integer.parseInt(mapData.substring(positions[i], positions[i + 1] - 1)) > indestructibleTileMaxNumber | Integer.parseInt(mapData.substring(positions[i], positions[i + 1] - 1)) < indestructibleTileMinNumber){
+                throw new ParserException("Map-Data corrupted - Right Edge must be border tiles!");
+            }
+        }
+
+        if(Integer.parseInt(mapData.substring(positions[mapWidth + 1], positions[mapWidth + 2] - 1)) < walkableTileMinNumber | Integer.parseInt(mapData.substring(positions[mapWidth + 1], positions[mapWidth + 2] - 1)) > walkableTileMaxNumber){
+            throw new ParserException("Map-Data corrupted - Player spawn top left must use walkable tile!");
+        }
+
+        if(Integer.parseInt(mapData.substring(positions[(mapWidth*2) - 2], positions[(mapWidth*2) - 1] - 1)) < walkableTileMinNumber | Integer.parseInt(mapData.substring(positions[(mapWidth*2) - 2], positions[(mapWidth*2) - 1] - 1)) > walkableTileMaxNumber){
+            throw new ParserException("Map-Data corrupted - Player spawn top right must use walkable tile!");
+        }
+
+        if(Integer.parseInt(mapData.substring(positions[positions.length - (mapWidth*2) + 1], positions[positions.length - (mapWidth*2) + 2] - 1)) < walkableTileMinNumber | Integer.parseInt(mapData.substring(positions[positions.length - (mapWidth*2) + 1], positions[positions.length - (mapWidth*2) + 2] - 1)) > walkableTileMaxNumber) {
+            throw new ParserException("Map-Data corrupted - Player spawn bottom left must use walkable tile!");
+        }
+
+        if(Integer.parseInt(mapData.substring(positions[positions.length - mapWidth - 2], positions[positions.length - mapWidth - 1] - 1)) < walkableTileMinNumber | Integer.parseInt(mapData.substring(positions[positions.length - mapWidth - 2], positions[positions.length - mapWidth - 1] - 1)) > walkableTileMaxNumber){
+            throw new ParserException("Map-Data corrupted - Player spawn bottom right must use walkable tile!");
+        }
+    }
+
+    public static void playerStatsValid(PlayerStatistics stats) throws ParserException{
+
+        if(stats.getGamesLost() < 0){
+            throw new ParserException("Player statistics data corrupted - Minimum value for lost games is 0!");
+        }
+
+        if(stats.getGamesWon() < 0){
+            throw new ParserException("Player statistics data corrupted - Minimum value for won games is 0!");
+        }
+
+        if(stats.getKills() < 0){
+            throw new ParserException("Player statistics data corrupted - Minimum value for kills is 0!");
+        }
+
+        if(stats.getDeaths() < 0){
+            throw new ParserException("Player statistics data corrupted - Minimum value for deaths is 0!");
+        }
+
+        if(stats.getBlocksDestroyed() < 0){
+            throw new ParserException("Player statistics data corrupted - Minimum value for destroyed blocks is 0!");
+        }
+
+        if(stats.getGameTime() < 0){
+            throw new ParserException("Player statistics data corrupted - Minimum value for ingame time is 0 seconds!");
+        }
+    }
+
+    public static void volumeValid(int volume) throws ParserException{
+
+        if(volume > 100 | volume < 0){
+            throw new ParserException("Volume must be between 0 and 100!");
+        }
+
+    }
+
+}
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..bd3b7cc0344912f98142b0a01760952356a327b7
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Scripts/DDL_Script_AzureDB.sql
@@ -0,0 +1,83 @@
+--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(1082) NOT NULL UNIQUE); --allows for map size up to 19x19 (when using double digit numbers for tiles)
+
+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(1082) NOT NULL UNIQUE,  --allows for map size up to 19x19 (when using double digit numbers for tiles)
+                                              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 ('09a02b54d05b5b7ebc29a4383ca12d3dda846b72',
+        'Arena1',
+        18,
+        18,
+        '12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12');
+
+INSERT INTO coremaps (map_id, map_name, map_width, map_height, map_data)
+VALUES ('0ab15557ab6dc4be60dfe6a9b0288bac3036bd97',
+        'Arena2',
+        18,
+        18,
+        '12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 5 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12');
+
+INSERT INTO communitymaps (map_id, map_name, map_width, map_height, map_data, map_downloads)
+VALUES ('fbf44184867512faecc195ae75ca55d5ab7bad2d',
+        'Arena3',
+        18,
+        18,
+        '12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 8 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12',
+        0);
+
+INSERT INTO communitymaps (map_id, map_name, map_width, map_height, map_data, map_downloads)
+VALUES ('1c23b362fd666c5fb7ed60ca611b17246424e49f',
+        'Arena4',
+        18,
+        18,
+        '12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 8 4 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12',
+        0);
+
+INSERT INTO players (player_name, player_pw, games_won, games_lost, kills, deaths, blocks_destroyed, ingame_time)
+VALUES ('Player1',
+        '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8', --Hash of password "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',
+        '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8', --Hash of password "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..22de38024bc74b449f2ca80e2afa3cc063aea840
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Scripts/DDL_Script_Oracle.sql
@@ -0,0 +1,100 @@
+--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(1082) NOT NULL UNIQUE); --allows for map size up to 19x19 (when using double digit numbers for tiles)
+
+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(1082) NOT NULL UNIQUE,  --allows for map size up to 19x19 (when using double digit numbers for tiles)
+                                              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 ('09a02b54d05b5b7ebc29a4383ca12d3dda846b72',
+        'Arena1',
+        18,
+        18,
+        '12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12');
+
+INSERT INTO battlearenadata.coremaps (map_id, map_name, map_width, map_height, map_data)
+VALUES ('0ab15557ab6dc4be60dfe6a9b0288bac3036bd97',
+        'Arena2',
+        18,
+        18,
+        '12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 5 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12');
+
+INSERT INTO battlearenadata.communitymaps (map_id, map_name, map_width, map_height, map_data, map_downloads)
+VALUES ('fbf44184867512faecc195ae75ca55d5ab7bad2d',
+        'Arena3',
+        18,
+        18,
+        '12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 8 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12',
+        0);
+
+INSERT INTO battlearenadata.communitymaps (map_id, map_name, map_width, map_height, map_data, map_downloads)
+VALUES ('1c23b362fd666c5fb7ed60ca611b17246424e49f',
+        'Arena4',
+        18,
+        18,
+        '12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 8 4 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12',
+        0);
+
+INSERT INTO battlearenadata.players (player_name, player_pw, games_won, games_lost, kills, deaths, blocks_destroyed, ingame_time)
+VALUES ('Player1',
+        '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8', --Hash of password "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',
+        '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8', --Hash of password "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/Entity/EntityFactory.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/EntityFactory.java
index d5b4b382213c197e503a598e855940aa18821998..2e49bcaca57667a7fbea0431ff0fe8c91b356ac5 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/EntityFactory.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/EntityFactory.java
@@ -1,5 +1,6 @@
 package de.hdm_stuttgart.battlearena.Model.Entity;
 
+import de.hdm_stuttgart.battlearena.Controller.Enum.PlayerMode;
 import de.hdm_stuttgart.battlearena.Controller.GameSceneController;
 import de.hdm_stuttgart.battlearena.Model.Inputs.InputHandler;
 
@@ -12,13 +13,14 @@ public class EntityFactory {
 
     private static final Logger log = LogManager.getLogger(EntityFactory.class);
 
-    public static IEntity createEntity(EntityType entityType, GraphicsContext gameScene, InputHandler inputHandler, EntityClass entityClass, GameSceneController gameSceneController) {
+    public static IEntity createEntity(EntityType entityType, GraphicsContext gameScene, InputHandler inputHandler,
+                                       EntityClass entityClass, GameSceneController gameSceneController, PlayerMode playerMode) {
         if (entityType == EntityType.PLAYER) {
             log.debug("Entity " + entityType + " created");
-            return new Player(gameScene, inputHandler, entityClass, gameSceneController);
-        } else if (entityType == EntityType.ENEMY_PLAYER) {
+            return new Player(gameScene, inputHandler, entityClass, gameSceneController, playerMode);
+        } else if (entityType == EntityType.NETWORK_PLAYER_TWO) {
             log.debug("Entity " + entityType + " created");
-            return new EnemyHandler();
+            return new NetworkPlayerTwo();
         }
 
         throw new IllegalArgumentException ("Entity type not supported " + entityType);
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/EntityType.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/EntityType.java
index 3e8560772b2e9f049e217bdeca99c30c24150e11..108c4c2037dbcb53d090dc19a59b9b79450d6b68 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/EntityType.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/EntityType.java
@@ -2,5 +2,6 @@ package de.hdm_stuttgart.battlearena.Model.Entity;
 
 public enum EntityType {
     PLAYER,
-    ENEMY_PLAYER
+    NETWORK_PLAYER_TWO,
+    LOKAL_PLAYER_TWO
 }
\ No newline at end of file
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/IEntity.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/IEntity.java
index 92ca5b53906697c1bad96c2cbb59524b7bc2c40b..f98ddeb7452f60866c2dfe661dff29162c0004b7 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/IEntity.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/IEntity.java
@@ -12,19 +12,23 @@ public interface IEntity {
 
    void updateEntityMovement(GameSceneController gameScene);
 
+   void checkHealTile(IEntity entity, GraphicsContext graphicsContext);
+
    void attack(IEntity entity, GraphicsContext graphicsContext);
 
    void updateEntityWalkAnimation();
 
    void renderEntity(GraphicsContext graphicsContext);
 
-   BoundingBox getBoxCollider();
+    void healPlayer(int heal);
+
+    BoundingBox getBoxCollider();
 
    EntityDirection getEntityDirection();
 
    int getEntitySpeed();
 
-   int gotHit(int damageDone);
+   void gotHit(int damageDone);
 
    int getMapPosX();
 
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/EnemyHandler.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/NetworkPlayerTwo.java
similarity index 75%
rename from src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/EnemyHandler.java
rename to src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/NetworkPlayerTwo.java
index c8fc714cc5aa2eefe30e616b5211fe76e6457ff2..d045a108bf051f2e40573e084199808f2edbc630 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/EnemyHandler.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/NetworkPlayerTwo.java
@@ -9,9 +9,9 @@ import javafx.scene.paint.Color;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.LogManager;
 
-class EnemyHandler implements IEntity{
+class NetworkPlayerTwo implements IEntity{
 
-    private static final Logger log = LogManager.getLogger(EnemyHandler.class);
+    private static final Logger log = LogManager.getLogger(NetworkPlayerTwo.class);
 
     private final BoundingBox boxCollider = new BoundingBox(300, 200, 48, 48);
 
@@ -36,6 +36,11 @@ class EnemyHandler implements IEntity{
 
     }
 
+    @Override
+    public void checkHealTile(IEntity entity, GraphicsContext graphicsContext) {
+
+    }
+
     @Override
     public void attack(IEntity entity, GraphicsContext graphicsContext) {
 
@@ -52,6 +57,12 @@ class EnemyHandler implements IEntity{
         graphicsContext.fillRect(300, 200, 48, 48);
     }
 
+    @Override
+    public void healPlayer(int heal) {
+        log.info("Network player health: " + health);
+        health -= heal;
+    }
+
     @Override
     public BoundingBox getBoxCollider() {
         return boxCollider;
@@ -68,9 +79,9 @@ class EnemyHandler implements IEntity{
     }
 
     @Override
-    public int gotHit(int damageDone) {
-        log.debug(health);
-        return health -= damageDone;
+    public void gotHit(int damageDone) {
+        log.debug("Network player health: " + health);
+        health -= damageDone;
     }
 
     @Override
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/Player.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/Player.java
index fffccf712e14e8a655bbc72622fae7e4c0d5d3b8..0eaf4b2ca5c23f540e284e5ef6e80bf1be36037f 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/Player.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Entity/Player.java
@@ -1,8 +1,10 @@
 package de.hdm_stuttgart.battlearena.Model.Entity;
 
+import de.hdm_stuttgart.battlearena.Controller.Enum.PlayerMode;
 import de.hdm_stuttgart.battlearena.Controller.GameSceneController;
 import de.hdm_stuttgart.battlearena.Model.Inputs.InputHandler;
 
+import de.hdm_stuttgart.battlearena.Model.Map.TileManager;
 import javafx.geometry.BoundingBox;
 import javafx.scene.canvas.GraphicsContext;
 import javafx.scene.image.Image;
@@ -16,6 +18,8 @@ class Player implements IEntity {
 
     private static final Logger log = LogManager.getLogger(Player.class);
 
+    private final PlayerMode PLAYER_MODE;
+
     InputHandler inputHandler;
     CollisionHandler collisionHandler = new CollisionHandler();
 
@@ -51,17 +55,24 @@ class Player implements IEntity {
 
     private int mapPosX;
     private int mapPosY;
+
+    private int lastMapPosX;
+    private int lastMapPosY;
+
     private int playerSpeed;
     private EntityDirection playerDirection;
 
-    private int health = 10;
-    private int damage = 1;
+    private int health;
+    private  int maxPlayerHealth;
+    private int damage;
 
-    public Player(GraphicsContext gameScene, InputHandler inputHandler, EntityClass entityClass, GameSceneController gameSceneController) {
+    public Player(GraphicsContext gameScene, InputHandler inputHandler, EntityClass entityClass,
+                  GameSceneController gameSceneController, PlayerMode PLAYER_MODE) {
         this.gameScene = gameScene;
         this.inputHandler = inputHandler;
         this.entityClass = entityClass;
         this.gameSceneController = gameSceneController;
+        this.PLAYER_MODE = PLAYER_MODE;
 
         initializeEntity();
         loadEntitySprites();
@@ -70,13 +81,45 @@ class Player implements IEntity {
     @Override
     public void initializeEntity() {
         scaledTileSize = gameSceneController.getScaledTileSize();
-        mapPosX = 60;
-        mapPosY = 60;
-        boxCollider = new BoundingBox(mapPosX+15,mapPosY+10, playerWidth, playerHeight);
-        playerSpeed = 5;
+        if (PLAYER_MODE == PlayerMode.PLAYER_ONE) {
+            mapPosX = 60;
+            mapPosY = 60;
+        } else if (PLAYER_MODE == PlayerMode.PLAYER_TWO) {
+            mapPosX = 760;
+            mapPosY = 735;
+        }
+
+        initializePlayerStats();
+
+        boxCollider = new BoundingBox(mapPosX + 15, mapPosY + 10, playerWidth, playerHeight);
         playerDirection = EntityDirection.DOWN;
     }
 
+    //Values result from balancing
+    private void initializePlayerStats() {
+        if (entityClass == EntityClass.HUMAN) {
+            maxPlayerHealth = 50;
+            health = 50;
+            damage = 5;
+            playerSpeed = 5;
+        } else if (entityClass == EntityClass.HIGH_BORN) {
+            maxPlayerHealth = 100;
+            health = 75;
+            damage = 2;
+            playerSpeed = 3;
+        } else if (entityClass == EntityClass.LOW_BORN) {
+            maxPlayerHealth = 10;
+            health = 10;
+            damage = 10;
+            playerSpeed = 7;
+        } else {
+            maxPlayerHealth = 40;
+            health = 15;
+            damage = 7;
+            playerSpeed = 5;
+        }
+    }
+
     @Override
     public void loadEntitySprites() {
         try {
@@ -99,19 +142,19 @@ class Player implements IEntity {
     }
 
     private void loadHumanSprites() {
-        directionDownOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/HumanDown01.png")));
-        directionDownTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/HumanDown02.png")));
-        directionUpOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/upOne.png")));
-        directionUpTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/upTwo.png")));
-        directionLeftOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/leftOne.png")));
-        directionLeftTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/leftTwo.png")));
-        directionRightOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/rightOne.png")));
-        directionRightTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/rightTwo.png")));
+        directionDownOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/human/HumanDown00.png")));
+        directionDownTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/human/HumanDown01.png")));
+        directionUpOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/human/HumanUp00.png")));
+        directionUpTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/human/HumanUp01.png")));
+        directionLeftOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/human/HumanLeft00.png")));
+        directionLeftTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/human/HumanLeft01.png")));
+        directionRightOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/human/HumanRight00.png")));
+        directionRightTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/human/HumanRight01.png")));
     }
 
     private void loadHighBornSprites() {
-        directionDownOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/HumanDown01.png")));
-        directionDownTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/HumanDown02.png")));
+        directionDownOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/high_born/HighBornDown00.png")));
+        directionDownTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/high_born/HighBornDown01.png")));
         directionUpOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/upOne.png")));
         directionUpTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/upTwo.png")));
         directionLeftOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/leftOne.png")));
@@ -132,15 +175,15 @@ class Player implements IEntity {
     }
 
     private void loadSentinelsSprites() {
-        directionDownOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/HumanDown01.png")));
-        directionDownTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/HumanDown02.png")));
+        directionDownOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/sentinels/SentinelDown00.png")));
+        directionDownTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/sentinels/SentinelDown01.png")));
         directionUpOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/upOne.png")));
         directionUpTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/upTwo.png")));
         directionLeftOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/leftOne.png")));
         directionLeftTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/leftTwo.png")));
         directionRightOne = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/rightOne.png")));
         directionRightTwo = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/player/rightTwo.png")));
-        }
+    }
 
     private void loadWeaponSprites() {
         swordUp = new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/weapons/SwordUp.png")));
@@ -151,57 +194,99 @@ class Player implements IEntity {
 
     @Override
     public void updateEntityMovement(GameSceneController gameScene) {
-        if (inputHandler.isMoveUp() || inputHandler.isMoveDown() || inputHandler.isMoveLeft() || inputHandler.isMoveRight()) {
-            if (inputHandler.isMoveUp()) {
-                playerDirection = EntityDirection.UP;
-            } else if (inputHandler.isMoveDown()) {
-                playerDirection = EntityDirection.DOWN;
-            } else if (inputHandler.isMoveLeft()) {
-                playerDirection = EntityDirection.LEFT;
-            } else {
-                playerDirection = EntityDirection.RIGHT;
-            }
-
-            boolean isWalkableTile = collisionHandler.handleMapCollision(this, scaledTileSize, gameSceneController);
-
-            int lastMapPosX = mapPosX;
-            int lastMapPosY = mapPosY;
-
-            if (isWalkableTile) {
-                switch (playerDirection) {
-                    case UP:
-                        mapPosY -= playerSpeed;
-                        break;
-                    case DOWN:
-                        mapPosY += playerSpeed;
-                        break;
-                    case LEFT:
-                        mapPosX -= playerSpeed;
-                        break;
-                    case RIGHT:
-                        mapPosX += playerSpeed;
+        if (PLAYER_MODE == PlayerMode.PLAYER_ONE) {
+            if (inputHandler.isMoveUp() || inputHandler.isMoveDown() || inputHandler.isMoveLeft() || inputHandler.isMoveRight()) {
+                if (inputHandler.isMoveUp()) {
+                    playerDirection = EntityDirection.UP;
+                } else if (inputHandler.isMoveDown()) {
+                    playerDirection = EntityDirection.DOWN;
+                } else if (inputHandler.isMoveLeft()) {
+                    playerDirection = EntityDirection.LEFT;
+                } else if (inputHandler.isMoveRight()) {
+                    playerDirection = EntityDirection.RIGHT;
                 }
-            }
 
-            boolean isEntityCollision = boxCollider.intersects(gameScene.getEnemy().getBoxCollider());
-            //boolean isEntityCollision = collisionHandler.handleBoxCollision(boxCollider, gameScene.getEnemy().getBoxCollider());
-
-            if (isEntityCollision) {
-                if (playerDirection == EntityDirection.UP) {
-                    mapPosY = lastMapPosY + 30;
-                } else if (playerDirection == EntityDirection.DOWN) {
-                    mapPosY = lastMapPosY - 30;
-                } else if (playerDirection == EntityDirection.LEFT) {
-                    mapPosX = lastMapPosX + 30;
-                } else {
-                    mapPosX = lastMapPosX - 30;
+                boolean isWalkableTile = collisionHandler.handleMapCollision(this, scaledTileSize, gameSceneController);
+
+                performEntityMovement(isWalkableTile);
+
+                boolean isEntityCollision = boxCollider.intersects(gameScene.getEnemy().getBoxCollider());
+                //boolean isEntityCollision = collisionHandler.handleBoxCollision(boxCollider, gameScene.getEnemy().getBoxCollider());
+
+                performEntityCollision(isEntityCollision);
+
+                updateEntityWalkAnimation();
+            }
+        } else if (PLAYER_MODE == PlayerMode.PLAYER_TWO) {
+            if (inputHandler.isSdMoveUp() || inputHandler.isSdMoveDown() || inputHandler.isSdMoveLeft() || inputHandler.isSdMoveRight()) {
+                if (inputHandler.isSdMoveUp()) {
+                    playerDirection = EntityDirection.UP;
+                } else if (inputHandler.isSdMoveDown()) {
+                    playerDirection = EntityDirection.DOWN;
+                } else if (inputHandler.isSdMoveLeft()) {
+                    playerDirection = EntityDirection.LEFT;
+                } else if (inputHandler.isSdMoveRight()) {
+                    playerDirection = EntityDirection.RIGHT;
                 }
+
+                boolean isWalkableTile = collisionHandler.handleMapCollision(this, scaledTileSize, gameSceneController);
+
+                performEntityMovement(isWalkableTile);
+
+                boolean isEntityCollision = boxCollider.intersects(gameScene.getPlayer().getBoxCollider());
+                //boolean isEntityCollision = collisionHandler.handleBoxCollision(boxCollider, gameScene.getEnemy().getBoxCollider());
+
+                performEntityCollision(isEntityCollision);
+
+                updateEntityWalkAnimation();
             }
+        }
+    }
 
-            boxCollider = new BoundingBox(mapPosX+15,mapPosY+10, playerWidth, playerHeight);
+    private void performEntityMovement(boolean isWalkableTile) {
+        lastMapPosX = mapPosX;
+        lastMapPosY = mapPosY;
+
+        if (isWalkableTile) {
+            switch (playerDirection) {
+                case UP:
+                    mapPosY -= playerSpeed;
+                    break;
+                case DOWN:
+                    mapPosY += playerSpeed;
+                    break;
+                case LEFT:
+                    mapPosX -= playerSpeed;
+                    break;
+                case RIGHT:
+                    mapPosX += playerSpeed;
+            }
+        }
+    }
 
-            updateEntityWalkAnimation();
+    private void performEntityCollision(boolean isEntityCollision) {
+        if (isEntityCollision) {
+            if (playerDirection == EntityDirection.UP) {
+                mapPosY = lastMapPosY + 30;
+            } else if (playerDirection == EntityDirection.DOWN) {
+                mapPosY = lastMapPosY - 30;
+            } else if (playerDirection == EntityDirection.LEFT) {
+                mapPosX = lastMapPosX + 30;
+            } else {
+                mapPosX = lastMapPosX - 30;
+            }
+        }
 
+        boxCollider = new BoundingBox(mapPosX + 15, mapPosY + 10, playerWidth, playerHeight);
+    }
+    @Override
+    public void checkHealTile(IEntity entity, GraphicsContext graphicsContext){
+        int xTile = entity.getMapPosX() / gameSceneController.getScaledTileSize();
+        int yTile = entity.getMapPosY() / gameSceneController.getScaledTileSize();
+        if(TileManager.tileMap[yTile][xTile +1 ] == 5){
+            entity.healPlayer(1);
+            TileManager.tileMap[yTile][xTile +1] = 2;
+            log.info("Healed +1: " + health);
         }
     }
 
@@ -209,47 +294,82 @@ class Player implements IEntity {
     public void attack(IEntity entity, GraphicsContext graphicsContext) {
         BoundingBox hitBox;
 
+        int xTile = mapPosX / gameSceneController.getScaledTileSize();
+        int yTile = mapPosY / gameSceneController.getScaledTileSize();
+        //log.info(xTile);
+        //log.info(yTile);
+        //int xTile = (int) (Math.random() * (18 - 1));   //Get xTile Coordinate +1 /-1 of playerTile
+        //int yTile = (int) (Math.random() * (18 - 1));   //Get yTile Coordinate +1 /-1 of playerTile
+        double dropChance = 0.5;
+        double randomDropChance = Math.random() * 1;
+        //log.info(randomDropChance);
+
         //Added and subtracted numbers from variables are the pixel insets of the player sprite
 
         int attackRange = 30;
         int attackWidth = 10;
 
-        if (inputHandler.isAttack()){
+        if (inputHandler.isAttack() && PLAYER_MODE == PlayerMode.PLAYER_ONE ||
+                inputHandler.isSdAttack() && PLAYER_MODE == PlayerMode.PLAYER_TWO) {
             if (playerDirection == EntityDirection.UP) {
-                hitBox = new BoundingBox(mapPosX+playerWidth, mapPosY-10, attackWidth, attackRange);
-                graphicsContext.strokeRect(mapPosX+playerWidth, mapPosY-10, attackWidth, attackRange);
-                graphicsContext.drawImage(swordUp, mapPosX+8, mapPosY-10, 32, 32);
+                hitBox = new BoundingBox(mapPosX + playerWidth, mapPosY - 10, attackWidth, attackRange);
+                graphicsContext.strokeRect(mapPosX + playerWidth, mapPosY - 10, attackWidth, attackRange);
+                graphicsContext.drawImage(swordUp, mapPosX + 8, mapPosY - 10, 32, 32);
                 if (hitBox.intersects(entity.getBoxCollider())) {
                     entity.gotHit(damage);
                     graphicsContext.strokeText("Hit", 10, 10);
+
+                    if (((TileManager.tileMap[xTile][yTile] == 3) && randomDropChance > dropChance)||
+                            ((TileManager.tileMap[xTile][yTile] == 1)  && randomDropChance > dropChance))
+                        TileManager.tileMap[yTile-1][xTile+1] = 5;
+                    //TileManager.tileMap[yTile-2][xTile] = 5;
+                    //TileManager.tileMap[yTile-3][xTile] = 5;
                 }
             } else if (playerDirection == EntityDirection.DOWN) {
-                hitBox = new BoundingBox(mapPosX+playerWidth, mapPosY+playerHeight, attackWidth, attackRange);
-                graphicsContext.strokeRect(mapPosX+playerWidth, mapPosY+playerHeight, attackWidth, attackRange);
-                graphicsContext.drawImage(swordDown, mapPosX+8, mapPosY+playerHeight, 32, 32);
+                hitBox = new BoundingBox(mapPosX + playerWidth, mapPosY + playerHeight, attackWidth, attackRange);
+                graphicsContext.strokeRect(mapPosX + playerWidth, mapPosY + playerHeight, attackWidth, attackRange);
+                graphicsContext.drawImage(swordDown, mapPosX + 8, mapPosY + playerHeight, 32, 32);
                 if (hitBox.intersects(entity.getBoxCollider())) {
                     entity.gotHit(damage);
                     graphicsContext.strokeText("Hit", 10, 10);
+
+                    if (((TileManager.tileMap[xTile][yTile] == 3) && randomDropChance > dropChance)||
+                            ((TileManager.tileMap[xTile][yTile] == 1)  && randomDropChance > dropChance))
+                        TileManager.tileMap[yTile-1][xTile+1] = 5;
+                    //TileManager.tileMap[yTile-2][xTile] = 5;
+                    //TileManager.tileMap[yTile-3][xTile] = 5;
                 }
             } else if (playerDirection == EntityDirection.LEFT) {
-                hitBox = new BoundingBox(mapPosX-attackWidth, mapPosY+((double) playerHeight /2),
+                hitBox = new BoundingBox(mapPosX - attackWidth, mapPosY + ((double) playerHeight / 2),
                         attackRange, attackWidth);
-                graphicsContext.strokeRect(mapPosX-attackWidth, mapPosY+((double) playerHeight /2),
+                graphicsContext.strokeRect(mapPosX - attackWidth, mapPosY + ((double) playerHeight / 2),
                         attackRange, attackWidth);
-                graphicsContext.drawImage(swordLeft, mapPosX-8, mapPosY+8, 32, 32);
+                graphicsContext.drawImage(swordLeft, mapPosX - 8, mapPosY + 8, 32, 32);
                 if (hitBox.intersects(entity.getBoxCollider())) {
                     entity.gotHit(damage);
                     graphicsContext.strokeText("Hit", 10, 10);
+
+                    if (((TileManager.tileMap[xTile][yTile] == 3) && randomDropChance > dropChance)||
+                            ((TileManager.tileMap[xTile][yTile] == 1)  && randomDropChance > dropChance))
+                        TileManager.tileMap[yTile-1][xTile+1] = 5;
+                    //TileManager.tileMap[yTile-2][xTile] = 5;
+                    //TileManager.tileMap[yTile-3][xTile] = 5;
                 }
             } else {
-                hitBox = new BoundingBox(mapPosX+playerWidth+attackWidth, mapPosY+((double) playerHeight /2),
+                hitBox = new BoundingBox(mapPosX + playerWidth + attackWidth, mapPosY + ((double) playerHeight / 2),
                         attackRange, attackWidth);
-                graphicsContext.strokeRect(mapPosX+playerWidth+attackWidth, mapPosY+((double) playerHeight /2),
+                graphicsContext.strokeRect(mapPosX + playerWidth + attackWidth, mapPosY + ((double) playerHeight / 2),
                         attackRange, attackWidth);
-                graphicsContext.drawImage(swordRight, mapPosX+playerWidth+8, mapPosY+8, 32, 32);
+                graphicsContext.drawImage(swordRight, mapPosX + playerWidth + 8, mapPosY + 8, 32, 32);
                 if (hitBox.intersects(entity.getBoxCollider())) {
                     entity.gotHit(damage);
                     graphicsContext.strokeText("Hit", 10, 10);
+
+                    if (((TileManager.tileMap[xTile][yTile] == 3) && randomDropChance > dropChance)||
+                            ((TileManager.tileMap[xTile][yTile] == 1)  && randomDropChance > dropChance))
+                        TileManager.tileMap[yTile-1][xTile+1] = 5;
+                    //TileManager.tileMap[yTile-2][xTile] = 5;
+                    //TileManager.tileMap[yTile-3][xTile] = 5;
                 }
             }
         }
@@ -274,7 +394,7 @@ class Player implements IEntity {
         Image playerSprite = null;
 
         //for debugging collision
-        graphicsContext.strokeRect(mapPosX+15,mapPosY+10, playerWidth, playerHeight);
+        graphicsContext.strokeRect(mapPosX + 15, mapPosY + 10, playerWidth, playerHeight);
 
         switch (playerDirection) {
             case UP:
@@ -314,6 +434,22 @@ class Player implements IEntity {
         graphicsContext.drawImage(playerSprite, mapPosX, mapPosY, 48, 48);
     }
 
+    @Override
+    public void gotHit(int damageDone) {
+        health -= damageDone;
+    }
+    @Override
+    public void healPlayer(int healthRegenerated) {
+        int regeneratedHealth = health + healthRegenerated;
+
+        if (regeneratedHealth < maxPlayerHealth) {
+            health += healthRegenerated;
+        } else {
+            health = maxPlayerHealth;
+        }
+        log.info(health);
+    }
+
     @Override
     public BoundingBox getBoxCollider() {
         return boxCollider;
@@ -329,11 +465,6 @@ class Player implements IEntity {
         return playerSpeed;
     }
 
-    @Override
-    public int gotHit(int damageDone) {
-        return health -= damageDone;
-    }
-
     @Override
     public int getMapPosX() {
         return mapPosX;
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Inputs/InputHandler.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Inputs/InputHandler.java
index 8dfd2f3d3d51063e409488e71a25814030ed2f68..a66f47e852aac620010f786bbff62a0700292535 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Inputs/InputHandler.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Inputs/InputHandler.java
@@ -18,26 +18,51 @@ public class InputHandler {
         return inputHandler;
     }
 
+    //Local Player/Player one controls
     private boolean moveUp, moveDown, moveLeft, moveRight, attack;
 
+    //Local player two controls
+    private boolean sdMoveUp, sdMoveDown, sdMoveLeft, sdMoveRight, sdAttack;
+
     public void handleKeyPress(KeyEvent event) {
         KeyCode code = event.getCode();
 
         switch (code) {
             case W:
                 moveUp = true;
+                log.debug("Player move up");
                 break;
             case S:
                 moveDown = true;
+                log.debug("Player move down");
                 break;
             case A:
                 moveLeft = true;
+                log.debug("Player move left");
                 break;
             case D:
                 moveRight = true;
+                log.debug("Player move right");
                 break;
-            case SPACE:
+            case E:
                 attack = true;
+                log.debug("Player attack");
+                break;
+            case UP:
+                sdMoveUp = true;
+                break;
+            case DOWN:
+                sdMoveDown = true;
+                break;
+            case LEFT:
+                sdMoveLeft = true;
+                break;
+            case RIGHT:
+                sdMoveRight = true;
+                break;
+            case MINUS:
+                sdAttack = true;
+                break;
         }
     }
 
@@ -57,8 +82,24 @@ public class InputHandler {
             case D:
                 moveRight = false;
                 break;
-            case SPACE:
+            case E:
                 attack = false;
+                break;
+            case UP:
+                sdMoveUp = false;
+                break;
+            case DOWN:
+                sdMoveDown = false;
+                break;
+            case LEFT:
+                sdMoveLeft = false;
+                break;
+            case RIGHT:
+                sdMoveRight = false;
+                break;
+            case MINUS:
+                sdAttack = false;
+                break;
         }
     }
 
@@ -81,4 +122,24 @@ public class InputHandler {
     public boolean isAttack() {
         return attack;
     }
+
+    public boolean isSdMoveUp() {
+        return sdMoveUp;
+    }
+
+    public boolean isSdMoveDown() {
+        return sdMoveDown;
+    }
+
+    public boolean isSdMoveLeft() {
+        return sdMoveLeft;
+    }
+
+    public boolean isSdMoveRight() {
+        return sdMoveRight;
+    }
+
+    public boolean isSdAttack() {
+        return sdAttack;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/BackgroundTile.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/BackgroundTile.java
index c7fd6bc3ad273c2e2667a9398a33c94764947ea7..b17fb79d9742336e3d008bce528846433d1db394 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/BackgroundTile.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/BackgroundTile.java
@@ -10,11 +10,12 @@ class BackgroundTile implements ITile{
     private static final Logger log = LogManager.getLogger(BackgroundTile.class);
 
     private final Image tileSprite;
-    private final boolean isWalkable;
+    private final boolean isWalkable, isDestructible;
 
-    public BackgroundTile(Image tileSprite, boolean isWalkable) {
+    public BackgroundTile(Image tileSprite, boolean isWalkable, boolean isDestructible) {
         this.tileSprite = tileSprite;
         this.isWalkable = isWalkable;
+        this.isDestructible = isDestructible;
     }
 
     @Override
@@ -22,6 +23,11 @@ class BackgroundTile implements ITile{
         log.debug("Collision type: " + isWalkable + " returned.");
         return isWalkable;
     }
+    @Override
+    public boolean getDestruction() {
+        log.debug("Collision type: " + isDestructible + " returned.");
+        return isWalkable;
+    }
 
     @Override
     public Image getTileSprite() {
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/ITile.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/ITile.java
index f33750bed5ede99e059da2a7fb4e31f33bb735ad..58f711083e43f6be1046bd4d394adf7a3b6e8825 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/ITile.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/ITile.java
@@ -4,5 +4,6 @@ import javafx.scene.image.Image;
 
 public interface ITile {
     boolean getCollision();
+    boolean getDestruction();
     Image getTileSprite();
 }
\ No newline at end of file
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/TileFactory.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/TileFactory.java
index 842781646eb4c59e1ba537d172414c7437b498b2..0da1a1558d0e6888a73fa456d3dd81f021d936fc 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/TileFactory.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/TileFactory.java
@@ -9,13 +9,19 @@ public class TileFactory {
 
     private static final Logger log = LogManager.getLogger(TileFactory.class);
 
-    public static ITile createTile(TileType tileType, Image tileSprite) {
-        if (tileType == TileType.WALKABLE) {
-            log.debug("Tile with type: " + tileType + " created.");
-            return new BackgroundTile(tileSprite, true);
-        } else if (tileType == TileType.NON_WALKABLE) {
-            log.debug("Tile with type: " + tileType + " created.");
-            return new BackgroundTile(tileSprite, false);
+    public static ITile createTile(TileType tileType, TileType tileType2, Image tileSprite) {
+        if (tileType == TileType.WALKABLE && tileType2 == TileType.DESTRUCTIBLE) {
+            log.info("Tile with type: " + tileType + " " + tileType2 + " created.");
+            return new BackgroundTile(tileSprite, true, true);
+        }else if (tileType == TileType.WALKABLE && tileType2 == TileType.NON_DESTRUCTIBLE) {
+            log.info("Tile with type: " + tileType + " " + tileType2 +" created.");
+            return new BackgroundTile(tileSprite, true, false);
+        }else if (tileType == TileType.NON_WALKABLE && tileType2 == TileType.DESTRUCTIBLE) {
+            log.info("Tile with type: " + tileType + " " + tileType2 +" created.");
+            return new BackgroundTile(tileSprite, false, true);
+        }else if (tileType == TileType.NON_WALKABLE && tileType2 == TileType.NON_DESTRUCTIBLE) {
+            log.info("Tile with type: " + tileType + " " + tileType2 +" created.");
+            return new BackgroundTile(tileSprite, false, false);
         }
 
         log.error("TileType: " + tileType + " not supported!");
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/TileManager.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/TileManager.java
index 480478d51823c0a4992de930e4eea5f2b73f82d8..0ac687dab223e1933fe99bbf42db3dfd3ed8b8b5 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/TileManager.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/TileManager.java
@@ -14,7 +14,7 @@ public class TileManager {
 
     private final GraphicsContext graphicsContext2D;
     private final ITile[] tileSet;
-    private final int[][] tileMap;
+    public static int[][] tileMap;
 
     private final int horizontalTileCount;
     private final int verticalTileCount;
@@ -34,16 +34,18 @@ public class TileManager {
 
     private void createTiles() {
         try {
-            tileSet[0] = TileFactory.createTile(TileType.WALKABLE,
+            tileSet[0] = TileFactory.createTile(TileType.WALKABLE, TileType.NON_DESTRUCTIBLE,
                     new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/map/Grass01.png"))));
-            tileSet[1] = TileFactory.createTile(TileType.WALKABLE,
+            tileSet[1] = TileFactory.createTile(TileType.WALKABLE, TileType.NON_DESTRUCTIBLE,
                     new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/map/Grass02.png"))));
-            tileSet[2] = TileFactory.createTile(TileType.WALKABLE,
+            tileSet[2] = TileFactory.createTile(TileType.WALKABLE, TileType.NON_DESTRUCTIBLE,
                     new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/map/Grass04.png"))));
-            tileSet[3] = TileFactory.createTile(TileType.NON_WALKABLE,
+            tileSet[3] = TileFactory.createTile(TileType.NON_WALKABLE, TileType.DESTRUCTIBLE,
                     new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/map/Stone01.png"))));
-            tileSet[4] = TileFactory.createTile(TileType.NON_WALKABLE,
+            tileSet[4] = TileFactory.createTile(TileType.NON_WALKABLE, TileType.DESTRUCTIBLE,
                     new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/map/Stone02.png"))));
+            tileSet[5] = TileFactory.createTile(TileType.WALKABLE,TileType.NON_DESTRUCTIBLE,
+                    new Image(Objects.requireNonNull(getClass().getResourceAsStream("/textures/map/finalheart.png"))));
         } catch (Exception e) {
             log.error(e);
         }
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/TileType.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/TileType.java
index 17e95c7e93fc890a5f993cc53b7eb6cfd1f4bd6b..efe35788d26be5839df9efee6934ce54ec2c0d63 100644
--- a/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/TileType.java
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Map/TileType.java
@@ -2,5 +2,8 @@ package de.hdm_stuttgart.battlearena.Model.Map;
 
 public enum TileType {
     WALKABLE,
-    NON_WALKABLE
+    NON_WALKABLE,
+    DESTRUCTIBLE,
+    NON_DESTRUCTIBLE
+
 }
\ 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/Model/Sound/ISoundManager.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Sound/ISoundManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f31c780e19380b4f58e02ab5a854d8b25ea2019
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Sound/ISoundManager.java
@@ -0,0 +1,16 @@
+package de.hdm_stuttgart.battlearena.Model.Sound;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.nio.file.Path;
+import java.util.List;
+
+public interface ISoundManager {
+
+
+
+    void playSoundEffect() throws InterruptedException, MalformedURLException; //plays sound effects only
+
+    List<Path> getFilePathsFromResources(Path folderPath) throws IOException; // gets file-paths in a Folder as a list
+
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Sound/MusicType.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Sound/MusicType.java
new file mode 100644
index 0000000000000000000000000000000000000000..b7d5924e85a9559d88db4bf4a295fd235fc2aa5b
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Sound/MusicType.java
@@ -0,0 +1,16 @@
+package de.hdm_stuttgart.battlearena.Model.Sound;
+
+public enum MusicType {
+    MENU("src/main/resources/sound/music/menu"),
+    OPTIONS("src/main/resources/sound/music/options"),
+    GAME("src/main/resources/sound/music/game");
+
+    private String path;
+    MusicType(String path){
+        this.path = path;
+    }
+
+    public String getPath(){
+        return path;
+    }
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Sound/SFX.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Sound/SFX.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c4dae812049378d829bd1a0c1d6d3504e350530
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Sound/SFX.java
@@ -0,0 +1,17 @@
+package de.hdm_stuttgart.battlearena.Model.Sound;
+
+public enum SFX {
+    GRASS("/sound/sfx/steps/grass"),
+    STONE("/sound/sfx/steps/stone"),
+    COLLISION("/sound/sfx/collision"),
+    ATTACK("/sound/sfx/attack");
+
+    private String path;
+    SFX(String path){
+        this.path = path;
+    }
+
+    public String getPath(){
+        return path;
+    }
+}
diff --git a/src/main/java/de/hdm_stuttgart/battlearena/Model/Sound/SoundManager.java b/src/main/java/de/hdm_stuttgart/battlearena/Model/Sound/SoundManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..41af98775814a73c36d2b5273f29540449d2bbbb
--- /dev/null
+++ b/src/main/java/de/hdm_stuttgart/battlearena/Model/Sound/SoundManager.java
@@ -0,0 +1,85 @@
+package de.hdm_stuttgart.battlearena.Model.Sound;
+
+
+import javafx.scene.media.Media;
+import javafx.scene.media.MediaPlayer;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.LogManager;
+
+import javafx.scene.media.AudioClip;
+
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Random;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class SoundManager implements ISoundManager {
+    private static final Logger log = LogManager.getLogger(SoundManager.class);
+
+
+    private final ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
+    private final List<SFX> soundEffectsRunning = new ArrayList<>();
+    private MediaPlayer mediaPlayer;
+
+    private final boolean stopLoop = false;
+    private List<Path> walkingSFXPaths;
+
+    //Todo Make music play
+    public void playMusic(MusicType musicType) throws IOException {
+        Path pathTypeOfMusic = Paths.get(musicType.getPath());
+        List<Path> musicPaths = getFilePathsFromResources(pathTypeOfMusic);
+        Random random = new Random();
+        int min = 0;
+        int max = musicPaths.size() - 1;
+        int randomIndex = random.nextInt(max - min + 1 ) + min;
+        String randomMusic = musicPaths.get(randomIndex).toString();
+        String normalizedPath = Paths.get(randomMusic).toString().replace('\\', '/');
+        String resource = normalizedPath.substring(18);
+        log.info(resource);
+        Thread thread = new Thread(() -> {
+            Media media = new Media(getClass().getResource(resource).toExternalForm());
+            mediaPlayer = new MediaPlayer(media);
+            mediaPlayer.setCycleCount(MediaPlayer.INDEFINITE);
+            mediaPlayer.play();
+            log.info("Music is playing");
+
+        });
+        thread.setDaemon(true);
+        thread.start();
+    }
+
+    public void stopMusic(){
+        if (mediaPlayer != null) {
+            mediaPlayer.dispose(); // Dispose of the MediaPlayer instance
+        }
+    }
+
+    @Override
+    public void playSoundEffect() throws InterruptedException, MalformedURLException {
+
+    }
+
+
+
+    public List<Path> getFilePathsFromResources(Path folderPath) throws IOException {
+        List<Path> result;
+        try (Stream<Path> walk = Files.walk(folderPath)) {
+            result = walk.filter(Files::isRegularFile)
+                    .collect(Collectors.toList());
+        }
+        return result;
+    }
+
+}
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 8a3132800c32f2c5b0c2bb3dabef96a0aae98b5d..f0029279f9b345c8bca30dd1ea57552d991b6c83 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -3,15 +3,25 @@ module gui {
     requires javafx.fxml;
     requires javafx.media;
     requires org.apache.logging.log4j;
+    requires java.desktop;
+    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;
+    opens de.hdm_stuttgart.battlearena to javafx.fxml;
+    opens de.hdm_stuttgart.battlearena.Model.Sound to javafx.media;
+    opens de.hdm_stuttgart.battlearena.Controller.Utilities to javafx.fxml;
+    opens de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.ENUMs to com.google.gson;
+
     exports de.hdm_stuttgart.battlearena.Main;
     exports de.hdm_stuttgart.battlearena.Controller;
     exports de.hdm_stuttgart.battlearena.Model.Entity;
     exports de.hdm_stuttgart.battlearena.Model.Inputs;
     exports de.hdm_stuttgart.battlearena.Model.Map;
     exports de.hdm_stuttgart.battlearena.Controller.Utilities;
-    opens de.hdm_stuttgart.battlearena.Controller.Utilities to javafx.fxml;
-}
\ No newline at end of file
+}
diff --git a/src/main/resources/sound/sfx/Footsteps, Human, Dirty Ground, Walk SND62078.wav b/src/main/resources/Footsteps, Human, Dirty Ground, Walk SND62078.wav
similarity index 100%
rename from src/main/resources/sound/sfx/Footsteps, Human, Dirty Ground, Walk SND62078.wav
rename to src/main/resources/Footsteps, Human, Dirty Ground, Walk SND62078.wav
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/fonts/AmaticSC-Bold.ttf b/src/main/resources/fonts/AmaticSC-Bold.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..63cd7ae5be0bce367f8c0aa0e30702d065680923
Binary files /dev/null and b/src/main/resources/fonts/AmaticSC-Bold.ttf differ
diff --git a/src/main/resources/fonts/AmaticSC-Regular.ttf b/src/main/resources/fonts/AmaticSC-Regular.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..b860368bec2246d3c268c075167c9d7333d454d0
Binary files /dev/null and b/src/main/resources/fonts/AmaticSC-Regular.ttf differ
diff --git a/src/main/resources/fonts/Arthemis-mLA22.ttf b/src/main/resources/fonts/Arthemis-mLA22.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..165d0d21fda6832a71ff683dcfafe042a5d2d016
Binary files /dev/null and b/src/main/resources/fonts/Arthemis-mLA22.ttf differ
diff --git a/src/main/resources/fonts/ShadowsIntoLight-Regular.ttf b/src/main/resources/fonts/ShadowsIntoLight-Regular.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..d20640513b188b6627c3b11383721eba624f1b26
Binary files /dev/null and b/src/main/resources/fonts/ShadowsIntoLight-Regular.ttf differ
diff --git a/src/main/resources/fxml/CreateAccount.fxml b/src/main/resources/fxml/CreateAccount.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..b75267745fd38367a38728324cf4b7a0aefa720c
--- /dev/null
+++ b/src/main/resources/fxml/CreateAccount.fxml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.control.RadioButton?>
+<?import javafx.scene.control.TextField?>
+<?import javafx.scene.control.ToggleGroup?>
+<?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.Pane?>
+<?import javafx.scene.layout.VBox?>
+<?import javafx.scene.text.Text?>
+
+<VBox fx:id="parent" alignment="CENTER" prefHeight="400.0" prefWidth="600.0" spacing="20.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.hdm_stuttgart.battlearena.Controller.CreateAccountController">
+   <children>
+      <Pane VBox.vgrow="ALWAYS" />
+      <VBox alignment="CENTER" VBox.vgrow="ALWAYS">
+         <children>
+            <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Tracking statistics:" />
+            <HBox alignment="CENTER" spacing="30.0" VBox.vgrow="ALWAYS">
+               <children>
+                  <RadioButton fx:id="local" mnemonicParsing="false" text="Local">
+                     <toggleGroup>
+                        <ToggleGroup fx:id="statistics" />
+                     </toggleGroup>
+                  </RadioButton>
+                  <RadioButton mnemonicParsing="false" text="Online" toggleGroup="$statistics" />
+               </children>
+            </HBox>
+         </children>
+      </VBox>
+      <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Player Name:" />
+      <TextField fx:id="playerName" alignment="CENTER" />
+      <Label fx:id="passwordLabel" text="Password:" />
+      <TextField fx:id="password" alignment="CENTER" />
+      <Label fx:id="errorMessage" />
+      <Button mnemonicParsing="false" onAction="#create" text="Create" />
+      <Button mnemonicParsing="false" onAction="#back" text="Back" />
+      <Pane VBox.vgrow="ALWAYS" />
+   </children>
+</VBox>
diff --git a/src/main/resources/fxml/LoadingScreen.fxml b/src/main/resources/fxml/LoadingScreen.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..4e242f48920d3c22e5351886ead0da65eaa80b44
--- /dev/null
+++ b/src/main/resources/fxml/LoadingScreen.fxml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.image.Image?>
+<?import javafx.scene.image.ImageView?>
+<?import javafx.scene.layout.BorderPane?>
+<?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.Pane?>
+<?import javafx.scene.shape.Rectangle?>
+<?import javafx.scene.text.Font?>
+
+<BorderPane id="loadingScreen" fx:id="parent" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.hdm_stuttgart.battlearena.Controller.LoadingScreenController">
+   <bottom>
+      <HBox alignment="BOTTOM_CENTER" BorderPane.alignment="BOTTOM_CENTER">
+         <children>
+            <Rectangle arcHeight="5.0" arcWidth="5.0" fill="#ffffff00" height="180.0" stroke="TRANSPARENT" strokeType="INSIDE" width="180.0" HBox.hgrow="NEVER">
+               <HBox.margin>
+                  <Insets bottom="50.0" left="50.0" right="50.0" />
+               </HBox.margin>
+            </Rectangle>
+            <Pane HBox.hgrow="ALWAYS" />
+            <Label fx:id="tips" alignment="CENTER" contentDisplay="CENTER" text="If you see this, then something went wrong lmao" textFill="WHITE" wrapText="true">
+               <font>
+                  <Font name="Helvetica Neue LT Com 53 Extended" size="40.0" />
+               </font>
+               <HBox.margin>
+                  <Insets bottom="50.0" />
+               </HBox.margin>
+            </Label>
+            <Pane HBox.hgrow="ALWAYS" />
+            <ImageView fx:id="throbber" fitHeight="180.0" fitWidth="180.0" pickOnBounds="true" preserveRatio="true">
+               <image>
+                  <Image url="@../textures/images/throbber.gif" />
+               </image>
+               <HBox.margin>
+                  <Insets bottom="50.0" left="50.0" right="50.0" />
+               </HBox.margin>
+            </ImageView>
+         </children>
+         <BorderPane.margin>
+            <Insets />
+         </BorderPane.margin>
+      </HBox>
+   </bottom>
+   <center>
+      <ImageView fx:id="logo" fitHeight="800.0" fitWidth="900.0" pickOnBounds="true" preserveRatio="true" BorderPane.alignment="CENTER">
+         <image>
+            <Image url="@../textures/images/logo_transparent.png" />
+         </image>
+      </ImageView>
+   </center>
+</BorderPane>
diff --git a/src/main/resources/fxml/Login.fxml b/src/main/resources/fxml/Login.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..a63c7c127ff2c30d0499ffc963851e061324bf58
--- /dev/null
+++ b/src/main/resources/fxml/Login.fxml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.control.TextField?>
+<?import javafx.scene.layout.Pane?>
+<?import javafx.scene.layout.VBox?>
+<?import javafx.scene.text.Text?>
+
+<VBox fx:id="parent" alignment="CENTER" prefHeight="400.0" prefWidth="600.0" spacing="20.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.hdm_stuttgart.battlearena.Controller.LoginController">
+   <children>
+      <Pane VBox.vgrow="ALWAYS" />
+      <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Login with existing online account" />
+      <Pane VBox.vgrow="ALWAYS" />
+      <Pane VBox.vgrow="ALWAYS" />
+      <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Player Name:" />
+      <TextField fx:id="playerName" alignment="CENTER" />
+      <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Password:" />
+      <TextField fx:id="password" alignment="CENTER" />
+      <Label fx:id="errorMessage" />
+      <Button mnemonicParsing="false" onAction="#login" text="Login" />
+      <Button mnemonicParsing="false" onAction="#back" text="Back" />
+      <Pane VBox.vgrow="ALWAYS" />
+   </children>
+</VBox>
diff --git a/src/main/resources/fxml/MapSelection.fxml b/src/main/resources/fxml/MapSelection.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..1be6734bac78aa59dd7db7a771411adfd64dd828
--- /dev/null
+++ b/src/main/resources/fxml/MapSelection.fxml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.Accordion?>
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.ScrollPane?>
+<?import javafx.scene.control.TitledPane?>
+<?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.Pane?>
+<?import javafx.scene.layout.VBox?>
+<?import javafx.scene.text.Text?>
+
+<VBox fx:id="parent" alignment="CENTER" prefHeight="400.0" prefWidth="600.0" spacing="20.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.hdm_stuttgart.battlearena.Controller.MapSelectionController">
+   <children>
+      <Pane VBox.vgrow="ALWAYS" />
+      <HBox alignment="TOP_CENTER" spacing="20.0">
+         <children>
+            <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Maps:" />
+            <Accordion>
+              <panes>
+                <TitledPane fx:id="roundsTitledPane" text="Select">
+                     <content>
+                        <ScrollPane minViewportHeight="40.0">
+                           <content>
+                              <VBox fx:id="boxBox" />
+                           </content>
+                        </ScrollPane>
+                     </content>
+                </TitledPane>
+              </panes>
+            </Accordion>
+         </children>
+         <VBox.margin>
+            <Insets />
+         </VBox.margin>
+      </HBox>
+      <HBox alignment="TOP_CENTER" maxWidth="-Infinity" minWidth="-Infinity" prefHeight="25.0" prefWidth="213.0" spacing="20.0">
+         <children>
+            <Text fx:id="selectedMapText" strokeType="OUTSIDE" strokeWidth="0.0" />
+         </children>
+      </HBox>
+      <Button mnemonicParsing="false" onAction="#gameScene" text="Start" />
+      <Button mnemonicParsing="false" onAction="#backButton" text="Back">
+         <VBox.margin>
+            <Insets bottom="50.0" />
+         </VBox.margin>
+      </Button>
+      <Pane VBox.vgrow="ALWAYS" />
+   </children>
+</VBox>
diff --git a/src/main/resources/fxml/MultiplayerCreate.fxml b/src/main/resources/fxml/MultiplayerCreate.fxml
index 3cf21a91e290fca2da1b2516320c1feb50a99cee..f95e2126f13aee4f89541b835ef2c90ffbbc7d9b 100644
--- a/src/main/resources/fxml/MultiplayerCreate.fxml
+++ b/src/main/resources/fxml/MultiplayerCreate.fxml
@@ -47,7 +47,7 @@
             <Insets top="20.0" />
          </VBox.margin>
       </AnchorPane>
-      <Button mnemonicParsing="false" text="Start" />
+      <Button mnemonicParsing="false" onAction="#start" text="Start" />
       <Button mnemonicParsing="false" onAction="#backButton" text="Back" />
       <Pane VBox.vgrow="ALWAYS" />
       <Pane VBox.vgrow="ALWAYS" />
diff --git a/src/main/resources/fxml/Placeholder.fxml b/src/main/resources/fxml/Placeholder.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..5b08cde3dfdf168d0e09cc1f005c3f62ac8e09c5
--- /dev/null
+++ b/src/main/resources/fxml/Placeholder.fxml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.layout.BorderPane?>
+<?import javafx.scene.layout.StackPane?>
+<?import javafx.scene.layout.VBox?>
+<?import javafx.scene.media.MediaView?>
+<?import javafx.scene.text.Text?>
+
+<BorderPane fx:id="parent" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.hdm_stuttgart.battlearena.Controller.PlaceholderController">
+   <center>
+      <StackPane BorderPane.alignment="CENTER">
+         <children>
+            <MediaView fx:id="mediaView" fitHeight="200.0" fitWidth="200.0" />
+            <VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0" spacing="10.0">
+               <children>
+                  <Text fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="WELCOME!" />
+                  <Text fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="This page is still under construction" />
+                  <Text fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="please have some patience" />
+                  <Text fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="Thank you" />
+                  <Button fx:id="button" mnemonicParsing="false" text="Get me out of here" />
+               </children>
+            </VBox>
+         </children>
+      </StackPane>
+   </center>
+</BorderPane>
diff --git a/src/main/resources/fxml/PlayerCreateScene.fxml b/src/main/resources/fxml/PlayerCreateScene.fxml
index 1563facf396815b701f237fdab3dd7e3769c7951..9a7e5e347bd49fc7a87467f5700922cbf3fdb937 100644
--- a/src/main/resources/fxml/PlayerCreateScene.fxml
+++ b/src/main/resources/fxml/PlayerCreateScene.fxml
@@ -1,28 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <?import javafx.scene.control.Button?>
-<?import javafx.scene.layout.BorderPane?>
-<?import javafx.scene.layout.StackPane?>
+<?import javafx.scene.layout.Pane?>
 <?import javafx.scene.layout.VBox?>
-<?import javafx.scene.media.MediaView?>
-<?import javafx.scene.text.Text?>
 
 
-<BorderPane fx:id="parent" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.hdm_stuttgart.battlearena.Controller.PlayerCreateController">
-   <center>
-      <StackPane BorderPane.alignment="CENTER">
-         <children>
-            <MediaView fx:id="mediaView" fitHeight="200.0" fitWidth="200.0" />
-            <VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0" spacing="10.0">
-               <children>
-                  <Text fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="WELCOME!" />
-                  <Text fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="This page is still under construction" />
-                  <Text fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="please have some patience" />
-                  <Text fill="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="Thank you" />
-                  <Button fx:id="button" mnemonicParsing="false" text="Get me out of here" />
-               </children>
-            </VBox>
-         </children>
-      </StackPane>
-   </center>
-</BorderPane>
+<VBox fx:id="parent" alignment="CENTER" prefHeight="400.0" prefWidth="600.0" spacing="50.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.hdm_stuttgart.battlearena.Controller.PlayerCreateController">
+   <children>
+      <Pane prefHeight="200.0" prefWidth="200.0" />
+      <Button mnemonicParsing="false" onAction="#createScene" text="Create Account" />
+      <Button mnemonicParsing="false" onAction="#loginScene" text="Login" />
+      <Pane prefHeight="200.0" prefWidth="200.0" />
+      <Button mnemonicParsing="false" onAction="#exit" text="Exit" />
+      <Pane prefHeight="200.0" prefWidth="200.0" />
+   </children>
+</VBox>
diff --git a/src/main/resources/fxml/Settings.fxml b/src/main/resources/fxml/Settings.fxml
index 6cab6585ef8f19e015fc3645684934a599ee9aec..3f84b3167228690e174a053e4d5ba4128fc44e72 100644
--- a/src/main/resources/fxml/Settings.fxml
+++ b/src/main/resources/fxml/Settings.fxml
@@ -15,19 +15,20 @@
                   <VBox alignment="CENTER" VBox.vgrow="ALWAYS">
                      <children>
                         <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Music volume:" />
-                        <Slider fx:id="musicVolume" blockIncrement="25.0" majorTickUnit="100.0" minorTickCount="1" prefHeight="14.0" prefWidth="480.0" showTickLabels="true" value="75.0" VBox.vgrow="NEVER" />
+                        <Slider fx:id="musicSlider" blockIncrement="25.0" majorTickUnit="100.0" minorTickCount="1" prefHeight="14.0" prefWidth="480.0" showTickLabels="true" value="75.0" VBox.vgrow="NEVER" />
                      </children>
                   </VBox>
                   <VBox alignment="CENTER" VBox.vgrow="ALWAYS">
                      <children>
                         <Text strokeType="OUTSIDE" strokeWidth="0.0" text="SFX volume:" />
-                        <Slider fx:id="sfxVolume" blockIncrement="25.0" majorTickUnit="100.0" minorTickCount="1" prefHeight="14.0" prefWidth="480.0" showTickLabels="true" value="75.0" />
+                        <Slider fx:id="sfxSlider" blockIncrement="25.0" majorTickUnit="100.0" minorTickCount="1" prefHeight="14.0" prefWidth="480.0" showTickLabels="true" value="75.0" />
                      </children>
                   </VBox>
                </children>
             </VBox>
          </children>
       </HBox>
+      <Button mnemonicParsing="false" onAction="#account" text="Account" />
       <Button mnemonicParsing="false" onAction="#creditScene" text="Credits" />
       <Button mnemonicParsing="false" onAction="#backButton" text="Back" />
    </children>
diff --git a/src/main/resources/fxml/Statistics.fxml b/src/main/resources/fxml/Statistics.fxml
index 6c98b4e5e5aa7e8efd880b6945b8c7091aa04d32..42b8646af9788053e25149e8a04a9d3d8f0bfb1f 100644
--- a/src/main/resources/fxml/Statistics.fxml
+++ b/src/main/resources/fxml/Statistics.fxml
@@ -7,11 +7,11 @@
 <?import javafx.scene.layout.VBox?>
 <?import javafx.scene.text.Text?>
 
-<VBox fx:id="parent" alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" spacing="50.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.hdm_stuttgart.battlearena.Controller.StatisticsController">
+<VBox fx:id="parent" alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.hdm_stuttgart.battlearena.Controller.StatisticsController">
    <children>
-      <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" spacing="30.0" VBox.vgrow="ALWAYS">
+      <HBox alignment="CENTER" prefHeight="411.0" prefWidth="677.0" spacing="30.0" VBox.vgrow="ALWAYS">
          <children>
-            <VBox alignment="CENTER_RIGHT" prefHeight="200.0" prefWidth="100.0" spacing="10.0" HBox.hgrow="ALWAYS">
+            <VBox alignment="CENTER_RIGHT" spacing="10.0" HBox.hgrow="ALWAYS">
                <children>
                   <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Kills:" />
                   <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Deaths:" />
@@ -21,7 +21,7 @@
                   <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Ingame time:" />
                </children>
             </VBox>
-            <VBox alignment="CENTER_LEFT" prefHeight="200.0" prefWidth="100.0" spacing="10.0" HBox.hgrow="ALWAYS">
+            <VBox alignment="CENTER_LEFT" spacing="10.0" HBox.hgrow="ALWAYS">
                <children>
                   <Text fx:id="kills" strokeType="OUTSIDE" strokeWidth="0.0" text="Text" />
                   <Text fx:id="deaths" strokeType="OUTSIDE" strokeWidth="0.0" text="Text" />
@@ -38,11 +38,11 @@
                <children>
                   <PieChart fx:id="kd" minHeight="-Infinity" minWidth="-Infinity" VBox.vgrow="ALWAYS">
                      <VBox.margin>
-                        <Insets bottom="-200.0" />
+                        <Insets bottom="-200.0" top="-250.0" />
                      </VBox.margin></PieChart>
                   <PieChart fx:id="wl" minHeight="-Infinity" minWidth="-Infinity" VBox.vgrow="ALWAYS">
                      <VBox.margin>
-                        <Insets top="-40.0" />
+                        <Insets bottom="-250.0" top="-40.0" />
                      </VBox.margin></PieChart>
                </children>
             </VBox>
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
index 6fb857169bf3b818c95f9a1a9ada8ad3b39b0d58..9a77de28c30d210dadfd85f28a594d9e5621d9c8 100644
--- a/src/main/resources/log4j2.xml
+++ b/src/main/resources/log4j2.xml
@@ -16,6 +16,7 @@
         </Logger>
         <Root level="info">
             <AppenderRef ref="STDOUT"/>
+            <AppenderRef ref="A1"/>
         </Root>
     </Loggers>
 </Configuration>
\ No newline at end of file
diff --git a/src/main/resources/maps/communityMaps.json b/src/main/resources/maps/communityMaps.json
new file mode 100644
index 0000000000000000000000000000000000000000..9c99ec44154627bf856e8eff30053efa9d624f9f
--- /dev/null
+++ b/src/main/resources/maps/communityMaps.json
@@ -0,0 +1,16 @@
+[
+  {
+    "mapID": "fbf44184867512faecc195ae75ca55d5ab7bad2d",
+    "mapName": "Arena3",
+    "mapWidth": 18,
+    "mapHeight": 18,
+    "mapData": "12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 8 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"
+  },
+  {
+    "mapID": "1c23b362fd666c5fb7ed60ca611b17246424e49f",
+    "mapName": "Arena4",
+    "mapWidth": 18,
+    "mapHeight": 18,
+    "mapData": "12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 8 4 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"
+  }
+]
\ No newline at end of file
diff --git a/src/main/resources/maps/coreMaps.json b/src/main/resources/maps/coreMaps.json
new file mode 100644
index 0000000000000000000000000000000000000000..ba63b040f5afc06edf39a660e0cd815b3bb7963b
--- /dev/null
+++ b/src/main/resources/maps/coreMaps.json
@@ -0,0 +1,16 @@
+[
+  {
+    "mapID": "09a02b54d05b5b7ebc29a4383ca12d3dda846b72",
+    "mapName": "Arena1",
+    "mapWidth": 18,
+    "mapHeight": 18,
+    "mapData": "12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"
+  },
+  {
+    "mapID": "0ab15557ab6dc4be60dfe6a9b0288bac3036bd97",
+    "mapName": "Arena2",
+    "mapWidth": 18,
+    "mapHeight": 18,
+    "mapData": "12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 5 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"
+  }
+]
\ 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..f7d371619fa1db8dd4701e6607908135293b820c
--- /dev/null
+++ b/src/main/resources/player/appSettings.json
@@ -0,0 +1,4 @@
+{
+  "sfxVolume": 100,
+  "musicVolume": 0
+}
\ No newline at end of file
diff --git a/src/main/resources/player/playerAccount.json b/src/main/resources/player/playerAccount.json
new file mode 100644
index 0000000000000000000000000000000000000000..60070b6ed6a4c8153907eaf7e737e2e997fb3377
--- /dev/null
+++ b/src/main/resources/player/playerAccount.json
@@ -0,0 +1,5 @@
+{
+  "playerName": "Player1",
+  "accountPassword": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
+  "accountType": "LOCAL"
+}
\ 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..4db3d0788fb3ff0fe8d593e5baed84279916821b
--- /dev/null
+++ b/src/main/resources/player/playerStatsLocal.json
@@ -0,0 +1,8 @@
+{
+  "gamesLost": 0,
+  "gamesWon": 0,
+  "kills": 0,
+  "deaths": 0,
+  "blocksDestroyed": 0,
+  "gameTime": 0
+}
\ No newline at end of file
diff --git a/src/main/resources/sound/music/cocBackgroundMusicTest.mp3 b/src/main/resources/sound/music/cocBackgroundMusicTest.mp3
index e916ecb6c0b6487e9bcb8ca6c3d54f6259eac9dc..fe39b45659600de8eb2ed2bdac281444be461261 100644
Binary files a/src/main/resources/sound/music/cocBackgroundMusicTest.mp3 and b/src/main/resources/sound/music/cocBackgroundMusicTest.mp3 differ
diff --git a/src/main/resources/sound/music/constructionJazz.mp3 b/src/main/resources/sound/music/constructionJazz.mp3
index 4abd8f438011630e16506118234837906d3ceb37..5669e8017883014e447765a405c6ec3b208db5bb 100644
Binary files a/src/main/resources/sound/music/constructionJazz.mp3 and b/src/main/resources/sound/music/constructionJazz.mp3 differ
diff --git a/src/main/resources/sound/music/musicPlaceholder.mp3 b/src/main/resources/sound/music/game/musicPlaceholder.mp3
similarity index 100%
rename from src/main/resources/sound/music/musicPlaceholder.mp3
rename to src/main/resources/sound/music/game/musicPlaceholder.mp3
diff --git a/src/main/resources/sound/music/menu/musicPlaceholder.wav b/src/main/resources/sound/music/menu/musicPlaceholder.wav
new file mode 100644
index 0000000000000000000000000000000000000000..e10258b8b48d0253ca1a3141482ee600c96d58e9
Binary files /dev/null and b/src/main/resources/sound/music/menu/musicPlaceholder.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 1.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 1.wav
new file mode 100644
index 0000000000000000000000000000000000000000..fb7dc6572c0c0232ddd17049a0801d8de0ef0035
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 1.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 10.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 10.wav
new file mode 100644
index 0000000000000000000000000000000000000000..7edaf5417e8f65c81092fbae60f309d0c469ae44
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 10.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 11.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 11.wav
new file mode 100644
index 0000000000000000000000000000000000000000..52dbe6393a2855313ab661be65b0cfa8c85838c8
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 11.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 12.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 12.wav
new file mode 100644
index 0000000000000000000000000000000000000000..24f9a5f098b6f55465cfbe41edac6324985396b2
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 12.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 13.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 13.wav
new file mode 100644
index 0000000000000000000000000000000000000000..ead5ebf730e986b5300ae859cb7804d9c5025bc6
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 13.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 14.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 14.wav
new file mode 100644
index 0000000000000000000000000000000000000000..128c1d579f44bace7190a3c855673eee901c98ec
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 14.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 15.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 15.wav
new file mode 100644
index 0000000000000000000000000000000000000000..e2c2c54985afc50b3f3f1de45b6dd68ae8c0db00
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 15.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 16.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 16.wav
new file mode 100644
index 0000000000000000000000000000000000000000..b28f00628e321a05293fa07c73503abc9cc9ec37
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 16.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 17.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 17.wav
new file mode 100644
index 0000000000000000000000000000000000000000..6481be5c73f1137e3b10f8483819292d3376056b
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 17.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 18.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 18.wav
new file mode 100644
index 0000000000000000000000000000000000000000..f828b12669df1b8a01a4956cc178bd0bed24243d
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 18.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 19.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 19.wav
new file mode 100644
index 0000000000000000000000000000000000000000..4e2be3515c1fdfc95226033cf304f56be65a5b6c
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 19.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 2.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 2.wav
new file mode 100644
index 0000000000000000000000000000000000000000..87570339d853042dd6dc4fcbd7b871ec3afcee34
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 2.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 20.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 20.wav
new file mode 100644
index 0000000000000000000000000000000000000000..85a71f7d9764cae6a3220c38393336cf320cb284
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 20.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 3.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 3.wav
new file mode 100644
index 0000000000000000000000000000000000000000..ba37dc8a23965323887983518a5e9274ff1938f6
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 3.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 4.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 4.wav
new file mode 100644
index 0000000000000000000000000000000000000000..e3acb0eb0e6d900fa67fc2500c06be7ab0383d16
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 4.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 5.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 5.wav
new file mode 100644
index 0000000000000000000000000000000000000000..dabe68f4c735ded390aa3de52d293e31ef0b4967
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 5.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 6.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 6.wav
new file mode 100644
index 0000000000000000000000000000000000000000..ce9dd0eb336d5129f78ceac527e28f60f39b554f
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 6.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 7.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 7.wav
new file mode 100644
index 0000000000000000000000000000000000000000..71e061472f1fddae9fbaa2ae5a186a71f078a008
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 7.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 8.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 8.wav
new file mode 100644
index 0000000000000000000000000000000000000000..9b8538a47aaa357ffcbe6bc8223809584be19e2c
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 8.wav differ
diff --git a/src/main/resources/sound/sfx/steps/grass/steps - Track 9.wav b/src/main/resources/sound/sfx/steps/grass/steps - Track 9.wav
new file mode 100644
index 0000000000000000000000000000000000000000..6ea17cb32406c61630d7975713742719070d3ef6
Binary files /dev/null and b/src/main/resources/sound/sfx/steps/grass/steps - Track 9.wav differ
diff --git a/src/main/resources/styles/style.css b/src/main/resources/styles/style.css
index 1f2a2030a2e67b98cb0869b5cf205d74b8cc9bca..938f7693c3a76d53bf9a90102efe2633d34cfb66 100644
--- a/src/main/resources/styles/style.css
+++ b/src/main/resources/styles/style.css
@@ -4,22 +4,43 @@
 }
 
 #button {
-    -fx-text-fill: black;
+    -fx-text-fill: #454545;
 }
 
 .root {
-    -fx-font-family: "Starship Shadow";
+    -fx-font-family: "Arthemis";
     -fx-text-fill: white;
     -fx-background-color: black;
+    -fx-font-size: 50 px;
+}
+
+#tips {
+    -fx-font-family: "Amatic SC Bold";
+    -fx-font-size: 40 px;
 }
 
+#loadingScreen {
+    -fx-background-color: radial-gradient(focus-distance 0% , center 50% 50% , radius 45% , #a31c31, #542b27);
+}
+
+.text-field {
+    -fx-background-color: transparent;
+    -fx-text-fill: black;
+    -fx-border-color: black;
+    -fx-border-width: 0 0 2 0;
+    -fx-prompt-text-fill: rgba(0, 0, 0, 0.5);
+    -fx-font-family: "Shadows Into Light";
+}
+
+
 #mainMenu{
     -fx-background-image: url("../textures/images/background.png");
     -fx-background-size: cover;
 }
 
 #gameTitle {
-    -fx-font-size: 100;
+    -fx-font-size: 100 px;
+    -fx-font-family: "Starship Shadow";
 }
 
 #gameScene {
@@ -35,6 +56,7 @@
 
 #btnLeft {
     -fx-skin: none;
+    -fx-text-fill: #7a7a7a;
 }
 
 .accordion {
diff --git a/src/main/resources/textures/images/logo_transparent.png b/src/main/resources/textures/images/logo_transparent.png
new file mode 100644
index 0000000000000000000000000000000000000000..4aa46908f9c28d66b837bfc3d073aab080759127
Binary files /dev/null and b/src/main/resources/textures/images/logo_transparent.png differ
diff --git a/src/main/resources/textures/images/logo_transparent_alt.png b/src/main/resources/textures/images/logo_transparent_alt.png
new file mode 100644
index 0000000000000000000000000000000000000000..817ba0a2f3103c351277b8598614836c377ce058
Binary files /dev/null and b/src/main/resources/textures/images/logo_transparent_alt.png differ
diff --git a/src/main/resources/textures/images/throbber.gif b/src/main/resources/textures/images/throbber.gif
new file mode 100644
index 0000000000000000000000000000000000000000..45caf1ef603429f181feebcc5505f4b01f512728
Binary files /dev/null and b/src/main/resources/textures/images/throbber.gif differ
diff --git a/src/main/resources/textures/map/finalheart.png b/src/main/resources/textures/map/finalheart.png
new file mode 100644
index 0000000000000000000000000000000000000000..b861b145ceb949abdd7222a2679fe8e10756340f
Binary files /dev/null and b/src/main/resources/textures/map/finalheart.png differ
diff --git a/src/main/resources/textures/player/high_born/HighBornDown00.png b/src/main/resources/textures/player/high_born/HighBornDown00.png
new file mode 100644
index 0000000000000000000000000000000000000000..b87b19b2ffe1ce2048c6d8bc96d1e4a66fd4c4af
Binary files /dev/null and b/src/main/resources/textures/player/high_born/HighBornDown00.png differ
diff --git a/src/main/resources/textures/player/high_born/HighBornDown01.png b/src/main/resources/textures/player/high_born/HighBornDown01.png
new file mode 100644
index 0000000000000000000000000000000000000000..787b4603347dac4b2d5f2c1063b3e3a3551fed4a
Binary files /dev/null and b/src/main/resources/textures/player/high_born/HighBornDown01.png differ
diff --git a/src/main/resources/textures/player/human/HumanDown00.png b/src/main/resources/textures/player/human/HumanDown00.png
new file mode 100644
index 0000000000000000000000000000000000000000..980612cb998a80e7710798fbd2f8a81791ef7322
Binary files /dev/null and b/src/main/resources/textures/player/human/HumanDown00.png differ
diff --git a/src/main/resources/textures/player/human/HumanDown01.png b/src/main/resources/textures/player/human/HumanDown01.png
new file mode 100644
index 0000000000000000000000000000000000000000..54792ff64f25e5c6e48e35f90502ff2d7fea9893
Binary files /dev/null and b/src/main/resources/textures/player/human/HumanDown01.png differ
diff --git a/src/main/resources/textures/player/human/HumanLeft00.png b/src/main/resources/textures/player/human/HumanLeft00.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d259ebb0c88259967e361c93138dd3367bcfe1b
Binary files /dev/null and b/src/main/resources/textures/player/human/HumanLeft00.png differ
diff --git a/src/main/resources/textures/player/human/HumanLeft01.png b/src/main/resources/textures/player/human/HumanLeft01.png
new file mode 100644
index 0000000000000000000000000000000000000000..3e25fce1c897aa94297d73248a54b1c09700d8d2
Binary files /dev/null and b/src/main/resources/textures/player/human/HumanLeft01.png differ
diff --git a/src/main/resources/textures/player/human/HumanRight00.png b/src/main/resources/textures/player/human/HumanRight00.png
new file mode 100644
index 0000000000000000000000000000000000000000..f20b2b692e98c68bc6671b0294a3582b4de65f0b
Binary files /dev/null and b/src/main/resources/textures/player/human/HumanRight00.png differ
diff --git a/src/main/resources/textures/player/human/HumanRight01.png b/src/main/resources/textures/player/human/HumanRight01.png
new file mode 100644
index 0000000000000000000000000000000000000000..ba2dd289825604b6730186ffb862592b2d94bb12
Binary files /dev/null and b/src/main/resources/textures/player/human/HumanRight01.png differ
diff --git a/src/main/resources/textures/player/human/HumanUp00.png b/src/main/resources/textures/player/human/HumanUp00.png
new file mode 100644
index 0000000000000000000000000000000000000000..bf2042d6a68463fa8c392c03d5cfaa973f9d1ae4
Binary files /dev/null and b/src/main/resources/textures/player/human/HumanUp00.png differ
diff --git a/src/main/resources/textures/player/human/HumanUp01.png b/src/main/resources/textures/player/human/HumanUp01.png
new file mode 100644
index 0000000000000000000000000000000000000000..c21f00058a48f3c99b1eeaae7f2d93f8baef1471
Binary files /dev/null and b/src/main/resources/textures/player/human/HumanUp01.png differ
diff --git a/src/main/resources/textures/player/sentinels/SentinelDown00.png b/src/main/resources/textures/player/sentinels/SentinelDown00.png
new file mode 100644
index 0000000000000000000000000000000000000000..c2fb803e03f3d459baeb4188975192ef83aa3b71
Binary files /dev/null and b/src/main/resources/textures/player/sentinels/SentinelDown00.png differ
diff --git a/src/main/resources/textures/player/sentinels/SentinelDown01.png b/src/main/resources/textures/player/sentinels/SentinelDown01.png
new file mode 100644
index 0000000000000000000000000000000000000000..bb87d3b89b7a54dd62fde0c509d9d0ae09e549c4
Binary files /dev/null and b/src/main/resources/textures/player/sentinels/SentinelDown01.png differ
diff --git a/src/main/resources/videos/allMyFellas.mp4 b/src/main/resources/videos/allMyFellas.mp4
index 4234d4da1c07a7e775bced2e4e44c2329c8be972..5371bd89089430d7fa4e467da0e857743a9cdd0b 100644
Binary files a/src/main/resources/videos/allMyFellas.mp4 and b/src/main/resources/videos/allMyFellas.mp4 differ
diff --git a/src/main/resources/videos/async.mp4 b/src/main/resources/videos/async.mp4
index a1fab12d8d746424ae6390ca6fe9eadef6136d62..4fef92ce7683b37e7e5dd01c5d6561fdaef4310c 100644
Binary files a/src/main/resources/videos/async.mp4 and b/src/main/resources/videos/async.mp4 differ
diff --git a/src/main/resources/videos/banana.mp4 b/src/main/resources/videos/banana.mp4
index 3d856e404f8b52494492d7a5150f17c7b7e951ec..389d4987f86aa037d333fc7f2c84ecf9d1bc02f8 100644
Binary files a/src/main/resources/videos/banana.mp4 and b/src/main/resources/videos/banana.mp4 differ
diff --git a/src/main/resources/videos/basketball.mp4 b/src/main/resources/videos/basketball.mp4
index 789d9579969084c45b1592f8e1abc1d6c6599edb..067fcfbcc003a71f39c03b43e1882ceda9e9869c 100644
Binary files a/src/main/resources/videos/basketball.mp4 and b/src/main/resources/videos/basketball.mp4 differ
diff --git a/src/main/resources/videos/catEating.mp4 b/src/main/resources/videos/catEating.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..530059520bc6a7ec848fca40e27371fac757171a
Binary files /dev/null and b/src/main/resources/videos/catEating.mp4 differ
diff --git a/src/main/resources/videos/catJump.mp4 b/src/main/resources/videos/catJump.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..cce5bdb3f5ecb0d515d9802848cd742d8b6bcb56
Binary files /dev/null and b/src/main/resources/videos/catJump.mp4 differ
diff --git a/src/main/resources/videos/catSitting.mp4 b/src/main/resources/videos/catSitting.mp4
index be5ae85619580861cdde91884d74fc44541c127b..28007e146999a02253044e4423819e80ec590c22 100644
Binary files a/src/main/resources/videos/catSitting.mp4 and b/src/main/resources/videos/catSitting.mp4 differ
diff --git a/src/main/resources/videos/chaCha.mp4 b/src/main/resources/videos/chaCha.mp4
index 4557a204bace6e377f812860ca794cf57dba63ad..700b233f8ce39926076fd7870bd6920d603c8d23 100644
Binary files a/src/main/resources/videos/chaCha.mp4 and b/src/main/resources/videos/chaCha.mp4 differ
diff --git a/src/main/resources/videos/cheezburger.mp4 b/src/main/resources/videos/cheezburger.mp4
index 28c72a6ebeb79d0d858e060ff98e0458d909e4f1..4910d355b7ef46d080954028c2c9376ba7993a92 100644
Binary files a/src/main/resources/videos/cheezburger.mp4 and b/src/main/resources/videos/cheezburger.mp4 differ
diff --git a/src/main/resources/videos/credits.mp4 b/src/main/resources/videos/credits.mp4
index cffe4eaf38603cdd817e4957f7a9b717a0578232..410d261aba44faf7e6f2ba606393f76ba1ba526f 100644
Binary files a/src/main/resources/videos/credits.mp4 and b/src/main/resources/videos/credits.mp4 differ
diff --git a/src/main/resources/videos/depression.mp4 b/src/main/resources/videos/depression.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..9e282df3676adcb28bc15d9238025fe6b37d9fcb
Binary files /dev/null and b/src/main/resources/videos/depression.mp4 differ
diff --git a/src/main/resources/videos/dog.mp4 b/src/main/resources/videos/dog.mp4
index 863031c0550b6745e167db051bd702e0827b5b32..2f291192b17204d93730dede0be6a24f1fa26066 100644
Binary files a/src/main/resources/videos/dog.mp4 and b/src/main/resources/videos/dog.mp4 differ
diff --git a/src/main/resources/videos/dog2.mp4 b/src/main/resources/videos/dog2.mp4
index 23cb49a3eedc11cfbcfa4a26d539bbfbef8f67ac..4500f7ae5c2e9d8d1ba8a06fdfb60a0cc47f2d7b 100644
Binary files a/src/main/resources/videos/dog2.mp4 and b/src/main/resources/videos/dog2.mp4 differ
diff --git a/src/main/resources/videos/dogCheese.mp4 b/src/main/resources/videos/dogCheese.mp4
index d94d1edf882ca1c57e220ec967b06f897309e106..eb24b7b5f7b5d2eb6a72dcb0b3ac1d3281cd789b 100644
Binary files a/src/main/resources/videos/dogCheese.mp4 and b/src/main/resources/videos/dogCheese.mp4 differ
diff --git a/src/main/resources/videos/firework.mp4 b/src/main/resources/videos/firework.mp4
index f102aa72a92bbe1989cf66c03785bcd937f1d3f7..706941c2cde672b81881056aa759308d67f433c0 100644
Binary files a/src/main/resources/videos/firework.mp4 and b/src/main/resources/videos/firework.mp4 differ
diff --git a/src/main/resources/videos/frog.mp4 b/src/main/resources/videos/frog.mp4
index 33462dcdf3a19edb59598e3320ced6c32f68ad88..e411b29309d38ffa3421e36ed3e9a3f4e9f9ad39 100644
Binary files a/src/main/resources/videos/frog.mp4 and b/src/main/resources/videos/frog.mp4 differ
diff --git a/src/main/resources/videos/gameboy.mp4 b/src/main/resources/videos/gameboy.mp4
index 91a1eaa78366adbb3686a07594417fd9c8832126..68821d3565f0efcc9995b2f7afaa220b9ca786eb 100644
Binary files a/src/main/resources/videos/gameboy.mp4 and b/src/main/resources/videos/gameboy.mp4 differ
diff --git a/src/main/resources/videos/gamecube.mp4 b/src/main/resources/videos/gamecube.mp4
index 135416e7b63fc25ed1e3e2b744c6d14a78692b99..a60bade2b34051ffd295a22de564a6476adbe8fc 100644
Binary files a/src/main/resources/videos/gamecube.mp4 and b/src/main/resources/videos/gamecube.mp4 differ
diff --git a/src/main/resources/videos/gta.mp4 b/src/main/resources/videos/gta.mp4
index c207c9177e116fde566d8bcd0d3a481d28574609..0259ca609572a35adb34f9c7293d49c9e97e37b8 100644
Binary files a/src/main/resources/videos/gta.mp4 and b/src/main/resources/videos/gta.mp4 differ
diff --git a/src/main/resources/videos/gtfo.mp4 b/src/main/resources/videos/gtfo.mp4
index 130f80032f69150a59fc7f41746a8cb1370f9738..536961ae8a9414f7b16ac646d4ceb0844d13a23f 100644
Binary files a/src/main/resources/videos/gtfo.mp4 and b/src/main/resources/videos/gtfo.mp4 differ
diff --git a/src/main/resources/videos/horse.mp4 b/src/main/resources/videos/horse.mp4
index c9b0cbe5d6b7f5e0d43345e26879225a922339fa..d4f6f7429a9f49344bf63f6602ac35131338b2a0 100644
Binary files a/src/main/resources/videos/horse.mp4 and b/src/main/resources/videos/horse.mp4 differ
diff --git a/src/main/resources/videos/kangaroo.mp4 b/src/main/resources/videos/kangaroo.mp4
index 9aec93f34ff0d3dfeaea5aa21f9a74e33634c88f..3cff449b6180fcbdbe367da02416525331ae94af 100644
Binary files a/src/main/resources/videos/kangaroo.mp4 and b/src/main/resources/videos/kangaroo.mp4 differ
diff --git a/src/main/resources/videos/minecraftCat2.mp4 b/src/main/resources/videos/minecraftCat2.mp4
index c510f7f42abce6847dce87197d2cb2697e3882df..1e9366af84a9aa9f363655de9b313cab98e77fba 100644
Binary files a/src/main/resources/videos/minecraftCat2.mp4 and b/src/main/resources/videos/minecraftCat2.mp4 differ
diff --git a/src/main/resources/videos/monke.mp4 b/src/main/resources/videos/monke.mp4
index c6d5f3c2e7f390276d22b26e46f462bb1e281d98..980756e7cd8fa4c3c00d5a246ad179b143c1fae1 100644
Binary files a/src/main/resources/videos/monke.mp4 and b/src/main/resources/videos/monke.mp4 differ
diff --git a/src/main/resources/videos/muecke.mp4 b/src/main/resources/videos/muecke.mp4
index 57c8641e7c2c4628f953d579c6f8acc9319e4207..c146f51e85f55df05f872781e4cfb09d5b222b87 100644
Binary files a/src/main/resources/videos/muecke.mp4 and b/src/main/resources/videos/muecke.mp4 differ
diff --git a/src/main/resources/videos/rejectHumanity.mp4 b/src/main/resources/videos/rejectHumanity.mp4
index ed006e08e75d76092c2ff9b7a7e89601cc822b32..6c2a377ca00e8f9381095c76661e5de75902b4f0 100644
Binary files a/src/main/resources/videos/rejectHumanity.mp4 and b/src/main/resources/videos/rejectHumanity.mp4 differ
diff --git a/src/main/resources/videos/rolling.mp4 b/src/main/resources/videos/rolling.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..07dd01a89cbc742e3a449aa8dae9c99b3f631e43
Binary files /dev/null and b/src/main/resources/videos/rolling.mp4 differ
diff --git a/src/main/resources/videos/roomba.mp4 b/src/main/resources/videos/roomba.mp4
index a8d2a9615476bb273b967f99bc007fde2a695d63..65a1e5aebe700b1b720182bf9ceaff3e6e160f88 100644
Binary files a/src/main/resources/videos/roomba.mp4 and b/src/main/resources/videos/roomba.mp4 differ
diff --git a/src/main/resources/videos/sad.mp4 b/src/main/resources/videos/sad.mp4
index fd3307de97c5c66f01f35f0274b58d87ced537b5..1868f52e473cad115b0dbe455c642211e5c50e81 100644
Binary files a/src/main/resources/videos/sad.mp4 and b/src/main/resources/videos/sad.mp4 differ
diff --git a/src/main/resources/videos/sadHorse.mp4 b/src/main/resources/videos/sadHorse.mp4
index c71f56706fdc239f72875d6206c91a4d40f80b46..dc6901a500652632c29c51d500b369044118ee58 100644
Binary files a/src/main/resources/videos/sadHorse.mp4 and b/src/main/resources/videos/sadHorse.mp4 differ
diff --git a/src/main/resources/videos/seal.mp4 b/src/main/resources/videos/seal.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..5f5f39382d212d1b1cf15a9eaf44fb90ee06e4f9
Binary files /dev/null and b/src/main/resources/videos/seal.mp4 differ
diff --git a/src/main/resources/videos/slippery.mp4 b/src/main/resources/videos/slippery.mp4
index 816308c9ae733e457266bf412df8301ef1bdd957..b26ecb1ceda0d65050f5244c98e76af43c717558 100644
Binary files a/src/main/resources/videos/slippery.mp4 and b/src/main/resources/videos/slippery.mp4 differ
diff --git a/src/main/resources/videos/sony.mp4 b/src/main/resources/videos/sony.mp4
index 9d96aebfc39a033d379d613070c97e6122f8a175..158c13874cb0cd60ddbc9903b2658d4c0cfd2ded 100644
Binary files a/src/main/resources/videos/sony.mp4 and b/src/main/resources/videos/sony.mp4 differ
diff --git a/src/main/resources/videos/yoinkySploinky.mp4 b/src/main/resources/videos/yoinkySploinky.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..ea88b4578ccc74f0228669792b4266b9860e3f0c
Binary files /dev/null and b/src/main/resources/videos/yoinkySploinky.mp4 differ
diff --git a/src/test/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/PersistenceTest.java b/src/test/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/PersistenceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..79b599da6c201b66ffe5d1c21293f44b9ee244e4
--- /dev/null
+++ b/src/test/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/PersistenceTest.java
@@ -0,0 +1,48 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.DatabaseException;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.SQLException;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.junit.Before;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class PersistenceTest {
+
+    private static final Logger log = LogManager.getLogger(PersistenceTest.class);
+    Persistence persistenceSingleton;
+
+    OracleDB inst = new OracleDB();
+
+    @Before
+    public void setup() throws SQLException {
+        persistenceSingleton = Persistence.getInstance();
+        persistenceSingleton.db = inst;
+        ArrayList<MapData> maps = new ArrayList<MapData>();
+        maps.add(new MapData("09a02b54d05b5b7ebc29a4383ca12d3dda846b72", "Arena1", 18, 18, "12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        maps.add(new MapData("0ab15557ab6dc4be60dfe6a9b0288bac3036bd97", "Arena2", 18, 18, "12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 5 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        when(inst.getCoreMaps()).thenReturn(maps);
+    }
+
+    @Test
+    void updateCoreMaps() throws RuntimeException, DatabaseException {
+            persistenceSingleton.updateCoreMaps();
+            assertEquals("09a02b54d05b5b7ebc29a4383ca12d3dda846b72", persistenceSingleton.getCoreMaps().get(0).getMapID());
+            assertEquals("0ab15557ab6dc4be60dfe6a9b0288bac3036bd97", persistenceSingleton.getCoreMaps().get(1).getMapID());
+    }
+
+    @Test
+    void loadPlayerStatistics() {
+    }
+
+
+
+
+}
\ No newline at end of file
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..6cbf6fc345bc7da7639d7b61c0299c9b89ac6930
--- /dev/null
+++ b/src/test/java/de/hdm_stuttgart/battlearena/Model/DataStorage/Classes/Utilities/ParserTest.java
@@ -0,0 +1,269 @@
+package de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Utilities;
+
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.Exceptions.ParserException;
+import de.hdm_stuttgart.battlearena.Model.DataStorage.Classes.PlayerStatistics;
+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",
+                            "0123456789012345678901234567890123456789"})
+    void usernameValid(String test){
+        assertDoesNotThrow(() -> Parser.usernameValid(test));
+    }
+
+    @Test
+    void usernameInvalid() {
+        ParserException testMe = assertThrows(ParserException.class, () -> Parser.usernameValid("lol"));
+        assertTrue(testMe.getMessage().contains("Username too short! Min length is 4 characters."));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.usernameValid("01234567890123456789012345678901234567890"));
+        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",
+                            "0123456789012345678901234567890123456789"})
+    void passwordValid(String test){
+        assertDoesNotThrow(() -> Parser.passwordValid(test));
+    }
+
+    @Test
+    void passwordInvalid() {
+        ParserException testMe = assertThrows(ParserException.class, () -> Parser.passwordValid("lol"));
+        assertTrue(testMe.getMessage().contains("Password too short! Min length is 4 characters."));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.passwordValid("01234567890123456789012345678901234567890"));
+        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 = {"012345678901234567890123456789",
+                            "de_dust",
+                            "Ziba-Tower"})
+    void mapNameValid(String test){
+        assertDoesNotThrow(() -> Parser.mapNameValid(test));
+    }
+
+    @Test
+    void mapNameInvalid() {
+        ParserException testMe = assertThrows(ParserException.class, () -> Parser.mapNameValid("lol"));
+        assertTrue(testMe.getMessage().contains("Map-Name too short! Min length is 4 characters."));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapNameValid("0123456789012345678901234567890"));
+        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 sha1HashValid(String test){
+        assertDoesNotThrow(() -> Parser.sha1HexHashValid(test));
+    }
+
+    @Test
+    void sha1HashInvalid() {
+
+        ParserException testMe = assertThrows(ParserException.class, () -> Parser.sha1HexHashValid("01234567890123456789012345678901234567890"));
+        assertTrue(testMe.getMessage().contains("SHA1 hash length not correct. Must have length of 40 characters!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.sha1HexHashValid("012345678901234567890123456789012345678"));
+        assertTrue(testMe.getMessage().contains("SHA1 hash length not correct. Must have length of 40 characters!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.sha1HexHashValid("XYZ3cafd1d061f0f463a2d2051bf4718aaaf5c48"));
+        assertTrue(testMe.getMessage().contains("Forbidden characters used! SHA1 hash 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 ipAddressInvalid() {
+
+        ParserException testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("255.255.255.2555"));
+        assertTrue(testMe.getMessage().contains("IP-Address too long. Must have maximum length of 15 characters including octet dividers (.) !"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("0.0.12"));
+        assertTrue(testMe.getMessage().contains("IP-Address too short. Must have minimum 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("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("12.12..2"));
+        assertTrue(testMe.getMessage().contains("IP-Address must not contain two or more consecutive dividers (.) without number in between!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("f1.12.12.12"));
+        assertTrue(testMe.getMessage().contains("IP address must consist out of numbers 0-9 and separators (.) !"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("12.12.12.1f"));
+        assertTrue(testMe.getMessage().contains("IP address must consist out of numbers 0-9 and separators (.) !"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("256.12.12.12"));
+        assertTrue(testMe.getMessage().contains("Octets of IP-address must not exceed 255!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("12.12.12.256"));
+        assertTrue(testMe.getMessage().contains("Octets of IP-address must not exceed 255!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("2500.12.12.12"));
+        assertTrue(testMe.getMessage().contains("Octets of IP-address must not exceed 255!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.ipAddressValid("12.12.12.2500"));
+        assertTrue(testMe.getMessage().contains("Octets of IP-address must not exceed 255!"));
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {"12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12",
+                            "12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 5 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12",
+                            "12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 8 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"})
+    void mapDataValid(String test){
+        assertDoesNotThrow(() -> Parser.mapDataValid(test));
+    }
+
+    @Test
+    void mapDataInvalid() {
+        ParserException testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - mapData String must not exceed length of 967 chars including spaces for 18x18 Tiles map!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("1 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 8 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - minimum length of mapData String must be 715 chars including spaces for 18x18 Tiles map!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid(" 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - must not start nor end with space!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 "));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - must not start nor end with space!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12  10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - must not contain two or more consecutive spaces without number in between!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 11 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10  12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - must not contain two or more consecutive spaces without number in between!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 13"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - number of spaces must be 323!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("10 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - number of spaces must be 323!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("a2 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - must consist out of numbers 0-9 and space as separator!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 1d"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - must consist out of numbers 0-9 and space as separator!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("42 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Tile number must be between 0 and 29!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 42"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Tile number must be between 0 and 29!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("22 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Top-Line must be border tiles!"));
+
+        //don't forget to reach minimum length with test String! Otherwise, wrong Exception will be thrown!
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 5 12 1 1 1 1 1 12 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Top-Line must be border tiles!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 22"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Bottom-Line must be border tiles!"));
+
+        //don't forget to reach minimum length with test String! Otherwise, wrong Exception will be thrown!
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 12 1 1 1 1 1 1 1 1 12 8 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Bottom-Line must be border tiles!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 22 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Left Edge must be border tiles!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 22 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Left Edge must be border tiles!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 22 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Right Edge must be border tiles!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 22 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Right Edge must be border tiles!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Player spawn top left must use walkable tile!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 25 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Player spawn top right must use walkable tile!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 25 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Player spawn bottom left must use walkable tile!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.mapDataValid("12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 12 12 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 25 12 12 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 12"));
+        assertTrue(testMe.getMessage().contains("Map-Data corrupted - Player spawn bottom right must use walkable tile!"));
+    }
+
+    @Test
+    void statsValid(){
+        PlayerStatistics stats = new PlayerStatistics(0, 0, 0, 0, 0, 0);
+        assertDoesNotThrow(() -> Parser.playerStatsValid(stats));
+    }
+
+    @Test
+    void statsInvalid(){
+        ParserException testMe = assertThrows(ParserException.class, () -> Parser.playerStatsValid(new PlayerStatistics(-1, 0, 0, 0, 0, 0)));
+        assertTrue(testMe.getMessage().contains("Player statistics data corrupted - Minimum value for lost games is 0!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.playerStatsValid(new PlayerStatistics(0, -1, 0, 0, 0, 0)));
+        assertTrue(testMe.getMessage().contains("Player statistics data corrupted - Minimum value for won games is 0!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.playerStatsValid(new PlayerStatistics(0, 0, -1, 0, 0, 0)));
+        assertTrue(testMe.getMessage().contains("Player statistics data corrupted - Minimum value for kills is 0!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.playerStatsValid(new PlayerStatistics(0, 0, 0, -1, 0, 0)));
+        assertTrue(testMe.getMessage().contains("Player statistics data corrupted - Minimum value for deaths is 0!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.playerStatsValid(new PlayerStatistics(0, 0, 0, 0, -1, 0)));
+        assertTrue(testMe.getMessage().contains("Player statistics data corrupted - Minimum value for destroyed blocks is 0!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.playerStatsValid(new PlayerStatistics(0, 0, 0, 0, 0, -1)));
+        assertTrue(testMe.getMessage().contains("Player statistics data corrupted - Minimum value for ingame time is 0 seconds!"));
+    }
+
+    @ParameterizedTest
+    @ValueSource(ints = {0, 100, 50})
+    void volumeValid(int test){
+        assertDoesNotThrow(() -> Parser.volumeValid(test));
+    }
+
+    @Test
+    void volumeInvalid(){
+        ParserException testMe = assertThrows(ParserException.class, () -> Parser.volumeValid(-1));
+        assertTrue(testMe.getMessage().contains("Volume must be between 0 and 100!"));
+
+        testMe = assertThrows(ParserException.class, () -> Parser.volumeValid(101));
+        assertTrue(testMe.getMessage().contains("Volume must be between 0 and 100!"));
+    }
+
+}
\ No newline at end of file