From 36e6d2ce2bff8106839c5c1980a202958055f9bf Mon Sep 17 00:00:00 2001 From: Brettflan Date: Sat, 9 Apr 2011 09:55:57 -0500 Subject: [PATCH] =?UTF-8?q?Several=20changes=20for=20v1.1=20release:=20mov?= =?UTF-8?q?ed=20border=20checking=20routine=20out=20into=20a=20timed=20tas?= =?UTF-8?q?k,=20for=20even=20lower=20server=20impact=20added=20new=20confi?= =?UTF-8?q?gurable=20"delay"=20value,=20for=20the=20number=20of=20ticks=20?= =?UTF-8?q?it=20will=20wait=20between=20border=20checks,=20the=20default?= =?UTF-8?q?=20is=204=20(~200ms);=20each=20server=20tick=20is=20~50ms=20or?= =?UTF-8?q?=20so=20added=20new=20configurable=20"knockback"=20value,=20for?= =?UTF-8?q?=20how=20far=20back=20inside=20the=20border=20to=20move=20a=20s?= =?UTF-8?q?tray=20player,=20the=20default=20is=203.0=20changed=20world-nam?= =?UTF-8?q?e=20encoding=20method=20for=20worlds=20with=20dots=20in=20the?= =?UTF-8?q?=20name=20to=20use=20an=20uncommon=20high-range=20ASCII=20chara?= =?UTF-8?q?cter=20("=C2=A8"),=20since=20forward-slash=20("/")=20can=20occu?= =?UTF-8?q?r=20in=20world=20names;=20don't=20worry,=20old=20configurations?= =?UTF-8?q?=20which=20have=20the=20"."->"/"=20encoding=20will=20be=20autom?= =?UTF-8?q?atically=20and=20safely=20converted=20split=20command=20listing?= =?UTF-8?q?=20to=202=20pages=20for=20players,=20since=20there=20are=20too?= =?UTF-8?q?=20many=20commands=20to=20fit=20on=20the=20screen=20now?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/com/wimbli/WorldBorder/BorderData.java | 21 ++-- src/com/wimbli/WorldBorder/Config.java | 104 +++++++++++++++--- src/com/wimbli/WorldBorder/WBCommand.java | 104 ++++++++++++++++-- .../wimbli/WorldBorder/WBPlayerListener.java | 103 ++--------------- src/com/wimbli/WorldBorder/WorldBorder.java | 9 +- src/plugin.yml | 6 +- 7 files changed, 208 insertions(+), 141 deletions(-) diff --git a/README.md b/README.md index aa7d8bf..84225e2 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,4 @@ This plugin is intended to be able to supersede BorderGuard Lite and rBorder in More Info ========= -Bukkit Forum Topic \ No newline at end of file +Bukkit Forum Topic \ No newline at end of file diff --git a/src/com/wimbli/WorldBorder/BorderData.java b/src/com/wimbli/WorldBorder/BorderData.java index f5b3a42..bec7d9f 100644 --- a/src/com/wimbli/WorldBorder/BorderData.java +++ b/src/com/wimbli/WorldBorder/BorderData.java @@ -1,8 +1,7 @@ package com.wimbli.WorldBorder; import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; +import java.util.LinkedHashSet; import org.bukkit.Location; import org.bukkit.World; @@ -112,13 +111,13 @@ public class BorderData if (!round) { if (xLoc <= minX) - xLoc = minX + 3; + xLoc = minX + Config.KnockBack(); else if (xLoc >= maxX) - xLoc = maxX - 3; + xLoc = maxX - Config.KnockBack(); if (zLoc <= minZ) - zLoc = minZ + 3; + zLoc = minZ + Config.KnockBack(); else if (zLoc >= maxZ) - zLoc = maxZ - 3; + zLoc = maxZ - Config.KnockBack(); } // round border @@ -128,8 +127,8 @@ public class BorderData double vX = xLoc - x; double vZ = zLoc - z; double magV = Math.sqrt(vX*vX + vZ*vZ); - xLoc = x + vX / magV * (radius - 3); - zLoc = z + vZ / magV * (radius - 3); + xLoc = x + vX / magV * (radius - Config.KnockBack()); + zLoc = z + vZ / magV * (radius - Config.KnockBack()); } yLoc = getSafeY(loc.getWorld(), Location.locToBlock(xLoc), Location.locToBlock(yLoc), Location.locToBlock(zLoc)); @@ -140,12 +139,12 @@ public class BorderData } //these material IDs are acceptable for places to teleport player; breathable blocks and water - private static Set acceptableBlocks = new HashSet(Arrays.asList( + private static LinkedHashSet acceptableBlocks = new LinkedHashSet(Arrays.asList( new Integer[] {0, 6, 8, 9, 37, 38, 39, 40, 50, 55, 59, 63, 64, 65, 66, 68, 69, 70, 71, 72, 75, 76, 77, 83, 93, 94} )); - //these material IDs are ones we don't want to drop the player onto - private static Set painfulBlocks = new HashSet(Arrays.asList( + //these material IDs are ones we don't want to drop the player onto, like cactus or lava + private static LinkedHashSet painfulBlocks = new LinkedHashSet(Arrays.asList( new Integer[] {10, 11, 81} )); diff --git a/src/com/wimbli/WorldBorder/Config.java b/src/com/wimbli/WorldBorder/Config.java index 7dd2ec2..14f7870 100644 --- a/src/com/wimbli/WorldBorder/Config.java +++ b/src/com/wimbli/WorldBorder/Config.java @@ -2,7 +2,7 @@ package com.wimbli.WorldBorder; import java.text.DecimalFormat; import java.util.Collections; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.HashSet; import java.util.Iterator; import java.util.logging.Level; @@ -30,12 +30,16 @@ public class Config private static GroupManager GroupPlugin = null; private static final Logger mcLog = Logger.getLogger("Minecraft"); public static DecimalFormat coord = new DecimalFormat("0.0"); + private static int borderTask = -1; + public static Set movedPlayers = Collections.synchronizedSet(new HashSet()); // actual configuration values which can be changed private static boolean shapeRound = false; - private static Map borders = Collections.synchronizedMap(new HashMap()); + private static Map borders = Collections.synchronizedMap(new LinkedHashMap()); private static String message; private static boolean DEBUG = false; + private static double knockBack = 3.0; + private static int timerTicks = 4; public static void setBorder(String world, BorderData border) { @@ -125,6 +129,54 @@ public class Config return DEBUG; } + public static void setKnockBack(double numBlocks) + { + knockBack = numBlocks; + Log("Knockback set to " + knockBack + " blocks inside the border."); + save(true); + } + + public static double KnockBack() + { + return knockBack; + } + + public static void setTimerTicks(int ticks) + { + timerTicks = ticks; + Log("Timer delay set to " + timerTicks + " tick(s). That is roughly " + (timerTicks * 50) + "ms."); + StartBorderTimer(); + save(true); + } + + public static int TimerTicks() + { + return timerTicks; + } + + + public static void StartBorderTimer() + { + StopBorderTimer(); + + borderTask = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new BorderCheckTask(plugin.getServer()), timerTicks, timerTicks); + + if (borderTask == -1) + LogWarn("Failed to start timed border-checking task! This will prevent the plugin from working. Try restarting Bukkit."); + + LogConfig("Border-checking timed task started."); + } + + public static void StopBorderTimer() + { + if (borderTask == -1) return; + + plugin.getServer().getScheduler().cancelTask(borderTask); + borderTask = -1; + LogConfig("Border-checking timed task stopped."); + } + + public static void loadPermissions(WorldBorder plugin) { if (GroupPlugin != null || Permissions != null || plugin == null) @@ -179,6 +231,7 @@ public class Config return true; } + public static void Log(Level lvl, String text) { String name = (plugin == null) ? "WorldBorder" : plugin.getDescription().getName(); @@ -197,18 +250,33 @@ public class Config Log(Level.INFO, "[CONFIG] " + text); } + public static void load(WorldBorder master, boolean logIt) { // load config from file plugin = master; cfg = plugin.getConfiguration(); + int cfgVersion = cfg.getInt("cfg-version", 1); + message = cfg.getString("message"); shapeRound = cfg.getBoolean("round-border", false); - LogConfig("Using " + (shapeRound ? "round" : "square") + " border shape."); DEBUG = cfg.getBoolean("debug-mode", false); + knockBack = cfg.getDouble("knock-back-dist", 3.0); + timerTicks = cfg.getInt("timer-delay-ticks", 5); + LogConfig("Using " + (shapeRound ? "round" : "square") + " border, knockback of " + knockBack + " blocks, and timer delay of " + timerTicks + "."); + + StartBorderTimer(); borders.clear(); + if (message == null || message.isEmpty()) + { // store defaults + LogConfig("Configuration not present, creating new file."); + message = "You have reached the edge of this world."; + save(false); + return; + } + Map worlds = cfg.getNodes("worlds"); if (worlds != null) { @@ -216,7 +284,14 @@ public class Config while(world.hasNext()) { Entry wdata = (Entry)world.next(); - String name = ((String)wdata.getKey()).replace("/", "."); + + String name = null; + // we're swapping "¨" (from extended ASCII set) and "." back and forth at save and load since periods denote configuration nodes, and world names with periods otherwise wreak havoc + if (cfgVersion > 1) + name = ((String)wdata.getKey()).replace("¨", "."); + else // old v1 format, periods encoded as slashes, which had problems + name = ((String)wdata.getKey()).replace("/", "."); + ConfigurationNode bord = (ConfigurationNode)wdata.getValue(); BorderData border = new BorderData(bord.getDouble("x", 0), bord.getDouble("z", 0), bord.getInt("radius", 0)); borders.put(name, border); @@ -224,24 +299,23 @@ public class Config } } - if (message == null || message.isEmpty()) - { // store defaults - LogConfig("Configuration not present, creating new file."); - message = "You have reached the edge of this world."; - shapeRound = false; - save(false); - } - else if (logIt) + if (logIt) LogConfig("Configuration loaded."); + + if (cfgVersion < 2) + save(false); } public static void save(boolean logIt) { // save config to file if (cfg == null) return; + cfg.setProperty("cfg-version", 2); cfg.setProperty("message", message); cfg.setProperty("round-border", shapeRound); cfg.setProperty("debug-mode", DEBUG); + cfg.setProperty("knock-back-dist", knockBack); + cfg.setProperty("timer-delay-ticks", timerTicks); cfg.removeProperty("worlds"); Iterator world = borders.entrySet().iterator(); @@ -250,9 +324,9 @@ public class Config Entry wdata = (Entry)world.next(); String name = (String)wdata.getKey(); BorderData bord = (BorderData)wdata.getValue(); - cfg.setProperty("worlds." + name.replace(".", "/") + ".x", bord.getX()); - cfg.setProperty("worlds." + name.replace(".", "/") + ".z", bord.getZ()); - cfg.setProperty("worlds." + name.replace(".", "/") + ".radius", bord.getRadius()); + cfg.setProperty("worlds." + name.replace(".", "¨") + ".x", bord.getX()); + cfg.setProperty("worlds." + name.replace(".", "¨") + ".z", bord.getZ()); + cfg.setProperty("worlds." + name.replace(".", "¨") + ".radius", bord.getRadius()); } cfg.save(); diff --git a/src/com/wimbli/WorldBorder/WBCommand.java b/src/com/wimbli/WorldBorder/WBCommand.java index 731d579..bebb93f 100644 --- a/src/com/wimbli/WorldBorder/WBCommand.java +++ b/src/com/wimbli/WorldBorder/WBCommand.java @@ -285,26 +285,106 @@ public class WBCommand implements CommandExecutor sender.sendMessage("Debug mode " + (Config.Debug() ? "enabled" : "disabled") + "."); } + // "knockback" command from player or console + else if (split.length == 2 && split[0].equalsIgnoreCase("knockback")) + { + if (!Config.HasPermission(player, "knockback")) return true; + + double numBlocks = 0.0; + try + { + numBlocks = Double.parseDouble(split[1]); + } + catch(NumberFormatException ex) + { + sender.sendMessage(ChatColor.RED + "The knockback must be a decimal value above 0."); + return true; + } + + if (numBlocks <= 0.0) + { + sender.sendMessage(ChatColor.RED + "The knockback must be a decimal value above 0."); + return true; + } + + Config.setKnockBack(numBlocks); + + if (player != null) + sender.sendMessage("Knockback set to " + numBlocks + " blocks inside the border."); + } + + // "delay" command from player or console + else if (split.length == 2 && split[0].equalsIgnoreCase("delay")) + { + if (!Config.HasPermission(player, "delay")) return true; + + int delay = 0; + try + { + delay = Integer.parseInt(split[1]); + } + catch(NumberFormatException ex) + { + sender.sendMessage(ChatColor.RED + "The timer delay must be an integer of 1 or higher."); + return true; + } + if (delay < 1) + { + sender.sendMessage(ChatColor.RED + "The timer delay must be an integer of 1 or higher."); + return true; + } + + Config.setTimerTicks(delay); + + if (player != null) + sender.sendMessage("Timer delay set to " + delay + " tick(s). That is roughly " + (delay * 50) + "ms."); + } + // we couldn't decipher any known commands, so show help else { if (!Config.HasPermission(player, "help")) return true; - sender.sendMessage(ChatColor.WHITE + plugin.getDescription().getFullName() + " - commands (" + (player != null ? ChatColor.DARK_GREEN + "[optional] " : "") + ChatColor.GREEN + "" + ChatColor.WHITE + "):"); - if (player != null) - sender.sendMessage(cmd+" set " + ChatColor.GREEN + "" + ChatColor.WHITE + " - set world border, centered on you."); - sender.sendMessage(cmdW+" set " + ChatColor.GREEN + " " + ChatColor.WHITE + " - set world border."); - sender.sendMessage(cmdW+" radius " + ChatColor.GREEN + "" + ChatColor.WHITE + " - change a border radius."); - sender.sendMessage(cmdW+" clear" + ChatColor.WHITE + " - remove border for this world."); - sender.sendMessage(cmd+" clear all" + ChatColor.WHITE + " - remove border for all worlds."); - sender.sendMessage(cmd+" list" + ChatColor.WHITE + " - show border information for all worlds."); - sender.sendMessage(cmd+" shape " + ChatColor.GREEN + "" + ChatColor.WHITE + " - set the border shape."); - sender.sendMessage(cmd+" getmsg" + ChatColor.WHITE + " - display border message."); - sender.sendMessage(cmd+" setmsg " + ChatColor.GREEN + "" + ChatColor.WHITE + " - set border message."); - if (player == null) + int page = (player == null) ? 0 : 1; + if (split.length == 1) { + try + { + page = Integer.parseInt(split[0]); + } + catch(NumberFormatException ex) + { + } + if (page > 2) + page = 1; + } + + sender.sendMessage(ChatColor.YELLOW + plugin.getDescription().getFullName() + " - commands (" + (player != null ? ChatColor.DARK_GREEN + "[optional] " : "") + ChatColor.GREEN + "" + ChatColor.YELLOW + ")" + (page > 0 ? " " + page + "/2" : "") + ":"); + + if (page == 0 || page == 1) + { + if (player != null) + sender.sendMessage(cmd+" set " + ChatColor.GREEN + "" + ChatColor.WHITE + " - set world border, centered on you."); + sender.sendMessage(cmdW+" set " + ChatColor.GREEN + " " + ChatColor.WHITE + " - set world border."); + sender.sendMessage(cmdW+" radius " + ChatColor.GREEN + "" + ChatColor.WHITE + " - change a border radius."); + sender.sendMessage(cmdW+" clear" + ChatColor.WHITE + " - remove border for this world."); + sender.sendMessage(cmd+" clear all" + ChatColor.WHITE + " - remove border for all worlds."); + sender.sendMessage(cmd+" list" + ChatColor.WHITE + " - show border information for all worlds."); + sender.sendMessage(cmd+" shape " + ChatColor.GREEN + "" + ChatColor.WHITE + " - set the border shape."); + sender.sendMessage(cmd+" knockback " + ChatColor.GREEN + "" + ChatColor.WHITE + " - how far to move the player back."); + if (page == 1) + sender.sendMessage(cmd+" 2" + ChatColor.WHITE + " - view second page of commands."); + } + + if (page == 0 || page == 2) + { + sender.sendMessage(cmd+" getmsg" + ChatColor.WHITE + " - display border message."); + sender.sendMessage(cmd+" setmsg " + ChatColor.GREEN + "" + ChatColor.WHITE + " - set border message."); + sender.sendMessage(cmd+" delay " + ChatColor.GREEN + "" + ChatColor.WHITE + " - time between border checks."); sender.sendMessage(cmd+" reload" + ChatColor.WHITE + " - re-load data from config.yml."); sender.sendMessage(cmd+" debug " + ChatColor.GREEN + "" + ChatColor.WHITE + " - turn console debug output on or off."); + if (page == 2) + sender.sendMessage(cmd + ChatColor.WHITE + " - view first page of commands."); } } diff --git a/src/com/wimbli/WorldBorder/WBPlayerListener.java b/src/com/wimbli/WorldBorder/WBPlayerListener.java index d2a224e..d78b77c 100644 --- a/src/com/wimbli/WorldBorder/WBPlayerListener.java +++ b/src/com/wimbli/WorldBorder/WBPlayerListener.java @@ -1,11 +1,9 @@ package com.wimbli.WorldBorder; -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; -import org.bukkit.event.player.*; -import org.bukkit.Location; -import org.bukkit.util.Vector; -import org.bukkit.World; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerListener; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerTeleportEvent; public class WBPlayerListener extends PlayerListener @@ -13,21 +11,7 @@ public class WBPlayerListener extends PlayerListener @Override public void onPlayerJoin(PlayerJoinEvent event) { - Player player = event.getPlayer(); - if (player == null) return; - Location loc = player.getLocation(); - if (loc == null) return; - World world = loc.getWorld(); - if (world == null) return; - BorderData border = Config.Border(world.getName()); - if (border == null) return; - - if (border.insideBorder(loc.getX(), loc.getZ(), Config.ShapeRound())) - return; - - Location newLoc = newLocation(player, loc, border); - - player.teleport(newLoc); + Config.movedPlayers.add(event.getPlayer().getName()); } @Override @@ -35,30 +19,7 @@ public class WBPlayerListener extends PlayerListener { if (event.isCancelled()) return; - Player player = event.getPlayer(); - if (player == null) return; - Location loc = event.getTo(); - if (loc == null) return; - World world = loc.getWorld(); - if (world == null) return; - BorderData border = Config.Border(world.getName()); - if (border == null) return; - - if (border.insideBorder(loc.getX(), loc.getZ(), Config.ShapeRound())) - return; - - Location newLoc = newLocation(player, loc, border); - - if (!player.isInsideVehicle()) - player.teleport(newLoc); - else - { - newLoc.setY(newLoc.getY() + 1); - player.getVehicle().setVelocity(new Vector(0, 0, 0)); - player.getVehicle().teleport(newLoc); - } - - event.setTo(newLoc); + Config.movedPlayers.add(event.getPlayer().getName()); } @Override @@ -66,56 +27,6 @@ public class WBPlayerListener extends PlayerListener { if (event.isCancelled()) return; - Player player = event.getPlayer(); - if (player == null) return; - Location loc = event.getTo(); - if (loc == null) return; - World world = loc.getWorld(); - if (world == null) return; - BorderData border = Config.Border(world.getName()); - if (border == null) return; - - if (border.insideBorder(loc.getX(), loc.getZ(), Config.ShapeRound())) - return; - - Location newLoc = newLocation(player, loc, border); - - if (!player.isInsideVehicle()) - player.teleport(newLoc); - else - { - newLoc.setY(newLoc.getY() + 1); - player.getVehicle().setVelocity(new Vector(0, 0, 0)); - player.getVehicle().teleport(newLoc); - } - - event.setTo(newLoc); - } - - - private static Location newLocation(Player player, Location loc, BorderData border) - { - if (Config.Debug()) - { - Config.LogWarn("Border crossing. Border " + border.toString()); - Config.LogWarn("Player position X: " + Config.coord.format(loc.getX()) + " Y: " + Config.coord.format(loc.getY()) + " Z: " + Config.coord.format(loc.getZ())); - } - - Location newLoc = border.correctedPosition(loc, Config.ShapeRound()); - - // it's remotely possible (such as in the Nether) a suitable location isn't available, in which case... - if (newLoc == null) - { - if (Config.Debug()) - Config.LogWarn("Target new location unviable, using spawn."); - newLoc = player.getServer().getWorlds().get(0).getSpawnLocation(); - } - - if (Config.Debug()) - Config.LogWarn("New position X: " + Config.coord.format(newLoc.getX()) + " Y: " + Config.coord.format(newLoc.getY()) + " Z: " + Config.coord.format(newLoc.getZ())); - - player.sendMessage(ChatColor.RED + Config.Message()); - - return newLoc; + Config.movedPlayers.add(event.getPlayer().getName()); } } diff --git a/src/com/wimbli/WorldBorder/WorldBorder.java b/src/com/wimbli/WorldBorder/WorldBorder.java index fe9806d..e4865cd 100644 --- a/src/com/wimbli/WorldBorder/WorldBorder.java +++ b/src/com/wimbli/WorldBorder/WorldBorder.java @@ -13,8 +13,8 @@ public class WorldBorder extends JavaPlugin public void onEnable() { - PluginDescriptionFile desc = this.getDescription(); - System.out.println( desc.getName() + " version " + desc.getVersion() + " loading" ); + PluginDescriptionFile desc = this.getDescription(); + System.out.println( desc.getName() + " version " + desc.getVersion() + " loading" ); // Load (or create new) config file, and connect to Permissions if it's available Config.load(this, false); @@ -35,7 +35,8 @@ public class WorldBorder extends JavaPlugin public void onDisable() { - PluginDescriptionFile desc = this.getDescription(); - System.out.println( desc.getName() + " version " + desc.getVersion() + " shutting down" ); + PluginDescriptionFile desc = this.getDescription(); + System.out.println( desc.getName() + " version " + desc.getVersion() + " shutting down" ); + Config.StopBorderTimer(); } } diff --git a/src/plugin.yml b/src/plugin.yml index eff49f8..0a62236 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -1,7 +1,7 @@ name: WorldBorder author: Brettflan description: Limit the size of your worlds with a border, round or square. -version: 1.0.1 +version: 1.1 main: com.wimbli.WorldBorder.WorldBorder commands: wborder: @@ -17,4 +17,6 @@ commands: / list - show border information for all worlds. / shape - set the border shape. / getmsg - display border message. - / setmsg - set border message. \ No newline at end of file + / setmsg - set border message. + / knockback - how far to move the player back. + / delay - time between border checks. \ No newline at end of file