diff --git a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/MissileWars.java b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/MissileWars.java index 0c97fb0c..ed734702 100644 --- a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/MissileWars.java +++ b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/MissileWars.java @@ -20,6 +20,7 @@ import co.aikar.commands.PaperCommandManager; import de.butzlabben.missilewars.commands.MWCommands; +import de.butzlabben.missilewars.commands.SetupCommands; import de.butzlabben.missilewars.commands.StatsCommands; import de.butzlabben.missilewars.commands.UserCommands; import de.butzlabben.missilewars.configuration.Config; @@ -57,9 +58,13 @@ public class MissileWars extends JavaPlugin { private static MissileWars instance; public final String version = getDescription().getVersion(); private SignRepository signRepository; + public PaperCommandManager commandManager; private boolean foundFAWE; + private PlayerListener playerListener; + private SignListener signListener; + public MissileWars() { instance = this; } @@ -99,7 +104,7 @@ public void onEnable() { Arenas.load(); SetupUtil.checkShields(); - GameManager.getInstance().loadGames(); + GameManager.getInstance().loadGamesOnStartup(); new Metrics(this, 3749); @@ -143,8 +148,11 @@ public void onDisable() { * This method registers all events of the missilewars event listener. */ 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 @@ private void registerCommands() { // Using the Paper Command Manager does not mean the plugin requires Paper. // It simply lets it take advantage of Paper specific features if available, // 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 boolean foundFAWE() { private void deleteTempWorlds() { File[] dirs = Bukkit.getWorldContainer().listFiles(); if (dirs == null) return; - + for (File dir : dirs) { if (dir.getName().startsWith("mw-")) { try { @@ -220,4 +229,12 @@ private void sendPluginInfo() { Logger.BOOT.log("Other authors: " + sb); } } + + public PlayerListener getPlayerListener() { + return playerListener; + } + + public SignListener getSignListener() { + return signListener; + } } diff --git a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/MWCommands.java b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/MWCommands.java index 0195761c..f54f779d 100644 --- a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/MWCommands.java +++ b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/MWCommands.java @@ -23,24 +23,21 @@ import de.butzlabben.missilewars.Logger; import de.butzlabben.missilewars.MissileWars; import de.butzlabben.missilewars.configuration.Config; -import de.butzlabben.missilewars.configuration.Lobby; import de.butzlabben.missilewars.configuration.Messages; import de.butzlabben.missilewars.configuration.arena.Arena; import de.butzlabben.missilewars.game.Arenas; import de.butzlabben.missilewars.game.Game; 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.MapChooseProcedure; import de.butzlabben.missilewars.game.missile.Missile; import de.butzlabben.missilewars.game.missile.MissileFacing; -import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; @CommandAlias("mw|missilewars") public class MWCommands extends BaseCommand { @@ -51,34 +48,48 @@ public void mwCommand(CommandSender sender) { 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 ", "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 [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") - @Description("Pastes a missile.") - @Syntax("/mw paste ") @CommandCompletion("@nothing") @CommandPermission("mw.paste") public void pasteCommand(CommandSender sender, String[] args) { @@ -86,42 +97,66 @@ public void pasteCommand(CommandSender sender, String[] args) { if (!senderIsPlayer(sender)) return; 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()); if (game == null) { player.sendMessage(Messages.getMessage("not_in_arena")); 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; } - 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") - @Description("Starts the game.") - @Syntax("/mw start") - @CommandCompletion("@nothing") + @CommandCompletion("@games") @CommandPermission("mw.start") public void startCommand(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")); + if (args.length > 1) { + player.sendMessage(Messages.getPrefix() + "§cToo many arguments."); 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) { player.sendMessage(Messages.getPrefix() + "§cGame already started"); return; } + if (game.isReady()) game.startGame(); else { @@ -146,67 +181,84 @@ public void startCommand(CommandSender sender, String[] args) { } @Subcommand("stop") - @Description("Stops the game.") - @Syntax("/mw stop") - @CommandCompletion("@nothing") + @CommandCompletion("@games") @CommandPermission("mw.stop") public void stopCommand(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")); + if (args.length > 1) { + player.sendMessage(Messages.getPrefix() + "§cToo many arguments."); 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; 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; } - 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); sender.sendMessage(Messages.getMessage("restart_after_game")); } @Subcommand("reload") - @Description("Reload the plugin.") - @Syntax("/mw reload") @CommandCompletion("@nothing") @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(); Messages.load(); @@ -215,11 +267,17 @@ public void onReload(CommandSender sender, String[] args) { } @Subcommand("debug") - @Description("Show debug info.") - @Syntax("/mw debug") @CommandCompletion("@nothing") @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; Logger.NORMAL.log("Starting to print debug information for MissileWars v" + MissileWars.getInstance().version); @@ -231,45 +289,34 @@ public void onDebug(CommandSender sender, String[] args) { } @Subcommand("restartall") - @Description("Restart all games.") - @Syntax("/mw restartall") @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"); - List 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; sender.sendMessage(Messages.getPrefix() + "§cYou are not a player"); 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); } } diff --git a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/SetupCommands.java b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/SetupCommands.java new file mode 100644 index 00000000..1bc3a2b3 --- /dev/null +++ b/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 . + */ + +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 [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; + } +} diff --git a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/StatsCommands.java b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/StatsCommands.java index 25c54fcb..05ddea48 100644 --- a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/StatsCommands.java +++ b/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"); @Default - @Description("Shows stats.") - @Syntax("/mw stats [from] [arena]") @CommandPermission("mw.stats") public void onStats(CommandSender sender, String[] args) { - if (!senderIsPlayer(sender)) return; + if (!MWCommands.senderIsPlayer(sender)) return; Player player = (Player) sender; StatsFetcher fetcher = getFetcher(player, args); @@ -106,12 +104,11 @@ public void onStats(CommandSender sender, String[] args) { } @Subcommand("recommendations") - @Description("Shows recommendations.") - @Syntax("/mw stats recommendations [from] [arena]") + @CommandCompletion("@nothing") @CommandPermission("mw.stats.recommendations") public void onRecommendations(CommandSender sender, String[] args) { - if (!senderIsPlayer(sender)) return; + if (!MWCommands.senderIsPlayer(sender)) return; Player player = (Player) sender; StatsFetcher fetcher = getFetcher(player, args); @@ -146,12 +143,11 @@ public void onRecommendations(CommandSender sender, String[] args) { } @Subcommand("players") - @Description("Shows player list.") - @Syntax("/mw stats players [from] [arena]") + @CommandCompletion("@nothing") @CommandPermission("mw.stats.players") public void onPlayers(CommandSender sender, String[] args) { - if (!senderIsPlayer(sender)) return; + if (!MWCommands.senderIsPlayer(sender)) return; Player player = (Player) sender; StatsFetcher fetcher = getFetcher(player, args); @@ -164,12 +160,11 @@ public void onPlayers(CommandSender sender, String[] args) { } @Subcommand("list") - @Description("Lists history of games.") - @Syntax("/mw stats list [from] [arena]") + @CommandCompletion("@nothing") @CommandPermission("mw.stats.list") public void onList(CommandSender sender, String[] args) { - if (!senderIsPlayer(sender)) return; + if (!MWCommands.senderIsPlayer(sender)) return; Player player = (Player) sender; StatsFetcher fetcher = getFetcher(player, args); @@ -213,11 +208,4 @@ private StatsFetcher getFetcher(Player player, String[] args) { player.sendMessage(Messages.getPrefix() + "Loading data..."); return fetcher; } - - private boolean senderIsPlayer(CommandSender sender) { - if (sender instanceof Player) return true; - - sender.sendMessage(Messages.getPrefix() + "§cYou are not a player"); - return false; - } } diff --git a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/UserCommands.java b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/UserCommands.java index ea4fa772..7ea70243 100644 --- a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/UserCommands.java +++ b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/commands/UserCommands.java @@ -19,8 +19,11 @@ package de.butzlabben.missilewars.commands; 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.arena.Arena; import de.butzlabben.missilewars.game.Arenas; @@ -30,7 +33,6 @@ import de.butzlabben.missilewars.game.enums.GameState; import de.butzlabben.missilewars.game.enums.MapChooseProcedure; import de.butzlabben.missilewars.player.MWPlayer; -import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -39,62 +41,19 @@ @CommandAlias("mw|missilewars") 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") - @Description("Stops the game.") - @Syntax("/mw vote ") + @CommandCompletion("@nothing") @CommandPermission("mw.vote") public void voteCommand(CommandSender sender, String[] args) { - // TODO more messageconfig - if (!senderIsPlayer(sender)) return; + 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")); @@ -116,11 +75,6 @@ public void voteCommand(CommandSender sender, String[] args) { return; } - if (args.length != 1) { - player.sendMessage(Messages.getPrefix() + "§c/mw vote "); - return; - } - String arenaName = args[0]; Optional arena = Arenas.getFromName(arenaName); if (!game.getVotes().containsKey(arenaName) || arena.isEmpty()) { @@ -132,39 +86,71 @@ public void voteCommand(CommandSender sender, String[] args) { 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; + 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; } - 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; } - 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); } } diff --git a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/configuration/Lobby.java b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/configuration/Lobby.java index 82ad52a6..b5d05c9b 100644 --- a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/configuration/Lobby.java +++ b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/configuration/Lobby.java @@ -24,6 +24,7 @@ import de.butzlabben.missilewars.game.Arenas; import de.butzlabben.missilewars.game.enums.MapChooseProcedure; import de.butzlabben.missilewars.util.geometry.Area; +import de.butzlabben.missilewars.util.serialization.Serializer; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Setter; @@ -33,6 +34,7 @@ import org.bukkit.World; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -45,6 +47,7 @@ public class Lobby { private String name = "lobby0"; @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("lobby_time") private int lobbyTime = 60; @SerializedName("join_ongoing_game") private boolean joinOngoingGame = false; @@ -54,8 +57,8 @@ public class Lobby { @SerializedName("team1_color") private String team1Color = "&c"; @SerializedName("team2_name") private String team2Name = "Team2"; @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()); @SerializedName("map_choose_procedure") private MapChooseProcedure mapChooseProcedure = MapChooseProcedure.FIRST; @SerializedName("possible_arenas") private List possibleArenas = new ArrayList<>() {{ @@ -90,4 +93,20 @@ public List getArenas() { .map(Optional::get) .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()); + } } diff --git a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/configuration/arena/Arena.java b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/configuration/arena/Arena.java index 818d0a59..7df438ee 100644 --- a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/configuration/arena/Arena.java +++ b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/configuration/arena/Arena.java @@ -21,12 +21,16 @@ import com.google.gson.annotations.SerializedName; import de.butzlabben.missilewars.util.geometry.FlatArea; import de.butzlabben.missilewars.util.geometry.Plane; +import de.butzlabben.missilewars.util.serialization.Serializer; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.bukkit.Location; import org.bukkit.util.Vector; +import java.io.File; +import java.io.IOException; + @Getter @ToString public class Arena implements Cloneable { @@ -65,6 +69,8 @@ public class Arena implements Cloneable { @SerializedName("team2_spawn") @Setter private Location team2Spawn = new Location(null, 0.5, 100, -45.5, 0, 0); + + @Setter private transient File file; public Arena() { @@ -102,4 +108,12 @@ public Arena clone() { throw new AssertionError(); } } + + public void updateConfig() { + try { + Serializer.serialize(file, this); + } catch (IOException e) { + throw new RuntimeException(e); + } + } } diff --git a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/Arenas.java b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/Arenas.java index e6a9577c..b88732db 100644 --- a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/Arenas.java +++ b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/Arenas.java @@ -59,20 +59,20 @@ public static void load() { Bukkit.getPluginManager().disablePlugin(MissileWars.getInstance()); return; } - files = new File[] {defaultArena}; + files = new File[]{defaultArena}; } for (File config : files) { if (!config.getName().endsWith(".yml") && !config.getName().endsWith(".yaml")) continue; try { Arena arena = Serializer.deserialize(config, Arena.class); + arena.setFile(config); if (getFromName(arena.getName()).isPresent()) { Logger.WARN.log("There are several arenas configured with the name \"" + arena.getName() + "\". Arenas must have a unique name"); continue; } SetupUtil.checkMap(arena.getTemplateWorld()); - // Save for possible new values - Serializer.serialize(config, arena); + arena.updateConfig(); arenas.add(arena); } catch (IOException exception) { Logger.ERROR.log("Could not load config for arena " + config.getName()); diff --git a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/Game.java b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/Game.java index ca85ae14..08089160 100644 --- a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/Game.java +++ b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/Game.java @@ -276,15 +276,14 @@ public void stopGame() { } public void reset() { - if (Config.isSetup()) - return; + if (Config.isSetup()) return; if (restart) { Bukkit.getServer().spigot().restart(); return; } - GameManager.getInstance().restartGame(lobby); + GameManager.getInstance().restartGame(lobby, false); } public void appendRestart() { @@ -292,11 +291,11 @@ public void appendRestart() { } public void disableGameOnServerStop() { - + for (MWPlayer mwPlayer : players.values()) { teleportToFallbackSpawn(mwPlayer.getPlayer()); } - + gameWorld.unload(); } @@ -416,11 +415,6 @@ private void checkTeamSize(Team team) { } public void resetGame() { - if (state == GameState.INGAME) { - stopGame(); - return; - } - HandlerList.unregisterAll(listener); stopTimer(); @@ -436,9 +430,6 @@ public void resetGame() { if (scoreboardManager != null) { scoreboardManager.removeScoreboard(); } - - team1 = null; - team2 = null; } public boolean isInLobbyArea(Location location) { diff --git a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/GameManager.java b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/GameManager.java index 48c257f9..865d7cf6 100644 --- a/missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/GameManager.java +++ b/missilewars-plugin/src/main/java/de/butzlabben/missilewars/game/GameManager.java @@ -29,7 +29,9 @@ import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; @Getter public class GameManager { @@ -44,14 +46,22 @@ public void disableAll() { 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; if (Config.isMultipleLobbies()) { lobbyFiles = new File(Config.getLobbiesFolder()).listFiles(); } else { File file = new File(Config.getLobbiesFolder() + "/" + Config.getDefaultLobby()); if (file.exists()) { - lobbyFiles = new File[] {file}; + lobbyFiles = new File[]{file}; } } if (lobbyFiles == null) lobbyFiles = new File[0]; @@ -69,62 +79,84 @@ public void loadGames() { Bukkit.getPluginManager().disablePlugin(MissileWars.getInstance()); 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."); - } - 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 { - 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) { - Logger.ERROR.log("Could not load lobby " + oldLobby.getName()); + Logger.ERROR.log("Could not load lobby of \"" + targetLobby.getFile().getName() + "\""); exception.printStackTrace(); } } @@ -133,6 +165,12 @@ public Game getGame(String name) { return games.get(name); } + public void addGame(String name, Game game) { + games.put(name, game); + List gameNames = new ArrayList<>(games.keySet()); + MissileWars.getInstance().commandManager.getCommandCompletions().registerCompletion("games", c -> gameNames); + } + public int getGameAmount() { return games.size(); }