Browse Source

Merge pull request #61 from RedstoneFuture/Improvements/Commands

Improvements/commands (B)
Daniel 2 years ago
parent
commit
e30211d0e0

+ 25 - 8
missilewars-plugin/src/main/java/de/butzlabben/missilewars/MissileWars.java

@@ -20,6 +20,7 @@ package de.butzlabben.missilewars;
 
 
 import co.aikar.commands.PaperCommandManager;
 import co.aikar.commands.PaperCommandManager;
 import de.butzlabben.missilewars.commands.MWCommands;
 import de.butzlabben.missilewars.commands.MWCommands;
+import de.butzlabben.missilewars.commands.SetupCommands;
 import de.butzlabben.missilewars.commands.StatsCommands;
 import de.butzlabben.missilewars.commands.StatsCommands;
 import de.butzlabben.missilewars.commands.UserCommands;
 import de.butzlabben.missilewars.commands.UserCommands;
 import de.butzlabben.missilewars.configuration.Config;
 import de.butzlabben.missilewars.configuration.Config;
@@ -57,9 +58,13 @@ public class MissileWars extends JavaPlugin {
     private static MissileWars instance;
     private static MissileWars instance;
     public final String version = getDescription().getVersion();
     public final String version = getDescription().getVersion();
     private SignRepository signRepository;
     private SignRepository signRepository;
+    public PaperCommandManager commandManager;
 
 
     private boolean foundFAWE;
     private boolean foundFAWE;
 
 
+    private PlayerListener playerListener;
+    private SignListener signListener;
+
     public MissileWars() {
     public MissileWars() {
         instance = this;
         instance = this;
     }
     }
@@ -99,7 +104,7 @@ public class MissileWars extends JavaPlugin {
         Arenas.load();
         Arenas.load();
         SetupUtil.checkShields();
         SetupUtil.checkShields();
 
 
-        GameManager.getInstance().loadGames();
+        GameManager.getInstance().loadGamesOnStartup();
 
 
         new Metrics(this, 3749);
         new Metrics(this, 3749);
 
 
@@ -143,8 +148,11 @@ public class MissileWars extends JavaPlugin {
      * This method registers all events of the missilewars event listener.
      * This method registers all events of the missilewars event listener.
      */
      */
     private void registerEvents() {
     private void registerEvents() {
-        Bukkit.getPluginManager().registerEvents(new PlayerListener(), this);
-        Bukkit.getPluginManager().registerEvents(new SignListener(), this);
+        playerListener = new PlayerListener();
+        signListener = new SignListener();
+
+        Bukkit.getPluginManager().registerEvents(playerListener, this);
+        Bukkit.getPluginManager().registerEvents(signListener, this);
     }
     }
 
 
     /**
     /**
@@ -156,11 +164,12 @@ public class MissileWars extends JavaPlugin {
         // Using the Paper Command Manager does not mean the plugin requires Paper.
         // Using the Paper Command Manager does not mean the plugin requires Paper.
         // It simply lets it take advantage of Paper specific features if available,
         // It simply lets it take advantage of Paper specific features if available,
         // such as Asynchronous Tab Completions.
         // such as Asynchronous Tab Completions.
-        PaperCommandManager manager = new PaperCommandManager(this);
+        commandManager = new PaperCommandManager(this);
 
 
-        manager.registerCommand(new MWCommands());
-        manager.registerCommand(new StatsCommands());
-        manager.registerCommand(new UserCommands());
+        commandManager.registerCommand(new MWCommands());
+        commandManager.registerCommand(new StatsCommands());
+        commandManager.registerCommand(new UserCommands());
+        commandManager.registerCommand(new SetupCommands());
     }
     }
 
 
     /**
     /**
@@ -178,7 +187,7 @@ public class MissileWars extends JavaPlugin {
     private void deleteTempWorlds() {
     private void deleteTempWorlds() {
         File[] dirs = Bukkit.getWorldContainer().listFiles();
         File[] dirs = Bukkit.getWorldContainer().listFiles();
         if (dirs == null) return;
         if (dirs == null) return;
-        
+
         for (File dir : dirs) {
         for (File dir : dirs) {
             if (dir.getName().startsWith("mw-")) {
             if (dir.getName().startsWith("mw-")) {
                 try {
                 try {
@@ -220,4 +229,12 @@ public class MissileWars extends JavaPlugin {
             Logger.BOOT.log("Other authors: " + sb);
             Logger.BOOT.log("Other authors: " + sb);
         }
         }
     }
     }
+
+    public PlayerListener getPlayerListener() {
+        return playerListener;
+    }
+
+    public SignListener getSignListener() {
+        return signListener;
+    }
 }
 }

+ 154 - 107
missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/MWCommands.java

@@ -23,24 +23,21 @@ import co.aikar.commands.annotation.*;
 import de.butzlabben.missilewars.Logger;
 import de.butzlabben.missilewars.Logger;
 import de.butzlabben.missilewars.MissileWars;
 import de.butzlabben.missilewars.MissileWars;
 import de.butzlabben.missilewars.configuration.Config;
 import de.butzlabben.missilewars.configuration.Config;
-import de.butzlabben.missilewars.configuration.Lobby;
 import de.butzlabben.missilewars.configuration.Messages;
 import de.butzlabben.missilewars.configuration.Messages;
 import de.butzlabben.missilewars.configuration.arena.Arena;
 import de.butzlabben.missilewars.configuration.arena.Arena;
 import de.butzlabben.missilewars.game.Arenas;
 import de.butzlabben.missilewars.game.Arenas;
 import de.butzlabben.missilewars.game.Game;
 import de.butzlabben.missilewars.game.Game;
 import de.butzlabben.missilewars.game.GameManager;
 import de.butzlabben.missilewars.game.GameManager;
+import de.butzlabben.missilewars.game.enums.GameResult;
 import de.butzlabben.missilewars.game.enums.GameState;
 import de.butzlabben.missilewars.game.enums.GameState;
 import de.butzlabben.missilewars.game.enums.MapChooseProcedure;
 import de.butzlabben.missilewars.game.enums.MapChooseProcedure;
 import de.butzlabben.missilewars.game.missile.Missile;
 import de.butzlabben.missilewars.game.missile.Missile;
 import de.butzlabben.missilewars.game.missile.MissileFacing;
 import de.butzlabben.missilewars.game.missile.MissileFacing;
-import org.bukkit.Bukkit;
 import org.bukkit.command.CommandSender;
 import org.bukkit.command.CommandSender;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
 
 
-import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Optional;
-import java.util.stream.Collectors;
 
 
 @CommandAlias("mw|missilewars")
 @CommandAlias("mw|missilewars")
 public class MWCommands extends BaseCommand {
 public class MWCommands extends BaseCommand {
@@ -51,34 +48,48 @@ public class MWCommands extends BaseCommand {
 
 
         sender.sendMessage(Messages.getPrefix() + "MissileWars v" + MissileWars.getInstance().version + " by Butzlabben");
         sender.sendMessage(Messages.getPrefix() + "MissileWars v" + MissileWars.getInstance().version + " by Butzlabben");
 
 
-        if (sender.hasPermission("mw.quit"))
-            sender.sendMessage(Messages.getPrefix() + "/mw quit -  Quit a game");
-        if (sender.hasPermission("mw.start"))
-            sender.sendMessage(Messages.getPrefix() + "/mw start - Starts the game");
-        if (sender.hasPermission("mw.stop"))
-            sender.sendMessage(Messages.getPrefix() + "/mw stop - Stops the game");
-        if (sender.hasPermission("mw.restart"))
-            sender.sendMessage(Messages.getPrefix() + "/mw start - Restarts the game");
-        if (sender.hasPermission("mw.appendrestart"))
-            sender.sendMessage(Messages.getPrefix()
-                    + "/mw appendrestart - Appends a restart after the next game ends");
-        if (sender.hasPermission("mw.paste"))
-            sender.sendMessage(Messages.getPrefix() + "/mw paste - Pastes a missile");
-        if (sender.hasPermission("mw.reload"))
-            sender.sendMessage(Messages.getPrefix() + "/mw reload - Reloads configurations");
-        if (sender.hasPermission("mw.stats"))
-            sender.sendMessage(Messages.getPrefix() + "/mw stats - Shows stats");
-        if (sender.hasPermission("mw.stats.recommendations"))
-            sender.sendMessage(Messages.getPrefix() + "/mw stats recommendations - Shows recommendations");
-        if (sender.hasPermission("mw.stats.players"))
-            sender.sendMessage(Messages.getPrefix() + "/mw stats players - Shows player list");
-        if (sender.hasPermission("mw.stats.list"))
-            sender.sendMessage(Messages.getPrefix() + "/mw stats list - Lists history of games");
+        sendHelpMessage(sender, "mw.vote", "/mw vote", "Vote for a arena.");
+        sendHelpMessage(sender, "mw.change", "/mw change <1|2>", "Changes your team.");
+        sendHelpMessage(sender, "mw.quit", "/mw quit", "Quit a game.");
+
+        sendHelpMessage(sender, "mw.stats", "/mw stats [from] [arena]", "Shows stats.");
+        sendHelpMessage(sender, "mw.stats.recommendations", "/mw stats recommendations [from] [arena]", "Shows recommendations.");
+        sendHelpMessage(sender, "mw.stats.players", "/mw stats players [from] [arena]", "Shows player list.");
+        sendHelpMessage(sender, "mw.stats.list", "/mw stats list [from] [arena]", "Lists history of games.");
+
+        sendHelpMessage(sender, "mw.listgames", "/mw listgames", "List the active games.");
+        sendHelpMessage(sender, "mw.paste", "/mw paste <missile>", "Pastes a missile.");
+        sendHelpMessage(sender, "mw.start", "/mw start [lobby]", "Starts the game.");
+        sendHelpMessage(sender, "mw.stop", "/mw stop [lobby]", "Stops the game.");
+        sendHelpMessage(sender, "mw.appendrestart", "/mw appendrestart [lobby]", "Appends a restart after the next game ends.");
+        sendHelpMessage(sender, "mw.reload", "/mw reload", "Reload the plugin.");
+        sendHelpMessage(sender, "mw.debug", "/mw debug", "Show debug info.");
+        sendHelpMessage(sender, "mw.restartall", "/mw restartall", "Restart all games.");
+
+        sendHelpMessage(sender, "mw.setup", "/mw setup <main|lobby|arena> <value> <set|teleport> [lobby]", "Setup the MW Locations or the lobby/arena locations.");
+    }
+    
+    @Subcommand("listgames|list|games")
+    @CommandCompletion("@nothing")
+    @CommandPermission("mw.listgames")
+    public void listgamesCommand(CommandSender sender, String[] args) {
+
+        sender.sendMessage(Messages.getPrefix() + "Current games:");
+
+        for (Game game : GameManager.getInstance().getGames().values()) {
+            sender.sendMessage("§e " + game.getLobby().getName() + "§7 -- Name: »" + game.getLobby().getDisplayName() + "§7« | Status: " + game.getState());
+            sender.sendMessage("§8 - §f" + "Load with startup: §7" + game.getLobby().isAutoLoad());
+            sender.sendMessage("§8 - §f" + "Current Arena: §7" + game.getArena().getName() + "§7 -- Name: »" + game.getArena().getDisplayName() + "§7«");
+            sender.sendMessage("§8 - §f" + "Total players: §7" + game.getPlayers().size() + "x");
+            sender.sendMessage("§8 - §f" + "Team 1: §7" + game.getTeam1().getColor() + game.getTeam1().getName()
+                    + " §7with " + game.getTeam1().getMembers().size() + " players");
+            sender.sendMessage("§8 - §f" + "Team 2: §7" + game.getTeam2().getColor() + game.getTeam2().getName()
+                    + " §7with " + game.getTeam2().getMembers().size() + " players");
+        }
+
     }
     }
 
 
     @Subcommand("paste")
     @Subcommand("paste")
-    @Description("Pastes a missile.")
-    @Syntax("/mw paste <missile>")
     @CommandCompletion("@nothing")
     @CommandCompletion("@nothing")
     @CommandPermission("mw.paste")
     @CommandPermission("mw.paste")
     public void pasteCommand(CommandSender sender, String[] args) {
     public void pasteCommand(CommandSender sender, String[] args) {
@@ -86,42 +97,66 @@ public class MWCommands extends BaseCommand {
         if (!senderIsPlayer(sender)) return;
         if (!senderIsPlayer(sender)) return;
         Player player = (Player) sender;
         Player player = (Player) sender;
 
 
+        if (args.length < 1) {
+            player.sendMessage(Messages.getPrefix() + "§cMissile needed.");
+            return;
+        }
+
+        if (args.length > 1) {
+            player.sendMessage(Messages.getPrefix() + "§cToo many arguments.");
+            return;
+        }
+
         Game game = GameManager.getInstance().getGame(player.getLocation());
         Game game = GameManager.getInstance().getGame(player.getLocation());
         if (game == null) {
         if (game == null) {
             player.sendMessage(Messages.getMessage("not_in_arena"));
             player.sendMessage(Messages.getMessage("not_in_arena"));
             return;
             return;
         }
         }
 
 
-        String arguments = getAllNextArgumentsAsString(args, false);
-        Missile m = game.getArena().getMissileConfiguration().getMissileFromName(arguments.trim());
-        if (m == null) {
-            player.sendMessage(Messages.getPrefix() + "§cUnknown missile");
+        Missile missile = game.getArena().getMissileConfiguration().getMissileFromName(args[0]);
+        if (missile == null) {
+            player.sendMessage(Messages.getPrefix() + "§cUnknown missile.");
             return;
             return;
         }
         }
-        MissileFacing mf = MissileFacing.getFacingPlayer(player, game.getArena().getMissileConfiguration());
-        m.paste(player, mf, game);
+
+        MissileFacing missileFacing = MissileFacing.getFacingPlayer(player, game.getArena().getMissileConfiguration());
+        missile.paste(player, missileFacing, game);
     }
     }
 
 
     @Subcommand("start")
     @Subcommand("start")
-    @Description("Starts the game.")
-    @Syntax("/mw start")
-    @CommandCompletion("@nothing")
+    @CommandCompletion("@games")
     @CommandPermission("mw.start")
     @CommandPermission("mw.start")
     public void startCommand(CommandSender sender, String[] args) {
     public void startCommand(CommandSender sender, String[] args) {
 
 
         if (!senderIsPlayer(sender)) return;
         if (!senderIsPlayer(sender)) return;
         Player player = (Player) sender;
         Player player = (Player) sender;
 
 
-        Game game = GameManager.getInstance().getGame(player.getLocation());
-        if (game == null) {
-            player.sendMessage(Messages.getMessage("not_in_arena"));
+        if (args.length > 1) {
+            player.sendMessage(Messages.getPrefix() + "§cToo many arguments.");
             return;
             return;
         }
         }
 
 
+        // Check optional game argument:
+        Game game;
+        if (args.length == 1) {
+            game = GameManager.getInstance().getGame(args[0]);
+            if (game == null) {
+                player.sendMessage(Messages.getPrefix() + "§cGame not found.");
+                return;
+            }
+        } else {
+            game = GameManager.getInstance().getGame(player.getLocation());
+            if (game == null) {
+                player.sendMessage(Messages.getMessage("not_in_arena"));
+                return;
+            }
+        }
+
         if (game.getState() != GameState.LOBBY) {
         if (game.getState() != GameState.LOBBY) {
             player.sendMessage(Messages.getPrefix() + "§cGame already started");
             player.sendMessage(Messages.getPrefix() + "§cGame already started");
             return;
             return;
         }
         }
+
         if (game.isReady())
         if (game.isReady())
             game.startGame();
             game.startGame();
         else {
         else {
@@ -146,67 +181,84 @@ public class MWCommands extends BaseCommand {
     }
     }
 
 
     @Subcommand("stop")
     @Subcommand("stop")
-    @Description("Stops the game.")
-    @Syntax("/mw stop")
-    @CommandCompletion("@nothing")
+    @CommandCompletion("@games")
     @CommandPermission("mw.stop")
     @CommandPermission("mw.stop")
     public void stopCommand(CommandSender sender, String[] args) {
     public void stopCommand(CommandSender sender, String[] args) {
 
 
         if (!senderIsPlayer(sender)) return;
         if (!senderIsPlayer(sender)) return;
         Player player = (Player) sender;
         Player player = (Player) sender;
 
 
-        Game game = GameManager.getInstance().getGame(player.getLocation());
-        if (game == null) {
-            player.sendMessage(Messages.getMessage("not_in_arena"));
+        if (args.length > 1) {
+            player.sendMessage(Messages.getPrefix() + "§cToo many arguments.");
             return;
             return;
         }
         }
 
 
-        // TODO more arguments to get "game.sendGameResult();"
-        Bukkit.getScheduler().runTask(MissileWars.getInstance(), () -> {
-            if (game.getState() == GameState.INGAME) game.stopGame();
-        });
+        // Check optional game argument:
+        Game game;
+        if (args.length == 1) {
+            game = GameManager.getInstance().getGame(args[0]);
+            if (game == null) {
+                player.sendMessage(Messages.getPrefix() + "§cGame not found.");
+                return;
+            }
+        } else {
+            game = GameManager.getInstance().getGame(player.getLocation());
+            if (game == null) {
+                player.sendMessage(Messages.getMessage("not_in_arena"));
+                return;
+            }
+        }
+
+        game.getTeam1().setGameResult(GameResult.DRAW);
+        game.getTeam2().setGameResult(GameResult.DRAW);
+        if (game.getState() == GameState.INGAME) game.stopGame();
     }
     }
 
 
-    @Subcommand("restart")
-    @Description("Restarts the game.")
-    @Syntax("/mw restart")
-    @CommandCompletion("@nothing")
-    @CommandPermission("mw.restart")
-    public void restartCommand(CommandSender sender, String[] args) {
+    @Subcommand("appendrestart")
+    @CommandCompletion("@games")
+    @CommandPermission("mw.appendrestart")
+    public void appendrestartCommand(CommandSender sender, String[] args) {
 
 
         if (!senderIsPlayer(sender)) return;
         if (!senderIsPlayer(sender)) return;
         Player player = (Player) sender;
         Player player = (Player) sender;
 
 
-        Game game = GameManager.getInstance().getGame(player.getLocation());
-
-        if (game == null) {
-            player.sendMessage(Messages.getMessage("not_in_arena"));
+        if (args.length > 1) {
+            player.sendMessage(Messages.getPrefix() + "§cToo many arguments.");
             return;
             return;
         }
         }
 
 
-        Bukkit.getScheduler().runTask(MissileWars.getInstance(), () -> {
-            if (game.getState() == GameState.INGAME) game.stopGame();
-            game.reset();
-        });
-    }
-
-    @Subcommand("appendrestart")
-    @Description("Appends a restart after the next game ends.")
-    @Syntax("/mw appendrestart")
-    @CommandCompletion("@nothing")
-    @CommandPermission("mw.appendrestart")
-    public void appendRestartCommand(CommandSender sender, String[] args) {
+        // Check optional game argument:
+        Game game;
+        if (args.length == 1) {
+            game = GameManager.getInstance().getGame(args[0]);
+            if (game == null) {
+                player.sendMessage(Messages.getPrefix() + "§cGame not found.");
+                return;
+            }
+        } else {
+            game = GameManager.getInstance().getGame(player.getLocation());
+            if (game == null) {
+                player.sendMessage(Messages.getMessage("not_in_arena"));
+                return;
+            }
+        }
 
 
         GameManager.getInstance().getGames().values().forEach(Game::appendRestart);
         GameManager.getInstance().getGames().values().forEach(Game::appendRestart);
         sender.sendMessage(Messages.getMessage("restart_after_game"));
         sender.sendMessage(Messages.getMessage("restart_after_game"));
     }
     }
 
 
     @Subcommand("reload")
     @Subcommand("reload")
-    @Description("Reload the plugin.")
-    @Syntax("/mw reload")
     @CommandCompletion("@nothing")
     @CommandCompletion("@nothing")
     @CommandPermission("mw.reload")
     @CommandPermission("mw.reload")
-    public void onReload(CommandSender sender, String[] args) {
+    public void reloadCommand(CommandSender sender, String[] args) {
+
+        if (!senderIsPlayer(sender)) return;
+        Player player = (Player) sender;
+
+        if (args.length > 0) {
+            player.sendMessage(Messages.getPrefix() + "§cToo many arguments.");
+            return;
+        }
 
 
         Config.load();
         Config.load();
         Messages.load();
         Messages.load();
@@ -215,11 +267,17 @@ public class MWCommands extends BaseCommand {
     }
     }
 
 
     @Subcommand("debug")
     @Subcommand("debug")
-    @Description("Show debug info.")
-    @Syntax("/mw debug")
     @CommandCompletion("@nothing")
     @CommandCompletion("@nothing")
     @CommandPermission("mw.debug")
     @CommandPermission("mw.debug")
-    public void onDebug(CommandSender sender, String[] args) {
+    public void debugCommand(CommandSender sender, String[] args) {
+
+        if (!senderIsPlayer(sender)) return;
+        Player player = (Player) sender;
+
+        if (args.length > 0) {
+            player.sendMessage(Messages.getPrefix() + "§cToo many arguments.");
+            return;
+        }
 
 
         int i = 0;
         int i = 0;
         Logger.NORMAL.log("Starting to print debug information for MissileWars v" + MissileWars.getInstance().version);
         Logger.NORMAL.log("Starting to print debug information for MissileWars v" + MissileWars.getInstance().version);
@@ -231,45 +289,34 @@ public class MWCommands extends BaseCommand {
     }
     }
 
 
     @Subcommand("restartall")
     @Subcommand("restartall")
-    @Description("Restart all games.")
-    @Syntax("/mw restartall")
     @CommandCompletion("@nothing")
     @CommandCompletion("@nothing")
-    @CommandPermission("mw.reload")
-    public void onRestartAll(CommandSender sender, String[] args) {
+    @CommandPermission("mw.restartall")
+    public void restartallCommand(CommandSender sender, String[] args) {
+
+        if (!senderIsPlayer(sender)) return;
+        Player player = (Player) sender;
+
+        if (args.length > 0) {
+            player.sendMessage(Messages.getPrefix() + "§cToo many arguments.");
+            return;
+        }
 
 
         sender.sendMessage(Messages.getPrefix() + "§cWarning - Restarting all games. This may take a while");
         sender.sendMessage(Messages.getPrefix() + "§cWarning - Restarting all games. This may take a while");
-        List<Lobby> arenaPropertiesList = GameManager.getInstance().getGames().values()
-                .stream().map(Game::getLobby).collect(Collectors.toList());
-        arenaPropertiesList.forEach(GameManager.getInstance()::restartGame);
-        sender.sendMessage(Messages.getPrefix() + "Reloaded configs");
+        GameManager.getInstance().restartAll();
+        sender.sendMessage(Messages.getPrefix() + "Restarted all games.");
     }
     }
 
 
-    private boolean senderIsPlayer(CommandSender sender) {
+    static boolean senderIsPlayer(CommandSender sender) {
         if (sender instanceof Player) return true;
         if (sender instanceof Player) return true;
 
 
         sender.sendMessage(Messages.getPrefix() + "§cYou are not a player");
         sender.sendMessage(Messages.getPrefix() + "§cYou are not a player");
         return false;
         return false;
     }
     }
 
 
-    /**
-     * This method returns all next command arguments as one String line.
-     * Separated with a " " between the arguments. It also removes all
-     * unnecessary "&" signs.
-     *
-     * @param args Argument Array
-     * @return (String) all next arguments
-     */
-    private String getAllNextArgumentsAsString(String[] args, boolean filterColorCode) {
-        StringBuilder sb = new StringBuilder();
-        String arguments;
-
-        for (int i = 0; i < args.length; i++) {
-            sb.append(" ");
+    static void sendHelpMessage(CommandSender sender, String permission, String command, String description) {
+        if (sender instanceof Player) {
+            if (!sender.hasPermission(permission)) return;
         }
         }
-        arguments = sb.toString();
-
-        if (filterColorCode) arguments.replaceAll("&.", "");
-
-        return arguments;
+        sender.sendMessage(Messages.getPrefix() + command + " - " + description);
     }
     }
 }
 }

+ 249 - 0
missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/SetupCommands.java

@@ -0,0 +1,249 @@
+/*
+ * This file is part of MissileWars (https://github.com/Butzlabben/missilewars).
+ * Copyright (c) 2018-2021 Daniel Nägele.
+ *
+ * MissileWars is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * MissileWars is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MissileWars.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package de.butzlabben.missilewars.commands;
+
+import co.aikar.commands.BaseCommand;
+import co.aikar.commands.annotation.*;
+import de.butzlabben.missilewars.configuration.Config;
+import de.butzlabben.missilewars.configuration.Messages;
+import de.butzlabben.missilewars.game.Game;
+import de.butzlabben.missilewars.game.GameManager;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+@CommandAlias("mw|missilewars")
+@Subcommand("setup")
+public class SetupCommands extends BaseCommand {
+
+    private Game game;
+    private Player player;
+
+    @Default
+    @CommandPermission("mw.setup")
+    public void setupCommands(CommandSender sender, String[] args) {
+        sender.sendMessage(Messages.getPrefix() + "§fSetup usage: §7/mw setup <main|lobby|arena> <value> <set|teleport> [lobby]");
+    }
+
+    @Subcommand("main")
+    public class mainSetupCommands extends BaseCommand {
+
+        @Subcommand("fallbackspawn")
+        public class fallbackspawnSetup extends BaseCommand {
+
+            @Subcommand("set")
+            @CommandCompletion("@nothing")
+            public void set(CommandSender sender, String[] args) {
+                if (!senderIsPlayer(sender)) return;
+
+                Config.setFallbackSpawn(player.getLocation());
+                player.sendMessage(Messages.getPrefix() + "§fSet new 'fallbackSpawn' to " + player.getLocation() + ".");
+            }
+
+            @Subcommand("teleport|tp")
+            @CommandCompletion("@nothing")
+            public void teleport(CommandSender sender, String[] args) {
+                if (!senderIsPlayer(sender)) return;
+
+                player.teleport(Config.getFallbackSpawn());
+                player.sendMessage(Messages.getPrefix() + "§fTeleported to 'fallbackSpawn'.");
+            }
+
+        }
+    }
+
+    @Subcommand("lobby")
+    public class lobbySetupCommands extends BaseCommand {
+
+        @Subcommand("spawnpoint")
+        public class spawnpointSetup extends BaseCommand {
+
+            @Subcommand("set")
+            @CommandCompletion("@games")
+            public void set(CommandSender sender, String[] args) {
+                if (!senderIsPlayer(sender)) return;
+                if (!isValidGame(args)) return;
+
+                game.getLobby().setSpawnPoint(player.getLocation());
+                game.getLobby().updateConfig();
+                player.sendMessage(Messages.getPrefix() + "§fSet new 'spawnPoint' to " + player.getLocation() + ".");
+            }
+
+            @Subcommand("teleport|tp")
+            @CommandCompletion("@games")
+            public void teleport(CommandSender sender, String[] args) {
+                if (!senderIsPlayer(sender)) return;
+                if (!isValidGame(args)) return;
+
+                player.teleport(game.getLobby().getSpawnPoint());
+                player.sendMessage(Messages.getPrefix() + "§fTeleported to 'spawnPoint'.");
+            }
+
+        }
+
+        @Subcommand("aftergamespawn")
+        public class aftergamespawnSetup extends BaseCommand {
+
+            @Subcommand("set")
+            @CommandCompletion("@games")
+            public void set(CommandSender sender, String[] args) {
+                if (!senderIsPlayer(sender)) return;
+                if (!isValidGame(args)) return;
+
+                game.getLobby().setAfterGameSpawn(player.getLocation());
+                game.getLobby().updateConfig();
+                player.sendMessage(Messages.getPrefix() + "§fSet new 'afterGameSpawn' to " + player.getLocation() + ".");
+            }
+
+            @Subcommand("teleport|tp")
+            @CommandCompletion("@games")
+            public void teleport(CommandSender sender, String[] args) {
+                if (!senderIsPlayer(sender)) return;
+                if (!isValidGame(args)) return;
+
+                player.teleport(game.getLobby().getAfterGameSpawn());
+                player.sendMessage(Messages.getPrefix() + "§fTeleported to 'afterGameSpawn'.");
+            }
+
+        }
+    }
+
+    @Subcommand("arena")
+    public class arenaSetupCommands extends BaseCommand {
+
+        @Subcommand("spectatorspawn")
+        public class spectatorspawnSetup extends BaseCommand {
+
+            @Subcommand("set")
+            @CommandCompletion("@games")
+            public void set(CommandSender sender, String[] args) {
+                if (!senderIsPlayer(sender)) return;
+                if (!isValidGame(args)) return;
+
+                game.getArena().setSpectatorSpawn(player.getLocation());
+                game.getArena().updateConfig();
+                player.sendMessage(Messages.getPrefix() + "§fSet new 'spectatorSpawn' to " + player.getLocation() + ".");
+            }
+
+            @Subcommand("teleport|tp")
+            @CommandCompletion("@games")
+            public void teleport(CommandSender sender, String[] args) {
+                if (!senderIsPlayer(sender)) return;
+                if (!isValidGame(args)) return;
+
+                player.teleport(game.getArena().getSpectatorSpawn());
+                player.sendMessage(Messages.getPrefix() + "§fTeleported to 'spectatorSpawn'.");
+            }
+
+        }
+
+        @Subcommand("team1spawn")
+        public class team1spawnSetup extends BaseCommand {
+
+            @Subcommand("set")
+            @CommandCompletion("@games")
+            public void set(CommandSender sender, String[] args) {
+                if (!senderIsPlayer(sender)) return;
+                if (!isValidGame(args)) return;
+
+                game.getArena().setTeam1Spawn(player.getLocation());
+                game.getArena().updateConfig();
+                player.sendMessage(Messages.getPrefix() + "§fSet new 'team1Spawn' to " + player.getLocation() + ".");
+            }
+
+            @Subcommand("teleport|tp")
+            @CommandCompletion("@games")
+            public void teleport(CommandSender sender, String[] args) {
+                if (!senderIsPlayer(sender)) return;
+                if (!isValidGame(args)) return;
+
+                player.teleport(game.getArena().getTeam1Spawn());
+                player.sendMessage(Messages.getPrefix() + "§fTeleported to 'team1Spawn'.");
+            }
+
+        }
+
+        @Subcommand("team2spawn")
+        public class team2spawnSetup extends BaseCommand {
+
+            @Subcommand("set")
+            @CommandCompletion("@games")
+            public void set(CommandSender sender, String[] args) {
+                if (!senderIsPlayer(sender)) return;
+                if (!isValidGame(args)) return;
+
+                game.getArena().setTeam2Spawn(player.getLocation());
+                game.getArena().updateConfig();
+                player.sendMessage(Messages.getPrefix() + "§fSet new 'team2Spawn' to " + player.getLocation() + ".");
+            }
+
+            @Subcommand("teleport|tp")
+            @CommandCompletion("@games")
+            public void teleport(CommandSender sender, String[] args) {
+                if (!senderIsPlayer(sender)) return;
+                if (!isValidGame(args)) return;
+
+                player.teleport(game.getArena().getTeam2Spawn());
+                player.sendMessage(Messages.getPrefix() + "§fTeleported to 'team2Spawn'.");
+            }
+
+        }
+    }
+
+    /**
+     * This method checks if the command sender is a valid ingame player.
+     * 
+     * @param sender = the command sender
+     * @return true, if it's an ingame player
+     */
+    private boolean senderIsPlayer(CommandSender sender) {
+        if (sender instanceof Player) {
+            player = (Player) sender;
+            return true;
+        }
+
+        sender.sendMessage(Messages.getPrefix() + "§cYou are not a player");
+        return false;
+    }
+
+    /**
+     * This method checks if the player execute the command on a valid
+     * game world (lobby or area).
+     *
+     * @return true, if it's a MissileWars game world
+     */
+    private boolean isValidGame(String[] args) {
+
+        // Check optional game argument:
+        if (args.length == 1) {
+            game = GameManager.getInstance().getGame(args[0]);
+            if (game == null) {
+                player.sendMessage(Messages.getPrefix() + "§cGame not found.");
+                return false;
+            }
+        } else {
+            game = GameManager.getInstance().getGame(player.getLocation());
+            if (game == null) {
+                player.sendMessage(Messages.getMessage("not_in_arena"));
+                return false;
+            }
+        }
+
+        return true;
+    }
+}

