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