From f0cf47deb6c48388055497010ddceda18fe56982 Mon Sep 17 00:00:00 2001 From: Max Kalus Date: Tue, 7 Feb 2012 23:56:21 +0100 Subject: [PATCH] 3.0 code base. Renew code base and make game simpler in its core. --- .../de/beimax/simplespleef/SimpleSpleef.java | 114 +- .../{admin => command}/SimpleSpleefAdmin.java | 94 +- .../command/SimpleSpleefCommandExecutor.java | 196 +- .../SimpleSpleefSignCommandExecutor.java | 22 +- .../de/beimax/simplespleef/game/Game.java | 252 ++- .../beimax/simplespleef/game/GameHandler.java | 897 ++++----- .../simplespleef/game/GameStandard.java | 1633 +++++++++-------- .../simplespleef/game/GameWithTeams.java | 57 +- .../game/PlayerOnBlockDegenerator.java | 173 -- .../simplespleef/game/SpleeferList.java | 27 +- .../game/arenarestoring/ArenaRestorer.java | 52 +- .../arenarestoring/HardArenaRestorer.java | 74 +- .../game/arenarestoring/SoftRestorer.java | 186 +- .../game/floortracking/FloorBaseWorker.java | 100 - .../game/floortracking/FloorTracker.java | 212 --- .../game/floortracking/FloorWorker.java | 47 - .../simplespleef/game/trackers/Countdown.java | 114 ++ .../game/trackers/FloorBaseWorker.java | 92 + .../FloorDissolveWorker.java | 57 +- .../FloorRepairWorker.java | 54 +- .../trackers/PlayerOnBlockDegenerator.java | 220 +++ .../simplespleef/game/trackers/Tracker.java | 53 + .../{util => gamehelpers}/Cuboid.java | 2 +- .../{util => gamehelpers}/CuboidImpl.java | 4 +- .../CuboidWorldGuard.java | 4 +- .../InventoryKeeper.java | 2 +- .../{util => gamehelpers}/LocationHelper.java | 2 +- .../{util => gamehelpers}/MaterialHelper.java | 2 +- .../OriginalPositionKeeper.java | 7 +- .../SerializableBlockData.java | 2 +- .../listeners/SimpleSpleefBlockListener.java | 57 - .../listeners/SimpleSpleefEntityListener.java | 110 -- .../listeners/SimpleSpleefPlayerListener.java | 182 -- .../simplespleef/util/UpdateChecker.java | 39 +- 34 files changed, 2424 insertions(+), 2715 deletions(-) rename src/main/java/de/beimax/simplespleef/{admin => command}/SimpleSpleefAdmin.java (76%) delete mode 100644 src/main/java/de/beimax/simplespleef/game/PlayerOnBlockDegenerator.java delete mode 100644 src/main/java/de/beimax/simplespleef/game/floortracking/FloorBaseWorker.java delete mode 100644 src/main/java/de/beimax/simplespleef/game/floortracking/FloorTracker.java delete mode 100644 src/main/java/de/beimax/simplespleef/game/floortracking/FloorWorker.java create mode 100644 src/main/java/de/beimax/simplespleef/game/trackers/Countdown.java create mode 100644 src/main/java/de/beimax/simplespleef/game/trackers/FloorBaseWorker.java rename src/main/java/de/beimax/simplespleef/game/{floortracking => trackers}/FloorDissolveWorker.java (55%) rename src/main/java/de/beimax/simplespleef/game/{floortracking => trackers}/FloorRepairWorker.java (64%) create mode 100644 src/main/java/de/beimax/simplespleef/game/trackers/PlayerOnBlockDegenerator.java create mode 100644 src/main/java/de/beimax/simplespleef/game/trackers/Tracker.java rename src/main/java/de/beimax/simplespleef/{util => gamehelpers}/Cuboid.java (97%) rename src/main/java/de/beimax/simplespleef/{util => gamehelpers}/CuboidImpl.java (96%) rename src/main/java/de/beimax/simplespleef/{util => gamehelpers}/CuboidWorldGuard.java (97%) rename src/main/java/de/beimax/simplespleef/{util => gamehelpers}/InventoryKeeper.java (98%) rename src/main/java/de/beimax/simplespleef/{util => gamehelpers}/LocationHelper.java (98%) rename src/main/java/de/beimax/simplespleef/{util => gamehelpers}/MaterialHelper.java (99%) rename src/main/java/de/beimax/simplespleef/{game => gamehelpers}/OriginalPositionKeeper.java (97%) rename src/main/java/de/beimax/simplespleef/{util => gamehelpers}/SerializableBlockData.java (97%) delete mode 100644 src/main/java/de/beimax/simplespleef/listeners/SimpleSpleefBlockListener.java delete mode 100644 src/main/java/de/beimax/simplespleef/listeners/SimpleSpleefEntityListener.java delete mode 100644 src/main/java/de/beimax/simplespleef/listeners/SimpleSpleefPlayerListener.java diff --git a/src/main/java/de/beimax/simplespleef/SimpleSpleef.java b/src/main/java/de/beimax/simplespleef/SimpleSpleef.java index 1b411d0..461357f 100644 --- a/src/main/java/de/beimax/simplespleef/SimpleSpleef.java +++ b/src/main/java/de/beimax/simplespleef/SimpleSpleef.java @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ + package de.beimax.simplespleef; import java.util.Map; @@ -33,19 +34,18 @@ import com.sk89q.worldedit.bukkit.WorldEditAPI; import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import de.beimax.simplespleef.admin.SimpleSpleefAdmin; import de.beimax.simplespleef.command.SimpleSpleefCommandExecutor; +import de.beimax.simplespleef.command.SimpleSpleefSignCommandExecutor; import de.beimax.simplespleef.game.GameHandler; -import de.beimax.simplespleef.game.OriginalPositionKeeper; -import de.beimax.simplespleef.listeners.*; +import de.beimax.simplespleef.gamehelpers.OriginalPositionKeeper; +import de.beimax.simplespleef.listeners.PluginListener; import de.beimax.simplespleef.util.ConfigHelper; import de.beimax.simplespleef.util.Translator; import de.beimax.simplespleef.util.UpdateChecker; /** - * SimpleSpleef for Bukkit - * * @author mkalus + * */ public class SimpleSpleef extends JavaPlugin { public static final Logger log = Logger.getLogger("Minecraft"); @@ -77,7 +77,7 @@ public static boolean checkPermission(CommandSender sender, String permission) { // fallback to default Bukkit permission checking system return sender.hasPermission(permission) || sender.hasPermission("simplespleef.*"); } - + /** * self reference to singleton */ @@ -123,12 +123,12 @@ public static void setWorldEditAPI(WorldEditAPI worldEditAPI) { public static WorldEditAPI getWorldEditAPI() { return SimpleSpleef.worldEditAPI; } - + /** * keeper of original positions */ private static OriginalPositionKeeper originalPositionKeeper; - + /** * get originalPositionKeeper instance (singleton) * @return @@ -138,11 +138,6 @@ public static OriginalPositionKeeper getOriginalPositionKeeper() { return originalPositionKeeper; } - /** - * reference to admin class - */ - private SimpleSpleefAdmin admin; - /** * reference to command handler */ @@ -151,18 +146,12 @@ public static OriginalPositionKeeper getOriginalPositionKeeper() { /** * reference to translator */ - private Translator lang; + private static Translator lang; - /** - * reference to event handlers/listeners - */ - private SimpleSpleefBlockListener blockListener; - private SimpleSpleefPlayerListener playerListener; - private SimpleSpleefEntityListener entityListener; - /** * Called when enabling plugin */ + @Override public void onEnable() { // initialize plugin log.info(this.toString() + " is loading."); @@ -176,9 +165,11 @@ public void onEnable() { // check updates, if turned on checkForUpdate(); - // create new handlers + // create new handler SimpleSpleef.gameHandler = new GameHandler(); - this.admin = new SimpleSpleefAdmin(); + SimpleSpleef.gameHandler.updateGameHandlerData(); + // start tracking + SimpleSpleef.getPlugin().getServer().getScheduler().scheduleAsyncRepeatingTask(this, gameHandler, 0L, 20L); // register vault stuff setupEconomy(); @@ -196,17 +187,19 @@ public void onEnable() { */ public void onDisable() { log.info(this.toString() + " is shutting down."); + // cancel all tasks for this plugin + SimpleSpleef.getPlugin().getServer().getScheduler().cancelTasks(this); // clean memory SimpleSpleef.worldEditAPI = null; + // stop game handler SimpleSpleef.gameHandler = null; SimpleSpleef.economy = null; SimpleSpleef.originalPositionKeeper = null; - this.admin = null; - this.lang = null; - this.playerListener = null; - this.entityListener = null; - this.blockListener = null; - this.commandExecutor = null; + lang = null; + //this.playerListener = null; + //this.entityListener = null; + //this.blockListener = null; + //this.commandExecutor = null; //TODO add if more stuff comes along //save config to disk @@ -215,6 +208,7 @@ public void onDisable() { // derefer self reference SimpleSpleef.simpleSpleef = null; } + /** * Run some configuration stuff at the initialization of the plugin @@ -235,7 +229,7 @@ public void configurePlugin() { // initialize the translator lang = new Translator(this, this.getConfig().getString("language", "en")); } - + /** * reload configuration and translation */ @@ -243,7 +237,7 @@ public void reloadSimpleSpleefConfiguration() { // reload the config file this.reloadConfig(); // have the game loader reload, too - SimpleSpleef.gameHandler.reloadConfig(); + SimpleSpleef.gameHandler.updateGameHandlerData(); // re-initialize the translator lang = new Translator(this, this.getConfig().getString("language", "en")); @@ -277,59 +271,19 @@ public void run() { * Configure event listeners */ protected void registerEvents() { - // add listener for other plugins - PluginListener pluginListener = new PluginListener(); - // let my command handler take care of commands this.commandExecutor = new SimpleSpleefCommandExecutor(); this.getCommand("spleef").setExecutor(commandExecutor); // Prepare listeners PluginManager pm = getServer().getPluginManager(); - this.blockListener = new SimpleSpleefBlockListener(); - this.entityListener = new SimpleSpleefEntityListener(); - this.playerListener = new SimpleSpleefPlayerListener(); - + + // add listener for other plugins + pm.registerEvents(new PluginListener(), this); // Register our events - pm.registerEvents(pluginListener, this); - pm.registerEvents(blockListener, this); - pm.registerEvents(entityListener, this); - pm.registerEvents(playerListener, this); - } - - /** - * @return the admin - */ - public SimpleSpleefAdmin getAdminClass() { - return admin; - } - - /** - * @return the commandExecutor - */ - public SimpleSpleefCommandExecutor getCommandExecutor() { - return commandExecutor; - } - - /** - * @return the blockListener - */ - public SimpleSpleefBlockListener getBlockListener() { - return blockListener; - } - - /** - * @return the playerListener - */ - public SimpleSpleefPlayerListener getPlayerListener() { - return playerListener; - } - - /** - * @return the entityListener - */ - public SimpleSpleefEntityListener getEntityListener() { - return entityListener; + pm.registerEvents(gameHandler, this); + pm.registerEvents(new UpdateChecker(), this); // check updates + pm.registerEvents(new SimpleSpleefSignCommandExecutor(), this); // check sign actions } /** @@ -337,7 +291,7 @@ public SimpleSpleefEntityListener getEntityListener() { * @param replacers an even number of key/value pairs to replace key entries * @return translated string */ - public String ll(String key, String... replacers) { + public static String ll(String key, String... replacers) { return lang.ll(key, replacers); } @@ -346,7 +300,7 @@ public String ll(String key, String... replacers) { * @param key * @return */ - public Map lls(String section) { + public static Map lls(String section) { return lang.lls(section); } @@ -411,4 +365,4 @@ private void checkForWorldEdit() { .info("[SimpleSpleef] Found WorldEdit " + plugin.getDescription().getVersion() + ". Using it for selections."); } } -} \ No newline at end of file +} diff --git a/src/main/java/de/beimax/simplespleef/admin/SimpleSpleefAdmin.java b/src/main/java/de/beimax/simplespleef/command/SimpleSpleefAdmin.java similarity index 76% rename from src/main/java/de/beimax/simplespleef/admin/SimpleSpleefAdmin.java rename to src/main/java/de/beimax/simplespleef/command/SimpleSpleefAdmin.java index f122269..1c35b12 100644 --- a/src/main/java/de/beimax/simplespleef/admin/SimpleSpleefAdmin.java +++ b/src/main/java/de/beimax/simplespleef/command/SimpleSpleefAdmin.java @@ -16,11 +16,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ -package de.beimax.simplespleef.admin; +package de.beimax.simplespleef.command; import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; import org.bukkit.ChatColor; import org.bukkit.Location; @@ -36,10 +34,9 @@ import com.sk89q.worldedit.regions.Region; import de.beimax.simplespleef.SimpleSpleef; -import de.beimax.simplespleef.command.SimpleSpleefCommandExecutor; import de.beimax.simplespleef.game.Game; +import de.beimax.simplespleef.gamehelpers.LocationHelper; import de.beimax.simplespleef.util.ConfigHelper; -import de.beimax.simplespleef.util.LocationHelper; /** * @author mkalus @@ -131,7 +128,7 @@ else if (checkThirdAB(sender, args, adminCommand)) { } else if (adminCommand.equals("reload")) { reloadConfig(sender); } else // unknown command feedback - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.unknownCommand", "[COMMAND]", adminCommand)); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.unknownCommand", "[COMMAND]", adminCommand)); // should arena definition be checked? if (checkArena) checkArena(sender); @@ -147,7 +144,7 @@ else if (checkThirdAB(sender, args, adminCommand)) { protected boolean checkThreeArgs(CommandSender sender, String[] args, String adminCommand) { // check argument length if (args.length != 3) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("adminerrors.oneArgument", "[COMMAND]", adminCommand)); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("adminerrors.oneArgument", "[COMMAND]", adminCommand)); return false; } return true; @@ -163,7 +160,7 @@ protected boolean checkThreeArgs(CommandSender sender, String[] args, String adm protected boolean checkFourArgs(CommandSender sender, String[] args, String adminCommand) { // check argument length if (args.length < 4) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("adminerrors.twoArguments", "[COMMAND]", adminCommand)); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("adminerrors.twoArguments", "[COMMAND]", adminCommand)); return false; } // more than four arguments -> reduce number three @@ -195,7 +192,7 @@ protected boolean checkThirdSpawnName(CommandSender sender, String[] args, Strin || spawn.equals("lose") || spawn.equals("red") || spawn.equals("blue") || spawn.equals("winner")) return true; // error feedback - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("adminerrors.oneArgumentSpawn")); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("adminerrors.oneArgumentSpawn")); return false; } @@ -209,12 +206,12 @@ protected boolean checkThirdSpawnName(CommandSender sender, String[] args, Strin protected boolean checkThirdAB(CommandSender sender, String[] args, String adminCommand) { if (args.length != 3) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("adminerrors.oneArgument", "[COMMAND]", adminCommand)); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("adminerrors.oneArgument", "[COMMAND]", adminCommand)); return false; } if (args[2].equalsIgnoreCase("a") || args[2].equalsIgnoreCase("b")) return true; - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("adminerrors.aOrB", "[COMMAND]", adminCommand)); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("adminerrors.aOrB", "[COMMAND]", adminCommand)); return false; } @@ -224,7 +221,7 @@ protected boolean checkThirdAB(CommandSender sender, String[] args, */ protected void helpCommand(CommandSender sender) { // get help lines - String[] lines = SimpleSpleef.getPlugin().ll("admin.help").split("\n"); + String[] lines = SimpleSpleef.ll("admin.help").split("\n"); for (String line : lines) SimpleSpleefCommandExecutor.printCommandString(sender, line); } @@ -235,17 +232,16 @@ protected void helpCommand(CommandSender sender) { * @param sender */ protected void selectedCommand(CommandSender sender) { - // get all possible games - Map arenas = SimpleSpleef.getGameHandler().getPossibleGames(); // get selected arena String selected = getSelectedArena(sender); - for (Entry arena: arenas.entrySet()) { - sender.sendMessage((arena.getValue()?ChatColor.DARK_BLUE:ChatColor.GRAY) + arena.getKey() + (selected.equals(arena.getKey())?ChatColor.WHITE + " *":"")); + // show selected + for (Game game : SimpleSpleef.getGameHandler().getGames()) { + sender.sendMessage((game.isEnabled()?ChatColor.DARK_BLUE:ChatColor.GRAY) + game.getId() + (selected.equals(game.getId())?ChatColor.WHITE + " *":"")); } } /** - * Add an arena + * Set active arena * @param sender * @param arena */ @@ -253,15 +249,15 @@ protected void setarenaCommand(CommandSender sender, String arena) { // arena name to lower case String id = arena.toLowerCase(); // check arena existence - if (!SimpleSpleef.getGameHandler().gameTypeOrNameExists(id)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.unknownArena", "[ARENA]", arena)); + if (!SimpleSpleef.getGameHandler().gameExists(id)) { + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.unknownArena", "[ARENA]", arena)); return; } // set new default arena setSelectedArena(sender, id); // feedback - sender.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("adminfeedback.setarena", "[ARENA]", id)); + sender.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("adminfeedback.setarena", "[ARENA]", id)); } /** @@ -270,13 +266,11 @@ protected void setarenaCommand(CommandSender sender, String arena) { * @param arena */ protected void addarenaCommand(CommandSender sender, String arena) { - // get all possible games - Map arenas = SimpleSpleef.getGameHandler().getPossibleGames(); // arena name to lower case String id = arena.toLowerCase(); // check if arena exists already - if (arenas.get(id) != null) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("adminerrors.addarenaArenaExists", "[ARENA]", arena)); + if (SimpleSpleef.getGameHandler().gameExists(id)) { + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("adminerrors.addarenaArenaExists", "[ARENA]", arena)); return; } // create new arena entry in config @@ -288,7 +282,7 @@ protected void addarenaCommand(CommandSender sender, String arena) { // set default arena setSelectedArena(sender, arena); // feedback to user - sender.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("adminfeedback.addarena", "[ARENA]", arena)); + sender.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("adminfeedback.addarena", "[ARENA]", arena)); } /** @@ -300,8 +294,8 @@ protected void delarenaCommand(CommandSender sender, String arena) { // arena name to lower case String id = arena.toLowerCase(); // does arena exist? - if (!SimpleSpleef.getGameHandler().gameTypeOrNameExists(id)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.unknownArena", "[ARENA]", id)); + if (!SimpleSpleef.getGameHandler().gameExists(id)) { + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.unknownArena", "[ARENA]", id)); return; } @@ -315,7 +309,7 @@ protected void delarenaCommand(CommandSender sender, String arena) { SimpleSpleef.getPlugin().saveConfig(); // feedback to user - sender.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("adminfeedback.delarena", "[ARENA]", arena)); + sender.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("adminfeedback.delarena", "[ARENA]", arena)); } /** @@ -327,7 +321,7 @@ protected void delarenaCommand(CommandSender sender, String arena) { protected void defineArenaPoint(CommandSender sender, String aOrB, String adminCommand) { if (!(sender instanceof Player)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.notAPlayer", "[PLAYER]", sender.getName())); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.notAPlayer", "[PLAYER]", sender.getName())); return; } @@ -338,8 +332,8 @@ protected void defineArenaPoint(CommandSender sender, String aOrB, // get player location and arena String arena = getSelectedArena(sender); //check arena existence - if (!SimpleSpleef.getGameHandler().gameTypeOrNameExists(arena)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.unknownArena", "[ARENA]", arena)); + if (!SimpleSpleef.getGameHandler().gameExists(arena)) { + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.unknownArena", "[ARENA]", arena)); return; } @@ -360,7 +354,7 @@ protected void defineArenaPoint(CommandSender sender, String aOrB, SimpleSpleef.getPlugin().saveConfig(); // feedback to player - sender.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("adminfeedback.defineArenaPoint", "[ARENA]", arena, "[POINT]", aOrB, "[SECTION]", adminCommand)); + sender.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("adminfeedback.defineArenaPoint", "[ARENA]", arena, "[POINT]", aOrB, "[SECTION]", adminCommand)); } /** @@ -371,7 +365,7 @@ protected void defineArenaPoint(CommandSender sender, String aOrB, protected void defineArenaPointWorldEdit(CommandSender sender, String adminCommand) { if (!(sender instanceof Player)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.notAPlayer", "[PLAYER]", sender.getName())); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.notAPlayer", "[PLAYER]", sender.getName())); return; } // correct case @@ -383,8 +377,8 @@ protected void defineArenaPointWorldEdit(CommandSender sender, // get player location and arena String arena = getSelectedArena(sender); //check arena existence - if (!SimpleSpleef.getGameHandler().gameTypeOrNameExists(arena)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.unknownArena", "[ARENA]", arena)); + if (!SimpleSpleef.getGameHandler().gameExists(arena)) { + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.unknownArena", "[ARENA]", arena)); return; } @@ -393,7 +387,7 @@ protected void defineArenaPointWorldEdit(CommandSender sender, try { region = session.getSelection(session.getSelectionWorld()); } catch (Exception e) { // error in selection - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("adminerrors.worldEditRegion")); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("adminerrors.worldEditRegion")); return; } // get minimum and maximum vectors @@ -403,7 +397,7 @@ protected void defineArenaPointWorldEdit(CommandSender sender, World world = SimpleSpleef.getPlugin().getServer().getWorld(region.getWorld().getName()); // sanity check if (world == null || minP == null || maxP == null) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("adminerrors.worldEditRegion")); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("adminerrors.worldEditRegion")); return; } @@ -425,7 +419,7 @@ protected void defineArenaPointWorldEdit(CommandSender sender, SimpleSpleef.getPlugin().saveConfig(); // feedback to player - sender.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("adminfeedback.defineArenaPointWorldEdit", "[ARENA]", arena, "[SECTION]", adminCommand)); + sender.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("adminfeedback.defineArenaPointWorldEdit", "[ARENA]", arena, "[SECTION]", adminCommand)); } /** @@ -437,7 +431,7 @@ protected void defineArenaPointWorldEdit(CommandSender sender, protected void defineSpawnPoint(CommandSender sender, String spawn, String adminCommand) { if (!(sender instanceof Player)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.notAPlayer", "[PLAYER]", sender.getName())); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.notAPlayer", "[PLAYER]", sender.getName())); return; } @@ -448,8 +442,8 @@ protected void defineSpawnPoint(CommandSender sender, String spawn, // get player location and arena String arena = getSelectedArena(sender); // check arena existence - if (!SimpleSpleef.getGameHandler().gameTypeOrNameExists(arena)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.unknownArena", "[ARENA]", arena)); + if (!SimpleSpleef.getGameHandler().gameExists(arena)) { + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.unknownArena", "[ARENA]", arena)); return; } @@ -463,7 +457,7 @@ protected void defineSpawnPoint(CommandSender sender, String spawn, SimpleSpleef.getPlugin().saveConfig(); // feedback to player - sender.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("adminfeedback.defineSpawnPoint", "[ARENA]", arena, "[SPAWN]", spawn)); + sender.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("adminfeedback.defineSpawnPoint", "[ARENA]", arena, "[SPAWN]", spawn)); } /** @@ -471,7 +465,7 @@ protected void defineSpawnPoint(CommandSender sender, String spawn, */ protected void checkArena(CommandSender sender) { // reload the configuration of everything - SimpleSpleef.getGameHandler().reloadConfig(); + SimpleSpleef.getGameHandler().updateGameHandlerData(); } /** @@ -480,7 +474,7 @@ protected void checkArena(CommandSender sender) { */ protected void reloadConfig(CommandSender sender) { SimpleSpleef.getPlugin().reloadSimpleSpleefConfiguration(); - sender.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("adminfeedback.reload")); + sender.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("adminfeedback.reload")); } /** @@ -491,13 +485,13 @@ protected void reloadConfig(CommandSender sender) { */ protected boolean enableArena(CommandSender sender, String arena) { // does arena exist? - if (!SimpleSpleef.getGameHandler().gameTypeOrNameExists(arena)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.unknownArena", "[ARENA]", arena)); + if (!SimpleSpleef.getGameHandler().gameExists(arena)) { + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.unknownArena", "[ARENA]", arena)); return false; } // enable arena SimpleSpleef.getPlugin().getConfig().set("arenas." + arena.toLowerCase() + ".enabled", true); - sender.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("adminfeedback.enable", "[ARENA]", arena)); + sender.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("adminfeedback.enable", "[ARENA]", arena)); return true; } @@ -509,13 +503,13 @@ protected boolean enableArena(CommandSender sender, String arena) { */ protected boolean disableArena(CommandSender sender, String arena) { // does arena exist? - if (!SimpleSpleef.getGameHandler().gameTypeOrNameExists(arena)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.unknownArena", "[ARENA]", arena)); + if (!SimpleSpleef.getGameHandler().gameExists(arena)) { + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.unknownArena", "[ARENA]", arena)); return false; } // disable arena SimpleSpleef.getPlugin().getConfig().set("arenas." + arena.toLowerCase() + ".enabled", false); - sender.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("adminfeedback.disable", "[ARENA]", arena)); + sender.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("adminfeedback.disable", "[ARENA]", arena)); return true; } diff --git a/src/main/java/de/beimax/simplespleef/command/SimpleSpleefCommandExecutor.java b/src/main/java/de/beimax/simplespleef/command/SimpleSpleefCommandExecutor.java index 05685a9..c02bed8 100644 --- a/src/main/java/de/beimax/simplespleef/command/SimpleSpleefCommandExecutor.java +++ b/src/main/java/de/beimax/simplespleef/command/SimpleSpleefCommandExecutor.java @@ -19,9 +19,7 @@ package de.beimax.simplespleef.command; import java.lang.reflect.Method; -import java.util.List; import java.util.Map; -import java.util.Map.Entry; import org.bukkit.ChatColor; import org.bukkit.command.Command; @@ -60,6 +58,11 @@ public static void printCommandString(CommandSender sender, String commandString + ": " + ChatColor.WHITE + commandString.substring(pos + 1)); } + /** + * reference to command executor for admin class + */ + private static SimpleSpleefAdmin simpleSpleefAdmin = new SimpleSpleefAdmin(); + /** * Executed whenever simplespeef is hit by a command */ @@ -134,13 +137,12 @@ else if (label.equalsIgnoreCase("spleefsigncmd")) { Object[] xargs = { sender, args }; // invoke it myCommand.invoke(this, xargs); - return true; } catch (Exception e) { e.printStackTrace(); sender.sendMessage("Error in command execution - command was not found in executor. Contact SimpleSpleef programmer!"); } - // any other stuff -> show help - return helpCommand(sender); + + return true; } /** @@ -153,7 +155,7 @@ protected boolean helpCommand(CommandSender sender) { if (!SimpleSpleef.checkPermission(sender, "simplespleef.help")) return false; // get all commands in language file - Map commands = SimpleSpleef.getPlugin().lls("command"); + Map commands = SimpleSpleef.lls("command"); // control if there is any output: boolean output = false; // either commands for player or for console @@ -172,7 +174,7 @@ protected boolean helpCommand(CommandSender sender) { } // was there output? if not show response if (!output) - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.noPermissionAtAll")); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.noPermissionAtAll")); return true; } @@ -185,7 +187,7 @@ protected void announceCommand(CommandSender sender, String[] args) { // too many arguments? if (tooManyArguments(sender, args, 1)) return; // get game from 2nd argument - String arena = this.getArenaNameFromArgument(sender, args, 1); + Game arena = this.getArenaFromArgument(sender, args, 1); if (arena != null) { // no errors - then try to announce new game SimpleSpleef.getGameHandler().announce(sender, arena); } @@ -200,7 +202,7 @@ protected void joinCommand(CommandSender sender, String[] args) { // too many arguments? if (tooManyArguments(sender, args, 1)) return; // get game from 2nd argument - String arena = this.getArenaNameFromArgument(sender, args, 1); + Game arena = this.getArenaFromArgument(sender, args, 1); if (arena != null) { // no errors - then try to announce new game SimpleSpleef.getGameHandler().join(sender, arena); } @@ -212,47 +214,7 @@ protected void joinCommand(CommandSender sender, String[] args) { * @param args */ protected void arenasCommand(CommandSender sender, String[] args) { - //get current games - List games = SimpleSpleef.getGameHandler().getGameIds(); - // get all possible games - Map arenas = SimpleSpleef.getGameHandler().getPossibleGames(); - if (arenas == null) return; // none - unlikely, but possible... - // cycle through possible games - for (Entry arena: arenas.entrySet()) { - // color and information on game - ChatColor color; - String name = arena.getKey(); // id of arena - // name of arena - String fullName = SimpleSpleef.getPlugin().getConfig().getString("arenas." + name + ".name"); - String information; - if (arena.getValue() == false) { - color = ChatColor.DARK_GRAY; // arena has been disabled in the the config - information = SimpleSpleef.getPlugin().ll("feedback.arenaDisabled"); - } - else if (games.contains(name)) { // is it an active game? - // game active or still joinable? - Game activeGame = SimpleSpleef.getGameHandler().getGameByName(name); - if (activeGame.isJoinable() || activeGame.isReady()) { - color = ChatColor.GREEN; // joinable - information = SimpleSpleef.getPlugin().ll("feedback.arenaJoinable"); - } - else { - color = ChatColor.LIGHT_PURPLE; // not joinable - because running - information = SimpleSpleef.getPlugin().ll("feedback.arenaInProgress"); - } - // ok, gather some more information on the game to display - information = information + " " + activeGame.getNumberOfPlayers(); - } else { - color = ChatColor.GRAY; // not an active game - information = null; // no information - } - // create feedback - StringBuilder builder = new StringBuilder(); - builder.append(color).append(name); - if (information != null) builder.append(ChatColor.GRAY).append(" - ").append(information); - if (fullName != null) builder.append(ChatColor.GRAY).append(" (").append(fullName).append(')'); - sender.sendMessage(builder.toString()); - } + SimpleSpleef.getGameHandler().arenas(sender); } /** @@ -263,47 +225,10 @@ else if (games.contains(name)) { // is it an active game? protected void infoCommand(CommandSender sender, String[] args) { // remember, we have 20 chat lines maximum... // get game from 2nd argument - String arena = this.getArenaNameFromArgument(sender, args, 1); - if (arena == null) return; // no arena found + Game game = this.getArenaFromArgument(sender, args, 1); + if (game == null) return; // no arena found - // if player and no arena defined - arena is unset, so player can start current arena - String possibleArena = getPossiblePlayerSpectatorArena(sender, args, arena); - if (possibleArena != null) arena = possibleArena; - - SimpleSpleef plugin = SimpleSpleef.getPlugin(); - - // is game active? - Game game = SimpleSpleef.getGameHandler().getGameByName(arena); - - // ok, define information on arena and print it - sender.sendMessage(plugin.ll("feedback.infoHeader", "[ARENA]", ChatColor.DARK_AQUA + arena)); - // full name of arena - sender.sendMessage(plugin.ll("feedback.infoName", "[NAME]", ChatColor.DARK_AQUA + plugin.getConfig().getString("arenas." + arena + ".name", "---"))); - // status of arena - String information; - ChatColor color; - if (game != null) { // game running - if (game.isJoinable() || game.isReady()) { - information = SimpleSpleef.getPlugin().ll("feedback.arenaJoinable"); - color = ChatColor.GREEN; - } else { - information = SimpleSpleef.getPlugin().ll("feedback.arenaInProgress"); - color = ChatColor.LIGHT_PURPLE; - } - // ok, gather some more information on the game to display - information = information + " " + game.getNumberOfPlayers(); - } else { // no game running - if (plugin.getConfig().getBoolean("arenas." + arena + ".enabled", true)) { - information = SimpleSpleef.getPlugin().ll("feedback.arenaOff"); - color = ChatColor.GRAY; - } else { - information = SimpleSpleef.getPlugin().ll("feedback.arenaDisabled"); - color = ChatColor.DARK_GRAY; - } - } - sender.sendMessage(plugin.ll("feedback.infoStatus", "[STATUS]", color + information)); - // list of spleefers and spectators - printGamePlayersAndSpectators(sender, game); + SimpleSpleef.getGameHandler().info(sender, game); } /** @@ -314,17 +239,10 @@ protected void infoCommand(CommandSender sender, String[] args) { protected void listCommand(CommandSender sender, String[] args) { // remember, we have 20 chat lines maximum... // get game from 2nd argument - String arena = this.getArenaNameFromArgument(sender, args, 1); - if (arena == null) return; // no arena found - - // if player and no arena defined - arena is unset, so player can start current arena - String possibleArena = getPossiblePlayerSpectatorArena(sender, args, arena); - if (possibleArena != null) arena = possibleArena; + Game game = this.getArenaFromArgument(sender, args, 1); + if (game == null) return; // no arena found - // is game active? - Game game = SimpleSpleef.getGameHandler().getGameByName(arena); - // list of spleefers and spectators - printGamePlayersAndSpectators(sender, game); + SimpleSpleef.getGameHandler().list(sender, game); } /** @@ -370,7 +288,7 @@ protected void countdownCommand(CommandSender sender, String[] args) { // too many arguments? if (tooManyArguments(sender, args, 1)) return; // get game from 2nd argument - String arena = this.getArenaNameFromArgument(sender, args, 1); + Game arena = this.getArenaFromArgument(sender, args, 1); // if player and no arena defined - arena is unset, so player can start current arena if (arena != null && args.length < 2 && !isConsole(sender)) SimpleSpleef.getGameHandler().start(sender); @@ -422,7 +340,7 @@ protected void resetCommand(CommandSender sender, String[] args) { if (tooManyArguments(sender, args, 1)) return; // too few arguments? if (tooFewArguments(sender, args, 1)) return; - String arena = this.getArenaNameFromArgument(sender, args, 1); + Game arena = this.getArenaFromArgument(sender, args, 1); if (arena != null) { SimpleSpleef.getGameHandler().delete(sender, arena); } @@ -437,7 +355,7 @@ protected void watchCommand(CommandSender sender, String[] args) { // too many arguments? if (tooManyArguments(sender, args, 1)) return; // get game from 2nd argument - String arena = this.getArenaNameFromArgument(sender, args, 1); + Game arena = this.getArenaFromArgument(sender, args, 1); if (arena != null) { // no errors - then try watch a game SimpleSpleef.getGameHandler().watch(sender, arena); } @@ -450,7 +368,7 @@ protected void watchCommand(CommandSender sender, String[] args) { */ protected void adminCommand(CommandSender sender, String[] args) { // delegate all further stuff to admin class - SimpleSpleef.getPlugin().getAdminClass().executeCommand(sender, args); + SimpleSpleefCommandExecutor.simpleSpleefAdmin.executeCommand(sender, args); } /** @@ -461,7 +379,7 @@ protected void adminCommand(CommandSender sender, String[] args) { protected void backCommand(CommandSender sender, String[] args) { // too many arguments? if (tooManyArguments(sender, args, 0)) return; - SimpleSpleef.getGameHandler().back(sender); + SimpleSpleef.getGameHandler().back(sender); } //TODO: add further commands here... @@ -473,7 +391,7 @@ protected void backCommand(CommandSender sender, String[] args) { * @return true */ protected boolean unknownCommand(CommandSender sender, String command) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.unknownCommand", "[COMMAND]", command)); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.unknownCommand", "[COMMAND]", command)); return true; } @@ -484,7 +402,7 @@ protected boolean unknownCommand(CommandSender sender, String command) { * @return true */ protected boolean unknownArena(CommandSender sender, String arena) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.unknownArena", "[ARENA]", arena)); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.unknownArena", "[ARENA]", arena)); return true; } @@ -497,7 +415,7 @@ protected boolean unknownArena(CommandSender sender, String arena) { */ protected boolean permissionMissing(CommandSender sender, String command, boolean signcommand) { String msg = signcommand?"errors.signPermissionMissing":"errors.permissionMissing"; - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll(msg, "[COMMAND]", command)); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll(msg, "[COMMAND]", command)); return true; } @@ -532,8 +450,8 @@ protected boolean isConsoleCommand(String command) { */ protected boolean tooFewArguments(CommandSender sender, String[] args, int min) { if (args.length < min+1) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.tooFewArguments", "[MIN]", String.valueOf(min))); - String commandString = SimpleSpleef.getPlugin().ll("command." + args[0]); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.tooFewArguments", "[MIN]", String.valueOf(min))); + String commandString = SimpleSpleef.ll("command." + args[0]); if (commandString != null) printCommandString(sender, commandString); return true; @@ -549,8 +467,8 @@ protected boolean tooFewArguments(CommandSender sender, String[] args, int min) */ protected boolean tooManyArguments(CommandSender sender, String[] args, int max) { if (args.length > max+1) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.tooManyArguments", "[MAX]", String.valueOf(max))); - String commandString = SimpleSpleef.getPlugin().ll("command." + args[0]); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.tooManyArguments", "[MAX]", String.valueOf(max))); + String commandString = SimpleSpleef.ll("command." + args[0]); if (commandString != null) printCommandString(sender, commandString); return true; @@ -564,61 +482,17 @@ protected boolean tooManyArguments(CommandSender sender, String[] args, int max) * @param index * @return null, if arena name is not found */ - protected String getArenaNameFromArgument(CommandSender sender, String[] args, int index) { + protected Game getArenaFromArgument(CommandSender sender, String[] args, int index) { String name; // of too short, get the default arena if (args.length <= index) name = SimpleSpleef.getGameHandler().getDefaultArena(); else name = args[index]; - + // check for the existence of the arena - if (!SimpleSpleef.getGameHandler().gameTypeOrNameExists(name)) { - // error output, if no arena has been found + Game game = SimpleSpleef.getGameHandler().getGameByName(name); + if (game == null) // error if no arena has been found unknownArena(sender, name); - return null; - } - return name.toLowerCase(); - } - - /** - * helper function to find a possible arena if no args are defined (info, list commands) - * @param sender - * @param args - * @param arena - * @return - */ - private String getPossiblePlayerSpectatorArena(CommandSender sender, String[] args, String arena) { - // if player and no arena defined - arena is unset, so player can start current arena - if (arena != null && args.length < 2 && !isConsole(sender)) { - Game checkGame = SimpleSpleef.getGameHandler().checkPlayerInGame((Player) sender); - if (checkGame == null) checkGame = SimpleSpleef.getGameHandler().checkSpectatorInGame((Player) sender); - if (checkGame != null) return checkGame.getId(); - } - return null; - } - - /** - * sends a list of players and spectators of a specific game to a sender - * @param sender - * @param game - */ - protected void printGamePlayersAndSpectators(CommandSender sender, Game game) { - // list of spleefers and spectators - if (game != null && sender != null) { - SimpleSpleef plugin = SimpleSpleef.getPlugin(); - String spleefers = game.getListOfSpleefers(); - if (spleefers != null) - sender.sendMessage(plugin.ll("feedback.infoSpleefers", "[SPLEEFERS]", spleefers)); - if (game.supportsCommandReady()) { - System.out.println("Unready"); - String unready = game.getListOfUnreadySpleefers(); - if (unready != null) - sender.sendMessage(plugin.ll("feedback.infoUnreadySpleefers", "[SPLEEFERS]", ChatColor.RED + unready)); - else if (game.getListOfUnreadySpleefers() != null) sender.sendMessage(ChatColor.GREEN + plugin.ll("feedback.infoAllReady")); - } - String spectators = game.getListOfSpectators(); - if (spectators != null) - sender.sendMessage(plugin.ll("feedback.infoSpectators", "[SPECTATORS]", spectators)); - } + return game; } } diff --git a/src/main/java/de/beimax/simplespleef/command/SimpleSpleefSignCommandExecutor.java b/src/main/java/de/beimax/simplespleef/command/SimpleSpleefSignCommandExecutor.java index e239244..8987d17 100644 --- a/src/main/java/de/beimax/simplespleef/command/SimpleSpleefSignCommandExecutor.java +++ b/src/main/java/de/beimax/simplespleef/command/SimpleSpleefSignCommandExecutor.java @@ -21,6 +21,10 @@ import org.bukkit.block.Sign; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; import de.beimax.simplespleef.SimpleSpleef; @@ -28,7 +32,7 @@ * @author mkalus * Execute sign commands */ -public class SimpleSpleefSignCommandExecutor { +public class SimpleSpleefSignCommandExecutor implements Listener { /** * main method of the class - takes a player and a clicked sign (to be analyzed and possibly executed) * @param player @@ -78,4 +82,20 @@ private boolean isSimpleSpleefSign(Sign sign) { // yes! return true; } + + /** + * listens to sign events + * @param event + */ + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + // clicked on a sign and signs enabled? + if (event.getPlayer() != null && event.getClickedBlock() != null && event.getClickedBlock().getState() instanceof Sign && SimpleSpleef.getPlugin().getConfig().getBoolean("settings.enableSigns", true)) { + // only right click allowed? + boolean signsOnlyRightClick = SimpleSpleef.getPlugin().getConfig().getBoolean("settings.signsOnlyRightClick", false); + if (!signsOnlyRightClick || (signsOnlyRightClick && event.getAction() == Action.RIGHT_CLICK_BLOCK)) + // let the sign command executor do the rest + parseSimpleSpleefSign(event.getPlayer(), (Sign)event.getClickedBlock().getState()); + } + } } diff --git a/src/main/java/de/beimax/simplespleef/game/Game.java b/src/main/java/de/beimax/simplespleef/game/Game.java index b349356..5680ec8 100644 --- a/src/main/java/de/beimax/simplespleef/game/Game.java +++ b/src/main/java/de/beimax/simplespleef/game/Game.java @@ -16,21 +16,29 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ + package de.beimax.simplespleef.game; +import org.bukkit.ChatColor; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.player.PlayerGameModeChangeEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerTeleportEvent; import de.beimax.simplespleef.SimpleSpleef; +import de.beimax.simplespleef.game.trackers.Tracker; /** * @author mkalus @@ -40,11 +48,12 @@ public abstract class Game { /** * game status constants */ - protected static final int STATUS_NEW = 1; - protected static final int STATUS_READY = 2; - protected static final int STATUS_COUNTDOWN = 3; - protected static final int STATUS_STARTED = 4; - protected static final int STATUS_FINISHED = 5; + protected static final int STATUS_INACTIVE = 0; // no game started + protected static final int STATUS_NEW = 1; // game initialized, players may join + protected static final int STATUS_READY = 2; // game is ready to be started + protected static final int STATUS_COUNTDOWN = 3; // game countdown is running + protected static final int STATUS_STARTED = 4; // game is actually running + protected static final int STATUS_FINISHED = 5; // game has finished, now cleaning up /** * name of the game/arena @@ -62,7 +71,7 @@ public abstract class Game { */ public Game(String name) { this.name = name; - this.status = STATUS_NEW; + this.status = STATUS_INACTIVE; } /** @@ -91,10 +100,29 @@ public int getStatus() { * @return */ public abstract String getType(); + + /** + * get the list of spleefers + * @return + */ + public abstract SpleeferList getSpleefers(); // read the configuration settings of this arena public abstract void defineSettings(ConfigurationSection conf); + /** + * call game ticker periodically + * @return + */ + public abstract void tick(); + + /** + * Player issues announce command + * @param player + * @return boolean successful? + */ + public abstract boolean announce(CommandSender sender); + /** * Player issues join command * @param player @@ -120,48 +148,92 @@ public int getStatus() { * @return boolean successful? */ public abstract boolean ready(Player player, boolean hitBlock); + + /** + * check whether a certain block may be broken + * => player has been checked before this, so this does only concern block breaks + * and interactions by spleefers + * @param block broken/interacted (on instant-break) by spleefer + * @param player - player or null for automatic changes (e.g. trackers) + * @return true, if block may be destroyed + */ + public abstract boolean checkMayBreakBlock(Block block, Player player); /** - * Return true, if game supports a "ready" players list. Override for your own inventions. + * Is this arena enabled? * @return */ - public boolean supportsReady() { - return supportsReady(false, false); + public abstract boolean isEnabled(); + + /** + * Arena contains active game? + * @return + */ + public boolean isActive() { + return this.status != STATUS_INACTIVE; } + /** + * is game joinable? + * @return true for joinable + */ + public boolean isJoinable() { + return this.status <= STATUS_READY; + } + + /** + * is game ready? + * @return true for game ready + */ + public boolean isReady() { + // game must be readied? + if (supportsReady()) + return this.status == STATUS_READY; + return this.status <= STATUS_READY; // without using ready, game is ready automatically + } + + /** + * is game in progress? + * @return true/false + */ + public boolean isInProgress() { + return this.status == STATUS_COUNTDOWN || this.status == STATUS_STARTED; + } + + /** + * has game started (not countdown)? + * @return true/false + */ + public boolean isInGame() { + return this.status == STATUS_STARTED; + } + + /** + * has game finished? + * @return true/false + */ + public boolean isFinished() { + return this.status == STATUS_FINISHED; + } + /** * Return true, if game supports a "ready" players list. Override for your own inventions. * @return */ - public boolean supportsCommandReady() { - return supportsReady(false, true); - } + public abstract boolean supportsReady(); /** * Return true, if game supports a "ready" players list. Override for your own inventions. * @return */ - public boolean supportsBlockReady() { - return supportsReady(true, false); - } - + public abstract boolean supportsCommandReady(); + /** - * Helper method to actually check useReady element - * @param noCommand - * @param noBlock + * Return true, if game supports a "ready" players list. Override for your own inventions. * @return */ - private boolean supportsReady(boolean noCommand, boolean noBlock) { - if (SimpleSpleef.getPlugin().getConfig().isBoolean("arenas." + getId() + ".useReady")) { - return SimpleSpleef.getPlugin().getConfig().getBoolean("arenas." + getId() + ".useReady", false); - } - if (SimpleSpleef.getPlugin().getConfig().isString("arenas." + getId() + ".useReady")) { - String ready = SimpleSpleef.getPlugin().getConfig().getString("arenas." + getId() + ".useReady"); - if (noCommand == false && ready.equalsIgnoreCase("command")) return true; - if (noBlock == false && ready.equalsIgnoreCase("block")) return true; - } - return false; - } + public abstract boolean supportsBlockReady(); + /** * Countdown started @@ -215,6 +287,12 @@ private boolean supportsReady(boolean noCommand, boolean noBlock) { * @return boolean */ public abstract boolean hasSpectator(Player player); + + /** + * Remove spectator from arena + * @return boolean + */ + public abstract boolean removeSpectator(Player player); /** * Called when a spleefer moves in this game @@ -272,6 +350,36 @@ private boolean supportsReady(boolean noCommand, boolean noBlock) { */ public abstract void onBlockPlace(BlockPlaceEvent event); + /** + * Called when a players food level changes + * @param event + */ + public abstract void onFoodLevelChange(FoodLevelChangeEvent event); + + /** + * Called when a player is damaged + * @param event + */ + public abstract void onEntityDamage(EntityDamageEvent event); + + /** + * Called when something explodes + * @param event + */ + public abstract void onEntityExplode(EntityExplodeEvent event); + + /** + * Called when a player teleports + * @param event + */ + public abstract void onPlayerTeleport(PlayerTeleportEvent event); + + /** + * Called when a player changes game mode + * @param event + */ + public abstract void onPlayerGameModeChange(PlayerGameModeChangeEvent event); + /** * Send a message to broadcast, or to players and spectators * @param message @@ -309,53 +417,71 @@ private boolean supportsReady(boolean noCommand, boolean noBlock) { * @return */ public abstract String getListOfSpectators(); - + /** - * is game joinable? - * @return true for joinable + * add a tracker + * @param tracker */ - public boolean isJoinable() { - return this.status <= STATUS_READY; - } + public abstract void addTracker(Tracker tracker); /** - * is game ready? - * @return true for game ready + * interrupt a tracker + * @param tracker */ - public boolean isReady() { - // game must be readied? - if (supportsReady()) - return this.status == STATUS_READY; - return this.status <= STATUS_READY; // without using ready, game is ready automatically - } + public abstract void interruptTracker(Tracker tracker); /** - * is game in progress? - * @return true/false + * interrupt all tracker + * @param tracker */ - public boolean isInProgress() { - return this.status == STATUS_COUNTDOWN || this.status == STATUS_STARTED; - } + public abstract void interruptAllTrackers(); /** - * has game started (not countdown)? - * @return true/false + * update a certain block location - notify trackers of this change + * @param block + * @param oldType - old type of block + * @param oldData - old data of block */ - public boolean isInGame() { - return this.status == STATUS_STARTED; - } + public abstract void trackersUpdateBlock(Block block, int oldType, byte oldData); + + /** + * Called by tick()-methods of trackers when they change a block, + * so other trackers can update their block database. + * @param block + * @param oldType - old type of block + * @param oldData - old data of block + * @param caller + */ + public abstract void notifyChangedBlock(Block block, int oldType, byte oldData, Tracker caller); /** - * cleaning routine called at end of game + * interrupt/end game */ - public abstract void clean(); - + public abstract boolean endGame(); + /** - * check whether a certain block may be broken - * => player has been checked before this, so this does only concern block breaks - * and interactions by spleefers - * @param block broken/interacted (on instant-break) by spleefer - * @return true, if block may be destroyed + * sends a list of players and spectators of a specific game to a sender + * @param sender + * @param game */ - public abstract boolean checkMayBreakBlock(Block block); + public void printGamePlayersAndSpectators(CommandSender sender) { + //TODO: info if there are no spleefers and spectators at all + + // list of spleefers and spectators + if (sender != null) { + String spleefers = getListOfSpleefers(); + if (spleefers != null) + sender.sendMessage(SimpleSpleef.ll("feedback.infoSpleefers", "[SPLEEFERS]", spleefers)); + if (supportsCommandReady()) { + System.out.println("Unready"); + String unready = getListOfUnreadySpleefers(); + if (unready != null) + sender.sendMessage(SimpleSpleef.ll("feedback.infoUnreadySpleefers", "[SPLEEFERS]", ChatColor.RED + unready)); + else if (getListOfUnreadySpleefers() != null) sender.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("feedback.infoAllReady")); + } + String spectators = getListOfSpectators(); + if (spectators != null) + sender.sendMessage(SimpleSpleef.ll("feedback.infoSpectators", "[SPECTATORS]", spectators)); + } + } } diff --git a/src/main/java/de/beimax/simplespleef/game/GameHandler.java b/src/main/java/de/beimax/simplespleef/game/GameHandler.java index 19bb774..159f0fe 100644 --- a/src/main/java/de/beimax/simplespleef/game/GameHandler.java +++ b/src/main/java/de/beimax/simplespleef/game/GameHandler.java @@ -16,24 +16,35 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ + package de.beimax.simplespleef.game; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.TreeMap; -import java.util.Map.Entry; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.block.Block; import org.bukkit.command.CommandSender; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.player.PlayerGameModeChangeEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.plugin.Plugin; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; @@ -41,334 +52,177 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion; import de.beimax.simplespleef.SimpleSpleef; -import de.beimax.simplespleef.util.Cuboid; -import de.beimax.simplespleef.util.CuboidImpl; -import de.beimax.simplespleef.util.CuboidWorldGuard; +import de.beimax.simplespleef.gamehelpers.Cuboid; +import de.beimax.simplespleef.gamehelpers.CuboidImpl; +import de.beimax.simplespleef.gamehelpers.CuboidWorldGuard; /** * @author mkalus - * Actual game handler - central part of the plugin + * */ -public class GameHandler { +public class GameHandler implements Listener, Runnable { /** * games array */ - private Game[] games; - - /** - * List of cuboids for arenas - help check arena protection - */ - private List arenaCubes; - - /** - * Constructor - * @param plugin reference to plugin - */ - public GameHandler() { - updateGameHandlerData(); - } - + private List games; + /** * Initialize game handler - mainly read arena cubes and update game data */ public void updateGameHandlerData() { - // define cubes as linked list - arenaCubes = new LinkedList(); - // get possible games - for (String game : getPossibleGames().keySet()) { - // game enabled? - if (!SimpleSpleef.getPlugin().getConfig().getBoolean("arenas." + game + ".enabled", false)) continue; - Cuboid cuboid = configToCuboid(game, "arena"); - if (cuboid != null) - arenaCubes.add(cuboid); // add to list - else - SimpleSpleef.log.warning("[SimpleSpleef] Unable to load coordinates of arena for arena " + game + ". Maybe the arena is not finished yet, or its world was deleted."); - } - } - - /** - * add a game - * @param game - * @return boolean if successful - */ - public boolean addGame(Game game) { - if (games == null) { - games = new Game[1]; - games[0] = game; - } else { - // copy array and add new game - Game[] newGames = new Game[games.length+1]; - for (int i = 0; i < games.length; i++) { - if (games[i] == game || games[i].getId().equals(game.getId())) return false; // one cannot add the same game twice - newGames[i] = games[i]; - } - games = newGames; - // add the new game, too - games[games.length-1] = game; + // recreate game list + games = new LinkedList(); + // cycle through config to get arenas + Set arenas = SimpleSpleef.getPlugin().getConfig().getConfigurationSection("arenas").getKeys(false); + for (String arena : arenas) { // have the game factory create game instances + String type = SimpleSpleef.getPlugin().getConfig().getString("arenas." + arena + ".type", "standard"); + Game game = GameFactory.createGame(type, arena); + // define configuration section for this game + game.defineSettings(SimpleSpleef.getPlugin().getConfig().getConfigurationSection("arenas." + game.getId())); + // add game to list + games.add(game); } - return true; } - + /** - * add a game by name - * @param type - * @return + * Heart of the game mechanic - the ticker */ - public boolean addGame(String type, String name) { - // let the factory handle the details - Game game = GameFactory.createGame(type, name); - if (game == null) return false; // no game created? - - return addGame(game); // add game + @Override + public void run() { + for (Game game : games) // cycle through games + game.tick(); // call tick } - + /** - * remove a game from the handler - * @param game - * @return + * get list of games + * @return List of games */ - public boolean removeGame(Game game) { - return removeGame(game.getId()); + public List getGames() { + // clone list + LinkedList games = new LinkedList(); + for (Game game : this.games) { + games.add(game); + } + return games; } /** - * remove a game from the handler (by name) - * @param game + * return game by name + * @param name of game * @return */ - public boolean removeGame(String game) { - if (games == null) return false; - // only one element left - if (games.length == 1) { - if (games[0].getId().equalsIgnoreCase(game)) { - games = null; - return true; - } - return false; - } - // reduce array - Game[] newGames = new Game[games.length-1]; - boolean found = false; - int pos = 0; - for (int i = 0; i < newGames.length; i++) { - if (games[i].getId().equalsIgnoreCase(game)) continue; - newGames[pos++] = games[i]; + public Game getGameByName(String name) { + for (Game game : games) { + if (game.getId().equalsIgnoreCase(name)) return game; } - if (found) games = newGames; - return found; - } - - /** - * check, if a certain running game name exists - * @param game name of game - * @return - */ - public boolean gameExists(String game) { - return getGameByName(game)==null?false:true; - } - - /** - * return running game by name - * @param game name of game - * @return - */ - public Game getGameByName(String game) { - // no games present - if (this.games == null) return null; - // try to find game - for (int i = 0; i < this.games.length; i++) - if (this.games[i].getId().equalsIgnoreCase(game)) - return this.games[i]; return null; } - + /** - * check, if a certain game type or name exists generally - * @param type + * check, if a certain game name exists + * @param name of game * @return */ - public boolean gameTypeOrNameExists(String type) { - Map arenas = getPossibleGames(); - if (arenas == null) return false; // none - unlikely, but possible... - // cycle through possible games - for (Entry arena: arenas.entrySet()) { - if (arena.getKey().equalsIgnoreCase(type)) return true; + public boolean gameExists(String name) { + for (Game game : games) { + if (game.getId().equalsIgnoreCase(name)) return true; } - return false; } - - /** - * returns type of arena from game name - * @param game - * @return - */ - public String gameNameToType(String game) { - return SimpleSpleef.getPlugin().getConfig().getString("arenas." + game + ".type", "standard"); - } /** - * Check if there are games on the server + * get the default arena name * @return */ - public boolean hasGames() { - return games != null; - } - - /** - * get list of games - * @return List of games - */ - public List getGames() { - LinkedList games = new LinkedList(); - if (this.games == null) return games; // no games present? - for (Game game : this.games) { - games.add(game); - } - return games; + public String getDefaultArena() { + return SimpleSpleef.getPlugin().getConfig().getString("settings.defaultArena", "default"); } /** - * get list of games - * @return List of games + * checks whether the player is part of a game or not + * @param player + * @return Game the player is part of or null, if not */ - public List getGameNames() { - LinkedList games = new LinkedList(); - if (this.games == null) return games; // no games present? - for (Game game : this.games) { - games.add(game.getName()); + public Game checkPlayerInGame(Player player) { + if (player == null) return null; // sanity check + for (Game checkGame : games) { + if (checkGame.hasPlayer(player)) return checkGame; } - return games; + return null; } /** - * get list of game ids - * @return List of games + * checks whether the player is watching a game or not + * @param player + * @return Game the player is part of or null, if not */ - public List getGameIds() { - LinkedList games = new LinkedList(); - if (this.games == null) return games; // no games present? - for (Game game : this.games) { - games.add(game.getId()); + public Game checkSpectatorInGame(Player player) { + if (player == null) return null; // sanity check + for (Game checkGame : games) { + if (checkGame.hasSpectator(player)) return checkGame; } - return games; + return null; } + /** - * get list of possible games - * @return Map of arena names with a boolean for active/passive - */ - public Map getPossibleGames() { - Map map = new TreeMap(); // sorting is maintained - // get arenas from config and check if they are enabled - Set arenas = SimpleSpleef.getPlugin().getConfig().getConfigurationSection("arenas").getKeys(false); - for (String arena : arenas) { - Boolean enabled = SimpleSpleef.getPlugin().getConfig().getBoolean("arenas." + arena + ".enabled", false); - map.put(arena, enabled); - } - return map; - } - - /** - * check, if arena has been disabled + * checks whether the player is either a spleefer or spectator of some game + * @param sender + * @param args * @param arena * @return */ - public boolean isArenaDisabled(String arena) { - arena = arena.toLowerCase(); - return !SimpleSpleef.getPlugin().getConfig().getBoolean("arenas." + arena + ".enabled", false); + public Game checkSpleeferOrSpectatorInGame(Player player) { + Game game = checkPlayerInGame(player); + if (game != null) return game; + game = checkSpectatorInGame(player); + return game; } - /** - * get the default arena name - * @return - */ - public String getDefaultArena() { - return SimpleSpleef.getPlugin().getConfig().getString("settings.defaultArena", "default"); - } - /** * try to announce a new game in an arena * @param sender - * @param arena + * @param game * @return announced game or null */ - public Game announce(CommandSender sender, String arena) { - Game game = getGameByName(arena); - // does the game exist already? - if (game != null) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.arenaExistsAlready", "[ARENA]", game.getName())); - return null; - } - // check if game is disabled - if (isArenaDisabled(arena)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.arenaDisabled", "[ARENA]", arena)); - return null; - } - game = createNewGame(arena); - // announce new game globally? - if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceGame", true)) - SimpleSpleef.getPlugin().getServer().broadcastMessage(ChatColor.GOLD + SimpleSpleef.getPlugin().ll("broadcasts.announce", "[PLAYER]", sender.getName(), "[ARENA]", game.getName())); - else - sender.sendMessage(ChatColor.GOLD + SimpleSpleef.getPlugin().ll("feedback.announce", "[ARENA]", game.getName())); - return game; + public void announce(CommandSender sender, Game game) { + game.announce(sender); } - + /** * try to join a game in an arena * @param sender - * @param arena + * @param game */ - public void join(CommandSender sender, String arena) { - arena = arena.toLowerCase(); - Game game = getGameByName(arena); + public void join(CommandSender sender, Game game) { Player player = (Player) sender; // cast to player - // does the game not exist? - if (game == null) { - // check if game is disabled - if (isArenaDisabled(arena)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.arenaDisabled", "[ARENA]", arena)); - return; - } - // do players have the right to join unstarted games? - if (SimpleSpleef.getPlugin().getConfig().getBoolean("arenas." + arena + ".announceOnJoin", true)) - game = announce(sender, arena); - else { // tell player that he may not announce game - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.announceBeforeJoin", "[ARENA]", arena)); - return; - } + // check, if player has already joined another game + Game checkDouble = checkPlayerInGame(player); + if (checkDouble != null && checkDouble != game) { // player already joined another arena? + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.joinDouble", "[ARENA]", checkDouble.getName())); + return; } - // player already joined another arena? - Game checkGame = checkPlayerInGame(player); - if (checkGame != null) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.joinDouble", "[ARENA]", checkGame.getName())); - return; - } else checkGame = null; - // ok, try to join the game itself... + + // join game - if something does not work as expected, return and ignore the rest if (!game.join(player)) return; - // now we announce the joining of the player... - String broadcastMessage = ChatColor.GREEN + SimpleSpleef.getPlugin().ll("broadcasts.join", "[PLAYER]", sender.getName(), "[ARENA]", game.getName()); - if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceJoin", true)) { // broadcast - SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); - } else { // player only - sender.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("feedback.join", "[ARENA]", game.getName())); - game.sendMessage(broadcastMessage, player); // notify players and spectators - } - } + // player already spectator in another arena? + checkDouble = checkSpectatorInGame(player); + if (checkDouble != null) // remove spectator from game on joining + checkDouble.removeSpectator(player); + } + /** * Attempt to join a team (spleefers only) * @param sender * @param team team name */ public void team(CommandSender sender, String team) { - // only senders in a game may start a game - Player player = (Player) sender; // cast to player - // find player in arena - Game checkGame = checkPlayerInGame(player); - if (checkGame != null) checkGame.team(player, team); - // sender not part of any game - else sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.teamNoGame")); + // find player's game + Game game = checkPlayerInGame((Player) sender); + if (game == null) + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.teamNoGame")); + else game.team((Player) sender, team); } /** @@ -376,163 +230,175 @@ public void team(CommandSender sender, String team) { * @param sender */ public void ready(CommandSender sender) { - // only senders in a game may start a game - Player player = (Player) sender; // cast to player - // find player in arena - Game checkGame = checkPlayerInGame(player); - if (checkGame != null) checkGame.ready(player, false); - // sender not part of any game - else sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.readyNoGame")); + // find player's game + Game game = checkPlayerInGame((Player) sender); + if (game == null) + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.readyNoGame")); + else game.ready((Player) sender, false); } - + /** * Attempt to start a game (spleefers only) * @param sender */ public void start(CommandSender sender) { - // only senders in a game may start a game - Player player = (Player) sender; // cast to player - // find player in arena - Game checkGame = checkPlayerInGame(player); - if (checkGame != null) { - String arena = checkGame.getId(); - //is config "spleeferStart" of arena is set to true? - isJoinable added to avoid error message and let game do this instead - if (checkGame.isReady() && !SimpleSpleef.getPlugin().getConfig().getBoolean("arenas." + arena + ".spleeferStart", true)) - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.startNoSpleefer", "[ARENA]", checkGame.getName())); - else // spleeferStart is true: attempt to start countdown - countdown(sender, arena); - return; - } - // sender not part of any game - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.start")); + // find player's game + Game game = checkPlayerInGame((Player) sender); + if (game == null) // sender not part of any game + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.start")); + else game.countdown(sender); } - + /** * Attempt to start countdown of a game * @param sender - * @param arena (may be null) + * @param game (may be null) */ - public void countdown(CommandSender sender, String arena) { - arena = arena.toLowerCase(); - Game game = getGameByName(arena); - // does the game not exist? - if (game == null) { - // check if game is disabled - if (isArenaDisabled(arena)) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.arenaDisabled", "[ARENA]", arena)); - return; - } - // game not announced yet... - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.noGameAnnounced", "[ARENA]", arena)); - return; - } + public void countdown(CommandSender sender, Game game) { // start countdown for game game.countdown(sender); } + /** * Attempt to leave a game (spleefers only) * @param sender */ public void leave(CommandSender sender) { - Player player; - try { - player = (Player) sender; // cast to player - } catch (Exception e) { // handle possible cast error - sender.sendMessage(ChatColor.DARK_RED + "Internal error while leaving game. CommandSender has to be player object if arena is null!"); - return; - } - if (player == null) { - sender.sendMessage(ChatColor.DARK_RED + "Internal error while leaving game. Player was null!"); - return; - } - // player part of an active game or he/she is a spectator? - Game game = checkPlayerInGame(player); - if (game == null) game = checkSpectatorInGame(player); - if (game != null) { - game.leave(player); - } else - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.leave")); + // find player's game + Game game = checkPlayerInGame((Player) sender); + if (game == null) // sender not part of any game + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.leave")); + else game.leave((Player) sender); } - + /** * Attempt to stop a game * @param sender */ public void stop(CommandSender sender) { - // only senders in a game may start a game - Player player = (Player) sender; // cast to player - // find player in arena - Game checkGame = checkPlayerInGame(player); - if (checkGame != null) { - checkGame.stop(player); // stop game - } else //print error, since player not part of a game - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.stopNoPlaying")); + // find player's game + Game game = checkPlayerInGame((Player) sender); + if (game == null) // sender not part of any game + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.stopNoPlaying")); + else game.stop((Player) sender); } - + /** * Attempt to delete a game * @param sender - * @param arena (may be null) - */ - public void delete(CommandSender sender, String arena) { - Game game; - // if arena is null, get it from sender - if (arena == null) { - Player player; - try { - player = (Player) sender; // cast to player - } catch (Exception e) { // handle possible cast error - sender.sendMessage(ChatColor.DARK_RED + "Internal error while deleting game. CommandSender has to be player object if arena is null!"); - return; - } - game = checkPlayerInGame(player); - if (game == null) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.deleteNoPlaying")); - return; - } - } else { // otherwise try to get arena by name - game = getGameByName(arena); - if (game == null) { // print error, arena was not found - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.unknownArena", "[ARENA]", arena)); - return; - } - } + * @param game (may be null) + */ + public void delete(CommandSender sender, Game game) { game.delete(sender); // delete game } - + /** * Attempt to watch a game * @param sender - * @param arena (may not be null) + * @param game (may not be null) */ - public void watch(CommandSender sender, String arena) { - Player player; - try { - player = (Player) sender; // cast to player - } catch (Exception e) { // handle possible cast error - sender.sendMessage(ChatColor.DARK_RED + "Internal error while deleting game. CommandSender has to be player object if arena is null!"); - return; - } + public void watch(CommandSender sender, Game game) { + // find player's game - check doubles + Game otherGame = checkPlayerInGame((Player) sender); // player part of an active game? - Game game = checkPlayerInGame(player); - if (game != null) { // part of a game - may not spectate - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.watchDouble", "[ARENA]", game.getName())); + if (otherGame != null) { // part of a game - may not spectate + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.watchDouble", "[ARENA]", game.getName())); return; } - if (!gameTypeOrNameExists(arena)) { // print error, arena was not found - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.unknownArena", "[ARENA]", arena)); - return; - } - Game activeGame = getGameByName(arena); - if (activeGame == null) { // game is not active - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.watchNoGame", "[ARENA]", arena)); - return; + game.watch((Player) sender); // attempt to watch game + } + + /** + * lists all the arenas in the game + * @param sender + */ + public void arenas(CommandSender sender) { + //TODO: info if there are no games at all + + // cycle through possible games + for (Game game: getGames()) { + // color and information on game + ChatColor color; + // name of arena + String fullName = game.getName(); // name of arena + String information; + if (game.isEnabled() == false) { + color = ChatColor.DARK_GRAY; // arena has been disabled in the the config + information = SimpleSpleef.ll("feedback.arenaDisabled"); + } else if (!game.isActive()) { + color = ChatColor.GRAY; // not an active game + information = null; // no information + } else { // is it an active game? + // game active or still joinable? + if (game.isJoinable() || game.isReady()) { + color = ChatColor.GREEN; // joinable + information = SimpleSpleef.ll("feedback.arenaJoinable"); + } + else { + color = ChatColor.LIGHT_PURPLE; // not joinable - because running + information = SimpleSpleef.ll("feedback.arenaInProgress"); + } + // ok, gather some more information on the game to display + information = information + " " + game.getNumberOfPlayers(); + } + // create feedback + StringBuilder builder = new StringBuilder(); + builder.append(color).append(game.getId()); + if (information != null) builder.append(ChatColor.GRAY).append(" - ").append(information); + if (fullName != null && !fullName.equalsIgnoreCase(game.getId())) + builder.append(ChatColor.GRAY).append(" (").append(fullName).append(')'); + sender.sendMessage(builder.toString()); } - // ok, player not in active game, game exists, let's watch! - activeGame.watch(player); // attempt to watch game } + /** + * Show information + * @param sender + * @param game + */ + public void info(CommandSender sender, Game game) { + //TODO: info if there are no games at all + + // ok, define information on arena and print it + sender.sendMessage(SimpleSpleef.ll("feedback.infoHeader", "[ARENA]", ChatColor.DARK_AQUA + game.getId())); + // full name of arena + sender.sendMessage(SimpleSpleef.ll("feedback.infoName", "[NAME]", ChatColor.DARK_AQUA + game.getName())); + // status of arena + String information; + ChatColor color; + if (game.isActive()) { // game running + if (game.isJoinable() || game.isReady()) { + information = SimpleSpleef.ll("feedback.arenaJoinable"); + color = ChatColor.GREEN; + } else { + information = SimpleSpleef.ll("feedback.arenaInProgress"); + color = ChatColor.LIGHT_PURPLE; + } + // ok, gather some more information on the game to display + information = information + " " + game.getNumberOfPlayers(); + } else if (game.isEnabled()) { + information = SimpleSpleef.ll("feedback.arenaOff"); + color = ChatColor.GRAY; + } else { + information = SimpleSpleef.ll("feedback.arenaDisabled"); + color = ChatColor.DARK_GRAY; + } + sender.sendMessage(SimpleSpleef.ll("feedback.infoStatus", "[STATUS]", color + information)); + // list of spleefers and spectators + game.printGamePlayersAndSpectators(sender); + } + + /** + * List spleefers in arena + * @param sender + * @param game + */ + public void list(CommandSender sender, Game game) { + // list of spleefers and spectators + game.printGamePlayersAndSpectators(sender); + } + /** * Attempt to teleport back to original position * @param sender @@ -542,7 +408,7 @@ public void back(CommandSender sender) { try { player = (Player) sender; // cast to player } catch (Exception e) { // handle possible cast error - sender.sendMessage(ChatColor.DARK_RED + "Internal error while deleting game. CommandSender has to be player object if arena is null!"); + sender.sendMessage(ChatColor.DARK_RED + "Internal error while issuing back command. CommandSender has to be player object if arena is null!"); return; } // check, if player is spleefer or spectator @@ -554,91 +420,13 @@ public void back(CommandSender sender) { Location originalLocation = SimpleSpleef.getOriginalPositionKeeper().getOriginalPosition(player); if (originalLocation != null) { player.teleport(originalLocation); - player.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("feedback.back")); + player.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("feedback.back")); } else { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.backNoLocation")); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.backNoLocation")); } } } - /** - * checks whether the player is part of a game or not - * @param player - * @return Game the player is part of or null, if not - */ - public Game checkPlayerInGame(Player player) { - if (player == null) return null; // sanity check - for (Game checkGame : getGames()) { - if (checkGame.hasPlayer(player)) return checkGame; - } - return null; - } - - /** - * checks whether the player is watching a game or not - * @param player - * @return Game the player is part of or null, if not - */ - public Game checkSpectatorInGame(Player player) { - if (player == null) return null; // sanity check - for (Game checkGame : getGames()) { - if (checkGame.hasSpectator(player)) return checkGame; - } - return null; - } - - /** - * helper to create new game and add it automatically to list - * @param arena - * @return new game added - */ - protected Game createNewGame(String arena) { - // get type of arena - String type = gameNameToType(arena); - Game game = GameFactory.createGame(type, arena); - // define configuration section for this game - game.defineSettings(SimpleSpleef.getPlugin().getConfig().getConfigurationSection("arenas." + game.getId())); - // add game to list - addGame(game); - // return newly created game - return game; - } - - /** - * check block breaks in- and outside of game - * @param event - */ - public void checkBlockBreak(BlockBreakEvent event) { - Player player = event.getPlayer(); - // check if player is a spleefer or not - Game game = checkPlayerInGame(player); - if (game != null) { // game is spleefer! - //send block break to game - game.onBlockBreak(event); - } else if (inProtectedArenaCube(event.getBlock())) { - // cancel event - event.setCancelled(true); - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.noDig")); - } - } - - /** - * check block placement in- and outside of game - * @param event - */ - public void checkBlockPlace(BlockPlaceEvent event) { - Player player = event.getPlayer(); - // check if player is a spleefer or not - Game game = checkPlayerInGame(player); - if (game != null) { // game is spleefer! - //send block place to game - game.onBlockPlace(event); - } else if (inProtectedArenaCube(event.getBlock())) { - // cancel event - event.setCancelled(true); - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.noPlacement")); - } - } /** * create a cuboid from a section @@ -687,58 +475,187 @@ public Cuboid configToCuboid(String arena, String section) { (firstX>secondX?firstX:secondX), (firstY>secondY?firstY:secondY), (firstZ>secondZ?firstZ:secondZ)); } } - + /** - * Check if a block is in protected arena - * @param block + * get a world guard instance if it exists - see http://wiki.sk89q.com/wiki/WorldGuard/Regions/API for source * @return */ - public boolean inProtectedArenaCube(Block block) { - if (arenaCubes == null) return false; - Location blockLoc = block.getLocation(); - // check position in each cube - for (Cuboid cuboid : arenaCubes) - if (cuboid.contains(blockLoc)) return true; // in protected cube! + private WorldGuardPlugin getWorldGuard() { + Plugin plugin = SimpleSpleef.getPlugin().getServer().getPluginManager().getPlugin("WorldGuard"); + + // WorldGuard may not be loaded + if (plugin == null || !(plugin instanceof WorldGuardPlugin)) { + return null; // Maybe you want throw an exception instead + } + + return (WorldGuardPlugin) plugin; + } + + + /** + * Catch block breaks + * @param event + */ + @EventHandler(priority = EventPriority.LOW) + public void onBlockBreak(BlockBreakEvent event) { + if (event.isCancelled()) return; - return false; + // pass event to games + for (Game game : games) { + game.onBlockBreak(event); + } } /** - * reload the configuration of the games + * Catch block placements + * @param event */ - public void reloadConfig() { - // update game handler data - updateGameHandlerData(); - // iterate through active games - for (Game game : getGames()) { - // redefine settings - game.defineSettings(SimpleSpleef.getPlugin().getConfig().getConfigurationSection("arenas." + game.getId())); + @EventHandler(priority = EventPriority.LOW) + public void onBlockPlace(BlockPlaceEvent event) { + if (event.isCancelled()) return; + + // pass event to games + for (Game game : games) { + game.onBlockPlace(event); + } + } + + /** + * @param event + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onEntityDeath(EntityDeathEvent event) { + if (!(event.getEntity() instanceof Player)) return; + + // pass event to games + for (Game game : games) { + game.onPlayerDeath((Player) event.getEntity()); + } + } + + /** + * @param event + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onFoodLevelChange(FoodLevelChangeEvent event) { + if (event.isCancelled() || !(event.getEntity() instanceof Player)) return; + + // pass event to games + for (Game game : games) { + game.onFoodLevelChange(event); + } + } + + /** + * @param event + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onEntityDamage(EntityDamageEvent event) { + if (event.isCancelled() || !(event.getEntity() instanceof Player)) return; + + // pass event to games + for (Game game : games) { + game.onEntityDamage(event); } } /** - * called by a game that has ended - * @param game + * @param event */ - public void gameOver(Game game) { - // call cleaning routine of game - game.clean(); - // remove game from active list - removeGame(game); + @EventHandler(priority = EventPriority.LOWEST) + public void onEntityExplode(EntityExplodeEvent event) { + if (event.isCancelled()) return; + + // pass event to games + for (Game game : games) { + game.onEntityExplode(event); + } } /** - * get a world guard instance if it exists - see http://wiki.sk89q.com/wiki/WorldGuard/Regions/API for source - * @return + * @param event */ - private WorldGuardPlugin getWorldGuard() { - Plugin plugin = SimpleSpleef.getPlugin().getServer().getPluginManager().getPlugin("WorldGuard"); - - // WorldGuard may not be loaded - if (plugin == null || !(plugin instanceof WorldGuardPlugin)) { - return null; // Maybe you want throw an exception instead - } - - return (WorldGuardPlugin) plugin; + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + // pass event to games + for (Game game : games) { + game.onPlayerJoin(event); + } + } + + /** + * @param event + */ + @EventHandler + public void onPlayerKick(PlayerKickEvent event) { + if (event.isCancelled()) return; + + // pass event to games + for (Game game : games) { + game.onPlayerKick(event); + } + } + + /** + * @param event + */ + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + // pass event to games + for (Game game : games) { + game.onPlayerQuit(event); + } + } + + /** + * @param event + */ + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + if (event.isCancelled()) return; + + // pass event to games + for (Game game : games) { + game.onPlayerMove(event); + } + } + + /** + * @param event + */ + @EventHandler(priority = EventPriority.LOW) + public void onPlayerInteract(PlayerInteractEvent event) { + if (event.isCancelled()) return; + + // pass event to games + for (Game game : games) { + game.onPlayerInteract(event); + } + } + + /** + * @param event + */ + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerTeleport(PlayerTeleportEvent event) { + if (event.isCancelled()) return; + + // pass event to games + for (Game game : games) { + game.onPlayerTeleport(event); + } + } + + /** + * @param event + */ + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerGameModeChange(PlayerGameModeChangeEvent event) { + if (event.isCancelled()) return; + + // pass event to games + for (Game game : games) { + game.onPlayerGameModeChange(event); + } } } diff --git a/src/main/java/de/beimax/simplespleef/game/GameStandard.java b/src/main/java/de/beimax/simplespleef/game/GameStandard.java index 5cb4810..d3474d4 100644 --- a/src/main/java/de/beimax/simplespleef/game/GameStandard.java +++ b/src/main/java/de/beimax/simplespleef/game/GameStandard.java @@ -16,9 +16,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ + package de.beimax.simplespleef.game; -import java.util.*; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; +import java.util.Set; import net.milkbowl.vault.economy.EconomyResponse; @@ -31,21 +37,40 @@ import org.bukkit.command.CommandSender; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; -import org.bukkit.event.block.*; -import org.bukkit.event.player.*; -import org.bukkit.inventory.*; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.player.PlayerGameModeChangeEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerKickEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; import de.beimax.simplespleef.SimpleSpleef; import de.beimax.simplespleef.game.arenarestoring.ArenaRestorer; import de.beimax.simplespleef.game.arenarestoring.HardArenaRestorer; import de.beimax.simplespleef.game.arenarestoring.SoftRestorer; -import de.beimax.simplespleef.game.floortracking.FloorWorker; -import de.beimax.simplespleef.game.floortracking.FloorTracker; -import de.beimax.simplespleef.util.*; +import de.beimax.simplespleef.game.trackers.Countdown; +import de.beimax.simplespleef.game.trackers.FloorDissolveWorker; +import de.beimax.simplespleef.game.trackers.FloorRepairWorker; +import de.beimax.simplespleef.game.trackers.PlayerOnBlockDegenerator; +import de.beimax.simplespleef.game.trackers.Tracker; +import de.beimax.simplespleef.gamehelpers.Cuboid; +import de.beimax.simplespleef.gamehelpers.InventoryKeeper; +import de.beimax.simplespleef.gamehelpers.MaterialHelper; +import de.beimax.simplespleef.gamehelpers.LocationHelper; /** * @author mkalus - * Simple Game implementation + * */ public class GameStandard extends Game { /** @@ -61,7 +86,7 @@ public class GameStandard extends Game { /** * Reference to spectators */ - protected LinkedList spectators; + protected List spectators; /** * Reference to configuration @@ -69,19 +94,14 @@ public class GameStandard extends Game { protected ConfigurationSection configuration; /** - * to make game faster: + * list of trackers called in each tick */ - protected Set loseOnTouchMaterial; + protected List trackers; /** - * private countdown class - */ - private Countdown countdown; - - /** - * Id of the countdown task + * to make game faster: */ - private int countdownId; + protected Set loseOnTouchMaterial; /** * list of players which may be teleported - used by teleportPlayer and playerMayTeleport @@ -113,21 +133,6 @@ public class GameStandard extends Game { */ protected InventoryKeeper inventoryKeeper; - /** - * block degenerator that keeps track of players standing on something, if needed - */ - protected PlayerOnBlockDegenerator playerOnBlockDegenerator; - - /** - * floor tracker - takes care of floor changes - */ - protected FloorTracker floorTracker; - - /** - * arena restorer for this game - */ - protected ArenaRestorer arenaRestorer; - /** * shortcuts for digging settings */ @@ -147,15 +152,14 @@ public class GameStandard extends Game { /** * Constructor - * @param gameHandler * @param name */ public GameStandard(String name) { super(name); this.spleefers = new SpleeferList(); this.spectators = new LinkedList(); - this.countdown = null; this.teleportOkList = new HashSet(); + this.trackers = new LinkedList(); } @Override @@ -171,10 +175,75 @@ public String getName() { public String getType() { return "standard"; } + + @Override + public SpleeferList getSpleefers() { + return spleefers; + } + + @Override + public void tick() { + if (!isEnabled() || !isActive()) return; //ignore disabled and inactive arenas + + // call trackers in each tick + for (Iterator iterator = trackers.iterator(); iterator.hasNext();) { + Tracker tracker = iterator.next(); + if (tracker.tick()) { // returned true - this means the tracker signalled its end - remove from list + iterator.remove(); // remove element + } + } + + //System.out.println(trackers.size()); + + // check game end and there are not open trackers any more + if (this.status == Game.STATUS_FINISHED && trackers.size() == 0) { + this.status = Game.STATUS_INACTIVE; // reset game to inactive status + renewTrackers(); // renew the trackers for the next game + } + } + + @Override + public void addTracker(Tracker tracker) { + if (!trackers.contains(tracker)) { // only add the same tracker once + trackers.add(tracker); + tracker.initialize(this); + } + } + + @Override + public void interruptTracker(Tracker tracker) { + if (trackers.contains(tracker)) + tracker.interrupt(); + } + + @Override + public void interruptAllTrackers() { + for (Tracker tracker : trackers) { + tracker.interrupt(); + } + } + + @Override + public void trackersUpdateBlock(Block block, int oldType, byte oldData) { + if (isEnabled() && isActive()) { // only call on active games + for(Tracker tracker : trackers) + tracker.updateBlock(block, oldType, oldData); + } + } + + @Override + public void notifyChangedBlock(Block block, int oldType, byte oldData, Tracker caller) { + if (isEnabled() && isActive()) { // only call on active games + for(Tracker tracker : trackers) + if (tracker != caller) // caller is not updated - has to do this itself - this avoids endless callbacks + tracker.updateBlock(block, oldType, oldData); + } + } @Override public void defineSettings(ConfigurationSection conf) { this.configuration = conf; + // define defaults/shortcuts if (conf.getBoolean("loseOnTouchBlocks", true)) { // is loseBlocks a valid list? @@ -189,6 +258,7 @@ public void defineSettings(ConfigurationSection conf) { if (this.loseOnTouchMaterial.size() == 0) this.loseOnTouchMaterial = null; //no } else this.loseOnTouchMaterial = null; //no } else this.loseOnTouchMaterial = null; // reset + // define arena, floor and lose cuboids arena = SimpleSpleef.getGameHandler().configToCuboid(getId(), "arena"); floor = SimpleSpleef.getGameHandler().configToCuboid(getId(), "floor"); @@ -221,74 +291,136 @@ public void defineSettings(ConfigurationSection conf) { else if (arena == null) diggingIfFloorUndefined = GameStandard.DIGGING_EVERYWHERE; else if (dig.equals("outsidearena")) diggingIfFloorUndefined = GameStandard.DIGGING_OUTSIDE_ARENA; else diggingIfFloorUndefined = GameStandard.DIGGING_IN_ARENA; - + // initialize inventory keeper if needed if (configuration.getBoolean("clearInventory", false)) this.inventoryKeeper = new InventoryKeeper(); else this.inventoryKeeper = null; // floor changes might be registered by the floor tracker - renewFloorTracker(); - - // block degeneration - renewPlayerOnBlockGenerator(); + renewTrackers(); //TODO: more definitions/shortcuts } - + /** - * renew the floor tracker + * renew the trackers */ - protected void renewFloorTracker() { + protected void renewTrackers() { + // renew the tracking list if needed + if (trackers.size() > 0) + trackers = new LinkedList(); + + // floor trackers that are only used with working floor if (floor != null) { - int arenaFloorDissolvesAfter = configuration.getInt("arenaFloorDissolvesAfter", -1); - int arenaFloorRepairsAfter = configuration.getInt("arenaFloorRepairsAfter", -1); - if (arenaFloorDissolvesAfter > -1 || arenaFloorRepairsAfter > -1) { - floorTracker = new FloorTracker(); - floorTracker.setArenaFloorDissolvesAfter(arenaFloorDissolvesAfter); - floorTracker.setArenaFloorRepairsAfter(arenaFloorRepairsAfter); - floorTracker.setArenaFloorDissolveTick(configuration.getInt("arenaFloorDissolveTick", 5)); - floorTracker.setArenaFloorRepairTick(configuration.getInt("arenaFloorRepairTick", 10)); - } else - floorTracker = null; // none is needed to track floor - } else floorTracker = null; // no floor, no floor tracker! + List diggableBlocks = floor.getDiggableBlocks(this); + + if (diggableBlocks != null) { + int arenaFloorDissolvesAfter = configuration.getInt("arenaFloorDissolvesAfter", -1); + if (arenaFloorDissolvesAfter > -1) { + addTracker(new FloorDissolveWorker(arenaFloorDissolvesAfter, configuration.getInt("arenaFloorDissolveTick", 5), diggableBlocks)); + } + int arenaFloorRepairsAfter = configuration.getInt("arenaFloorRepairsAfter", -1); + if (arenaFloorRepairsAfter > -1) { + addTracker(new FloorRepairWorker(arenaFloorRepairsAfter, configuration.getInt("arenaFloorRepairTick", 10), diggableBlocks)); + } + int blockDegeneration = configuration.getInt("blockDegeneration", -1); + if (blockDegeneration > -1) { + addTracker(new PlayerOnBlockDegenerator(blockDegeneration, configuration.getStringList("degeneratingBlocks"))); + } + } + } + + // determine type of arena + String type; + if (configuration.isBoolean("restoreArenaAfterGame")) type = "soft"; + else if (configuration.isString("restoreArenaAfterGame")) type = configuration.getString("restoreArenaAfterGame"); + else type = "soft"; // fall back + + ArenaRestorer arenaRestorer = null; + if (type.equals("arenahard")) { // hard arena restorer + arenaRestorer = new HardArenaRestorer(configuration.getInt("restoreArenaAfterGameTimer", 0)); + arenaRestorer.setArena(arena); + } else if (type.equals("floorhard")) { // hard floor restorer + arenaRestorer = new HardArenaRestorer(configuration.getInt("restoreArenaAfterGameTimer", 0)); + arenaRestorer.setArena(floor); + } else { // soft restorer + Cuboid possibleFloor = floor==null?arena:floor; + if (possibleFloor == null) { + arenaRestorer = null; + return; // freestyle spleefing does not implement any floor + // TODO: we could relax this, though... + } + + // create soft restorer + arenaRestorer = new SoftRestorer(configuration.getInt("restoreArenaAfterGameTimer", 0)); + arenaRestorer.setArena(possibleFloor); + } + if (arenaRestorer != null) + addTracker(arenaRestorer); } - /** - * renew the block degenerator for players - */ - protected void renewPlayerOnBlockGenerator() { - if (configuration == null) playerOnBlockDegenerator = null; // fix NPE + @Override + public boolean announce(CommandSender sender) { + // prechecks + if (preCheckArenaActive(sender)) return false; + if (preCheckArenaDisabled(sender)) return false; + + // activate game + this.status = Game.STATUS_READY; - int blockDegeneration = configuration .getInt("blockDegeneration", -1); - if (blockDegeneration >= 0) playerOnBlockDegenerator = new PlayerOnBlockDegenerator(blockDegeneration, configuration.getStringList("degeneratingBlocks"), floorTracker); - else playerOnBlockDegenerator = null; + // announce new game globally? + if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceGame", true)) + SimpleSpleef.getPlugin().getServer().broadcastMessage(ChatColor.GOLD + SimpleSpleef.ll("broadcasts.announce", "[PLAYER]", sender.getName(), "[ARENA]", getName())); + else + sender.sendMessage(ChatColor.GOLD + SimpleSpleef.ll("feedback.announce", "[ARENA]", getName())); + + return true; } - + @Override public boolean join(Player player) { - //check joinable status + // prechecks + if (preCheckArenaDisabled(player)) return false; + // announce before join activated for new game? + if (!isActive()) { + if (configuration.getBoolean("announceOnJoin", true)) + announce(player); // announce game, too + else { // tell player that he/she may not announce game + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.announceBeforeJoin", "[ARENA]", getName())); + return false; + } + } + + // game is not joinable any more? if (!isJoinable()) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.join", "[ARENA]", getName())); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.join", "[ARENA]", getName())); + return false; + } + + // has player already joined this game? + if (hasPlayer(player)) { + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.joinDouble", "[ARENA]", getName())); return false; } + // max number of players? int maximumPlayers = configuration.getInt("maximumPlayers", 0); if (spleefers == null) spleefers = new SpleeferList(); //restore spleefers list if it was null for some reason - strange that this would happen... if (maximumPlayers > 0 && spleefers.size() >= maximumPlayers) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.joinMax", "[ARENA]", getName(), "[NUMBER]", String.valueOf(maximumPlayers))); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.joinMax", "[ARENA]", getName(), "[NUMBER]", String.valueOf(maximumPlayers))); return false; } - // already joined this game? => is caught by GameHandler, so we do not check this here... + // check funds of player... if (SimpleSpleef.economy != null) { double entryFee = configuration.getDouble("entryFee", 0.0); if (entryFee > 0.0) { EconomyResponse response = SimpleSpleef.economy.withdrawPlayer(player.getName(), entryFee); if (response.type == EconomyResponse.ResponseType.SUCCESS) { // ok, tell the player about the amount charged - player.sendMessage(SimpleSpleef.getPlugin().ll("feedback.joinFee", "[AMOUNT]", SimpleSpleef.economy.format(entryFee))); + player.sendMessage(SimpleSpleef.ll("feedback.joinFee", "[AMOUNT]", SimpleSpleef.economy.format(entryFee))); } else { //insufficient funds - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.joinFee", "[AMOUNT]", SimpleSpleef.economy.format(entryFee))); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.joinFee", "[AMOUNT]", SimpleSpleef.economy.format(entryFee))); return false; } // ok, is a part of the fee paid to a player? @@ -297,78 +429,37 @@ public boolean join(Player player) { SimpleSpleef.economy.depositPlayer(playerNameGettingFees, configuration.getDouble("entryFeeAmountToPlayer", entryFee)); } } + // check gamemode and change it if needed if (player.getGameMode() != GameMode.SURVIVAL) { player.setGameMode(GameMode.SURVIVAL); - player.sendMessage(ChatColor.YELLOW + SimpleSpleef.getPlugin().ll("feedback.gamemodeChanged")); + player.sendMessage(ChatColor.YELLOW + SimpleSpleef.ll("feedback.gamemodeChanged")); } + + // actually add player if (!spleefers.addSpleefer(player)) { // some weird error player.sendMessage(ChatColor.DARK_RED + "Internal error while joining occured! Please tell the SimpleSpleef creator!"); return false; } - // unready game, if needed + + // unready game, if needed - this is needed because the game can have the status "ready", if all players are ready, but it has not started if (supportsReady()) { this.status = Game.STATUS_NEW; } - // remove from spectators, if needed - unwatch(player); - // inform/broadcast join is done by the game handler + // remember player's last position if (configuration.getBoolean("enableBackCommand", true)) SimpleSpleef.getOriginalPositionKeeper().keepPosition(player); // teleport player to lounge teleportPlayer(player, "lounge"); - return true; - } - @Override - public boolean leave(Player player) { - // is the player a spectator? - if (spectators != null && spectators.contains(player)) { - return back(player); // redirect to back command instead - } - // check, if player is not a spleefer - if (!spleefers.hasSpleefer(player)) { - player.sendMessage(ChatColor.DARK_RED + "Internal error while leave occured! Please tell the SimpleSpleef creator!"); - return false; - } - // inform player - player.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("feedback.leave")); - // broadcast message of somebody loosing - String broadcastMessage = ChatColor.DARK_PURPLE + SimpleSpleef.getPlugin().ll("broadcasts.leave", "[PLAYER]", player.getDisplayName(), "[ARENA]", getName()); - if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceJoin", true)) { - SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message - } else { - // send message to all receivers - sendMessage(broadcastMessage, player); - } - // if degeneration keeper is on, delete player from list - if (playerOnBlockDegenerator != null) playerOnBlockDegenerator.removePlayer(player); - // teleport him/her back to original position, if supported - if (configuration.getBoolean("enableBackCommand", true)) { - // get original position - Location originalLocation = SimpleSpleef.getOriginalPositionKeeper().getOriginalPosition(player); - if (originalLocation == null) { // no position - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.backNoLocation")); - return false; - } - // add player to teleport ok list - this.teleportOkList.add(player); - // teleport player to original position - player.teleport(originalLocation); - player.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("feedback.back")); - } - // check game status - if (isJoinable() || isReady()) { //still joinable or ready state - not so bad! - // just remove spleefer - spleefers.removeSpleefer(player); - } else if (countdown != null) { // during countdown - end the game... - // set player to lost, so that the player is not teleported twice - spleefers.setLost(player); - endGame(); // actually end the game - } else { // game is in progress - player loses - simple as that - // player loses - playerLoses(player, false); // do not teleport leaving players... + // now we announce the joining of the player... + String broadcastMessage = ChatColor.GREEN + SimpleSpleef.ll("broadcasts.join", "[PLAYER]", player.getName(), "[ARENA]", getName()); + if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceJoin", true)) { // broadcast + SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); + } else { // player only + player.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("feedback.join", "[ARENA]", getName())); + sendMessage(broadcastMessage, player); // notify players and spectators } return true; } @@ -376,103 +467,114 @@ public boolean leave(Player player) { @Override public boolean team(Player player, String team) { // no team games possible in this arena - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.teamNotPossible", "[ARENA]", getName())); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.teamNotPossible", "[ARENA]", getName())); return false; } @Override public boolean ready(Player player, boolean hitBlock) { - // game started already? - if (isInProgress() || countdown != null) { // avoid possible memory leak - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.readyAlreadyStarted", "[ARENA]", getName())); - return false; - } // readying is not used in this game if (!supportsReady()) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.readyNotUsed", "[ARENA]", getName())); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.readyNotUsed", "[ARENA]", getName())); + return false; + } + + // game started already? + if (!isJoinable()) { // avoid possible memory leak + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.readyAlreadyStarted", "[ARENA]", getName())); return false; } + // right command? if (!hitBlock && !supportsCommandReady()) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.readyBlock", "[ARENA]", getName())); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.readyBlock", "[ARENA]", getName())); return false; } + // get spleefer Spleefer spleefer = spleefers.getSpleefer(player); if (spleefer == null) { // internal error player.sendMessage(ChatColor.DARK_RED + "Internal error: Player " + player.getName() + " should be in spleefers list, but isn't!"); return false; } + // player already ready? if (spleefer.isReady()) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.readyAlready", "[ARENA]", getName())); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.readyAlready", "[ARENA]", getName())); return false; } + // ok, ready player now spleefer.setReady(true); - player.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("feedback.ready", "[ARENA]", getName(), "[PLAYER]", player.getDisplayName())); + + // send messages + player.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("feedback.ready", "[ARENA]", getName(), "[PLAYER]", player.getDisplayName())); // broadcast message of somebody readying - String broadcastMessage = ChatColor.DARK_PURPLE + SimpleSpleef.getPlugin().ll("broadcasts.ready", "[PLAYER]", player.getDisplayName(), "[ARENA]", getName()); + String broadcastMessage = ChatColor.DARK_PURPLE + SimpleSpleef.ll("broadcasts.ready", "[PLAYER]", player.getDisplayName(), "[ARENA]", getName()); if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceReady", false)) { SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message } else { // send message to all receivers sendMessage(broadcastMessage, player); } + // is the game ready? checkReadyAndStartGame(); return true; } - /** - * check the readiness status of a game and possibly start it - */ - protected void checkReadyAndStartGame() { - if (spleefers.countUnreadyPlayers() == 0) { - // autostart game once all are ready - if (configuration.getBoolean("readyAutoStart", false)) { - // test for minumum players - int minimumPlayers = configuration.getInt("minimumPlayers", 0); - if (minimumPlayers > 0 && spleefers.size() < minimumPlayers) { - // wait for more players to join and ready - sendMessage(SimpleSpleef.getPlugin().ll("broadcasts.ready", "[NUMBER]", String.valueOf(spleefers.size() - minimumPlayers)), false); - this.status = Game.STATUS_READY; - } - else startGameOrCountdown(); // start game right away - } - // otherwise, just set game as ready - else this.status = Game.STATUS_READY; - } - } - @Override public boolean countdown(CommandSender sender) { // game started already? - if (isInProgress() || countdown != null) { // avoid possible memory leak - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.startDouble", "[ARENA]", getName())); + if (!isJoinable()) { // avoid possible memory leak + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.startDouble", "[ARENA]", getName())); return false; } + // minimum number of players? int minimumPlayers = configuration.getInt("minimumPlayers", 0); if (minimumPlayers > 0 && spleefers.size() < minimumPlayers) { - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.startMin", "[ARENA]", getName(), "[NUMBER]", String.valueOf(minimumPlayers))); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.startMin", "[ARENA]", getName(), "[NUMBER]", String.valueOf(minimumPlayers))); return false; } + // game is not ready yet? if (!isReady()) { //get list of unready spleefers String unreadyList = getListOfUnreadySpleefers(); if (unreadyList == null) unreadyList = "---"; // in any case... // send error message to player - sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.startNotReady", "[ARENA]", getName(), "[PLAYERS]", unreadyList)); + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.startNotReady", "[ARENA]", getName(), "[PLAYERS]", unreadyList)); return false; } + // start game or countdown startGameOrCountdown(); return true; } - + + /** + * check the readiness status of a game and possibly start it + */ + protected void checkReadyAndStartGame() { + if (spleefers.countUnreadyPlayers() == 0) { + // autostart game once all are ready + if (configuration.getBoolean("readyAutoStart", false)) { + // test for minumum players + int minimumPlayers = configuration.getInt("minimumPlayers", 0); + if (minimumPlayers > 0 && spleefers.size() < minimumPlayers) { + // wait for more players to join and ready + sendMessage(SimpleSpleef.ll("broadcasts.ready", "[NUMBER]", String.valueOf(spleefers.size() - minimumPlayers)), false); + this.status = Game.STATUS_READY; + } + else startGameOrCountdown(); // start game right away + } + // otherwise, just set game as ready + else this.status = Game.STATUS_READY; + } + } + /** * helper to start game or countdown - used by ready and countdown methods */ @@ -480,110 +582,120 @@ private void startGameOrCountdown() { // teleport players to arena teleportPlayersAtGameStart(); // start countdown, if setting is 0 or higher - if (configuration.getInt("countdownFrom", 10) == 0) { + int countdown = configuration.getInt("countdownFrom", 10); + if (countdown == 0) { start(); // if countdown is null, start game right away } else { - // create countdown and start it - countdown = new Countdown(); - countdownId = SimpleSpleef.getPlugin().getServer().getScheduler().scheduleAsyncRepeatingTask(SimpleSpleef.getPlugin(), countdown, 0L, 20L); + // initiate countdown - tick() will do the rest + this.status = Game.STATUS_COUNTDOWN; + addTracker(new Countdown(countdown)); // add countdown tracker + } + } + + /** + * teleport players to arena + */ + protected void teleportPlayersAtGameStart() { + for (Spleefer spleefer : spleefers.get()) { + teleportPlayer(spleefer.getPlayer(), "game"); } } @Override public boolean start() { - // delete countdown - deleteCountdown(); // change game status status = STATUS_STARTED; - // save arena information - saveArena(); - // start floor tracker, if needed - if (floorTracker != null) - floorTracker.startTracking(this, floor); - // start degenerator if needed - if (playerOnBlockDegenerator != null) - playerOnBlockDegenerator.startBlockDegenerator(); + // possibly clear inventory clearInventories(); + // optionally add to inventory addToInventories(); + // and/or give shovels addShovelItems(); + return true; } - + @Override - public boolean stop(Player player) { - // game is not in progress! - if (!isInProgress()) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.stop", "[ARENA]", getName())); + public boolean leave(Player player) { + // is the player a spectator? + if (hasSpectator(player)) { + return back(player); // redirect to back command instead + } + + // check, if player is not a spleefer + if (!spleefers.hasSpleefer(player)) { + player.sendMessage(ChatColor.DARK_RED + "Internal error while leave occured! Please tell the SimpleSpleef creator!"); return false; } - // actually end the game - if (!endGame()) return false; - // send message - sendMessage(SimpleSpleef.getPlugin().ll("feedback.stop", "[ARENA]", getName(), "[PLAYER]", player.getDisplayName()), - SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceStop", true)); - return true; - } - - - @Override - public boolean delete(CommandSender sender) { - // end the game first, if game is started - if (!endGame()) return false; - // send message - sendMessage(SimpleSpleef.getPlugin().ll("feedback.delete", "[ARENA]", getName(), "[PLAYER]", sender.getName()), - SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceStop", true)); - // call the game handler to tell it that the game is over - only if game status has been reset - if (status == STATUS_NEW) SimpleSpleef.getGameHandler().gameOver(this); - return true; - } - - /** - * Do end game maintenance - * @return - */ - protected boolean endGame() { - //check what the current status is and end game then - boolean wasInProgress = isInProgress(); - //isJoinable() - //isReady() - // + other cases? - - // still in countdown? if yes, kill it! - if (countdown != null) - countdown.interrupted = true; - - // if floor tracker is on, delete it and renew it - if (floorTracker != null) - floorTracker.stopTracking(); - renewFloorTracker(); // renew the tracker + + // inform player + player.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("feedback.leave")); + // broadcast message of somebody loosing + String broadcastMessage = ChatColor.DARK_PURPLE + SimpleSpleef.ll("broadcasts.leave", "[PLAYER]", player.getDisplayName(), "[ARENA]", getName()); + if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceJoin", true)) { + SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message + } else { + // send message to all receivers + sendMessage(broadcastMessage, player); + } + + // teleport him/her back to original position, if supported + if (configuration.getBoolean("enableBackCommand", true)) { + // get original position + Location originalLocation = SimpleSpleef.getOriginalPositionKeeper().getOriginalPosition(player); + if (originalLocation == null) { // no position + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.backNoLocation")); + return false; + } + // add player to teleport ok list + this.teleportOkList.add(player); + // teleport player to original position + player.teleport(originalLocation); + player.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("feedback.back")); + } + + // check game status + if (isJoinable() || isReady() || isFinished()) { //still joinable or ready or finished state - not so bad! + // just remove spleefer + spleefers.removeSpleefer(player); + } else if (status == Game.STATUS_COUNTDOWN) { // during countdown - end the game... + // set player to lost, so that the player is not teleported twice + spleefers.setLost(player); + endGame(); // actually end the game + } else { // game is in progress - player loses - simple as that + // player loses + playerLoses(player, false); // do not teleport leaving players... + } + return true; + } - // if degeneration keeper is on, delete and renew it - if (playerOnBlockDegenerator != null) - playerOnBlockDegenerator.stopBlockDegenerator(); - renewPlayerOnBlockGenerator(); // renew the degenerator + @Override + public boolean stop(Player player) { + // game is not in progress! + if (!isInProgress()) { + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.stop", "[ARENA]", getName())); + return false; + } - // change game status - status = STATUS_FINISHED; + // actually end the game + if (!endGame()) return false; - // only do this when game was in progress - if (wasInProgress) { - // possibly take away shovel items - removeShovelItems(); - // possibly restore inventories - restoreAllInventories(); - // teleport remaining players to lounge - for (Spleefer spleefer : spleefers.get()) { - if (!spleefer.hasLost()) - teleportPlayer(spleefer.getPlayer(), "lounge"); - } - // restore arena - restoreArena(); // this will also eventually reset the game status and call the game handler - } else - // change game status - status = STATUS_NEW; + // send message + sendMessage(SimpleSpleef.ll("feedback.stop", "[ARENA]", getName(), "[PLAYER]", player.getDisplayName()), + SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceStop", true)); + return true; + } + + @Override + public boolean delete(CommandSender sender) { + // end the game first, if game is started + if (!endGame()) return false; + // send message + sendMessage(SimpleSpleef.ll("feedback.delete", "[ARENA]", getName(), "[PLAYER]", sender.getName()), + SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceStop", true)); return true; } @@ -591,215 +703,148 @@ protected boolean endGame() { public boolean watch(Player player) { // check, if player is spleefer if (spleefers.hasSpleefer(player)) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.watchSpleefer", "[ARENA]", getName())); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.watchSpleefer", "[ARENA]", getName())); return false; } + // check, if player is in spectator list already if (spectators.contains(player)) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.watchAlready", "[ARENA]", getName())); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.watchAlready", "[ARENA]", getName())); return false; } + // check, if we have a spectator spawn defined if (!configuration.isConfigurationSection("spectatorSpawn") || !configuration.getBoolean("spectatorSpawn.enabled", false)) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.watchNoSpawnDefined", "[ARENA]", getName())); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.watchNoSpawnDefined", "[ARENA]", getName())); return false; } + // save spectator's original position if (configuration.getBoolean("enableBackCommand", true)) SimpleSpleef.getOriginalPositionKeeper().keepPosition(player); + // teleport spectator Location teleportTo = LocationHelper.configToExactLocation(configuration.getConfigurationSection("spectatorSpawn")); player.teleport(teleportTo); + // add to spectator list spectators.add(player); + // send message to player - player.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("feedback.watch", "[ARENA]", getName())); + player.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("feedback.watch", "[ARENA]", getName())); return true; } - + @Override public boolean back(Player player) { // not allowed if (!configuration.getBoolean("enableBackCommand", true)) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.commandNotAllowed", "[ARENA]", getName())); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.commandNotAllowed", "[ARENA]", getName())); return false; } + // check, if player is spleefer if (spleefers.hasSpleefer(player)) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.backSpleefer", "[ARENA]", getName())); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.backSpleefer", "[ARENA]", getName())); return false; } + // check, if player is not a spectator if (spectators == null || !spectators.contains(player)) { player.sendMessage(ChatColor.DARK_RED + "Internal error while back occured! Please tell the SimpleSpleef creator!"); return false; } + // get original position Location originalLocation = SimpleSpleef.getOriginalPositionKeeper().getOriginalPosition(player); if (originalLocation == null) { // no position - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.backNoLocation")); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.backNoLocation")); return false; } + // remove player from watch list - unwatch(player); + removeSpectator(player); // teleport player to original position player.teleport(originalLocation); - player.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("feedback.back")); - return true; - } - - /** - * Helper method to remove player from spectator list - * @param player - * @return - */ - protected boolean unwatch(Player player) { - // check if player is in specator list - if (!spectators.contains(player)) return false; - // remove from spectator list - spectators.remove(player); + + player.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("feedback.back")); return true; } @Override - public boolean hasPlayer(Player player) { - if (spleefers == null || player == null) return false; - return spleefers.hasSpleefer(player); - } - - @Override - public boolean hasSpectator(Player player) { - if (spectators == null) return false; - return spectators.contains(player); + public void onPlayerQuit(PlayerQuitEvent event) { + if (!isEnabled() || !hasPlayer(event.getPlayer())) return; // ignore disabled arenas and if player not here + + // call helper method + loseOnQuitOrKick(event.getPlayer()); } - /** - * only delete countdown - */ - protected void deleteCountdown() { - countdown = null; + @Override + public void onPlayerKick(PlayerKickEvent event) { + if (!isEnabled()) return; // ignore disabled arenas + + // in game? + if (hasPlayer(event.getPlayer())) { + // call helper method + loseOnQuitOrKick(event.getPlayer()); + } + + // delete original position, because player is banned anyhow + SimpleSpleef.getOriginalPositionKeeper().deleteOriginalPosition(event.getPlayer()); } /** - * Send a message to broadcast, or to players and spectators - * @param message - * @param broadcast + * helper method for onPlayerQuit and onPlayerKick + * @param player */ - public void sendMessage(String message, boolean broadcast) { - if (message == null) { - SimpleSpleef.log.warning("[SimpleSpleef] Message was null and could not be broadcasted!"); - return; - } - // global broadcast - if (broadcast) SimpleSpleef.getPlugin().getServer().broadcastMessage(message); - else { // only players and specators - // players - for (Spleefer spleefer : spleefers.get()) { - spleefer.getPlayer().sendMessage(message); - } - // spectators - for (Player player : this.spectators) { - player.sendMessage(message); + protected void loseOnQuitOrKick(Player player) { + if (configuration.getBoolean("loseOnLogout", true)) { + // broadcast message of somebody loosing + String broadcastMessage = ChatColor.GREEN + SimpleSpleef.ll("broadcasts.lostByQuitting", "[PLAYER]", player.getName(), "[ARENA]", getName()); + if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceLose", true)) { + SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message + } else { + // send message to all receivers + sendMessage(broadcastMessage, player); } - // send to console, too - SimpleSpleef.log.info(message); - } - } - - @Override - public String getNumberOfPlayers() { - // no spleefers - return empty string - if (spleefers == null || spleefers.size() == 0) return ""; - - int active; - int max; - // shows information depending on state - if (isInProgress()) { - active = spleefers.inGame(); - max = spleefers.size(); - } else { // joinable -> show number of players joined, open places - active = spleefers.size(); - max = configuration.getInt("maximumPlayers", 0); - } - return "(" + active + "/" + (max>0?max:"-") + ")"; + // player loses, if set to true + playerLoses(player, false); // do not teleport dead players... + } // else - do nothing... } @Override - public String getListOfSpleefers() { - // no spleefers - return null - if (spleefers == null || spleefers.size() == 0) return null; - // create list of spleefers - String comma = SimpleSpleef.getPlugin().ll("feedback.infoComma"); - StringBuilder builder = new StringBuilder(); - int i = 0; - for (Spleefer spleefer : spleefers.get()) { - if (i > 0 && i == spleefers.size() - 1) builder.append(SimpleSpleef.getPlugin().ll("feedback.infoAnd")); // last element with end - else if (i > 0) builder.append(comma); // other elements with , - // lost or in game? - if (spleefer.hasLost()) builder.append(ChatColor.RED); - else builder.append(ChatColor.GREEN); - builder.append(spleefer.getPlayer().getDisplayName()); - builder.append(ChatColor.GRAY); - i++; - } - return builder.toString(); - } + public void onPlayerJoin(PlayerJoinEvent event) { + if (!isEnabled()) return; // ignore disabled arenas - @Override - public String getListOfSpectators() { - // no spectators - return null - if (spectators == null || spectators.size() == 0) return null; - // create list of spectators - String comma = SimpleSpleef.getPlugin().ll("feedback.infoComma"); - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < spectators.size(); i++) { - if (i > 0 && i == spectators.size() - 1) builder.append(SimpleSpleef.getPlugin().ll("feedback.infoAnd")); // last element with end - else if (i > 0) builder.append(comma); // other elements with , - builder.append(spectators.get(i).getDisplayName()); - } - return builder.toString(); + // right now, do nothing... later on maybe give shovel back or so (if it has been taken away before the game ended - that gets complicated...) } - + @Override - public String getListOfUnreadySpleefers() { - // no spleefers - return null - if (spleefers == null || spleefers.size() == 0) return null; - // get unready spleefers - LinkedList list = new LinkedList(); - for (Spleefer spleefer : spleefers.get()) { - if (!spleefer.isReady()) list.add(spleefer); - } - // is the list empty? - if (list.size() == 0) return null; // no unready spleefes - // compile list - return SpleeferList.getPrintablePlayerList(list); - } + public void onPlayerDeath(Player player) { + if (!isEnabled()) return; // ignore disabled arenas + + // delete original position, because player spawns somewhere else anyhow + SimpleSpleef.getOriginalPositionKeeper().deleteOriginalPosition(player); - /** - * Send a message to broadcast, or to players and spectators - * @param message - * @param exception exception - this player does not receive message - */ - public void sendMessage(String message, Player exception) { - // players - for (Spleefer spleefer : spleefers.get()) { - if (exception != spleefer.getPlayer()) - spleefer.getPlayer().sendMessage(message); - } - // spectators - for (Player player : this.spectators) { - if (exception != player) - player.sendMessage(message); - } - // send to console, too - SimpleSpleef.log.info(message); + if (configuration.getBoolean("loseOnDeath", true)) { + // broadcast message of somebody loosing + String broadcastMessage = ChatColor.GREEN + SimpleSpleef.ll("broadcasts.lostByDeath", "[PLAYER]", player.getName(), "[ARENA]", getName()); + if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceLose", true)) { + SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message + } else { + // send message to all receivers + sendMessage(broadcastMessage, player); + } + // player loses, if set to true + playerLoses(player, false); // do not teleport dead players... + } // else - do nothing... } - @Override public void onPlayerMove(PlayerMoveEvent event) { + if (!isEnabled()) return; // ignore disabled arenas Player player = event.getPlayer(); - if (!isInGame() || spleefers.hasLost(player)) return; // if game is not in progress or player has lost, return + if (!hasPlayer(player) || !isInGame() || spleefers.hasLost(player)) return; // if not in game or game is not in progress or player has lost, return //player touched certain block (setting loseOnTouchBlocks) if (loseOnTouchMaterial != null) { @@ -814,10 +859,10 @@ public void onPlayerMove(PlayerMoveEvent event) { if (lostByTouching) blockName = touchedBlock.name(); else blockName = onBlock.name(); // translate block name - String translatedBlockName = SimpleSpleef.getPlugin().ll("material." + blockName); + String translatedBlockName = SimpleSpleef.ll("material." + blockName); if (translatedBlockName != null) blockName = translatedBlockName; // broadcast message of somebody loosing - String broadcastMessage = ChatColor.GREEN + SimpleSpleef.getPlugin().ll("broadcasts.lostByTouching", "[PLAYER]", player.getName(), "[ARENA]", getName(), "[MATERIAL]", blockName); + String broadcastMessage = ChatColor.GREEN + SimpleSpleef.ll("broadcasts.lostByTouching", "[PLAYER]", player.getName(), "[ARENA]", getName(), "[MATERIAL]", blockName); if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceLose", true)) { SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message } else { @@ -829,11 +874,11 @@ public void onPlayerMove(PlayerMoveEvent event) { return; } } - + // check location within "lose" cuboid (setting lose) if (lose != null && lose.contains(player.getLocation())) { // broadcast message of somebody loosing - String broadcastMessage = ChatColor.GREEN + SimpleSpleef.getPlugin().ll("broadcasts.lostByCuboid", "[PLAYER]", player.getName(), "[ARENA]", getName()); + String broadcastMessage = ChatColor.GREEN + SimpleSpleef.ll("broadcasts.lostByCuboid", "[PLAYER]", player.getName(), "[ARENA]", getName()); if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceLose", true)) { SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message } else { @@ -844,37 +889,16 @@ public void onPlayerMove(PlayerMoveEvent event) { playerLoses(player, true); return; } - - // check block degeneration - if (playerOnBlockDegenerator != null && isInGame()) { - // get block player is standing on - Block block = player.getLocation().getBlock().getRelative(BlockFace.DOWN); - if (block != null && checkMayBreakBlockLocation(block)) // only degenerate blocks that are within the arena/floor - playerOnBlockDegenerator.updatePlayer(player); - } - } - - @Override - public boolean playerMayTeleport(Player player) { - // at the start of game, teleportation is ok - if (isJoinable() && (spleefers == null || spleefers.size() == 0)) return true; - // check if the player is on the teleport-ok-list, delete him/her from list and return true - if (this.teleportOkList.contains(player)) { - this.teleportOkList.remove(player); - player.setFallDistance(0.0f); // set fall distance to 0 to negate damager - return true; - } - // otherwise return preventTeleportingDuringGames for this arena - return !configuration.getBoolean("preventTeleportingDuringGames", true); } @Override public void onPlayerInteract(PlayerInteractEvent event) { + if (!isEnabled()) return; // ignore disabled arenas Block block = event.getClickedBlock(); - if (block == null || event.getPlayer() == null) return; // ignore null blocks and null players - + if (block == null || event.getPlayer() == null || !hasPlayer(event.getPlayer())) return; // ignore null blocks and null players and players not in game + // check instant dig and block may be broken - if (event.getAction() == Action.LEFT_CLICK_BLOCK && configuration.getBoolean("instantDig", true) && checkMayBreakBlock(block)) { + if (event.getAction() == Action.LEFT_CLICK_BLOCK && configuration.getBoolean("instantDig", true) && checkMayBreakBlock(block, event.getPlayer())) { // cancel event event.setCancelled(true); // get block data @@ -884,8 +908,8 @@ public void onPlayerInteract(PlayerInteractEvent event) { // set block to air clickedBlock.setType(Material.AIR); clickedBlock.setData((byte) 0); - // notify floor tracker - updateTrackers(clickedBlock, oldType, oldData); + // notify trackers + trackersUpdateBlock(clickedBlock, oldType, oldData); } else //check if player clicked on a "ready" block (e.g. iron block) and the game is readyable if (supportsBlockReady() && isJoinable()) { @@ -904,104 +928,461 @@ public void onPlayerInteract(PlayerInteractEvent event) { } @Override - public void onPlayerQuit(PlayerQuitEvent event) { - // call helper method - loseOnQuitOrKick(event.getPlayer()); + public void onBlockBreak(BlockBreakEvent event) { + if (!isEnabled()) return; // ignore disabled arenas + Player player = event.getPlayer(); + if (player == null) return; // no NPEs + + // is player a spleefer? + if (hasPlayer(player)) { + blockBreakInGame(event); + } else { // not in spleefer list, check arena area nevertheless + if (inProtectedArenaCube(event.getBlock())) { //check if block is in cube + // cancel event + event.setCancelled(true); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.noDig")); + } + } + } + + /** + * execute a block break within the game + * @param event + */ + protected void blockBreakInGame(BlockBreakEvent event) { + Block block = event.getBlock(); + if (block == null) return; // sanity check + // get block data + int oldType = block.getTypeId(); + byte oldData = block.getData(); + boolean floorBroken = false; + // may the block be broken? + if (!checkMayBreakBlock(block, event.getPlayer())) { + // cancel event + event.setCancelled(true); + // message to player + event.getPlayer().sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.noDig")); + } else if (!configuration.getBoolean("blockDropping", true)) { // otherwise: block dropping set to false => destroy blocks + // cancel event - because we will handle the block destruction ourselves + event.setCancelled(true); + floorBroken = true; + // set block to air + block.setType(Material.AIR); + block.setData((byte) 0); + } else floorBroken = true; // block was broken + + if (floorBroken) // update trackers + trackersUpdateBlock(block, oldType, oldData); + } + + /** + * Check if a block is in protected arena + * @param block + * @return + */ + protected boolean inProtectedArenaCube(Block block) { + if (arena == null) return false; + + // check block position + Location blockLoc = block.getLocation(); + return arena.contains(blockLoc); } @Override - public void onPlayerKick(PlayerKickEvent event) { - // call helper method - loseOnQuitOrKick(event.getPlayer()); - // delete original position, because player is banned anyhow - SimpleSpleef.getOriginalPositionKeeper().deleteOriginalPosition(event.getPlayer()); + public void onBlockPlace(BlockPlaceEvent event) { + if (!isEnabled()) return; // ignore disabled arenas + Player player = event.getPlayer(); + if (player == null) return; // no NPEs + + // is player a spleefer? + if (hasPlayer(player)) { + blockPlaceInGame(event); + } else { // not in spleefer list, check arena area nevertheless + if (inProtectedArenaCube(event.getBlock())) { //check if block is in cube + // cancel event + event.setCancelled(true); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.noPlacement")); + } + } } /** - * helper method for onPlayerQuit and onPlayerKick - * @param player + * execute a block place within the game + * @param event */ - protected void loseOnQuitOrKick(Player player) { - if (configuration.getBoolean("loseOnLogout", true)) { - // broadcast message of somebody loosing - String broadcastMessage = ChatColor.GREEN + SimpleSpleef.getPlugin().ll("broadcasts.lostByQuitting", "[PLAYER]", player.getName(), "[ARENA]", getName()); - if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceLose", true)) { - SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message - } else { - // send message to all receivers - sendMessage(broadcastMessage, player); + protected void blockPlaceInGame(BlockPlaceEvent event) { + // joined players may not place blocks as long as game has not started + // also, if allowBlockPlacing is false, disallow block placing during game + if (!isInGame() || !configuration.getBoolean("allowBlockPlacing", false)) { + // cancel event + event.setCancelled(true); + event.getPlayer().sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.noPlacement")); + } + + // if there is a floor tracker running, tell it about the change + if (!event.isCancelled()) + trackersUpdateBlock(event.getBlock(), Material.AIR.getId(), (byte) 0); + } + + @Override + public void onFoodLevelChange(FoodLevelChangeEvent event) { + if (!isEnabled()) return; // ignore disabled arenas + //if (event.getEntity() == null || !(event.getEntity() instanceof Player)) return; + Player player = (Player) event.getEntity(); + + if (hasPlayer(player) && configuration.getBoolean("noHunger", true)) // if setting noHunger has been set for this arena, do not feel any hunger + event.setCancelled(true); + } + + @Override + public void onEntityDamage(EntityDamageEvent event) { + //if (event.getEntity() == null || !(event.getEntity() instanceof Player)) return; + Player player = (Player) event.getEntity(); + + // player in game and in PVP world? Consider settings and only damage by other entities + if (hasPlayer(player) && player.getWorld().getPVP() && configuration.getBoolean("noPvP", true) && event instanceof EntityDamageByEntityEvent) { + EntityDamageByEntityEvent damageEvent = (EntityDamageByEntityEvent) event; + // only consider player damage + if (damageEvent.getDamager() instanceof Player) + event.setCancelled(true); // cancel damage event by caused by other players + } + } + + @Override + public void onEntityExplode(EntityExplodeEvent event) { + if (!isEnabled()) return; // ignore disabled arenas + // TODO: check if any exploded blocks were within the arena perimeter -> restore those or cancel event + + // TODO: check for blocks exploded within the reach of a tracker -> track changed blocks! + } + + @Override + public void onPlayerTeleport(PlayerTeleportEvent event) { + if (!isEnabled()) return; // ignore disabled arenas + if (hasPlayer(event.getPlayer())) { + // check, if arena allows the player's teleportation + if (!playerMayTeleport(event.getPlayer())) { + event.getPlayer().sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.teleport", "[ARENA]", getName())); + event.setCancelled(true); //cancel event } - // player loses, if set to true - playerLoses(player, false); // do not teleport dead players... - } // else - do nothing... + } } @Override - public void onPlayerJoin(PlayerJoinEvent event) { - // right now, do nothing... later on maybe give shovel back or so (if it has been taken away before the game ended - that gets complicated...) + public void onPlayerGameModeChange(PlayerGameModeChangeEvent event) { + if (!isEnabled()) return; // ignore disabled arenas + Player player = event.getPlayer(); + + // players and spectators may not change game mode + if (hasPlayer(player) || hasSpectator(player)) { + event.getPlayer().sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.gamemodeChange")); + event.setCancelled(true); //cancel event + } + } + + /** + * Do end game maintenance + * @return + */ + public boolean endGame() { + //check what the current status is and end game then + boolean wasInProgress = isInProgress(); + //isJoinable() + //isReady() + // + other cases? + + // change game status + status = STATUS_FINISHED; + + // only do this when game was in progress + if (wasInProgress) { + // possibly take away shovel items + removeShovelItems(); + // possibly restore inventories + restoreAllInventories(); + // teleport remaining players to lounge + for (Spleefer spleefer : spleefers.get()) { + if (!spleefer.hasLost()) + teleportPlayer(spleefer.getPlayer(), "lounge"); + } + } + return true; + } + + /** + * check whether a certain block may be broken + * => player has been checked before this, so this does only concern block breaks + * and interactions by spleefers + * @param block broken/interacted (on instant-break) by spleefer + * @param player - player or null for automatic changes (e.g. trackers) + * @return true, if block may be destroyed + */ + @Override + public boolean checkMayBreakBlock(Block block, Player player) { + // sanity check + if (block == null) return true; + // joined players may not break blocks as long as game has not started + if (player != null && !isInGame()) + return false; + // joined players may not break blocks as long as game has not started + return checkMayBreakBlockMaterial(block) && checkMayBreakBlockLocation(block); + } + + /** + * helper function for the above checkMayBreakBlock method to check the material of a block + * @param block + * @return + */ + protected boolean checkMayBreakBlockMaterial(Block block) { + // allowed blocks? => allowDigBlocks + // alternatively: disallowDigBlocks + if (digBlocks != null) { + if (MaterialHelper.isSameBlockType(block, digBlocks)) return allowDigBlocks; // found -> return state + else // not found + return !allowDigBlocks; // negate + } + return true; + } + + /** + * helper function for the above checkMayBreakBlock method to check the location of a block + * @param block + * @return + */ + protected boolean checkMayBreakBlockLocation(Block block) { + Location blockLocation = block.getLocation(); + // is arena undefined? + if (arena == null) { + switch (diggingIfArenaUndefined) { + case GameStandard.DIGGING_NONE: return false; // digging is not allowed + case GameStandard.DIGGING_EVERYWHERE: return true; // digging is allowed everywhere + default: // allowed in the arena floor in all other cases + return this.floor.contains(blockLocation); + } + } else { // arena defined + // is floor undefined? + if (floor == null) { + switch (diggingIfFloorUndefined) { + case GameStandard.DIGGING_NONE: return false; // digging is not allowed + case GameStandard.DIGGING_EVERYWHERE: return true; // digging is allowed everywhere + case GameStandard.DIGGING_OUTSIDE_ARENA: return !this.arena.contains(blockLocation); // digging is allowed outside of arena + default: // allowed within the arena in other cases + return this.arena.contains(blockLocation); + } + } else { // floor and arena defined + return this.floor.contains(blockLocation); // only arena floor can be broken during game + } + } + } + + @Override + public boolean hasPlayer(Player player) { + if (spleefers == null || player == null) return false; + return spleefers.hasSpleefer(player); + } + + @Override + public boolean hasSpectator(Player player) { + if (spectators == null) return false; + return spectators.contains(player); + } + + @Override + public boolean removeSpectator(Player player) { + return spectators.remove(player); + } + + @Override + public String getNumberOfPlayers() { + // no spleefers - return empty string + if (spleefers == null || spleefers.size() == 0) return ""; + + int active; + int max; + // shows information depending on state + if (isInProgress()) { + active = spleefers.inGame(); + max = spleefers.size(); + } else { // joinable -> show number of players joined, open places + active = spleefers.size(); + max = configuration.getInt("maximumPlayers", 0); + } + return "(" + active + "/" + (max>0?max:"-") + ")"; + } + + @Override + public String getListOfSpleefers() { + // no spleefers - return null + if (spleefers == null || spleefers.size() == 0) return null; + // create list of spleefers + String comma = SimpleSpleef.ll("feedback.infoComma"); + StringBuilder builder = new StringBuilder(); + int i = 0; + for (Spleefer spleefer : spleefers.get()) { + if (i > 0 && i == spleefers.size() - 1) builder.append(SimpleSpleef.ll("feedback.infoAnd")); // last element with end + else if (i > 0) builder.append(comma); // other elements with , + // lost or in game? + if (spleefer.hasLost()) builder.append(ChatColor.RED); + else builder.append(ChatColor.GREEN); + builder.append(spleefer.getPlayer().getDisplayName()); + builder.append(ChatColor.GRAY); + i++; + } + return builder.toString(); + } + + @Override + public String getListOfUnreadySpleefers() { + // no spleefers - return null + if (spleefers == null || spleefers.size() == 0) return null; + // get unready spleefers + LinkedList list = new LinkedList(); + for (Spleefer spleefer : spleefers.get()) { + if (!spleefer.isReady()) list.add(spleefer); + } + // is the list empty? + if (list.size() == 0) return null; // no unready spleefes + // compile list + return SpleeferList.getPrintablePlayerList(list); + } + + @Override + public String getListOfSpectators() { + // no spectators - return null + if (spectators == null || spectators.size() == 0) return null; + // create list of spectators + String comma = SimpleSpleef.ll("feedback.infoComma"); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < spectators.size(); i++) { + if (i > 0 && i == spectators.size() - 1) builder.append(SimpleSpleef.ll("feedback.infoAnd")); // last element with end + else if (i > 0) builder.append(comma); // other elements with , + builder.append(spectators.get(i).getDisplayName()); + } + return builder.toString(); + } + + + @Override + public boolean isEnabled() { + return configuration.getBoolean("enabled", true); + } + + @Override + public boolean supportsReady() { + return supportsReady(false, false); + } + + @Override + public boolean supportsCommandReady() { + return supportsReady(false, true); + } + + @Override + public boolean supportsBlockReady() { + return supportsReady(true, false); } + /** + * Helper method to actually check useReady element + * @param noCommand + * @param noBlock + * @return + */ + protected boolean supportsReady(boolean noCommand, boolean noBlock) { + if (configuration.isBoolean("useReady")) { + return configuration.getBoolean("useReady", false); + } + if (configuration.isString("useReady")) { + String ready = configuration.getString("useReady"); + if (noCommand == false && ready.equalsIgnoreCase("command")) return true; + if (noBlock == false && ready.equalsIgnoreCase("block")) return true; + } + return false; + } + + + /** + * Send a message to broadcast, or to players and spectators + * @param message + * @param broadcast + */ @Override - public void onPlayerDeath(Player player) { - // delete original position, because player spawns somewhere else anyhow - SimpleSpleef.getOriginalPositionKeeper().deleteOriginalPosition(player); - if (configuration.getBoolean("loseOnDeath", true)) { - // broadcast message of somebody loosing - String broadcastMessage = ChatColor.GREEN + SimpleSpleef.getPlugin().ll("broadcasts.lostByDeath", "[PLAYER]", player.getName(), "[ARENA]", getName()); - if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceLose", true)) { - SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message - } else { - // send message to all receivers - sendMessage(broadcastMessage, player); + public void sendMessage(String message, boolean broadcast) { + if (message == null) { + SimpleSpleef.log.warning("[SimpleSpleef] Message was null and could not be broadcasted!"); + return; + } + // global broadcast + if (broadcast) SimpleSpleef.getPlugin().getServer().broadcastMessage(message); + else { // only players and specators + // players + for (Spleefer spleefer : spleefers.get()) { + spleefer.getPlayer().sendMessage(message); } - // player loses, if set to true - playerLoses(player, false); // do not teleport dead players... - } // else - do nothing... + // spectators + for (Player player : this.spectators) { + player.sendMessage(message); + } + // send to console, too + SimpleSpleef.log.info(message); + } } + /** + * Send a message to broadcast, or to players and spectators + * @param message + * @param exception exception - this player does not receive message + */ @Override - public void onBlockBreak(BlockBreakEvent event) { - Block block = event.getBlock(); - if (block == null) return; // sanity check - // get block data - int oldType = block.getTypeId(); - byte oldData = block.getData(); - boolean floorBroken = false; - // may the block be broken? - if (!checkMayBreakBlock(block)) { - // cancel event - event.setCancelled(true); - // message to player - event.getPlayer().sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.noDig")); - } else if (!configuration.getBoolean("blockDropping", true)) { // otherwise: block dropping set to false => destroy blocks - // cancel event - because we will handle the block destruction ourselves - event.setCancelled(true); - floorBroken = true; - // set block to air - block.setType(Material.AIR); - block.setData((byte) 0); - } else floorBroken = true; // block was broken - - // if there is a floor tracker running, tell it about the change - if (floorTracker != null && floorBroken) - updateTrackers(block, oldType, oldData); + public void sendMessage(String message, Player exception) { + // players + for (Spleefer spleefer : spleefers.get()) { + if (exception != spleefer.getPlayer()) + spleefer.getPlayer().sendMessage(message); + } + // spectators + for (Player player : this.spectators) { + if (exception != player) + player.sendMessage(message); + } + // send to console, too + SimpleSpleef.log.info(message); } - + + @Override - public void onBlockPlace(BlockPlaceEvent event) { - // joined players may not place blocks as long as game has not started - // also, if allowBlockPlacing is false, disallow block placing during game - if (!isInGame() || !configuration.getBoolean("allowBlockPlacing", false)) { - // cancel event - event.setCancelled(true); - event.getPlayer().sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.noPlacement")); + public boolean playerMayTeleport(Player player) { + // at the start of game, teleportation is ok + if (isJoinable() && (spleefers == null || spleefers.size() == 0)) return true; + // check if the player is on the teleport-ok-list, delete him/her from list and return true + if (this.teleportOkList.contains(player)) { + this.teleportOkList.remove(player); + player.setFallDistance(0.0f); // set fall distance to 0 to negate damager + return true; } + // otherwise return preventTeleportingDuringGames for this arena + return !configuration.getBoolean("preventTeleportingDuringGames", true); + } - // if there is a floor tracker running, tell it about the change - if (floorTracker != null && !event.isCancelled()) - updateTrackers(event.getBlock(), Material.AIR.getId(), (byte) 0); + /** + * teleport a player to named spawn, if it exists and it is enabled + * @param player + * @param string + */ + protected void teleportPlayer(Player player, String spawn) { + if (!configuration.isConfigurationSection(spawn + "Spawn") || !configuration.getBoolean(spawn + "Spawn.enabled", false)) + return; // just ignore, if not set or not enabled + // everything ok -> teleport player + Location teleportTo = LocationHelper.configToExactLocation(configuration.getConfigurationSection(spawn + "Spawn")); + if (teleportTo == null) SimpleSpleef.log.warning("[SimpleSpleef] Teleport error - location was null!"); + // load chunk, if needed + teleportTo.getWorld().loadChunk(teleportTo.getChunk()); + // add player to teleport ok list + this.teleportOkList.add(player); + player.teleport(teleportTo); } + /** * called when player loses a game * (broadcast message has to be sent by calling method) @@ -1012,9 +1393,9 @@ protected void playerLoses(Player player, boolean teleport) { // set player to lost spleefers.setLost(player); // if degeneration keeper is on, delete player from list - if (playerOnBlockDegenerator != null) playerOnBlockDegenerator.removePlayer(player); + //if (playerOnBlockDegenerator != null) playerOnBlockDegenerator.removePlayer(player); //TODO check on how to do this // message to player - player.sendMessage(ChatColor.RED + SimpleSpleef.getPlugin().ll("feedback.lost")); + player.sendMessage(ChatColor.RED + SimpleSpleef.ll("feedback.lost")); // broadcast message has to be sent by calling method // shovel lost, too removeShovelItem(player, true); @@ -1049,7 +1430,7 @@ protected void gameOver() { Player player = spleefer.getPlayer(); if (!spleefer.hasLost()) { // not lost? //this guy is a winner - send a message - player.sendMessage(ChatColor.DARK_GREEN + SimpleSpleef.getPlugin().ll("feedback.won")); + player.sendMessage(ChatColor.DARK_GREEN + SimpleSpleef.ll("feedback.won")); winners.add(spleefer); // aggregate the winners to broadcast them later on // pay prizes payPrizeMoney(player); @@ -1068,8 +1449,6 @@ protected void gameOver() { // clean up game and end it endGame(); - // call the game handler to tell it that the game is over - only if game status has been reset - if (status == STATUS_NEW) SimpleSpleef.getGameHandler().gameOver(this); } /** @@ -1091,7 +1470,7 @@ else if (winners.size() == 1) { // one winner? replacePlayer = SpleeferList.getPrintablePlayerList(winners); } // broadcast message - String broadcastMessage = ChatColor.GOLD + SimpleSpleef.getPlugin().ll("broadcasts.win" + broadcastKey, "[PLAYER]", replacePlayer, "[ARENA]", getName()); + String broadcastMessage = ChatColor.GOLD + SimpleSpleef.ll("broadcasts.win" + broadcastKey, "[PLAYER]", replacePlayer, "[ARENA]", getName()); sendMessage(broadcastMessage, SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceWin", true)); } @@ -1110,9 +1489,9 @@ protected void payPrizeMoney(Player player) { // give money to player SimpleSpleef.economy.depositPlayer(player.getName(), win); // player gets message - player.sendMessage(ChatColor.AQUA + SimpleSpleef.getPlugin().ll("feedback.prizeMoney", "[ARENA]", getName(), "[MONEY]", formated)); + player.sendMessage(ChatColor.AQUA + SimpleSpleef.ll("feedback.prizeMoney", "[ARENA]", getName(), "[MONEY]", formated)); // broadcast prize? - String broadcastMessage = ChatColor.AQUA + SimpleSpleef.getPlugin().ll("broadcasts.prizeMoney", "[PLAYER]", player.getName(), "[ARENA]", getName(), "[MONEY]", formated); + String broadcastMessage = ChatColor.AQUA + SimpleSpleef.ll("broadcasts.prizeMoney", "[PLAYER]", player.getName(), "[ARENA]", getName(), "[MONEY]", formated); if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announcePrize", true)) { SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message } else { @@ -1134,9 +1513,9 @@ protected void payPrizeExperience(Player player) { // add player experience player.giveExp(win); // player gets message - player.sendMessage(ChatColor.AQUA + SimpleSpleef.getPlugin().ll("broadcasts.prizeExperience", "[ARENA]", getName(), "[EXPERIENCE]", String.valueOf(win))); + player.sendMessage(ChatColor.AQUA + SimpleSpleef.ll("broadcasts.prizeExperience", "[ARENA]", getName(), "[EXPERIENCE]", String.valueOf(win))); // broadcast prize? - String broadcastMessage = ChatColor.AQUA + SimpleSpleef.getPlugin().ll("broadcasts.prizeExperience", "[PLAYER]", player.getName(), "[ARENA]", getName(), "[EXPERIENCE]", String.valueOf(win)); + String broadcastMessage = ChatColor.AQUA + SimpleSpleef.ll("broadcasts.prizeExperience", "[PLAYER]", player.getName(), "[ARENA]", getName(), "[EXPERIENCE]", String.valueOf(win)); if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announcePrize", true)) { SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message } else { @@ -1166,9 +1545,9 @@ protected void payPrizeItems(Player player) { // give prizes to player player.getInventory().addItem(itemStack); // player gets message - player.sendMessage(ChatColor.AQUA + SimpleSpleef.getPlugin().ll("feedback.prizeItems", "[ARENA]", getName(), "[ITEM]", itemStack.getType().toString(), "[AMOUNT]", String.valueOf(itemStack.getAmount()))); + player.sendMessage(ChatColor.AQUA + SimpleSpleef.ll("feedback.prizeItems", "[ARENA]", getName(), "[ITEM]", itemStack.getType().toString(), "[AMOUNT]", String.valueOf(itemStack.getAmount()))); // broadcast prize? - String broadcastMessage = ChatColor.AQUA + SimpleSpleef.getPlugin().ll("broadcasts.prizeItems", "[PLAYER]", player.getName(), "[ARENA]", getName(), "[ITEM]", itemStack.getType().toString(), "[AMOUNT]", String.valueOf(itemStack.getAmount())); + String broadcastMessage = ChatColor.AQUA + SimpleSpleef.ll("broadcasts.prizeItems", "[PLAYER]", player.getName(), "[ARENA]", getName(), "[ITEM]", itemStack.getType().toString(), "[AMOUNT]", String.valueOf(itemStack.getAmount())); if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announcePrize", true)) { SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message } else { @@ -1353,249 +1732,31 @@ protected boolean removeShovelItem(Player player, boolean checkSetting) { return true; } - - /** - * teleport a player to named spawn, if it exists and it is enabled - * @param player - * @param string - */ - protected void teleportPlayer(Player player, String spawn) { - if (!configuration.isConfigurationSection(spawn + "Spawn") || !configuration.getBoolean(spawn + "Spawn.enabled", false)) - return; // just ignore, if not set or not enabled - // everything ok -> teleport player - Location teleportTo = LocationHelper.configToExactLocation(configuration.getConfigurationSection(spawn + "Spawn")); - if (teleportTo == null) SimpleSpleef.log.warning("[SimpleSpleef] Teleport error - location was null!"); - // load chunk, if needed - teleportTo.getWorld().loadChunk(teleportTo.getChunk()); - // add player to teleport ok list - this.teleportOkList.add(player); - player.teleport(teleportTo); - } - - /** - * check whether a certain block may be broken - * => player has been checked before this, so this does only concern block breaks - * and interactions by spleefers - * @param block broken/interacted (on instant-break) by spleefer - * @return true, if block may be destroyed - */ - @Override - public boolean checkMayBreakBlock(Block block) { - // sanity check - if (block == null) return true; - // joined players may not break blocks as long as game has not started - if (!isInGame()) return false; - return checkMayBreakBlockMaterial(block) && checkMayBreakBlockLocation(block); - } - - /** - * helper function for the above checkMayBreakBlock method to check the material of a block - * @param block - * @return - */ - protected boolean checkMayBreakBlockMaterial(Block block) { - // allowed blocks? => allowDigBlocks - // alternatively: disallowDigBlocks - if (digBlocks != null) { - if (MaterialHelper.isSameBlockType(block, digBlocks)) return allowDigBlocks; // found -> return state - else // not found - return !allowDigBlocks; // negate - } - return true; - } - - /** - * helper function for the above checkMayBreakBlock method to check the location of a block - * @param block - * @return - */ - protected boolean checkMayBreakBlockLocation(Block block) { - Location blockLocation = block.getLocation(); - // is arena undefined? - if (arena == null) { - switch (diggingIfArenaUndefined) { - case GameStandard.DIGGING_NONE: return false; // digging is not allowed - case GameStandard.DIGGING_EVERYWHERE: return true; // digging is allowed everywhere - default: // allowed in the arena floor in all other cases - return this.floor.contains(blockLocation); - } - } else { // arena defined - // is floor undefined? - if (floor == null) { - switch (diggingIfFloorUndefined) { - case GameStandard.DIGGING_NONE: return false; // digging is not allowed - case GameStandard.DIGGING_EVERYWHERE: return true; // digging is allowed everywhere - case GameStandard.DIGGING_OUTSIDE_ARENA: return !this.arena.contains(blockLocation); // digging is allowed outside of arena - default: // allowed within the arena in other cases - return this.arena.contains(blockLocation); - } - } else { // floor and arena defined - return this.floor.contains(blockLocation); // only arena floor can be broken during game - } - } - } - - /** - * update the trackers when blocks are changed - * @param newBlock - new block (after change) - * @param oldType - old type of block - * @param oldData - old data of block - */ - protected void updateTrackers(Block newBlock, int oldType, byte oldData) { - if (floorTracker != null) - floorTracker.updateBlock(newBlock, oldType, oldData); - } - - /** - * save arena information, if setting restoreArenaAfterGame has been set - */ - protected void saveArena() { - // explicitly set to false - if (configuration.isBoolean("restoreArenaAfterGame") && !configuration.getBoolean("restoreArenaAfterGame")) { - arenaRestorer = null; - return; // ignore, if arena not defined or setting false - } - - // determine type of arena - String type; - if (configuration.isBoolean("restoreArenaAfterGame")) type = "soft"; - else if (configuration.isString("restoreArenaAfterGame")) type = configuration.getString("restoreArenaAfterGame"); - else type = "soft"; // fall back - - if (type.equals("arenahard")) { // hard arena restorer - arenaRestorer = new HardArenaRestorer(); - arenaRestorer.saveArena(this, arena); - } else if (type.equals("floorhard")) { // hard floor restorer - arenaRestorer = new HardArenaRestorer(); - arenaRestorer.saveArena(this, floor); - } else { // soft restorer - Cuboid possibleFloor = floor==null?arena:floor; - if (possibleFloor == null) { - arenaRestorer = null; - return; // freestyle spleefing does not implement any floor - } - - // create soft restorer - arenaRestorer = new SoftRestorer(); - arenaRestorer.saveArena(this, possibleFloor); - - if (floorTracker == null) // create floor tracker, if needed - floorTracker = new FloorTracker(); - // create a new tracker/restorer - floorTracker.addFloorWorker((FloorWorker) arenaRestorer); - } - } - - /** - * restore arena information, if setting restoreArenaAfterGame has been set - */ - protected void restoreArena() { - if (arenaRestorer == null) { - SimpleSpleef.getGameHandler().gameOver(this); // notify game handler that the game has stopped - return; - } - - final int wait = configuration.getInt("restoreArenaAfterGameTimer", 0); - if (wait > 0) { // start in timer - SimpleSpleef.getPlugin().getServer().getScheduler().scheduleSyncDelayedTask(SimpleSpleef.getPlugin(), new Runnable() { - @Override - public void run() { - arenaRestorer.restoreArena(); - } - }, (long) (20 * wait)); // ticks * 20 = secs - } else arenaRestorer.restoreArena(); // restore right away - } - - @Override - public void clean() { - // dereference stuff - this.configuration = null; - this.spleefers = null; - this.spectators = null; - this.loseOnTouchMaterial = null; - this.countdown = null; - this.teleportOkList = null; - this.arena = null; - this.floor = null; - this.lose = null; - this.inventoryKeeper = null; - if (this.playerOnBlockDegenerator != null) - this.playerOnBlockDegenerator.stopBlockDegenerator(); // to play it safe - this.playerOnBlockDegenerator = null; - if (this.floorTracker != null) - this.floorTracker.stopTracking(); // to play it safe, too - this.floorTracker = null; - this.arenaRestorer = null; - //TODO add more - } /** - * teleport players to arena + * Check if arena is disabled + * @param sender + * @return true, if arena disabled */ - protected void teleportPlayersAtGameStart() { - for (Spleefer spleefer : spleefers.get()) { - teleportPlayer(spleefer.getPlayer(), "game"); + private boolean preCheckArenaDisabled(CommandSender sender) { + if (!isEnabled()) { + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.arenaDisabled", "[ARENA]", getName())); + return true; } + return false; } /** - * Countdown class - * - * @author mkalus - * + * Check if game is already active + * @param sender + * @return true, if game is active */ - private class Countdown implements Runnable { - // flag to toggle interrupts - private boolean interrupted = false; - - private int count = -1; - - private boolean broadcast; - - // start countdown - private void start() { - // change game status - status = STATUS_COUNTDOWN; - - // announce countdown? - broadcast = SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceCountdown", true); - sendMessage(ChatColor.BLUE + SimpleSpleef.getPlugin().ll("feedback.countdownStart"), broadcast); - - // get time - count = configuration.getInt("countdownFrom", 10); - } - - /** - * Thread method - */ - @Override - public void run() { - if (interrupted) { - // send message - sendMessage(ChatColor.RED + SimpleSpleef.getPlugin().ll("feedback.countdownInterrupted"), broadcast); - // cancel countdown - SimpleSpleef.getPlugin().getServer().getScheduler().cancelTask(countdownId); - // end the game - GameStandard.this.endGame(); - } - - // start? - if (count < 0) { - start(); - } - - // do countdown - if (count > 0) { - sendMessage(ChatColor.BLUE + SimpleSpleef.getPlugin().ll("feedback.countdown", "[COUNT]", String.valueOf(count), "[ARENA]", GameStandard.this.getName()), broadcast); - count--; - } else { - // send message - sendMessage(ChatColor.BLUE + SimpleSpleef.getPlugin().ll("feedback.countdownGo"), broadcast); - // start the game itself! - GameStandard.this.start(); - // cancel countdown - SimpleSpleef.getPlugin().getServer().getScheduler().cancelTask(countdownId); - } + private boolean preCheckArenaActive(CommandSender sender) { + // already running? + if (isActive()) { + sender.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.arenaExistsAlready", "[ARENA]", getName())); + return false; } + return false; } } diff --git a/src/main/java/de/beimax/simplespleef/game/GameWithTeams.java b/src/main/java/de/beimax/simplespleef/game/GameWithTeams.java index 21ef3c4..03fd5a8 100644 --- a/src/main/java/de/beimax/simplespleef/game/GameWithTeams.java +++ b/src/main/java/de/beimax/simplespleef/game/GameWithTeams.java @@ -1,6 +1,22 @@ /** + * This file is part of the SimpleSpleef bukkit plugin. + * Copyright (C) 2011 Maximilian Kalus + * See http://dev.bukkit.org/server-mods/simple-spleef/ + * + * This program 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. + * + * This program 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 this program. If not, see . + **/ + package de.beimax.simplespleef.game; import java.util.LinkedList; @@ -14,8 +30,8 @@ import org.bukkit.inventory.ItemStack; import de.beimax.simplespleef.SimpleSpleef; -import de.beimax.simplespleef.util.LocationHelper; -import de.beimax.simplespleef.util.MaterialHelper; +import de.beimax.simplespleef.gamehelpers.LocationHelper; +import de.beimax.simplespleef.gamehelpers.MaterialHelper; /** * @author mkalus @@ -29,12 +45,12 @@ public class GameWithTeams extends GameStandard { public GameWithTeams(String name) { super(name); } - + @Override public String getType() { return "randomteams"; } - + @Override public String getNumberOfPlayers() { // if in progress - tell about teams @@ -57,7 +73,7 @@ public String getListOfSpleefers() { // no spleefers - return null if (spleefers == null || spleefers.size() == 0) return null; // create list of spleefers - String comma = SimpleSpleef.getPlugin().ll("feedback.infoComma"); + String comma = SimpleSpleef.ll("feedback.infoComma"); StringBuilder builder = new StringBuilder(); for (int team = Spleefer.TEAM_RED; team >= Spleefer.TEAM_NONE; team--) { // color @@ -69,8 +85,8 @@ public String getListOfSpleefers() { } // append team - builder.append(SimpleSpleef.getPlugin().ll("feedback.infoTeam", - "[TEAM]", teamColor + SimpleSpleef.getPlugin().ll("feedback.team" + Spleefer.getTeamId(team)) + ChatColor.WHITE)).append(' '); + builder.append(SimpleSpleef.ll("feedback.infoTeam", + "[TEAM]", teamColor + SimpleSpleef.ll("feedback.team" + Spleefer.getTeamId(team)) + ChatColor.WHITE)).append(' '); int i = 0; for (Spleefer spleefer : spleefers.get()) { if (i > 0) builder.append(comma); // no ands here... @@ -99,12 +115,12 @@ public boolean team(Player player, String team) { // no teams during gaming if (!isJoinable()) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.teamAlreadyStarted", "[ARENA]", getName())); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.teamAlreadyStarted", "[ARENA]", getName())); return false; } // is team command disallowed in the arena? if (!configuration.getBoolean("teamCommand", true)) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.teamNoTeamCommand", "[ARENA]", getName())); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.teamNoTeamCommand", "[ARENA]", getName())); return false; } // parse team string @@ -112,24 +128,24 @@ public boolean team(Player player, String team) { if (team.equalsIgnoreCase("red")) teamId = Spleefer.TEAM_RED; else if (team.equalsIgnoreCase("blue")) teamId = Spleefer.TEAM_BLUE; else { // no valid team name - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.teamNoValidTeam", "[NAME]", team)); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.teamNoValidTeam", "[NAME]", team)); return false; } // localize team name - String teamName = SimpleSpleef.getPlugin().ll("feedback." + Spleefer.getTeamId(teamId)); + String teamName = SimpleSpleef.ll("feedback." + Spleefer.getTeamId(teamId)); // is the player already part of this team? if (spleefer.getTeam() == teamId) { - player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.teamAlreadyInTeam", "[TEAM]", teamName)); + player.sendMessage(ChatColor.DARK_RED + SimpleSpleef.ll("errors.teamAlreadyInTeam", "[TEAM]", teamName)); return false; } // clear: join the team spleefer.setTeam(teamId); - player.sendMessage(ChatColor.GREEN + SimpleSpleef.getPlugin().ll("feedback.team", "[TEAM]", teamName)); + player.sendMessage(ChatColor.GREEN + SimpleSpleef.ll("feedback.team", "[TEAM]", teamName)); // broadcast message of somebody joining a team - String broadcastMessage = ChatColor.DARK_PURPLE + SimpleSpleef.getPlugin().ll("broadcasts.team", "[PLAYER]", player.getDisplayName(), "[ARENA]", getName(), "[TEAM]", teamName); + String broadcastMessage = ChatColor.DARK_PURPLE + SimpleSpleef.ll("broadcasts.team", "[PLAYER]", player.getDisplayName(), "[ARENA]", getName(), "[TEAM]", teamName); if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceTeam", false)) { SimpleSpleef.getPlugin().getServer().broadcastMessage(broadcastMessage); // broadcast message } else { @@ -207,11 +223,11 @@ protected void broadcastWinners(LinkedList winners) { else { // winning team broadcastKey = ""; // just winTeam // get winning team - team = SimpleSpleef.getPlugin().ll("feedback.team" + Spleefer.getTeamId(winners.getFirst().getTeam())); + team = SimpleSpleef.ll("feedback.team" + Spleefer.getTeamId(winners.getFirst().getTeam())); replacePlayer = SpleeferList.getPrintablePlayerList(winners); } // broadcast message - String broadcastMessage = ChatColor.GOLD + SimpleSpleef.getPlugin().ll("broadcasts.winTeam" + broadcastKey, "[PLAYER]", replacePlayer, "[ARENA]", getName(), "[TEAM]", team); + String broadcastMessage = ChatColor.GOLD + SimpleSpleef.ll("broadcasts.winTeam" + broadcastKey, "[PLAYER]", replacePlayer, "[ARENA]", getName(), "[TEAM]", team); sendMessage(broadcastMessage, SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceWin", true)); } @@ -259,10 +275,15 @@ protected void createTeams() { for (Spleefer spleefer : redTeam) spleefer.setTeam(Spleefer.TEAM_RED); // broadcast message of player teams, so everyone knows this... - String broadcastMessage = ChatColor.WHITE + SimpleSpleef.getPlugin().ll("broadcasts.teams", "[TEAMS]", getListOfSpleefers()); + String broadcastMessage = ChatColor.WHITE + SimpleSpleef.ll("broadcasts.teams", "[TEAMS]", getListOfSpleefers()); sendMessage(broadcastMessage, SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceTeam", false)); } + /** + * even out the teams + * @param smaller + * @param larger + */ protected void evenOutTeamLists(LinkedList smaller, LinkedList larger) { // if the size difference is 1, ignore evening out - also ignore 1 member teams if (larger.size()-1 == smaller.size() || larger.size() <= 1) return; diff --git a/src/main/java/de/beimax/simplespleef/game/PlayerOnBlockDegenerator.java b/src/main/java/de/beimax/simplespleef/game/PlayerOnBlockDegenerator.java deleted file mode 100644 index 81fc2a0..0000000 --- a/src/main/java/de/beimax/simplespleef/game/PlayerOnBlockDegenerator.java +++ /dev/null @@ -1,173 +0,0 @@ -/** - * - */ -package de.beimax.simplespleef.game; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - -import de.beimax.simplespleef.SimpleSpleef; -import de.beimax.simplespleef.game.floortracking.FloorTracker; -import de.beimax.simplespleef.util.MaterialHelper; - -/** - * @author mkalus - * Keeps tracks of blocks players are standing on etc. - */ -public class PlayerOnBlockDegenerator implements Runnable { - /** - * seconds to wait for degeneration - */ - private int seconds; - - /** - * list of blocks that will degenerate when standing on them for too long - */ - private List degeneratingBlocks; - - /** - * list of DegenerationKeeper to players - */ - private Map degenerationList; - - /** - * reference to floor tracker - */ - private FloorTracker floorTracker; - - /** - * id of the scheduler - */ - private int schedulerId; - - /** - * Constructor - * @param numberOfSecondsToDegenerate - */ - public PlayerOnBlockDegenerator(int numberOfSecondsToDegenerate, List degeneratingBlocks, FloorTracker floorTracker) { - seconds = numberOfSecondsToDegenerate; - - // fill with degenerating blocks - this.degeneratingBlocks = new LinkedList(); - for (String string : degeneratingBlocks) { - ItemStack stack = MaterialHelper.getItemStackFromString(string, true); - if (stack != null) this.degeneratingBlocks.add(stack); - } - - degenerationList = new HashMap(); - - this.floorTracker = floorTracker; - } - - /** - * start the degenerator task - */ - public void startBlockDegenerator() { - schedulerId = SimpleSpleef.getPlugin().getServer().getScheduler().scheduleAsyncRepeatingTask(SimpleSpleef.getPlugin(), this, 0L, 4L); - } - - /** - * update player's position - * @param player - */ - public void updatePlayer(Player player) { - // get block player is standing on - Block block = player.getLocation().getBlock().getRelative(BlockFace.DOWN); - - // get keeper - DegenerationKeeper keeper = degenerationList.get(player); - - // add player if needed - if (keeper == null) { - keeper = new DegenerationKeeper(); - keeper.updateBlock(block); - degenerationList.put(player, keeper); - } else // just update the block - keeper.updateBlock(block); - } - - public void removePlayer(Player player) { - // get keeper - DegenerationKeeper keeper = degenerationList.get(player); - - // if keeper found for player - if (keeper != null) { - degenerationList.remove(player); //remove from list - } - } - - /** - * stop the block degenerator - */ - public void stopBlockDegenerator() { - SimpleSpleef.getPlugin().getServer().getScheduler().cancelTask(schedulerId); - } - - @Override - public void run() { - // cycle through keepers and update them - for (DegenerationKeeper keeper : degenerationList.values()) { - keeper.tick(); - } - } - - /** - * Keeps track of player's block and its degeneration - * @author mkalus - * - */ - private class DegenerationKeeper { - /** - * keeps track of the checked block - */ - private Block checkedBlock = null; - - /** - * timestamp at which the block will dissolve - */ - private long timestamp; - - public void tick() { - // has timestamp been exceeded? - if (checkedBlock != null && System.currentTimeMillis() >= timestamp) { - // get original data - int oldType = checkedBlock.getTypeId(); - byte oldData = checkedBlock.getData(); - checkedBlock.setType(Material.AIR); // block dissolves into thin air - checkedBlock.setData((byte) 0); - timestamp = Long.MAX_VALUE; // to not have this happen again - - // notify floor tracker - if (floorTracker != null) - floorTracker.updateBlock(checkedBlock, oldType, oldData); - - // clean up - checkedBlock = null; - } - } - - /** - * called by updatePlayer to update a block - * @param block - */ - public void updateBlock(Block block) { - if (block == null) return; //no NPEs - if (block.getType() != Material.AIR && - (checkedBlock == null || block.getX() != checkedBlock.getX() || block.getY() != checkedBlock.getY() || block.getZ() != checkedBlock.getZ())) { // ignore air... - // only if in list of blocks - if (degeneratingBlocks == null || degeneratingBlocks.size() == 0 || MaterialHelper.isSameBlockType(block, degeneratingBlocks)) { - timestamp = System.currentTimeMillis() + ((long) seconds * 1000); // update timestamp - checkedBlock = block; // update block - } - } - } - } -} diff --git a/src/main/java/de/beimax/simplespleef/game/SpleeferList.java b/src/main/java/de/beimax/simplespleef/game/SpleeferList.java index 168bd3b..fa75412 100644 --- a/src/main/java/de/beimax/simplespleef/game/SpleeferList.java +++ b/src/main/java/de/beimax/simplespleef/game/SpleeferList.java @@ -18,6 +18,7 @@ **/ package de.beimax.simplespleef.game; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -39,10 +40,10 @@ public static String getPrintablePlayerList(LinkedList players) { // build list of winners StringBuilder builder = new StringBuilder(); int i = 0; - String comma = SimpleSpleef.getPlugin().ll("feedback.infoComma"); + String comma = SimpleSpleef.ll("feedback.infoComma"); // compile list of spleefers for (Spleefer spleefer : players) { - if (i > 0 && i == players.size() - 1) builder.append(SimpleSpleef.getPlugin().ll("feedback.infoAnd")); // last element with end + if (i > 0 && i == players.size() - 1) builder.append(SimpleSpleef.ll("feedback.infoAnd")); // last element with end else if (i > 0) builder.append(comma); // other elements with , builder.append(spleefer.getPlayer().getDisplayName()); } @@ -168,13 +169,21 @@ public int size() { } /** - * get the whole list + * gets a list of spleefers * @return */ public List get() { return spleefers; } + /** + * return iterator of spleefers list + * @return + */ + public Iterator iterator() { + return spleefers.iterator(); + } + /** * return a specific team list * @param team @@ -201,4 +210,16 @@ public int countUnreadyPlayers() { } return unready; } + + /** + * count lost spleefers + * @return + */ + public int countLostPlayers() { + int lost = 0; + for (Spleefer spleefer : spleefers) { + if (!spleefer.hasLost()) lost++; + } + return lost; + } } diff --git a/src/main/java/de/beimax/simplespleef/game/arenarestoring/ArenaRestorer.java b/src/main/java/de/beimax/simplespleef/game/arenarestoring/ArenaRestorer.java index 1846983..b7efcf2 100644 --- a/src/main/java/de/beimax/simplespleef/game/arenarestoring/ArenaRestorer.java +++ b/src/main/java/de/beimax/simplespleef/game/arenarestoring/ArenaRestorer.java @@ -4,24 +4,64 @@ package de.beimax.simplespleef.game.arenarestoring; import de.beimax.simplespleef.game.Game; -import de.beimax.simplespleef.util.Cuboid; +import de.beimax.simplespleef.game.trackers.Tracker; +import de.beimax.simplespleef.gamehelpers.Cuboid; /** * @author mkalus - * Interface for classes that restore the arena eventually - these classes also have to call the + * Abstract class for classes that restore the arena eventually - these classes also have to call the * handler's game over method to delete the game when finished. */ -public interface ArenaRestorer { +public abstract class ArenaRestorer implements Tracker { /** - * Store the arena for one game + * interrupted signal + */ + protected boolean interrupted = false; + + /** + * game reference + */ + protected Game game; + + /** + * wait seconds before restoring - implement wait in children of this class + */ + protected int waitBeforeRestoring; + + /** + * Constructor + * @param waitBeforeRestoring + */ + public ArenaRestorer(int waitBeforeRestoring) { + this.waitBeforeRestoring = waitBeforeRestoring; + } + + /** + * Set the arena for one game * @param game * @param cuboid */ - public void saveArena(Game game, Cuboid cuboid); + public abstract void setArena(Cuboid cuboid); + + /** + * Store the arena for one game + */ + public abstract void saveArena(); /** * Restore the arena for one game - please call handler's game over method to delete the game when finished restoring. * @param game */ - public void restoreArena(); + public abstract void restoreArena(); + + + @Override + public void initialize(Game game) { + this.game = game; + } + + @Override + public void interrupt() { + interrupted = true; + } } diff --git a/src/main/java/de/beimax/simplespleef/game/arenarestoring/HardArenaRestorer.java b/src/main/java/de/beimax/simplespleef/game/arenarestoring/HardArenaRestorer.java index acdebe8..95b6dc0 100644 --- a/src/main/java/de/beimax/simplespleef/game/arenarestoring/HardArenaRestorer.java +++ b/src/main/java/de/beimax/simplespleef/game/arenarestoring/HardArenaRestorer.java @@ -9,34 +9,50 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import org.bukkit.block.Block; + import de.beimax.simplespleef.SimpleSpleef; -import de.beimax.simplespleef.game.Game; -import de.beimax.simplespleef.util.Cuboid; -import de.beimax.simplespleef.util.SerializableBlockData; +import de.beimax.simplespleef.gamehelpers.Cuboid; +import de.beimax.simplespleef.gamehelpers.SerializableBlockData; /** * @author mkalus * */ -public class HardArenaRestorer implements ArenaRestorer { - /** - * game to restore - */ - private Game game; +public class HardArenaRestorer extends ArenaRestorer { + public static final int STATUS_NONE = 0; + public static final int STATUS_SAVED = 1; + public static final int STATUS_RESTORED = 2; + + private int status = HardArenaRestorer.STATUS_NONE; /** * cuboid to store/restore */ private Cuboid cuboid; + /** + * Constructor + * @param waitBeforeRestoring + */ + public HardArenaRestorer(int waitBeforeRestoring) { + super(waitBeforeRestoring); + } + /* (non-Javadoc) - * @see de.beimax.simplespleef.game.arenarestoring.ArenaRestorer#saveArena(de.beimax.simplespleef.game.Game) + * @see de.beimax.simplespleef.game.arenarestoring.ArenaRestorer#setArena(de.beimax.simplespleef.game.Game) */ @Override - public void saveArena(Game game, Cuboid cuboid) { - if (game == null || cuboid == null) return; //ignore invalid stuff - this.game = game; + public void setArena(Cuboid cuboid) { this.cuboid = cuboid; + } + + /* (non-Javadoc) + * @see de.beimax.simplespleef.game.arenarestoring.ArenaRestorer#saveArena() + */ + @Override + public void saveArena() { + if (game == null || cuboid == null) return; //ignore invalid stuff SerializableBlockData[][][] blockData = this.cuboid.getSerializedBlocks(); @@ -86,8 +102,38 @@ public void restoreArena() { cuboid.setSerializedBlocks(blockData); // delete file at the end - cleanup work... if (!file.delete()) SimpleSpleef.log.warning("[SimpleSpleef] Could not delete file " + file.getName()); + } + + @Override + public boolean tick() { + if (interrupted == true) { // when interrupted, restore arena right awaw + restoreArena(); // finish arena at once + return true; // finish restorer + } + + // wait for game to start + if (status == HardArenaRestorer.STATUS_NONE && game.isInGame()) { // game started and not saved yet + saveArena(); + status = HardArenaRestorer.STATUS_SAVED; + return false; + } - // call game handler to finish the game off - SimpleSpleef.getGameHandler().gameOver(game); + // wait for game to finish - or return, if already restored + if (!game.isFinished() || status == HardArenaRestorer.STATUS_RESTORED) return false; + + // before start restoring count restore ticker to 0 + if (this.waitBeforeRestoring > 0) { + this.waitBeforeRestoring--; + return false; + } + + restoreArena(); // finish arena at once + status = HardArenaRestorer.STATUS_RESTORED; + return true; // finish restorer + } + + @Override + public boolean updateBlock(Block block, int oldType, byte oldData) { // ignore + return false; } } diff --git a/src/main/java/de/beimax/simplespleef/game/arenarestoring/SoftRestorer.java b/src/main/java/de/beimax/simplespleef/game/arenarestoring/SoftRestorer.java index ed02c7a..4aa5ba0 100644 --- a/src/main/java/de/beimax/simplespleef/game/arenarestoring/SoftRestorer.java +++ b/src/main/java/de/beimax/simplespleef/game/arenarestoring/SoftRestorer.java @@ -5,168 +5,120 @@ import java.util.Iterator; import java.util.LinkedList; -import java.util.List; import org.bukkit.Location; import org.bukkit.block.Block; -import de.beimax.simplespleef.SimpleSpleef; -import de.beimax.simplespleef.game.Game; -import de.beimax.simplespleef.game.floortracking.FloorWorker; -import de.beimax.simplespleef.util.Cuboid; -import de.beimax.simplespleef.util.SerializableBlockData; +import de.beimax.simplespleef.gamehelpers.Cuboid; +import de.beimax.simplespleef.gamehelpers.SerializableBlockData; /** * @author mkalus * */ -public class SoftRestorer implements ArenaRestorer, FloorWorker { - /** - * flag to stop worker - actually starts restoration - */ - private boolean startRestoring = false; - - /** - * game to restore - */ - private Game game; - +public class SoftRestorer extends ArenaRestorer { /** * cuboid to store/restore */ private Cuboid cuboid; - - /** - * worker has finished restoring? - */ - private boolean isStopped = false; + //TODO: not really needed at this place, is it? /** * keeps the data of the changed blocks */ private LinkedList changedBlocks; - - /* (non-Javadoc) - * @see de.beimax.simplespleef.game.floortracking.FloorWorker#initialize(de.beimax.simplespleef.game.Game, java.util.List) + + /** + * iterator for the reconstruction of the arena */ - @Override - public void initialize(Game game, List floor) { - //Do nothing - } + Iterator it; - /* (non-Javadoc) - * @see de.beimax.simplespleef.game.floortracking.FloorWorker#stopTracking() + /** + * Constructor + * @param waitBeforeRestoring */ - @Override - public void stopTracking() { - startRestoring = true; + public SoftRestorer(int waitBeforeRestoring) { + super(waitBeforeRestoring); } - /* (non-Javadoc) - * @see de.beimax.simplespleef.game.floortracking.FloorWorker#updateBlock(org.bukkit.block.Block) - */ @Override - public void updateBlock(Block block, int oldType, byte oldData) { - if (block == null || changedBlocks == null) return; // no NPEs - // just add original block type to list - BlockChange change = new BlockChange(); - change.location = block.getLocation(); - change.blockData = new SerializableBlockData(oldType, oldData); - // add at first position, so the restoration is done from the last block changed - changedBlocks.addFirst(change); - //System.out.println("Added!"); + public void setArena(Cuboid cuboid) { + this.cuboid = cuboid; + saveArena(); } - /* (non-Javadoc) - * @see de.beimax.simplespleef.game.arenarestoring.ArenaRestorer#saveArena(de.beimax.simplespleef.game.Game, de.beimax.simplespleef.util.Cuboid) - */ @Override - public void saveArena(Game game, Cuboid cuboid) { - if (game == null || cuboid == null) { - startRestoring = true; // run restore right away - return; //ignore invalid stuff - } - this.game = game; - this.cuboid = cuboid; - + public void saveArena() { // initialize task data this.changedBlocks = new LinkedList(); + this.it = null; } - /* (non-Javadoc) - * @see de.beimax.simplespleef.game.arenarestoring.ArenaRestorer#restoreArena() - */ @Override public void restoreArena() { - if (changedBlocks == null) return; - RestoreWorker worker = new RestoreWorker(); - - // start restore task called every tick - worker.schedulerId = SimpleSpleef.getPlugin().getServer().getScheduler().scheduleAsyncRepeatingTask(SimpleSpleef.getPlugin(), worker, 0L, 1L); - } - - /** - * keeps original positions for blocks - * @author mkalus - * - */ - private class BlockChange { - private Location location; - private SerializableBlockData blockData; + // just started + if (it == null) + it = changedBlocks.iterator(); + + // 40 blocks per tick max + for (int i = 0; i < 40; i++) { + if (!it.hasNext()) { + it = null; + break; + } else { // restore blocks + BlockChange changedBlock = it.next(); + Block block = changedBlock.location.getBlock(); + block.setTypeId(changedBlock.blockData.getTypeId()); + block.setData(changedBlock.blockData.getData()); + } + } + } @Override - public void tick() { - if (game == null || cuboid == null) return; //ignore invalid stuff - - // wait for the restoration process to start - if (!startRestoring) return; + public boolean tick() { + if (interrupted == true) { // when interrupted, restore arena right awaw + restoreArena(); // finish arena at once + return true; // finish restorer + } + + // wait for game to finish + if (!game.isFinished()) return false; - restoreArena(); + // before start restoring count restore ticker to 0 + if (this.waitBeforeRestoring > 0) { + this.waitBeforeRestoring--; + return false; + } + + restoreArena(); // start restoring + // test, if all blocks have been restored + if (it == null) return true; + // otherwise wait another tick + return false; } @Override - public boolean isStopped() { - return isStopped; + public boolean updateBlock(Block block, int oldType, byte oldData) { + if (block == null || changedBlocks == null) return false; // no NPEs + // just add original block type to list + BlockChange change = new BlockChange(); + change.location = block.getLocation(); + change.blockData = new SerializableBlockData(oldType, oldData); + // add at first position, so the restoration is done from the last block changed + changedBlocks.addFirst(change); + //System.out.println("Added!"); + return true; } - + /** - * restorer task - called every server tick + * keeps original positions for blocks * @author mkalus * */ - private class RestoreWorker implements Runnable { - private int schedulerId = -1; - - Iterator it = null; - - @Override - public void run() { - // just started - if (it == null) - it = changedBlocks.iterator(); - - // 40 blocks per tick max - for (int i = 0; i < 40; i++) { - if (!it.hasNext()) { - isStopped = true; // yes, we are finished - break; - } else { // restore blocks - BlockChange changedBlock = it.next(); - Block block = changedBlock.location.getBlock(); - block.setTypeId(changedBlock.blockData.getTypeId()); - block.setData(changedBlock.blockData.getData()); - } - } - - // have we finished? - if (isStopped) { - // stop scheduler task - SimpleSpleef.getPlugin().getServer().getScheduler().cancelTask(schedulerId); - // call game handler to finish the game off - SimpleSpleef.getGameHandler().gameOver(game); - } - } + private class BlockChange { + private Location location; + private SerializableBlockData blockData; } } diff --git a/src/main/java/de/beimax/simplespleef/game/floortracking/FloorBaseWorker.java b/src/main/java/de/beimax/simplespleef/game/floortracking/FloorBaseWorker.java deleted file mode 100644 index d9a309e..0000000 --- a/src/main/java/de/beimax/simplespleef/game/floortracking/FloorBaseWorker.java +++ /dev/null @@ -1,100 +0,0 @@ -/** - * - */ -package de.beimax.simplespleef.game.floortracking; - -import java.util.List; - -import org.bukkit.block.Block; - -import de.beimax.simplespleef.game.Game; - -/** - * @author mkalus - * - */ -public abstract class FloorBaseWorker implements FloorWorker { - /** - * seconds after which task actually starts doing something - */ - private int startAfter; - - /** - * seconds to wait each tick of the task - */ - private int tickTime; - - /** - * system time to start task at - */ - private long startAt = 0; - - /** - * system time for next tick - */ - private long nextTick = 0; - - /** - * reference to tracker - */ - private FloorTracker tracker; - - /** - * flag to stop task - */ - protected boolean stop = false; - - /** - * Constructor - * @param startAfter - * @param tickTime - */ - public FloorBaseWorker(int startAfter, int tickTime, FloorTracker tracker) { - this.startAfter = startAfter; - this.tickTime = tickTime; - this.tracker = tracker; - } - - /** - * initialize task - */ - @Override - public void initialize(Game game, List floor) { - startAt = System.currentTimeMillis() + ((long) startAfter * 1000); - nextTick = startAt; - } - - /** - * do a tick - */ - @Override - public void tick() { - long now = System.currentTimeMillis(); - // first, wait for worker to start and wait for the next tick - if (now < startAt || now < nextTick) return; - - // now do the actual tick work - executeTick(); - // update tick - nextTick = nextTick + ((long) tickTime * 1000); - } - - /** - * do a tick within the task - */ - public abstract void executeTick(); - - /** - * Notify the tracker about a block change - called by tick() when a block changes, - * so other trackers can update this block - * @param block changed block - */ - protected void notifyTracker(Block block, int oldType, byte oldData) { - tracker.notifyChangedBlock(block, oldType, oldData, this); - } - - @Override - public boolean isStopped() { - return stop; - } -} diff --git a/src/main/java/de/beimax/simplespleef/game/floortracking/FloorTracker.java b/src/main/java/de/beimax/simplespleef/game/floortracking/FloorTracker.java deleted file mode 100644 index bad8211..0000000 --- a/src/main/java/de/beimax/simplespleef/game/floortracking/FloorTracker.java +++ /dev/null @@ -1,212 +0,0 @@ -/** - * - */ - -package de.beimax.simplespleef.game.floortracking; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import org.bukkit.block.Block; - -import de.beimax.simplespleef.SimpleSpleef; -import de.beimax.simplespleef.game.Game; -import de.beimax.simplespleef.util.Cuboid; - -/** - * @author mkalus - * Keeps track of the floor - used by automatic arena degeneration and repair spleefs - */ -public class FloorTracker implements Runnable { - /** - * Time in seconds, after which the arena floor starts to dissolve slowly (-1 disables this) - */ - private int arenaFloorDissolvesAfter = -1; - - /** - * Time in seconds for new blocks to dissolve into thin air - */ - private int arenaFloorDissolveTick = 5; - - /** - * Time in seconds, after which the arena floor starts to repair slowly (-1 disables this) - */ - private int arenaFloorRepairsAfter = -1; - - /** - * Time in seconds for new blocks to get repaired - */ - private int arenaFloorRepairTick = 10; - - /** - * flag to stop worker - */ - private boolean stop = false; - - /** - * id of the Bukkit scheduler for the tracker - */ - int schedulerId = -1; - - /** - * list of floor workers to be called - */ - LinkedList floorWorkers = new LinkedList(); - - /** - * @return the arenaFloorDissolvesAfter - */ - public int getArenaFloorDissolvesAfter() { - return arenaFloorDissolvesAfter; - } - - /** - * @param arenaFloorDissolvesAfter the arenaFloorDissolvesAfter to set - */ - public void setArenaFloorDissolvesAfter(int arenaFloorDissolvesAfter) { - this.arenaFloorDissolvesAfter = arenaFloorDissolvesAfter; - } - - /** - * @return the arenaFloorDissolveTick - */ - public int getArenaFloorDissolveTick() { - return arenaFloorDissolveTick; - } - - /** - * @param arenaFloorDissolveTick the arenaFloorDissolveTick to set - */ - public void setArenaFloorDissolveTick(int arenaFloorDissolveTick) { - this.arenaFloorDissolveTick = arenaFloorDissolveTick; - } - - /** - * @return the arenaFloorRepairsAfter - */ - public int getArenaFloorRepairsAfter() { - return arenaFloorRepairsAfter; - } - - /** - * @param arenaFloorRepairsAfter the arenaFloorRepairsAfter to set - */ - public void setArenaFloorRepairsAfter(int arenaFloorRepairsAfter) { - this.arenaFloorRepairsAfter = arenaFloorRepairsAfter; - } - - /** - * @return the arenaFloorRepairTick - */ - public int getArenaFloorRepairTick() { - return arenaFloorRepairTick; - } - - /** - * @param arenaFloorRepairTick the arenaFloorRepairTick to set - */ - public void setArenaFloorRepairTick(int arenaFloorRepairTick) { - this.arenaFloorRepairTick = arenaFloorRepairTick; - } - - /** - * start tracking floor changes - * @param game - * @param floor - */ - public void startTracking(Game game, Cuboid floor) { - //initialize floor dissolve task - if (arenaFloorDissolvesAfter >= 0) { - floorWorkers.add(new FloorDissolveWorker(arenaFloorDissolvesAfter, arenaFloorDissolveTick, this)); - } - - //initialize floor repair task - if (arenaFloorRepairsAfter >= 0) { - floorWorkers.add(new FloorRepairWorker(arenaFloorRepairsAfter, arenaFloorRepairTick, this)); - } - - // get diggable floor - List blocks; - if (floor != null) blocks = floor.getDiggableBlocks(game); - else blocks = null; // this will stop some of the trackers right away - - // initialize tasks one by one - for (FloorWorker floorWorker : floorWorkers) { - floorWorker.initialize(game, blocks); - } - - // start tracking - schedulerId = SimpleSpleef.getPlugin().getServer().getScheduler().scheduleAsyncRepeatingTask(SimpleSpleef.getPlugin(), this, 0L, 20L); - } - - @Override - public void run() { - // not stopped: normal operations - if (!stop) { - // actual worker task: execute ticks for all workers - for (FloorWorker floorWorker : floorWorkers) { - floorWorker.tick(); - } - } - - //wait for floor workers to be stopped - Iterator i = floorWorkers.iterator(); //use iterator, because one can remove while traversing... - while (i.hasNext()) { - FloorWorker floorWorker = i.next(); - if (floorWorker.isStopped()) i.remove(); - } - - // is our list empty? If yes, cancel scheduler - if (floorWorkers.size() == 0) { - SimpleSpleef.getPlugin().getServer().getScheduler().cancelTask(schedulerId); - } - } - - /** - * stop tracking floor changes - */ - public void stopTracking() { - stop = true; - // stop tracking for all floors workers - for (FloorWorker floorWorker : floorWorkers) { - floorWorker.stopTracking(); - } - } - - /** - * update a certain block location - * @param block - * @param oldType - old type of block - * @param oldData - old data of block - */ - public void updateBlock(Block block, int oldType, byte oldData) { - if (!stop) // if stopped, do not update changes any more - for (FloorWorker floorWorker : floorWorkers) { - floorWorker.updateBlock(block, oldType, oldData); - } - } - - /** - * Called by tick()-methods of FloorWorkers when they change a block, - * so other trackers can update their block database. - * @param block - * @param oldType - old type of block - * @param oldData - old data of block - * @param caller - */ - public void notifyChangedBlock(Block block, int oldType, byte oldData, FloorWorker caller) { - for (FloorWorker floorWorker : floorWorkers) { - if (floorWorker != caller) // caller is not updated - has to do this itself - floorWorker.updateBlock(block, oldType, oldData); - } - } - - /** - * Add a new floor worker to tracker - * @param worker - */ - public void addFloorWorker(FloorWorker worker) { - floorWorkers.add(worker); - } -} diff --git a/src/main/java/de/beimax/simplespleef/game/floortracking/FloorWorker.java b/src/main/java/de/beimax/simplespleef/game/floortracking/FloorWorker.java deleted file mode 100644 index 290e851..0000000 --- a/src/main/java/de/beimax/simplespleef/game/floortracking/FloorWorker.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * - */ -package de.beimax.simplespleef.game.floortracking; - -import java.util.List; - -import org.bukkit.block.Block; - -import de.beimax.simplespleef.game.Game; - -/** - * @author mkalus - * Interface for individual tracker tasks - */ -public interface FloorWorker { - /** - * Initialize the tracker - * @param game - * @param floor - */ - public void initialize(Game game, List floor); - - /** - * do an action tick, possible do floor change or the like here - */ - public void tick(); - - /** - * Stop tracking - */ - public void stopTracking(); - - /** - * update a certain block location - * @param block - new block data - * @param oldType - old type of block - * @param oldData - old data of block - */ - public void updateBlock(Block block, int oldType, byte oldData); - - /** - * returns true if tracker has been stopped - * @return - */ - public boolean isStopped(); -} diff --git a/src/main/java/de/beimax/simplespleef/game/trackers/Countdown.java b/src/main/java/de/beimax/simplespleef/game/trackers/Countdown.java new file mode 100644 index 0000000..029c2aa --- /dev/null +++ b/src/main/java/de/beimax/simplespleef/game/trackers/Countdown.java @@ -0,0 +1,114 @@ +/** + * This file is part of the SimpleSpleef bukkit plugin. + * Copyright (C) 2011 Maximilian Kalus + * See http://dev.bukkit.org/server-mods/simple-spleef/ + * + * This program 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. + * + * This program 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 this program. If not, see . + **/ + +package de.beimax.simplespleef.game.trackers; + +import org.bukkit.ChatColor; +import org.bukkit.block.Block; + +import de.beimax.simplespleef.SimpleSpleef; +import de.beimax.simplespleef.game.Game; + +/** + * Implements countdown tracker + * @author mkalus + * + */ +public class Countdown implements Tracker { + /** + * flag to toggle interrupts + */ + private boolean interrupted = false; + + /** + * counter + */ + private int count = -1; + + /** + * should coundown be broadcast? + */ + private boolean broadcast; + + /** + * game reference + */ + private Game game; + + /** + * Constructor + * @param count + */ + public Countdown(int count) { + this.count = count; + } + + /* (non-Javadoc) + * @see de.beimax.simplespleef.game.trackers.Tracker#initialize(de.beimax.simplespleef.game.Game) + */ + @Override + public void initialize(Game game) { + this.game = game; + + // announce countdown? + broadcast = SimpleSpleef.getPlugin().getConfig().getBoolean("settings.announceCountdown", true); + // start announcing + game.sendMessage(ChatColor.BLUE + SimpleSpleef.ll("feedback.countdownStart"), broadcast); + } + + /* (non-Javadoc) + * @see de.beimax.simplespleef.game.trackers.Tracker#interrupt() + */ + @Override + public void interrupt() { + this.interrupted = true; + } + + /* (non-Javadoc) + * @see de.beimax.simplespleef.game.trackers.Tracker#tick() + */ + @Override + public boolean tick() { + if (interrupted) { + // send message + game.sendMessage(ChatColor.RED + SimpleSpleef.ll("feedback.countdownInterrupted"), broadcast); + game.endGame(); + } + + // do countdown + if (count > 0) { + game.sendMessage(ChatColor.BLUE + SimpleSpleef.ll("feedback.countdown", "[COUNT]", String.valueOf(count), "[ARENA]", game.getName()), broadcast); + count--; + } else { + // send message + game.sendMessage(ChatColor.BLUE + SimpleSpleef.ll("feedback.countdownGo"), broadcast); + // start the game itself! + game.start(); + // cancel countdown + return true; + } + + return false; + } + + @Override + public boolean updateBlock(Block block, int oldType, byte oldData) { // ignore + return false; + } +} diff --git a/src/main/java/de/beimax/simplespleef/game/trackers/FloorBaseWorker.java b/src/main/java/de/beimax/simplespleef/game/trackers/FloorBaseWorker.java new file mode 100644 index 0000000..61ff823 --- /dev/null +++ b/src/main/java/de/beimax/simplespleef/game/trackers/FloorBaseWorker.java @@ -0,0 +1,92 @@ +/** + * + */ +package de.beimax.simplespleef.game.trackers; + +import de.beimax.simplespleef.game.Game; + +/** + * @author mkalus + * + */ +public abstract class FloorBaseWorker implements Tracker { + /** + * flag to toggle interrupts + */ + protected boolean interrupted = false; + + /** + * game reference + */ + protected Game game; + + /** + * seconds after which task actually starts doing something + */ + protected int startAfter; + + /** + * seconds to wait each tick of the task + */ + protected int tickTime; + + /** + * system time to start task at + */ + protected long startCounter = 0; + + /** + * system time for next tick + */ + protected long tickCounter = 0; + + /** + * Constructor + * @param startAfter + * @param tickTime + */ + public FloorBaseWorker(int startAfter, int tickTime) { + this.startAfter = startAfter; + this.tickTime = tickTime; + } + + @Override + public void initialize(Game game) { + this.game = game; + startCounter = startAfter; // initial counter + } + + @Override + public void interrupt() { + this.interrupted = true; + } + + @Override + public boolean tick() { + if (interrupted || game.isFinished()) return true; // stop at the end of the game + + // wait for game to start + if (!game.isInGame()) return false; + + // game started, initial countdown in progress? + if (startCounter > 0) { + startCounter--; + return false; + } + + // count down ticks + if (tickCounter > 0) { + tickCounter--; + } else { // it's time! + executeTick(); + tickCounter = tickTime; // renew counter + } + + return false; + } + + /** + * do a tick within the task + */ + public abstract void executeTick(); +} diff --git a/src/main/java/de/beimax/simplespleef/game/floortracking/FloorDissolveWorker.java b/src/main/java/de/beimax/simplespleef/game/trackers/FloorDissolveWorker.java similarity index 55% rename from src/main/java/de/beimax/simplespleef/game/floortracking/FloorDissolveWorker.java rename to src/main/java/de/beimax/simplespleef/game/trackers/FloorDissolveWorker.java index d506796..bb5a13e 100644 --- a/src/main/java/de/beimax/simplespleef/game/floortracking/FloorDissolveWorker.java +++ b/src/main/java/de/beimax/simplespleef/game/trackers/FloorDissolveWorker.java @@ -1,7 +1,7 @@ /** * */ -package de.beimax.simplespleef.game.floortracking; +package de.beimax.simplespleef.game.trackers; import java.util.HashSet; import java.util.List; @@ -11,8 +11,6 @@ import org.bukkit.Material; import org.bukkit.block.Block; -import de.beimax.simplespleef.game.Game; - /** * @author mkalus * @@ -28,21 +26,8 @@ public class FloorDissolveWorker extends FloorBaseWorker { * @param startAfter * @param tickTime */ - public FloorDissolveWorker(int startAfter, int tickTime, FloorTracker tracker) { - super(startAfter, tickTime, tracker); - } - - /* (non-Javadoc) - * @see de.beimax.simplespleef.game.floortracking.FloorWorker#initialize(de.beimax.simplespleef.game.Game, java.util.List) - */ - @Override - public void initialize(Game game, List floor) { - if (floor == null) { - stop = true; - return; // ignore null floors - } - - super.initialize(game, floor); + public FloorDissolveWorker(int startAfter, int tickTime, List floor) { + super(startAfter, tickTime); for (Block block : floor) { if (block == null) continue; // no NPEs if (block.getType() != Material.AIR) // add location to nonAir locations @@ -50,29 +35,29 @@ public void initialize(Game game, List floor) { } } - /* (non-Javadoc) - * @see de.beimax.simplespleef.game.floortracking.FloorWorker#updateBlock(org.bukkit.block.Block) - */ @Override - public void updateBlock(Block block, int oldType, byte oldData) { - if (block == null) return; // no NPEs - if (stop) return; + public boolean updateBlock(Block block, int oldType, byte oldData) { + if (block == null) return false; // no NPEs Location loc = block.getLocation(); if (nonAir.contains(loc)) { - if (block.getType() == Material.AIR) // dissolve to air + if (block.getType() == Material.AIR) { // dissolve to air nonAir.remove(loc); // remove because it is air anyway - } else if (block.getType() != Material.AIR) // non air added - add to dissolveable parts of arena - nonAir.add(loc); + return true; + } + } else if (block.getType() != Material.AIR) { // non air added - add to dissolveable parts of arena + nonAir.add(loc); + return true; + } + + return false; } - /* (non-Javadoc) - * @see de.beimax.simplespleef.game.floortracking.FloorBaseWorker#executeTick() - */ @Override public void executeTick() { // get a random entry Location location = getRandomEntry(); + //System.out.println("Tick FloorDissolveWorker " + location); if (location != null) { Block block = location.getBlock(); // get old data @@ -82,11 +67,11 @@ public void executeTick() { block.setType(Material.AIR); block.setData((byte) 0); nonAir.remove(location); - // notify others - notifyTracker(block, oldType, oldData); + // notify others - and myself + game.trackersUpdateBlock(block, oldType, oldData); } } - + /** * picks a random entry from non-air set */ @@ -102,10 +87,4 @@ private Location getRandomEntry() { return null; // if all locations have been dissolved } - - @Override - public void stopTracking() { - nonAir = null; - stop = true; - } } diff --git a/src/main/java/de/beimax/simplespleef/game/floortracking/FloorRepairWorker.java b/src/main/java/de/beimax/simplespleef/game/trackers/FloorRepairWorker.java similarity index 64% rename from src/main/java/de/beimax/simplespleef/game/floortracking/FloorRepairWorker.java rename to src/main/java/de/beimax/simplespleef/game/trackers/FloorRepairWorker.java index 64b9ed7..b050c39 100644 --- a/src/main/java/de/beimax/simplespleef/game/floortracking/FloorRepairWorker.java +++ b/src/main/java/de/beimax/simplespleef/game/trackers/FloorRepairWorker.java @@ -1,7 +1,7 @@ /** * */ -package de.beimax.simplespleef.game.floortracking; +package de.beimax.simplespleef.game.trackers; import java.util.HashMap; import java.util.HashSet; @@ -12,8 +12,7 @@ import org.bukkit.Material; import org.bukkit.block.Block; -import de.beimax.simplespleef.game.Game; -import de.beimax.simplespleef.util.SerializableBlockData; +import de.beimax.simplespleef.gamehelpers.SerializableBlockData; /** * @author mkalus @@ -29,28 +28,14 @@ public class FloorRepairWorker extends FloorBaseWorker { * areas of the floor that are air (changed areas) */ private HashSet air = new HashSet(); - + /** * Constructor * @param startAfter * @param tickTime */ - public FloorRepairWorker(int startAfter, int tickTime, FloorTracker tracker) { - super(startAfter, tickTime, tracker); - } - - /* (non-Javadoc) - * @see de.beimax.simplespleef.game.floortracking.FloorWorker#initialize(de.beimax.simplespleef.game.Game, java.util.List) - */ - @Override - public void initialize(Game game, List floor) { - if (floor == null) { - stop = true; - return; // ignore null floors - } - - super.initialize(game, floor); - //TODO: do we really need an original block memory or can we do something like in the SoftRestorer? + public FloorRepairWorker(int startAfter, int tickTime, List floor) { + super(startAfter, tickTime); for (Block block : floor) { if (block == null) continue; // no NPEs if (block.getType() != Material.AIR) // add location to original locations @@ -58,29 +43,25 @@ public void initialize(Game game, List floor) { } } - /* (non-Javadoc) - * @see de.beimax.simplespleef.game.floortracking.FloorWorker#updateBlock(org.bukkit.block.Block) - */ @Override - public void updateBlock(Block block, int oldType, byte oldData) { - if (block == null) return; // no NPEs - if (stop) return; + public boolean updateBlock(Block block, int oldType, byte oldData) { + if (block == null) return false; // no NPEs Location loc = block.getLocation(); if (originalBlocks.containsKey(loc)) { // only locations that are contained in the original block database if (block.getType() == Material.AIR) // dissolved to air? air.add(loc); //add location to repair it later on else air.remove(loc); // if not dissolved, remove from repair list to prevent repairs - } + return true; + } + return false; } - /* (non-Javadoc) - * @see de.beimax.simplespleef.game.floortracking.FloorBaseWorker#executeTick() - */ @Override public void executeTick() { // get a random entry Location location = getRandomEntry(); + //System.out.println("Tick FloorRepairWorker " + location); if (location != null) { SerializableBlockData blockData = originalBlocks.get(location); // get original block data if (blockData == null) return; // no NPEs, should not happen here, but just to make sure... @@ -92,11 +73,11 @@ public void executeTick() { block.setTypeId(blockData.getTypeId()); block.setData(blockData.getData()); air.remove(location); - // notify others - notifyTracker(block, oldType, oldData); + // notify others - and myself + game.trackersUpdateBlock(block, oldType, oldData); } } - + /** * picks a random entry from air set */ @@ -112,11 +93,4 @@ private Location getRandomEntry() { return null; // if all locations have been dissolved } - - @Override - public void stopTracking() { - originalBlocks = null; - air = null; - stop = true; - } } diff --git a/src/main/java/de/beimax/simplespleef/game/trackers/PlayerOnBlockDegenerator.java b/src/main/java/de/beimax/simplespleef/game/trackers/PlayerOnBlockDegenerator.java new file mode 100644 index 0000000..f4b3fa1 --- /dev/null +++ b/src/main/java/de/beimax/simplespleef/game/trackers/PlayerOnBlockDegenerator.java @@ -0,0 +1,220 @@ +/** + * This file is part of the SimpleSpleef bukkit plugin. + * Copyright (C) 2011 Maximilian Kalus + * See http://dev.bukkit.org/server-mods/simple-spleef/ + * + * This program 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. + * + * This program 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 this program. If not, see . + **/ + +package de.beimax.simplespleef.game.trackers; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import de.beimax.simplespleef.game.Game; +import de.beimax.simplespleef.game.Spleefer; +import de.beimax.simplespleef.gamehelpers.MaterialHelper; + +/** + * @author mkalus + * + */ +public class PlayerOnBlockDegenerator implements Tracker { + /** + * flag to toggle interrupts + */ + private boolean interrupted = false; + + /** + * game reference + */ + private Game game; + + /** + * count block degeneration + */ + private int blockDegeneration; + + /** + * list of blocks that will degenerate when standing on them for too long + */ + private List degeneratingBlocks; + + /** + * list of DegenerationKeeper to players + */ + private Map degenerationList; + + /** + * Constructor + * @param blockDegeneration + */ + public PlayerOnBlockDegenerator(int blockDegeneration, List degeneratingBlocks) { + this.blockDegeneration = blockDegeneration; + this.degenerationList = new HashMap(); + + // fill with degenerating blocks + this.degeneratingBlocks = new LinkedList(); + for (String string : degeneratingBlocks) { + ItemStack stack = MaterialHelper.getItemStackFromString(string, true); + if (stack != null) this.degeneratingBlocks.add(stack); + } + } + + /* (non-Javadoc) + * @see de.beimax.simplespleef.game.trackers.Tracker#initialize(de.beimax.simplespleef.game.Game) + */ + @Override + public void initialize(Game game) { + this.game = game; + } + + /* (non-Javadoc) + * @see de.beimax.simplespleef.game.trackers.Tracker#interrupt() + */ + @Override + public void interrupt() { + interrupted = true; + } + + /* (non-Javadoc) + * @see de.beimax.simplespleef.game.trackers.Tracker#tick() + */ + @Override + public boolean tick() { + // if interrupted or finished - finish tracker, too + if (interrupted || game.isFinished()) { + return true; + } + + // wait for game to start + if (!game.isInGame()) return false; + + // run through active spleefers and check their positions + for (Spleefer spleefer : game.getSpleefers().get()) { + if (!spleefer.hasLost()) + updatePosition(spleefer.getPlayer()); + } + + return false; + } + + /** + * update player position in list + * @param player + */ + private void updatePosition(Player player) { + // try to get from list + DegenerationKeeper keeper = degenerationList.get(player); + + if (keeper == null) { // new entry? + addNewBlock(player); + } else { + // check player position + Block playerOnBlock = player.getLocation().getBlock().getRelative(BlockFace.DOWN); + // did the player move? + if (playerOnBlock != keeper.checkedBlock) { + degenerationList.remove(player); // remove player from list + addNewBlock(player); // new block for player + return; + } + + // decrement counter and check + keeper.counter--; + if (keeper.counter <= 0) { // reset counter + // if for some reason, block has already dissolved into air + if (keeper.checkedBlock.getType() == Material.AIR) { + degenerationList.remove(player); // remove player from list + return; + } + + // get original data + int oldType = keeper.checkedBlock.getTypeId(); + byte oldData = keeper.checkedBlock.getData(); + keeper.checkedBlock.setType(Material.AIR); // block dissolves into thin air + keeper.checkedBlock.setData((byte) 0); + + degenerationList.remove(player); // remove player from list + + // update trackers + game.trackersUpdateBlock(keeper.checkedBlock, oldType, oldData); + } + } + } + + /** + * get the block player is standing on - if is is degeneratable + * @param player + * @return block or null, if block is not degeneratable + */ + private Block getPlayerOnBlock(Player player) { + // get block player is standing on + Block block = player.getLocation().getBlock().getRelative(BlockFace.DOWN); + + // do not degenerate air + if (block.getType() == Material.AIR) return null; + + // only if in list of blocks + if (degeneratingBlocks == null || degeneratingBlocks.size() == 0 || MaterialHelper.isSameBlockType(block, degeneratingBlocks)) { + return block; + } + + return null; + } + + /** + * helper method to add new block for player + * @param player + */ + private Block addNewBlock(Player player) { + Block block = getPlayerOnBlock(player); + if (block != null) { // create new keeper + DegenerationKeeper keeper = new DegenerationKeeper(); + keeper.checkedBlock = block; + keeper.counter = blockDegeneration; + degenerationList.put(player, keeper); + } + return block; + } + + /* (non-Javadoc) + * @see de.beimax.simplespleef.game.trackers.Tracker#updateBlock(org.bukkit.block.Block, int, byte) + */ + @Override + public boolean updateBlock(Block block, int oldType, byte oldData) { + return false; // ignore + } + + /** + * Keeps track of player's block and its degeneration + * @author mkalus + * + */ + private class DegenerationKeeper { + /** + * keeps track of the checked block + */ + private Block checkedBlock = null; + + private int counter = 0; + } +} diff --git a/src/main/java/de/beimax/simplespleef/game/trackers/Tracker.java b/src/main/java/de/beimax/simplespleef/game/trackers/Tracker.java new file mode 100644 index 0000000..ba068bc --- /dev/null +++ b/src/main/java/de/beimax/simplespleef/game/trackers/Tracker.java @@ -0,0 +1,53 @@ +/** + * This file is part of the SimpleSpleef bukkit plugin. + * Copyright (C) 2011 Maximilian Kalus + * See http://dev.bukkit.org/server-mods/simple-spleef/ + * + * This program 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. + * + * This program 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 this program. If not, see . + **/ + +package de.beimax.simplespleef.game.trackers; + +import org.bukkit.block.Block; + +import de.beimax.simplespleef.game.Game; + +/** + * @author mkalus + * + */ +public interface Tracker { + /** + * Initialize a tracker + * @param game reference + */ + public void initialize(Game game); + + /** + * Interrupt a tracker + */ + public void interrupt(); + + /** + * Call tracker tick + * @return true, if tracker has ended + */ + public boolean tick(); + + /** + * Called when a block in the arena is changed + * @return true if tracker did something with the block + */ + public boolean updateBlock(Block block, int oldType, byte oldData); +} diff --git a/src/main/java/de/beimax/simplespleef/util/Cuboid.java b/src/main/java/de/beimax/simplespleef/gamehelpers/Cuboid.java similarity index 97% rename from src/main/java/de/beimax/simplespleef/util/Cuboid.java rename to src/main/java/de/beimax/simplespleef/gamehelpers/Cuboid.java index 79407f5..a345567 100644 --- a/src/main/java/de/beimax/simplespleef/util/Cuboid.java +++ b/src/main/java/de/beimax/simplespleef/gamehelpers/Cuboid.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ -package de.beimax.simplespleef.util; +package de.beimax.simplespleef.gamehelpers; import java.util.List; diff --git a/src/main/java/de/beimax/simplespleef/util/CuboidImpl.java b/src/main/java/de/beimax/simplespleef/gamehelpers/CuboidImpl.java similarity index 96% rename from src/main/java/de/beimax/simplespleef/util/CuboidImpl.java rename to src/main/java/de/beimax/simplespleef/gamehelpers/CuboidImpl.java index 2eb7f73..7ab9fdd 100644 --- a/src/main/java/de/beimax/simplespleef/util/CuboidImpl.java +++ b/src/main/java/de/beimax/simplespleef/gamehelpers/CuboidImpl.java @@ -1,7 +1,7 @@ /** * */ -package de.beimax.simplespleef.util; +package de.beimax.simplespleef.gamehelpers; import java.util.LinkedList; import java.util.List; @@ -151,7 +151,7 @@ public List getDiggableBlocks(Game game) { for (int y = this.coords[1]; y <= this.coords[4]; y++) for (int z = this.coords[2]; z <= this.coords[5]; z++) { Block block = this.world.getBlockAt(x, y, z); - if (block != null && game.checkMayBreakBlock(block)) { // can this block be broken + if (block != null && game.checkMayBreakBlock(block, null)) { // can this block be broken diggableBlocks.add(block); } } diff --git a/src/main/java/de/beimax/simplespleef/util/CuboidWorldGuard.java b/src/main/java/de/beimax/simplespleef/gamehelpers/CuboidWorldGuard.java similarity index 97% rename from src/main/java/de/beimax/simplespleef/util/CuboidWorldGuard.java rename to src/main/java/de/beimax/simplespleef/gamehelpers/CuboidWorldGuard.java index af14d04..1e10e66 100644 --- a/src/main/java/de/beimax/simplespleef/util/CuboidWorldGuard.java +++ b/src/main/java/de/beimax/simplespleef/gamehelpers/CuboidWorldGuard.java @@ -1,7 +1,7 @@ /** * */ -package de.beimax.simplespleef.util; +package de.beimax.simplespleef.gamehelpers; import java.util.LinkedList; import java.util.List; @@ -123,7 +123,7 @@ public List getDiggableBlocks(Game game) { for (int y = coords[1]; y <= coords[4]; y++) for (int z = coords[2]; z <= coords[5]; z++) { Block block = this.world.getBlockAt(x, y, z); - if (block != null && this.region.contains(x, y, z) && game.checkMayBreakBlock(block)) { // can this block be broken and within the region + if (block != null && this.region.contains(x, y, z) && game.checkMayBreakBlock(block, null)) { // can this block be broken and within the region diggableBlocks.add(block); } } diff --git a/src/main/java/de/beimax/simplespleef/util/InventoryKeeper.java b/src/main/java/de/beimax/simplespleef/gamehelpers/InventoryKeeper.java similarity index 98% rename from src/main/java/de/beimax/simplespleef/util/InventoryKeeper.java rename to src/main/java/de/beimax/simplespleef/gamehelpers/InventoryKeeper.java index 7ad61a9..7186550 100644 --- a/src/main/java/de/beimax/simplespleef/util/InventoryKeeper.java +++ b/src/main/java/de/beimax/simplespleef/gamehelpers/InventoryKeeper.java @@ -1,7 +1,7 @@ /** * */ -package de.beimax.simplespleef.util; +package de.beimax.simplespleef.gamehelpers; import java.util.HashMap; diff --git a/src/main/java/de/beimax/simplespleef/util/LocationHelper.java b/src/main/java/de/beimax/simplespleef/gamehelpers/LocationHelper.java similarity index 98% rename from src/main/java/de/beimax/simplespleef/util/LocationHelper.java rename to src/main/java/de/beimax/simplespleef/gamehelpers/LocationHelper.java index e92a549..3ab2075 100644 --- a/src/main/java/de/beimax/simplespleef/util/LocationHelper.java +++ b/src/main/java/de/beimax/simplespleef/gamehelpers/LocationHelper.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ -package de.beimax.simplespleef.util; +package de.beimax.simplespleef.gamehelpers; import java.util.Map; diff --git a/src/main/java/de/beimax/simplespleef/util/MaterialHelper.java b/src/main/java/de/beimax/simplespleef/gamehelpers/MaterialHelper.java similarity index 99% rename from src/main/java/de/beimax/simplespleef/util/MaterialHelper.java rename to src/main/java/de/beimax/simplespleef/gamehelpers/MaterialHelper.java index 7128100..8f184eb 100644 --- a/src/main/java/de/beimax/simplespleef/util/MaterialHelper.java +++ b/src/main/java/de/beimax/simplespleef/gamehelpers/MaterialHelper.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ -package de.beimax.simplespleef.util; +package de.beimax.simplespleef.gamehelpers; import java.util.List; diff --git a/src/main/java/de/beimax/simplespleef/game/OriginalPositionKeeper.java b/src/main/java/de/beimax/simplespleef/gamehelpers/OriginalPositionKeeper.java similarity index 97% rename from src/main/java/de/beimax/simplespleef/game/OriginalPositionKeeper.java rename to src/main/java/de/beimax/simplespleef/gamehelpers/OriginalPositionKeeper.java index a746589..beb78ed 100644 --- a/src/main/java/de/beimax/simplespleef/game/OriginalPositionKeeper.java +++ b/src/main/java/de/beimax/simplespleef/gamehelpers/OriginalPositionKeeper.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ -package de.beimax.simplespleef.game; +package de.beimax.simplespleef.gamehelpers; import java.util.HashMap; import java.util.Map.Entry; @@ -83,8 +83,7 @@ public Location getOriginalPosition(Player player) { * @param player */ public void updateOriginalLocationTimestamp(Player player) { - PlayerOriginalLocation loc = playerOriginalLocations.get(player - .getName()); + PlayerOriginalLocation loc = playerOriginalLocations.get(player.getName()); if (loc != null) loc.timestamp = System.currentTimeMillis() / 1000; } @@ -95,7 +94,7 @@ public void updateOriginalLocationTimestamp(Player player) { * @param player */ public void deleteOriginalPosition(Player player) { - + playerOriginalLocations.remove(player.getName()); } /** diff --git a/src/main/java/de/beimax/simplespleef/util/SerializableBlockData.java b/src/main/java/de/beimax/simplespleef/gamehelpers/SerializableBlockData.java similarity index 97% rename from src/main/java/de/beimax/simplespleef/util/SerializableBlockData.java rename to src/main/java/de/beimax/simplespleef/gamehelpers/SerializableBlockData.java index face85b..64d0af5 100644 --- a/src/main/java/de/beimax/simplespleef/util/SerializableBlockData.java +++ b/src/main/java/de/beimax/simplespleef/gamehelpers/SerializableBlockData.java @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . **/ -package de.beimax.simplespleef.util; +package de.beimax.simplespleef.gamehelpers; import java.io.Serializable; diff --git a/src/main/java/de/beimax/simplespleef/listeners/SimpleSpleefBlockListener.java b/src/main/java/de/beimax/simplespleef/listeners/SimpleSpleefBlockListener.java deleted file mode 100644 index fc60f08..0000000 --- a/src/main/java/de/beimax/simplespleef/listeners/SimpleSpleefBlockListener.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * This file is part of the SimpleSpleef bukkit plugin. - * Copyright (C) 2011 Maximilian Kalus - * See http://dev.bukkit.org/server-mods/simple-spleef/ - * - * This program 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. - * - * This program 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 this program. If not, see . - **/ -package de.beimax.simplespleef.listeners; - -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.BlockPlaceEvent; - -import de.beimax.simplespleef.SimpleSpleef; - -/** - * Listener for block breaks - * - * @author mkalus - * - */ -public class SimpleSpleefBlockListener implements Listener { - /** - * @param event - */ - @EventHandler(priority = EventPriority.LOW) - public void onBlockBreak(BlockBreakEvent event) { - if (event.isCancelled()) return; - - // check block breaks globally, since blocks could be broken from a protected arena - SimpleSpleef.getGameHandler().checkBlockBreak(event); - } - - /** - * @param event - */ - @EventHandler(priority = EventPriority.LOW) - public void onBlockPlace(BlockPlaceEvent event) { - if (event.isCancelled()) return; - - // check block breaks globally, since blocks could be places in a protected arena - SimpleSpleef.getGameHandler().checkBlockPlace(event); - } -} diff --git a/src/main/java/de/beimax/simplespleef/listeners/SimpleSpleefEntityListener.java b/src/main/java/de/beimax/simplespleef/listeners/SimpleSpleefEntityListener.java deleted file mode 100644 index 7991082..0000000 --- a/src/main/java/de/beimax/simplespleef/listeners/SimpleSpleefEntityListener.java +++ /dev/null @@ -1,110 +0,0 @@ -/** - * This file is part of the SimpleSpleef bukkit plugin. - * Copyright (C) 2011 Maximilian Kalus - * See http://dev.bukkit.org/server-mods/simple-spleef/ - * - * This program 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. - * - * This program 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 this program. If not, see . - **/ -package de.beimax.simplespleef.listeners; - -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.entity.EntityDeathEvent; -import org.bukkit.event.entity.EntityExplodeEvent; -import org.bukkit.event.entity.FoodLevelChangeEvent; - -import de.beimax.simplespleef.SimpleSpleef; -import de.beimax.simplespleef.game.Game; - -/** - * Handle events for all Entity related events - * - * @author mkalus - */ -public class SimpleSpleefEntityListener implements Listener { - /** - * @param event - */ - @EventHandler(priority = EventPriority.HIGHEST) - public void onEntityDeath(EntityDeathEvent event) { - // check if games are running and the entity is indeed a player - if (SimpleSpleef.getGameHandler().hasGames() && event.getEntity() instanceof Player) { - Player player = (Player) event.getEntity(); - // player part of a game? - Game game = SimpleSpleef.getGameHandler().checkPlayerInGame(player); - if (game != null) game.onPlayerDeath(player); - } - } - - /** - * @param event - */ - @EventHandler(priority = EventPriority.HIGHEST) - public void onFoodLevelChange(FoodLevelChangeEvent event) { - if (event.isCancelled()) return; - - // check if games are running and the entity is indeed a player - if (SimpleSpleef.getGameHandler().hasGames() && event.getEntity() instanceof Player) { - Player player = (Player) event.getEntity(); - // player part of a game? - Game game = SimpleSpleef.getGameHandler().checkPlayerInGame(player); - // if setting noHunger has been set for this arena, do not feel any hunger - if (game != null && SimpleSpleef.getPlugin().getConfig().getBoolean("arenas." + game.getId() + ".noHunger", true)) - event.setCancelled(true); - } - } - - /** - * @param event - */ - @EventHandler(priority = EventPriority.HIGHEST) - public void onEntityDamage(EntityDamageEvent event) { - if (event.isCancelled()) return; - - // check if games are running and the entity is indeed a player - if (SimpleSpleef.getGameHandler().hasGames() && event.getEntity() instanceof Player) { - Player player = (Player) event.getEntity(); - // no PVP is allowed anyway - if (!player.getWorld().getPVP()) return; - - // player part of a game? - Game game = SimpleSpleef.getGameHandler().checkPlayerInGame(player); - // if setting noPvP has been set for this arena, check further - if (game != null && SimpleSpleef.getPlugin().getConfig().getBoolean("arenas." + game.getId() + ".noPvP", true)) { - // get cause of damage - only consider damage by other entities - if (event instanceof EntityDamageByEntityEvent) { - EntityDamageByEntityEvent damageEvent = (EntityDamageByEntityEvent) event; - // only consider player damage - if (damageEvent.getDamager() instanceof Player) { - event.setCancelled(true); // cancel damage event by caused by other players - } - } - } - } - } - - /** - * @param event - */ - @EventHandler(priority = EventPriority.LOWEST) - public void onEntityExplode(EntityExplodeEvent event) { - // TODO: check if any exploded blocks were within the arena perimeter -> restore those or cancel event - - // TODO: check for blocks exploded within the reach of a tracker -> track changed blocks! - } -} diff --git a/src/main/java/de/beimax/simplespleef/listeners/SimpleSpleefPlayerListener.java b/src/main/java/de/beimax/simplespleef/listeners/SimpleSpleefPlayerListener.java deleted file mode 100644 index 9423be5..0000000 --- a/src/main/java/de/beimax/simplespleef/listeners/SimpleSpleefPlayerListener.java +++ /dev/null @@ -1,182 +0,0 @@ -/** - * This file is part of the SimpleSpleef bukkit plugin. - * Copyright (C) 2011 Maximilian Kalus - * See http://dev.bukkit.org/server-mods/simple-spleef/ - * - * This program 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. - * - * This program 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 this program. If not, see . - **/ -package de.beimax.simplespleef.listeners; - -import org.bukkit.ChatColor; -import org.bukkit.block.Sign; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerGameModeChangeEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerKickEvent; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.player.PlayerTeleportEvent; - -import de.beimax.simplespleef.SimpleSpleef; -import de.beimax.simplespleef.command.SimpleSpleefSignCommandExecutor; -import de.beimax.simplespleef.game.Game; -import de.beimax.simplespleef.util.UpdateChecker; - -/** - * Handle events for all Player related events - * - * @author maxkalus - */ -public class SimpleSpleefPlayerListener implements Listener { - /** - * @param event - */ - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - // update checker activated - if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.updateNotificationOnLogin", true)) { - final Player player = event.getPlayer(); - // Check for updates whenever an operator or user with the right simplespleef.admin joins the game - if (player != null && (player.isOp() || SimpleSpleef.checkPermission(player, "simplespleef.admin"))) { - SimpleSpleef.getPlugin().getServer().getScheduler().scheduleSyncDelayedTask(SimpleSpleef.getPlugin(), new Runnable() { // create a new anonymous task/thread that will check the version asyncronously - @Override - public void run() { - UpdateChecker checker = new UpdateChecker(); - try { - // compare versions - String oldVersion = SimpleSpleef.getPlugin().getDescription().getVersion(); - String newVersion = checker.checkForUpdate(oldVersion); - if (newVersion != null) // do we have a version update? => notify player - player.sendMessage(SimpleSpleef.getPlugin().ll("feedback.update", "[OLDVERSION]", oldVersion, "[NEWVERSION]", newVersion)); - } catch (Exception e) { - player.sendMessage("SimpleSpleef could not get version update - see log for details."); - SimpleSpleef.log.warning("[SimpleSpleef] Could not connect to remote server to check for update. Exception said: " + e.getMessage()); - } - } - }, 0L); - } - } - - // tell games about somebody joining, too - if (SimpleSpleef.getGameHandler().hasGames()) { - // tell all games about it - for (Game game : SimpleSpleef.getGameHandler().getGames()) { - game.onPlayerJoin(event); - } - } - } - - /** - * @param event - */ - @EventHandler - public void onPlayerKick(PlayerKickEvent event) { - if (event.isCancelled()) return; - - if (SimpleSpleef.getGameHandler().hasGames()) { - // player part of a game? - Game game = SimpleSpleef.getGameHandler().checkPlayerInGame(event.getPlayer()); - if (game != null) game.onPlayerKick(event); - } - } - - /** - * @param event - */ - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - if (SimpleSpleef.getGameHandler().hasGames()) { - // player part of a game? - Game game = SimpleSpleef.getGameHandler().checkPlayerInGame(event.getPlayer()); - if (game != null) game.onPlayerQuit(event); - } - } - - /** - * @param event - */ - @EventHandler - public void onPlayerMove(PlayerMoveEvent event) { - if (SimpleSpleef.getGameHandler().hasGames()) { - // player part of a game? - Game game = SimpleSpleef.getGameHandler().checkPlayerInGame(event.getPlayer()); - if (game != null) game.onPlayerMove(event); - } - } - - /** - * @param event - */ - @EventHandler(priority = EventPriority.LOW) - public void onPlayerInteract(PlayerInteractEvent event) { - if (event.isCancelled()) return; - - // clicked on a sign and signs enabled? - if (event.getPlayer() != null && event.getClickedBlock() != null && event.getClickedBlock().getState() instanceof Sign && SimpleSpleef.getPlugin().getConfig().getBoolean("settings.enableSigns", true)) { - // only right click allowed? - boolean signsOnlyRightClick = SimpleSpleef.getPlugin().getConfig().getBoolean("settings.signsOnlyRightClick", false); - if (!signsOnlyRightClick || (signsOnlyRightClick && event.getAction() == Action.RIGHT_CLICK_BLOCK)) - // let the sign command executor do the rest - new SimpleSpleefSignCommandExecutor().parseSimpleSpleefSign(event.getPlayer(), (Sign)event.getClickedBlock().getState()); - } - - if (SimpleSpleef.getGameHandler().hasGames()) { - // player part of a game? - Game game = SimpleSpleef.getGameHandler().checkPlayerInGame(event.getPlayer()); - if (game != null) game.onPlayerInteract(event); - } - } - - /** - * @param event - */ - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerTeleport(PlayerTeleportEvent event) { - if (event.isCancelled()) return; - - if (SimpleSpleef.getGameHandler().hasGames()) { - // player part of a game? - Game game = SimpleSpleef.getGameHandler().checkPlayerInGame(event.getPlayer()); - if (game != null) { - // check, if arena allows the player's teleportation - if (!game.playerMayTeleport(event.getPlayer())) { - event.getPlayer().sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.teleport", "[ARENA]", game.getName())); - event.setCancelled(true); //cancel event - } - } - } - } - - /** - * @param event - */ - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerGameModeChange(PlayerGameModeChangeEvent event) { - if (event.isCancelled()) return; - - if (SimpleSpleef.getGameHandler().hasGames()) { - // player part of a game? - Game game = SimpleSpleef.getGameHandler().checkPlayerInGame(event.getPlayer()); - if (game != null) { // generally disallow changes of game modes for spleefers - event.getPlayer().sendMessage(ChatColor.DARK_RED + SimpleSpleef.getPlugin().ll("errors.gamemodeChange")); - event.setCancelled(true); //cancel event - } - } - } -} diff --git a/src/main/java/de/beimax/simplespleef/util/UpdateChecker.java b/src/main/java/de/beimax/simplespleef/util/UpdateChecker.java index 64aac2f..49c164e 100644 --- a/src/main/java/de/beimax/simplespleef/util/UpdateChecker.java +++ b/src/main/java/de/beimax/simplespleef/util/UpdateChecker.java @@ -25,13 +25,17 @@ import org.bukkit.configuration.Configuration; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; import de.beimax.simplespleef.SimpleSpleef; /** * @author mkalus Helper class that checks for updates. */ -public class UpdateChecker { +public class UpdateChecker implements Listener { /** * actually check for an update * @param String version version of current system to check @@ -48,8 +52,7 @@ public String checkForUpdate(String version) throws Exception { String inputLine = in.readLine(); in.close(); - if (inputLine != null && (inputLine.equals(version))) return null; // no new update - //if (inputLine != null && inputLine.equals(version)) return null; // no new update + if (inputLine != null && inputLine.equals(version)) return null; // no new update return inputLine; // new version } @@ -126,4 +129,34 @@ public void updateConfigurationVersion(SimpleSpleef simpleSpleef) { SimpleSpleef.getPlugin().saveConfig(); } } + + /** + * Checks if a player logs in and checks for updates + * @param event + */ + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + // update checker activated + if (SimpleSpleef.getPlugin().getConfig().getBoolean("settings.updateNotificationOnLogin", true)) { + final Player player = event.getPlayer(); + // Check for updates whenever an operator or user with the right simplespleef.admin joins the game + if (player != null && (player.isOp() || SimpleSpleef.checkPermission(player, "simplespleef.admin"))) { + SimpleSpleef.getPlugin().getServer().getScheduler().scheduleSyncDelayedTask(SimpleSpleef.getPlugin(), new Runnable() { // create a new anonymous task/thread that will check the version asyncronously + @Override + public void run() { + try { + // compare versions + String oldVersion = SimpleSpleef.getPlugin().getDescription().getVersion(); + String newVersion = checkForUpdate(oldVersion); + if (newVersion != null) // do we have a version update? => notify player + player.sendMessage(SimpleSpleef.ll("feedback.update", "[OLDVERSION]", oldVersion, "[NEWVERSION]", newVersion)); + } catch (Exception e) { + player.sendMessage("SimpleSpleef could not get version update - see log for details."); + SimpleSpleef.log.warning("[SimpleSpleef] Could not connect to remote server to check for update. Exception said: " + e.getMessage()); + } + } + }, 0L); + } + } + } }