+ 7 - 19
missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/StatsCommands.java

@@ -53,12 +53,10 @@ public class StatsCommands extends BaseCommand {
     private final SimpleDateFormat preciseFormat = new SimpleDateFormat("hh:mm dd.MM.yyyy");
     private final SimpleDateFormat preciseFormat = new SimpleDateFormat("hh:mm dd.MM.yyyy");
 
 
     @Default
     @Default
-    @Description("Shows stats.")
-    @Syntax("/mw stats [from] [arena]")
     @CommandPermission("mw.stats")
     @CommandPermission("mw.stats")
     public void onStats(CommandSender sender, String[] args) {
     public void onStats(CommandSender sender, String[] args) {
 
 
-        if (!senderIsPlayer(sender)) return;
+        if (!MWCommands.senderIsPlayer(sender)) return;
         Player player = (Player) sender;
         Player player = (Player) sender;
 
 
         StatsFetcher fetcher = getFetcher(player, args);
         StatsFetcher fetcher = getFetcher(player, args);
@@ -106,12 +104,11 @@ public class StatsCommands extends BaseCommand {
     }
     }
 
 
     @Subcommand("recommendations")
     @Subcommand("recommendations")
-    @Description("Shows recommendations.")
-    @Syntax("/mw stats recommendations [from] [arena]")
+    @CommandCompletion("@nothing")
     @CommandPermission("mw.stats.recommendations")
     @CommandPermission("mw.stats.recommendations")
     public void onRecommendations(CommandSender sender, String[] args) {
     public void onRecommendations(CommandSender sender, String[] args) {
 
 
-        if (!senderIsPlayer(sender)) return;
+        if (!MWCommands.senderIsPlayer(sender)) return;
         Player player = (Player) sender;
         Player player = (Player) sender;
 
 
         StatsFetcher fetcher = getFetcher(player, args);
         StatsFetcher fetcher = getFetcher(player, args);
@@ -146,12 +143,11 @@ public class StatsCommands extends BaseCommand {
     }
     }
 
 
     @Subcommand("players")
     @Subcommand("players")
-    @Description("Shows player list.")
-    @Syntax("/mw stats players [from] [arena]")
+    @CommandCompletion("@nothing")
     @CommandPermission("mw.stats.players")
     @CommandPermission("mw.stats.players")
     public void onPlayers(CommandSender sender, String[] args) {
     public void onPlayers(CommandSender sender, String[] args) {
 
 
-        if (!senderIsPlayer(sender)) return;
+        if (!MWCommands.senderIsPlayer(sender)) return;
         Player player = (Player) sender;
         Player player = (Player) sender;
 
 
         StatsFetcher fetcher = getFetcher(player, args);
         StatsFetcher fetcher = getFetcher(player, args);
@@ -164,12 +160,11 @@ public class StatsCommands extends BaseCommand {
     }
     }
 
 
     @Subcommand("list")
     @Subcommand("list")
-    @Description("Lists history of games.")
-    @Syntax("/mw stats list [from] [arena]")
+    @CommandCompletion("@nothing")
     @CommandPermission("mw.stats.list")
     @CommandPermission("mw.stats.list")
     public void onList(CommandSender sender, String[] args) {
     public void onList(CommandSender sender, String[] args) {
 
 
-        if (!senderIsPlayer(sender)) return;
+        if (!MWCommands.senderIsPlayer(sender)) return;
         Player player = (Player) sender;
         Player player = (Player) sender;
 
 
         StatsFetcher fetcher = getFetcher(player, args);
         StatsFetcher fetcher = getFetcher(player, args);
@@ -213,11 +208,4 @@ public class StatsCommands extends BaseCommand {
         player.sendMessage(Messages.getPrefix() + "Loading data...");
         player.sendMessage(Messages.getPrefix() + "Loading data...");
         return fetcher;
         return fetcher;
     }
     }
-
-    private boolean senderIsPlayer(CommandSender sender) {
-        if (sender instanceof Player) return true;
-
-        sender.sendMessage(Messages.getPrefix() + "§cYou are not a player");
-        return false;
-    }
 }
 }

+ 64 - 78
missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/UserCommands.java

@@ -19,8 +19,11 @@
 package de.butzlabben.missilewars.commands;
 package de.butzlabben.missilewars.commands;
 
 
 import co.aikar.commands.BaseCommand;
 import co.aikar.commands.BaseCommand;
-import co.aikar.commands.annotation.*;
-import de.butzlabben.missilewars.configuration.Config;
+import co.aikar.commands.annotation.CommandAlias;
+import co.aikar.commands.annotation.CommandCompletion;
+import co.aikar.commands.annotation.CommandPermission;
+import co.aikar.commands.annotation.Subcommand;
+import de.butzlabben.missilewars.MissileWars;
 import de.butzlabben.missilewars.configuration.Messages;
 import de.butzlabben.missilewars.configuration.Messages;
 import de.butzlabben.missilewars.configuration.arena.Arena;
 import de.butzlabben.missilewars.configuration.arena.Arena;
 import de.butzlabben.missilewars.game.Arenas;
 import de.butzlabben.missilewars.game.Arenas;
@@ -30,7 +33,6 @@ import de.butzlabben.missilewars.game.Team;
 import de.butzlabben.missilewars.game.enums.GameState;
 import de.butzlabben.missilewars.game.enums.GameState;
 import de.butzlabben.missilewars.game.enums.MapChooseProcedure;
 import de.butzlabben.missilewars.game.enums.MapChooseProcedure;
 import de.butzlabben.missilewars.player.MWPlayer;
 import de.butzlabben.missilewars.player.MWPlayer;
-import org.bukkit.Location;
 import org.bukkit.command.CommandSender;
 import org.bukkit.command.CommandSender;
 import org.bukkit.entity.Player;
 import org.bukkit.entity.Player;
 
 
@@ -39,62 +41,19 @@ import java.util.Optional;
 @CommandAlias("mw|missilewars")
 @CommandAlias("mw|missilewars")
 public class UserCommands extends BaseCommand {
 public class UserCommands extends BaseCommand {
 
 
-    @Subcommand("change")
-    @Description("Changes your team.")
-    @Syntax("/mw change <1|2>")
-    @CommandCompletion("@range:1-2")
-    @CommandPermission("mw.change")
-    public void changeCommand(CommandSender sender, String[] args) {
-
-        if (!senderIsPlayer(sender)) return;
-        Player player = (Player) sender;
-
-        Game game = GameManager.getInstance().getGame(player.getLocation());
-        if (game == null) {
-            player.sendMessage(Messages.getMessage("not_in_arena"));
-            return;
-        }
-
-        if (game.getState() != GameState.LOBBY) {
-            player.sendMessage(Messages.getPrefix() + "§cThe game is not in the right state to change your team right now");
-            return;
-        }
-
-        if (args.length != 1) {
-            player.sendMessage(Messages.getPrefix() + "§c/mw change <1|2>");
-            return;
-        }
-        try {
-            MWPlayer mwPlayer = game.getPlayer(player);
-            int teamNumber = Integer.parseInt(args[0]);
-            Team to = teamNumber == 1 ? game.getTeam1() : game.getTeam2();
-            int otherCount = to.getEnemyTeam().getMembers().size() - 1;
-            int toCount = to.getMembers().size() + 1;
-            int diff = toCount - otherCount;
-            if (diff > 1) {
-                player.sendMessage(Messages.getMessage("cannot_change_difference"));
-                return;
-            }
-
-            // Remove the player from the old team and add him to the new team
-            to.addMember(mwPlayer);
-
-            player.sendMessage(Messages.getMessage("team_changed").replace("%team%", to.getFullname()));
-        } catch (NumberFormatException exception) {
-            player.sendMessage(Messages.getPrefix() + "§c/mw change <1|2>");
-        }
-    }
-
     @Subcommand("vote")
     @Subcommand("vote")
-    @Description("Stops the game.")
-    @Syntax("/mw vote <arena>")
+    @CommandCompletion("@nothing")
     @CommandPermission("mw.vote")
     @CommandPermission("mw.vote")
     public void voteCommand(CommandSender sender, String[] args) {
     public void voteCommand(CommandSender sender, String[] args) {
 
 
-        // TODO more messageconfig
-        if (!senderIsPlayer(sender)) return;
+        if (!MWCommands.senderIsPlayer(sender)) return;
         Player player = (Player) sender;
         Player player = (Player) sender;
 
 
+        if (args.length > 0) {
+            player.sendMessage(Messages.getPrefix() + "§cToo many arguments.");
+            return;
+        }
+
         Game game = GameManager.getInstance().getGame(player.getLocation());
         Game game = GameManager.getInstance().getGame(player.getLocation());
         if (game == null) {
         if (game == null) {
             player.sendMessage(Messages.getMessage("not_in_arena"));
             player.sendMessage(Messages.getMessage("not_in_arena"));
@@ -116,11 +75,6 @@ public class UserCommands extends BaseCommand {
             return;
             return;
         }
         }
 
 
-        if (args.length != 1) {
-            player.sendMessage(Messages.getPrefix() + "§c/mw vote <arena>");
-            return;
-        }
-
         String arenaName = args[0];
         String arenaName = args[0];
         Optional<Arena> arena = Arenas.getFromName(arenaName);
         Optional<Arena> arena = Arenas.getFromName(arenaName);
         if (!game.getVotes().containsKey(arenaName) || arena.isEmpty()) {
         if (!game.getVotes().containsKey(arenaName) || arena.isEmpty()) {
@@ -132,39 +86,71 @@ public class UserCommands extends BaseCommand {
         player.sendMessage(Messages.getMessage("vote.success").replace("%map%", arena.get().getDisplayName()));
         player.sendMessage(Messages.getMessage("vote.success").replace("%map%", arena.get().getDisplayName()));
     }
     }
 
 
-    @Subcommand("quit|leave")
-    @Description("Quit a game.")
-    @Syntax("/mw quit")
-    @CommandCompletion("@nothing")
-    @CommandPermission("mw.quit")
-    public void onQuit(CommandSender sender, String[] args) {
+    @Subcommand("change")
+    @CommandCompletion("@range:1-2")
+    @CommandPermission("mw.change")
+    public void changeCommand(CommandSender sender, String[] args) {
 
 
-        // TODO message config
-        if (!senderIsPlayer(sender)) return;
+        if (!MWCommands.senderIsPlayer(sender)) return;
         Player player = (Player) sender;
         Player player = (Player) sender;
 
 
+        if (args.length > 0) {
+            player.sendMessage(Messages.getPrefix() + "§cToo many arguments.");
+            return;
+        }
+
         Game game = GameManager.getInstance().getGame(player.getLocation());
         Game game = GameManager.getInstance().getGame(player.getLocation());
         if (game == null) {
         if (game == null) {
             player.sendMessage(Messages.getMessage("not_in_arena"));
             player.sendMessage(Messages.getMessage("not_in_arena"));
             return;
             return;
         }
         }
-        MWPlayer mwPlayer = game.getPlayer(player);
-        if (mwPlayer == null) {
-            player.sendMessage(Messages.getPrefix() + "§cYou are not a member in this arena. Something went wrong pretty badly :(");
+
+        if (game.getState() != GameState.LOBBY) {
+            player.sendMessage(Messages.getPrefix() + "§cThe game is not in the right state to change your team right now");
             return;
             return;
         }
         }
-        Location endSpawn = game.getLobby().getAfterGameSpawn();
-        if (GameManager.getInstance().getGame(endSpawn) != null) {
-            endSpawn = Config.getFallbackSpawn();
+
+        try {
+            MWPlayer mwPlayer = game.getPlayer(player);
+            int teamNumber = Integer.parseInt(args[0]);
+            Team to = teamNumber == 1 ? game.getTeam1() : game.getTeam2();
+            int otherCount = to.getEnemyTeam().getMembers().size() - 1;
+            int toCount = to.getMembers().size() + 1;
+            int diff = toCount - otherCount;
+            if (diff > 1) {
+                player.sendMessage(Messages.getMessage("cannot_change_difference"));
+                return;
+            }
+
+            // Remove the player from the old team and add him to the new team
+            to.addMember(mwPlayer);
+
+            player.sendMessage(Messages.getMessage("team_changed").replace("%team%", to.getFullname()));
+        } catch (NumberFormatException exception) {
+            player.sendMessage(Messages.getPrefix() + "§c/mw change <1|2>");
         }
         }
-        player.teleport(endSpawn);
-        player.sendMessage(Messages.getMessage("game_quit"));
     }
     }
 
 
-    private boolean senderIsPlayer(CommandSender sender) {
-        if (sender instanceof Player) return true;
+    @Subcommand("quit|leave")
+    @CommandCompletion("@nothing")
+    @CommandPermission("mw.quit")
+    public void quitCommand(CommandSender sender, String[] args) {
+
+        if (!MWCommands.senderIsPlayer(sender)) return;
+        Player player = (Player) sender;
+
+        if (args.length > 0) {
+            player.sendMessage(Messages.getPrefix() + "§cToo many arguments.");
+            return;
+        }
+
+        Game game = GameManager.getInstance().getGame(player.getLocation());
+        if (game == null) {
+            player.sendMessage(Messages.getMessage("not_in_arena"));
+            return;
+        }
 
 
-        sender.sendMessage(Messages.getPrefix() + "§cYou are not a player");
-        return false;
+        MissileWars.getInstance().getPlayerListener().registerPlayerArenaLeaveEvent(player, game);
+        game.teleportToFallbackSpawn(player);
     }
     }
 }
 }

+ 21 - 2
missilewars-plugin/src/main/java/de/butzlabben/missilewars/configuration/Lobby.java

@@ -24,6 +24,7 @@ import de.butzlabben.missilewars.configuration.arena.Arena;
 import de.butzlabben.missilewars.game.Arenas;
 import de.butzlabben.missilewars.game.Arenas;
 import de.butzlabben.missilewars.game.enums.MapChooseProcedure;
 import de.butzlabben.missilewars.game.enums.MapChooseProcedure;
 import de.butzlabben.missilewars.util.geometry.Area;
 import de.butzlabben.missilewars.util.geometry.Area;
+import de.butzlabben.missilewars.util.serialization.Serializer;
 import lombok.Getter;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import lombok.RequiredArgsConstructor;
 import lombok.Setter;
 import lombok.Setter;
@@ -33,6 +34,7 @@ import org.bukkit.Location;
 import org.bukkit.World;
 import org.bukkit.World;
 
 
 import java.io.File;
 import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 import java.util.Optional;
 import java.util.Optional;
@@ -45,6 +47,7 @@ public class Lobby {
 
 
     private String name = "lobby0";
     private String name = "lobby0";
     @SerializedName("display_name") private String displayName = "&eDefault game";
     @SerializedName("display_name") private String displayName = "&eDefault game";
+    @SerializedName("auto_load") private boolean autoLoad = true;
     @SerializedName("world") private String world = Bukkit.getWorlds().get(0).getName();
     @SerializedName("world") private String world = Bukkit.getWorlds().get(0).getName();
     @SerializedName("lobby_time") private int lobbyTime = 60;
     @SerializedName("lobby_time") private int lobbyTime = 60;
     @SerializedName("join_ongoing_game") private boolean joinOngoingGame = false;
     @SerializedName("join_ongoing_game") private boolean joinOngoingGame = false;
@@ -54,8 +57,8 @@ public class Lobby {
     @SerializedName("team1_color") private String team1Color = "&c";
     @SerializedName("team1_color") private String team1Color = "&c";
     @SerializedName("team2_name") private String team2Name = "Team2";
     @SerializedName("team2_name") private String team2Name = "Team2";
     @SerializedName("team2_color") private String team2Color = "&a";
     @SerializedName("team2_color") private String team2Color = "&a";
-    @SerializedName("spawn_point") private Location spawnPoint = Bukkit.getWorlds().get(0).getSpawnLocation();
-    @SerializedName("after_game_spawn") private Location afterGameSpawn = Bukkit.getWorlds().get(0).getSpawnLocation();
+    @Setter @SerializedName("spawn_point") private Location spawnPoint = Bukkit.getWorlds().get(0).getSpawnLocation();
+    @Setter @SerializedName("after_game_spawn") private Location afterGameSpawn = Bukkit.getWorlds().get(0).getSpawnLocation();
     private Area area = Area.defaultAreaAround(Bukkit.getWorlds().get(0).getSpawnLocation());
     private Area area = Area.defaultAreaAround(Bukkit.getWorlds().get(0).getSpawnLocation());
     @SerializedName("map_choose_procedure") private MapChooseProcedure mapChooseProcedure = MapChooseProcedure.FIRST;
     @SerializedName("map_choose_procedure") private MapChooseProcedure mapChooseProcedure = MapChooseProcedure.FIRST;
     @SerializedName("possible_arenas") private List<String> possibleArenas = new ArrayList<>() {{
     @SerializedName("possible_arenas") private List<String> possibleArenas = new ArrayList<>() {{
@@ -90,4 +93,20 @@ public class Lobby {
                 .map(Optional::get)
                 .map(Optional::get)
                 .collect(Collectors.toList());
                 .collect(Collectors.toList());
     }
     }
+
+    public void updateConfig() {
+        try {
+            Serializer.serialize(file, this);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public Location getAreaMinLocation() {
+        return new Location(getBukkitWorld(), area.getMinX(), area.getMinY(), area.getMinZ());
+    }
+
+    public Location getAreaMaxLocation() {
+        return new Location(getBukkitWorld(), area.getMaxX(), area.getMaxY(), area.getMaxZ());
+    }
 }
 }

+ 14 - 0
missilewars-plugin/src/main/java/de/butzlabben/missilewars/configuration/arena/Arena.java

@@ -21,12 +21,16 @@ package de.butzlabben.missilewars.configuration.arena;
 import com.google.gson.annotations.SerializedName;
 import com.google.gson.annotations.SerializedName;
 import de.butzlabben.missilewars.util.geometry.FlatArea;
 import de.butzlabben.missilewars.util.geometry.FlatArea;
 import de.butzlabben.missilewars.util.geometry.Plane;
 import de.butzlabben.missilewars.util.geometry.Plane;
+import de.butzlabben.missilewars.util.serialization.Serializer;
 import lombok.Getter;
 import lombok.Getter;
 import lombok.Setter;
 import lombok.Setter;
 import lombok.ToString;
 import lombok.ToString;
 import org.bukkit.Location;
 import org.bukkit.Location;
 import org.bukkit.util.Vector;
 import org.bukkit.util.Vector;
 
 
+import java.io.File;
+import java.io.IOException;
+
 @Getter
 @Getter
 @ToString
 @ToString
 public class Arena implements Cloneable {
 public class Arena implements Cloneable {
@@ -65,6 +69,8 @@ public class Arena implements Cloneable {
     @SerializedName("team2_spawn")
     @SerializedName("team2_spawn")
     @Setter
     @Setter
     private Location team2Spawn = new Location(null, 0.5, 100, -45.5, 0, 0);
     private Location team2Spawn = new Location(null, 0.5, 100, -45.5, 0, 0);
+
+    @Setter private transient File file;
     
     
     public Arena() {
     public Arena() {
 
 
@@ -102,4 +108,12 @@ public class Arena implements Cloneable {
             throw new AssertionError();
             throw new AssertionError();
         }
         }
     }
     }
+
+    public void updateConfig() {
+        try {
+            Serializer.serialize(file, this);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
 }

+ 3 - 3
missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/Arenas.java

@@ -59,20 +59,20 @@ public class Arenas {
                 Bukkit.getPluginManager().disablePlugin(MissileWars.getInstance());
                 Bukkit.getPluginManager().disablePlugin(MissileWars.getInstance());
                 return;
                 return;
             }
             }
-            files = new File[] {defaultArena};
+            files = new File[]{defaultArena};
         }
         }
 
 
         for (File config : files) {
         for (File config : files) {
             if (!config.getName().endsWith(".yml") && !config.getName().endsWith(".yaml")) continue;
             if (!config.getName().endsWith(".yml") && !config.getName().endsWith(".yaml")) continue;
             try {
             try {
                 Arena arena = Serializer.deserialize(config, Arena.class);
                 Arena arena = Serializer.deserialize(config, Arena.class);
+                arena.setFile(config);
                 if (getFromName(arena.getName()).isPresent()) {
                 if (getFromName(arena.getName()).isPresent()) {
                     Logger.WARN.log("There are several arenas configured with the name \"" + arena.getName() + "\". Arenas must have a unique name");
                     Logger.WARN.log("There are several arenas configured with the name \"" + arena.getName() + "\". Arenas must have a unique name");
                     continue;
                     continue;
                 }
                 }
                 SetupUtil.checkMap(arena.getTemplateWorld());
                 SetupUtil.checkMap(arena.getTemplateWorld());
-                // Save for possible new values
-                Serializer.serialize(config, arena);
+                arena.updateConfig();
                 arenas.add(arena);
                 arenas.add(arena);
             } catch (IOException exception) {
             } catch (IOException exception) {
                 Logger.ERROR.log("Could not load config for arena " + config.getName());
                 Logger.ERROR.log("Could not load config for arena " + config.getName());

+ 4 - 13
missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/Game.java

@@ -276,15 +276,14 @@ public class Game {
     }
     }
 
 
     public void reset() {
     public void reset() {
-        if (Config.isSetup())
-            return;
+        if (Config.isSetup()) return;
 
 
         if (restart) {
         if (restart) {
             Bukkit.getServer().spigot().restart();
             Bukkit.getServer().spigot().restart();
             return;
             return;
         }
         }
 
 
-        GameManager.getInstance().restartGame(lobby);
+        GameManager.getInstance().restartGame(lobby, false);
     }
     }
 
 
     public void appendRestart() {
     public void appendRestart() {
@@ -292,11 +291,11 @@ public class Game {
     }
     }
 
 
     public void disableGameOnServerStop() {
     public void disableGameOnServerStop() {
-        
+
         for (MWPlayer mwPlayer : players.values()) {
         for (MWPlayer mwPlayer : players.values()) {
             teleportToFallbackSpawn(mwPlayer.getPlayer());
             teleportToFallbackSpawn(mwPlayer.getPlayer());
         }
         }
-        
+
         gameWorld.unload();
         gameWorld.unload();
     }
     }
 
 
@@ -416,11 +415,6 @@ public class Game {
     }
     }
 
 
     public void resetGame() {
     public void resetGame() {
-        if (state == GameState.INGAME) {
-            stopGame();
-            return;
-        }
-
         HandlerList.unregisterAll(listener);
         HandlerList.unregisterAll(listener);
 
 
         stopTimer();
         stopTimer();
@@ -436,9 +430,6 @@ public class Game {
         if (scoreboardManager != null) {
         if (scoreboardManager != null) {
             scoreboardManager.removeScoreboard();
             scoreboardManager.removeScoreboard();
         }
         }
-
-        team1 = null;
-        team2 = null;
     }
     }
 
 
     public boolean isInLobbyArea(Location location) {
     public boolean isInLobbyArea(Location location) {

+ 80 - 42
missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/GameManager.java

@@ -29,7 +29,9 @@ import org.bukkit.Location;
 
 
 import java.io.File;
 import java.io.File;
 import java.io.IOException;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashMap;
+import java.util.List;
 
 
 @Getter
 @Getter
 public class GameManager {
 public class GameManager {
@@ -44,14 +46,22 @@ public class GameManager {
         games.clear();
         games.clear();
     }
     }
 
 
-    public void loadGames() {
+    public void restartAll() {
+        games.values().forEach(game -> restartGame(game.getLobby(), false));
+    }
+
+    /**
+     * This method is for starting up the server. The game lobby configurations
+     * are loaded here.
+     */
+    public void loadGamesOnStartup() {
         File[] lobbyFiles = null;
         File[] lobbyFiles = null;
         if (Config.isMultipleLobbies()) {
         if (Config.isMultipleLobbies()) {
             lobbyFiles = new File(Config.getLobbiesFolder()).listFiles();
             lobbyFiles = new File(Config.getLobbiesFolder()).listFiles();
         } else {
         } else {
             File file = new File(Config.getLobbiesFolder() + "/" + Config.getDefaultLobby());
             File file = new File(Config.getLobbiesFolder() + "/" + Config.getDefaultLobby());
             if (file.exists()) {
             if (file.exists()) {
-                lobbyFiles = new File[] {file};
+                lobbyFiles = new File[]{file};
             }
             }
         }
         }
         if (lobbyFiles == null) lobbyFiles = new File[0];
         if (lobbyFiles == null) lobbyFiles = new File[0];
@@ -69,62 +79,84 @@ public class GameManager {
                 Bukkit.getPluginManager().disablePlugin(MissileWars.getInstance());
                 Bukkit.getPluginManager().disablePlugin(MissileWars.getInstance());
                 return;
                 return;
             }
             }
-            lobbyFiles = new File[] {file};
+            lobbyFiles = new File[]{file};
         }
         }
 
 
-        loadGames(lobbyFiles);
+        for (File lobbyFile : lobbyFiles) {
+            if (lobbyFile == null) continue;
+            if (!lobbyFile.getName().endsWith(".yml") && !lobbyFile.getName().endsWith(".yaml")) continue;
+
+            debugStart(lobbyFile);
+        }
     }
     }
 
 
-    private void loadGames(File[] lobbyFileList) {
+    /**
+     * This method attempts to read the game lobby configuration and build a game
+     * from it. Config mistakes are recognized and the config is saved again.
+     * 
+     * @param lobbyFile (File) the arena configuration file
+     */
+    private void debugStart(File lobbyFile) {
+        Logger.BOOT.log("Try to loading lobby of \"" + lobbyFile.getName() + "\"");
 
 
-        for (File lobbyFile : lobbyFileList) {
-            if (lobbyFile == null)
-                continue;
-            if (!lobbyFile.getName().endsWith(".yml") && !lobbyFile.getName().endsWith(".yaml")) continue;
+        try {
+            Lobby lobby = Serializer.deserialize(lobbyFile, Lobby.class);
 
 
-            Logger.BOOT.log("Loading lobby " + lobbyFile.getName());
-            try {
-                Lobby lobby = Serializer.deserialize(lobbyFile, Lobby.class);
-                if (lobby == null) {
-                    Logger.ERROR.log("Could not load lobby " + lobbyFile.getName());
-                    continue;
-                }
-                Game potentialOtherGame = getGame(lobby.getName());
-                if (potentialOtherGame != null) {
-                    Logger.ERROR.log("A lobby with the same name was already loaded. Names of lobbies must be unique, this lobby will not be loaded");
-                    continue;
-                }
-                lobby.setFile(lobbyFile);
-                restartGame(lobby);
-                Logger.BOOTDONE.log("Loaded lobby " + lobbyFile.getName());
-            } catch (IOException exception) {
-                Logger.ERROR.log("Could not load lobby " + lobbyFile.getName());
-                exception.printStackTrace();
+            if (lobby == null) {
+                Logger.ERROR.log("Could not load lobby of \"" + lobbyFile.getName() + "\"");
+                return;
             }
             }
+
+            if (getGame(lobby.getName()) != null) {
+                Logger.ERROR.log("A lobby with the same name was already loaded. Names of lobbies must be unique, this lobby will not be loaded");
+                return;
+            }
+
+            lobby.setFile(lobbyFile);
+            restartGame(lobby, false);
+
+        } catch (IOException exception) {
+            Logger.ERROR.log("Could not load lobby of \"" + lobbyFile.getName() + "\"");
+            exception.printStackTrace();
         }
         }
     }
     }
 
 
-    public void disableGame(String lobbyName) {
-        Game game = getGame(lobbyName);
-        if (game == null) return;
+    /**
+     * This method (re)starts a MissileWars game.
+     * 
+     * @param targetLobby (Lobby) the existing lobby of the game
+     * @param forceStart true, if it should also (re)start, if it's not an automatically
+     *                   starting game according to the lobby configuration
+     */
+    public void restartGame(Lobby targetLobby, boolean forceStart) {
+        if (!targetLobby.isAutoLoad() && !forceStart) return;
+
+        String targetLobbyName = targetLobby.getName();
+
+        // reset the old game
+        Game game = getGame(targetLobbyName);
+        if (game != null) {
+            game.resetGame();
+        }
 
 
-        game.resetGame();
-        games.remove(lobbyName);
+        // delete the old game from the list
+        if (games.get(targetLobbyName) != null) {
+            games.remove(targetLobby);
+        }
 
 
         Logger.DEBUG.log("Old Game disabled.");
         Logger.DEBUG.log("Old Game disabled.");
-    }
 
 
-    public void restartGame(Lobby oldLobby) {
-        String oldLobbyName = oldLobby.getName();
-        disableGame(oldLobbyName);
+        // read the game lobby configuration and build a new game and lobby from it
         try {
         try {
-            Lobby lobby = Serializer.deserialize(oldLobby.getFile(), Lobby.class);
-            lobby.setFile(oldLobby.getFile());
-            // Save for possible new values
-            Serializer.serialize(oldLobby.getFile(), lobby);
-            games.put(oldLobbyName, new Game(lobby));
+            Lobby lobby = Serializer.deserialize(targetLobby.getFile(), Lobby.class);
+            lobby.setFile(targetLobby.getFile());
+            lobby.updateConfig();
+
+            Logger.BOOTDONE.log("Reloaded lobby \"" + targetLobbyName + "\" (" + targetLobby.getFile().getName() + ")");
+            addGame(targetLobbyName, new Game(lobby));
+
         } catch (IOException exception) {
         } catch (IOException exception) {
-            Logger.ERROR.log("Could not load lobby " + oldLobby.getName());
+            Logger.ERROR.log("Could not load lobby of \"" + targetLobby.getFile().getName() + "\"");
             exception.printStackTrace();
             exception.printStackTrace();
         }
         }
     }
     }
@@ -133,6 +165,12 @@ public class GameManager {
         return games.get(name);
         return games.get(name);
     }
     }
 
 
+    public void addGame(String name, Game game) {
+        games.put(name, game);
+        List<String> gameNames = new ArrayList<>(games.keySet());
+        MissileWars.getInstance().commandManager.getCommandCompletions().registerCompletion("games", c -> gameNames);
+    }
+
     public int getGameAmount() {
     public int getGameAmount() {
         return games.size();
         return games.size();
     }
     }