Major rework of command handling. This is mostly internal code changes rather than something noticeable to the end user, though on command input errors (wrong number or format of arguments, etc.) it will now have it show examples for the command the same as seen in the command list provided by the root wb command.

Replacing the monolithic and crude "if...else if...else if..." command handler in WBCommand.java with every command crammed in there, each command is now handled in a separate subclass in the new "com.wimbli.WorldBorder.cmd" package. This is inspired by the way the Factions plugin handles subclassed commands.

This is the first pass of the command handling rework. I still need to do some further testing, and I plan to further improve feedback for input errors to also show some basic help info along with the command examples.
This commit is contained in:
Brettflan 2014-03-06 15:03:44 -06:00
parent 6e7f79711a
commit cd9ee900ae
30 changed files with 1811 additions and 1185 deletions

View File

@ -62,33 +62,38 @@ public class Config
}
public static void setBorder(String world, BorderData border)
public static void setBorder(String world, BorderData border, boolean logIt)
{
borders.put(world, border);
log("Border set. " + BorderDescription(world));
if (logIt)
log("Border set. " + BorderDescription(world));
save(true);
DynMapFeatures.showBorder(world, border);
}
public static void setBorder(String world, BorderData border)
{
setBorder(world, border, true);
}
public static void setBorder(String world, int radiusX, int radiusZ, double x, double z, Boolean shapeRound)
{
BorderData old = Border(world);
boolean oldWrap = (old != null) && old.getWrapping();
setBorder(world, new BorderData(x, z, radiusX, radiusZ, shapeRound, oldWrap));
setBorder(world, new BorderData(x, z, radiusX, radiusZ, shapeRound, oldWrap), true);
}
public static void setBorder(String world, int radiusX, int radiusZ, double x, double z)
{
BorderData old = Border(world);
Boolean oldShape = (old == null) ? null : old.getShape();
boolean oldWrap = (old != null) && old.getWrapping();
setBorder(world, new BorderData(x, z, radiusX, radiusZ, oldShape, oldWrap));
setBorder(world, new BorderData(x, z, radiusX, radiusZ, oldShape, oldWrap), true);
}
// backwards-compatible methods from before elliptical/rectangular shapes were supported
public static void setBorder(String world, int radius, double x, double z, Boolean shapeRound)
{
setBorder(world, new BorderData(x, z, radius, radius, shapeRound));
setBorder(world, new BorderData(x, z, radius, radius, shapeRound), true);
}
public static void setBorder(String world, int radius, double x, double z)
{
@ -103,7 +108,7 @@ public class Config
double radiusZ = Math.abs(z1 - z2) / 2;
double x = ((x1 < x2) ? x1 : x2) + radiusX;
double z = ((z1 < z2) ? z1 : z2) + radiusZ;
setBorder(world, new BorderData(x, z, (int)Math.round(radiusX), (int)Math.round(radiusZ), shapeRound, wrap));
setBorder(world, new BorderData(x, z, (int)Math.round(radiusX), (int)Math.round(radiusZ), shapeRound, wrap), true);
}
public static void setBorderCorners(String world, double x1, double z1, double x2, double z2, Boolean shapeRound)
{
@ -168,7 +173,6 @@ public class Config
public static void setMessage(String msg)
{
updateMessage(msg);
log("Border message is now set to: " + MessageRaw());
save(true);
}
@ -209,8 +213,10 @@ public class Config
{
return ShapeName(shapeRound);
}
public static String ShapeName(boolean round)
public static String ShapeName(Boolean round)
{
if (round == null)
return "default";
return round ? "elliptic/round" : "rectangular/square";
}
@ -312,9 +318,11 @@ public class Config
if (remountDelayTicks == 0)
log("Remount delay set to 0. Players will be left dismounted when knocked back from the border while on a vehicle.");
else
{
log("Remount delay set to " + remountDelayTicks + " tick(s). That is roughly " + (remountDelayTicks * 50) + "ms / " + (((double)remountDelayTicks * 50.0) / 1000.0) + " seconds.");
if (ticks < 10)
logWarn("setting the remount delay to less than 10 (and greater than 0) is not recommended. This can lead to nasty client glitches.");
if (ticks < 10)
logWarn("setting the remount delay to less than 10 (and greater than 0) is not recommended. This can lead to nasty client glitches.");
}
save(true);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdBypass extends WBCmd
{
public CmdBypass()
{
name = permission = "bypass";
minParams = 0;
maxParams = 2;
addCmdExample(nameEmphasized() + "{player} [on/off] - let player go beyond border.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
if (player == null && params.isEmpty())
{
sendErrorAndHelp(sender, "When running this command from console, you must specify a player.");
return;
}
String sPlayer = (params.isEmpty()) ? player.getName() : params.get(0);
boolean bypassing = !Config.isPlayerBypassing(sPlayer);
if (params.size() > 1)
bypassing = strAsBool(params.get(1));
Config.setPlayerBypass(sPlayer, bypassing);
Player target = Bukkit.getPlayer(sPlayer);
if (target != null && target.isOnline())
target.sendMessage("Border bypass is now " + enabledColored(bypassing) + ".");
Config.log("Border bypass for player \"" + sPlayer + "\" is " + (bypassing ? "enabled" : "disabled") + (player != null ? " at the command of player \"" + player.getName() + "\"" : "") + ".");
if (player != null && player != target)
sender.sendMessage("Border bypass for player \"" + sPlayer + "\" is " + enabledColored(bypassing) + ".");
}
}

View File

@ -0,0 +1,26 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdBypasslist extends WBCmd
{
public CmdBypasslist()
{
name = permission = "bypasslist";
minParams = maxParams = 0;
addCmdExample(nameEmphasized() + "- list players with border bypass enabled.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
sender.sendMessage("Players with border bypass enabled: " + Config.getPlayerBypassList());
}
}

View File

@ -0,0 +1,66 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdClear extends WBCmd
{
public CmdClear()
{
name = permission = "clear";
hasWorldNameInput = true;
consoleRequiresWorldName = false;
minParams = 0;
maxParams = 1;
addCmdExample(nameEmphasizedW() + "- remove border for this world.");
addCmdExample(nameEmphasized() + "^all - remove border for all worlds.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
// handle "clear all" command separately
if (params.size() == 1 && params.get(0).equalsIgnoreCase("all"))
{
if (worldName != null)
{
sendErrorAndHelp(sender, "You should not specify a world with \"clear all\".");
return;
}
Config.removeAllBorders();
if (player != null)
sender.sendMessage("All borders have been cleared for all worlds.");
return;
}
if (worldName == null)
{
if (player == null)
{
sendErrorAndHelp(sender, "You must specify a world name from console if not using \"clear all\".");
return;
}
worldName = player.getWorld().getName();
}
BorderData border = Config.Border(worldName);
if (border == null)
{
sendErrorAndHelp(sender, "This world (\"" + worldName + "\") does not have a border set.");
return;
}
Config.removeBorder(worldName);
if (player != null)
sender.sendMessage("Border cleared for world \"" + worldName + "\".");
}
}

View File

@ -0,0 +1,74 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdCommands extends WBCmd
{
private static int pageSize = 8; // examples to list per page; 10 lines available, 1 for header, 1 for footer
public CmdCommands()
{
name = "commands";
permission = "help";
hasWorldNameInput = false;
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
// determine which page we're viewing
int page = (player == null) ? 0 : 1;
if (!params.isEmpty())
{
try
{
page = Integer.parseInt(params.get(0));
}
catch(NumberFormatException ignored) {}
}
// see whether we're showing examples to player or to console, and determine number of pages available
List<String> examples = (player == null) ? cmdExamplesConsole : cmdExamplesPlayer;
int pageCount = (int) Math.ceil(examples.size() / (double) pageSize);
// if specified page number is negative or higher than we have available, default back to first page
if (page < 0 || page > pageCount)
page = (player == null) ? 0 : 1;
// send command example header
sender.sendMessage( clrHead + WorldBorder.plugin.getDescription().getFullName() + " - key: " +
commandEmphasized("command") + clrReq + "<required> " + clrOpt + "[optional]" );
if (page > 0)
{
// send examples for this page
int first = ((page - 1) * pageSize);
int count = Math.min(pageSize, examples.size() - first);
for(int i = first; i < first + count; i++)
{
sender.sendMessage(examples.get(i));
}
// send page footer, if relevant; manual spacing to get right side lined up near edge is crude, but sufficient
String footer = clrHead + " (Page " + page + "/" + pageCount + ") " + ((player == null) ? cmdC : cmdP);
if (page < pageCount)
sender.sendMessage(footer + Integer.toString(page + 1) + clrDesc + " - view next page of commands.");
else if (page > 1)
sender.sendMessage(footer + clrDesc + "- view first page of commands.");
}
else
{
// if page "0" is specified, send all examples; done by default for console but can be specified by player
for (String example : examples)
{
sender.sendMessage(example);
}
}
}
}

View File

@ -0,0 +1,32 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdDebug extends WBCmd
{
public CmdDebug()
{
name = permission = "debug";
minParams = maxParams = 1;
addCmdExample(nameEmphasized() + "<on|off> - turn console debug output on or off.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
Config.setDebug(strAsBool(params.get(0)));
if (player != null)
{
Config.log((Config.Debug() ? "Enabled" : "Disabled") + " debug output at the command of player \"" + player.getName() + "\".");
sender.sendMessage("Debug mode " + enabledColored(Config.Debug()) + ".");
}
}
}

View File

@ -0,0 +1,42 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdDelay extends WBCmd
{
public CmdDelay()
{
name = permission = "delay";
minParams = maxParams = 1;
addCmdExample(nameEmphasized() + "<amount> - time between border checks.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
int delay = 0;
try
{
delay = Integer.parseInt(params.get(0));
if (delay < 1)
throw new NumberFormatException();
}
catch(NumberFormatException ex)
{
sendErrorAndHelp(sender, "The timer delay must be an integer of 1 or higher.");
return;
}
Config.setTimerTicks(delay);
if (player != null)
sender.sendMessage("Timer delay set to " + delay + " tick(s). That is roughly " + (delay * 50) + "ms.");
}
}

View File

@ -0,0 +1,32 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdDenypearl extends WBCmd
{
public CmdDenypearl()
{
name = permission = "denypearl";
minParams = maxParams = 1;
addCmdExample(nameEmphasized() + "<on|off> - stop ender pearls past the border.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
Config.setDenyEnderpearl(strAsBool(params.get(0)));
if (player != null)
{
Config.log((Config.getDenyEnderpearl() ? "Enabled" : "Disabled") + " direct cancellation of ender pearls thrown past the border at the command of player \"" + player.getName() + "\".");
sender.sendMessage("Direct cancellation of ender pearls thrown past the border " + enabledColored(Config.getDenyEnderpearl()) + ".");
}
}
}

View File

@ -0,0 +1,32 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdDynmap extends WBCmd
{
public CmdDynmap()
{
name = permission = "dynmap";
minParams = maxParams = 1;
addCmdExample(nameEmphasized() + "<on|off> - turn DynMap border display on or off.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
Config.setDynmapBorderEnabled(strAsBool(params.get(0)));
if (player != null)
{
sender.sendMessage("DynMap border display " + (Config.DynmapBorderEnabled() ? "enabled" : "disabled") + ".");
Config.log((Config.DynmapBorderEnabled() ? "Enabled" : "Disabled") + " DynMap border display at the command of player \"" + player.getName() + "\".");
}
}
}

View File

@ -0,0 +1,39 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdDynmapmsg extends WBCmd
{
public CmdDynmapmsg()
{
name = permission = "dynmapmsg";
minParams = 1;
addCmdExample(nameEmphasized() + "<text> - DynMap border labels will show this.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
StringBuilder message = new StringBuilder();
boolean first = true;
for (String param : params)
{
if (!first)
message.append(" ");
message.append(param);
first = false;
}
Config.setDynmapMessage(message.toString());
if (player != null)
sender.sendMessage("DynMap border label is now set to: " + clrErr + Config.DynmapMessage());
}
}

View File

@ -0,0 +1,179 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdFill extends WBCmd
{
public CmdFill()
{
name = permission = "fill";
hasWorldNameInput = true;
consoleRequiresWorldName = false;
minParams = 0;
maxParams = 3;
addCmdExample(nameEmphasizedW() + "[freq] [pad] [force] - fill world to border.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
boolean confirm = false;
// check for "cancel", "pause", or "confirm"
if (params.size() >= 1)
{
String check = params.get(0).toLowerCase();
if (check.equals("cancel") || check.equals("stop"))
{
if (!makeSureFillIsRunning(sender))
return;
sender.sendMessage(clrHead + "Cancelling the world map generation task.");
fillDefaults();
Config.StopFillTask();
return;
}
else if (check.equals("pause"))
{
if (!makeSureFillIsRunning(sender))
return;
Config.fillTask.pause();
sender.sendMessage(clrHead + "The world map generation task is now " + (Config.fillTask.isPaused() ? "" : "un") + "paused.");
return;
}
confirm = check.equals("confirm");
}
// if not just confirming, make sure a world name is available
if (worldName == null && !confirm)
{
if (player != null)
worldName = player.getWorld().getName();
else
{
sendErrorAndHelp(sender, "You must specify a world!");
return;
}
}
// colorized "/wb fill "
String cmd = ((player == null) ? cmdC : cmdP) + nameEmphasized() + clrCmd;
// make sure Fill isn't already running
if (Config.fillTask != null && Config.fillTask.valid())
{
sender.sendMessage(clrErr + "The world map generation task is already running.");
sender.sendMessage(clrDesc + "You can cancel at any time with " + cmd + "cancel" + clrDesc + ", or pause/unpause with " + cmd + "pause" + clrDesc + ".");
return;
}
// set frequency and/or padding if those were specified
try
{
if (params.size() >= 1 && !confirm)
fillFrequency = Math.abs(Integer.parseInt(params.get(0)));
if (params.size() >= 2 && !confirm)
fillPadding = Math.abs(Integer.parseInt(params.get(1)));
}
catch(NumberFormatException ex)
{
sendErrorAndHelp(sender, "The frequency and padding values must be integers.");
fillDefaults();
return;
}
if (fillFrequency <= 0)
{
sendErrorAndHelp(sender, "The frequency value must be greater than zero.");
fillDefaults();
return;
}
// see if the command specifies to load even chunks which should already be fully generated
if (params.size() == 3)
fillForceLoad = strAsBool(params.get(2));
// set world if it was specified
if (worldName != null)
fillWorld = worldName;
if (confirm)
{ // command confirmed, go ahead with it
if (fillWorld.isEmpty())
{
sendErrorAndHelp(sender, "You must first use this command successfully without confirming.");
return;
}
if (player != null)
Config.log("Filling out world to border at the command of player \"" + player.getName() + "\".");
int ticks = 1, repeats = 1;
if (fillFrequency > 20)
repeats = fillFrequency / 20;
else
ticks = 20 / fillFrequency;
/* */ Config.log("world: " + fillWorld + " padding: " + fillPadding + " repeats: " + repeats + " ticks: " + ticks);
Config.fillTask = new WorldFillTask(Bukkit.getServer(), player, fillWorld, fillPadding, repeats, ticks, fillForceLoad);
if (Config.fillTask.valid())
{
int task = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(WorldBorder.plugin, Config.fillTask, ticks, ticks);
Config.fillTask.setTaskID(task);
sender.sendMessage("WorldBorder map generation task for world \"" + fillWorld + "\" started.");
}
else
sender.sendMessage(clrErr + "The world map generation task failed to start.");
fillDefaults();
}
else
{
if (fillWorld.isEmpty())
{
sendErrorAndHelp(sender, "You must first specify a valid world.");
return;
}
sender.sendMessage(clrHead + "World generation task is ready for world \"" + fillWorld + "\", attempting to process up to " + fillFrequency + " chunks per second (default 20). The map will be padded out " + fillPadding + " blocks beyond the border (default " + defaultPadding + "). Parts of the world which are already fully generated will be " + (fillForceLoad ? "loaded anyway." : "skipped."));
sender.sendMessage(clrHead + "This process can take a very long time depending on the world's border size. Also, depending on the chunk processing rate, players will likely experience severe lag for the duration.");
sender.sendMessage(clrDesc + "You should now use " + cmd + "confirm" + clrDesc + " to start the process.");
sender.sendMessage(clrDesc + "You can cancel at any time with " + cmd + "cancel" + clrDesc + ", or pause/unpause with " + cmd + "pause" + clrDesc + ".");
}
}
/* with "view-distance=10" in server.properties on a fast VM test server and "Render Distance: Far" in client,
* hitting border during testing was loading 11+ chunks beyond the border in a couple of directions (10 chunks in
* the other two directions). This could be worse on a more loaded or worse server, so:
*/
private final int defaultPadding = CoordXZ.chunkToBlock(13);
private String fillWorld = "";
private int fillFrequency = 20;
private int fillPadding = defaultPadding;
private boolean fillForceLoad = false;
private void fillDefaults()
{
fillWorld = "";
fillFrequency = 20;
fillPadding = defaultPadding;
fillForceLoad = false;
}
private boolean makeSureFillIsRunning(CommandSender sender)
{
if (Config.fillTask != null && Config.fillTask.valid())
return true;
sendErrorAndHelp(sender, "The world map generation task is not currently running.");
return false;
}
}

View File

@ -0,0 +1,53 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdFillautosave extends WBCmd
{
public CmdFillautosave()
{
name = permission = "fillautosave";
minParams = maxParams = 1;
addCmdExample(nameEmphasized() + "<seconds> - world save interval for Fill.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
int seconds = 0;
try
{
seconds = Integer.parseInt(params.get(0));
if (seconds < 0)
throw new NumberFormatException();
}
catch(NumberFormatException ex)
{
sendErrorAndHelp(sender, "The world autosave frequency must be an integer of 0 or higher. Setting to 0 will disable autosaving of the world during the Fill process.");
return;
}
Config.setFillAutosaveFrequency(seconds);
if (player != null)
{
if (seconds == 0)
{
sender.sendMessage("World autosave frequency during Fill process set to 0, disabling it.");
sender.sendMessage("Note that much progress can be lost this way if there is a bug or crash in the world generation process from Bukkit or any world generation plugin you use.");
}
else
{
sender.sendMessage("World autosave frequency during Fill process set to " + seconds + " seconds (rounded to a multiple of 5).");
sender.sendMessage("New chunks generated by the Fill process will be forcibly saved to disk this often to prevent loss of progress due to bugs or crashes in the world generation process.");
}
}
}
}

View File

@ -0,0 +1,29 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdGetmsg extends WBCmd
{
public CmdGetmsg()
{
name = permission = "getmsg";
minParams = maxParams = 0;
addCmdExample(nameEmphasized() + "- display border message.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
sender.sendMessage("Border message is currently set to:");
sender.sendMessage(Config.MessageRaw());
sender.sendMessage("Formatted border message:");
sender.sendMessage(Config.Message());
}
}

View File

@ -0,0 +1,42 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdKnockback extends WBCmd
{
public CmdKnockback()
{
name = permission = "knockback";
minParams = maxParams = 1;
addCmdExample(nameEmphasized() + "<distance> - how far to move the player back.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
double numBlocks = 0.0;
try
{
numBlocks = Double.parseDouble(params.get(0));
if (numBlocks < 0.0 || (numBlocks > 0.0 && numBlocks < 1.0))
throw new NumberFormatException();
}
catch(NumberFormatException ex)
{
sendErrorAndHelp(sender, "The knockback must be a decimal value of at least 1.0, or it can be 0.");
return;
}
Config.setKnockBack(numBlocks);
if (player != null)
sender.sendMessage("Knockback set to " + numBlocks + " blocks inside the border.");
}
}

View File

@ -0,0 +1,40 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import java.util.Set;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdList extends WBCmd
{
public CmdList()
{
name = permission = "list";
minParams = maxParams = 0;
addCmdExample(nameEmphasized() + "- show border information for all worlds.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
sender.sendMessage("Default border shape for all worlds is \"" + Config.ShapeName() + "\".");
Set<String> list = Config.BorderDescriptions();
if (list.isEmpty())
{
sender.sendMessage("There are no borders currently set.");
return;
}
for(String borderDesc : list)
{
sender.sendMessage(borderDesc);
}
}
}

View File

@ -0,0 +1,32 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdPortal extends WBCmd
{
public CmdPortal()
{
name = permission = "portal";
minParams = maxParams = 1;
addCmdExample(nameEmphasized() + "<on|off> - turn portal redirection on or off.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
Config.setPortalRedirection(strAsBool(params.get(0)));
if (player != null)
{
Config.log((Config.portalRedirection() ? "Enabled" : "Disabled") + " portal redirection at the command of player \"" + player.getName() + "\".");
sender.sendMessage("Portal redirection " + enabledColored(Config.portalRedirection()) + ".");
}
}
}

View File

@ -0,0 +1,59 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdRadius extends WBCmd
{
public CmdRadius()
{
name = permission = "radius";
hasWorldNameInput = true;
minParams = 1;
maxParams = 2;
addCmdExample(nameEmphasizedW() + "<radiusX> [radiusZ] - change radius.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
if (worldName == null)
worldName = player.getWorld().getName();
BorderData border = Config.Border(worldName);
if (border == null)
{
sendErrorAndHelp(sender, "This world (\"" + worldName + "\") must first have a border set normally.");
return;
}
double x = border.getX();
double z = border.getZ();
int radiusX;
int radiusZ;
try
{
radiusX = Integer.parseInt(params.get(0));
if (params.size() == 2)
radiusZ = Integer.parseInt(params.get(1));
else
radiusZ = radiusX;
}
catch(NumberFormatException ex)
{
sendErrorAndHelp(sender, "The radius value(s) must be integers.");
return;
}
Config.setBorder(worldName, radiusX, radiusZ, x, z);
if (player != null)
sender.sendMessage("Radius has been set. " + Config.BorderDescription(worldName));
}
}

View File

@ -0,0 +1,32 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdReload extends WBCmd
{
public CmdReload()
{
name = permission = "reload";
minParams = maxParams = 0;
addCmdExample(nameEmphasized() + "- re-load data from config.yml.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
if (player != null)
Config.log("Reloading config file at the command of player \"" + player.getName() + "\".");
Config.load(WorldBorder.plugin, true);
if (player != null)
sender.sendMessage("WorldBorder configuration reloaded.");
}
}

View File

@ -0,0 +1,51 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdRemount extends WBCmd
{
public CmdRemount()
{
name = permission = "remount";
minParams = maxParams = 1;
addCmdExample(nameEmphasized() + "<amount> - player remount delay after knockback.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
int delay = 0;
try
{
delay = Integer.parseInt(params.get(0));
if (delay < 0)
throw new NumberFormatException();
}
catch(NumberFormatException ex)
{
sendErrorAndHelp(sender, "The remount delay must be an integer of 0 or higher. Setting to 0 will disable remounting.");
return;
}
Config.setRemountTicks(delay);
if (player != null)
{
if (delay == 0)
sender.sendMessage("Remount delay set to 0. Players will be left dismounted when knocked back from the border while on a vehicle.");
else
{
sender.sendMessage("Remount delay set to " + delay + " tick(s). That is roughly " + (delay * 50) + "ms / " + (((double)delay * 50.0) / 1000.0) + " seconds. Setting to 0 would disable remounting.");
if (delay < 10)
sender.sendMessage(clrErr + "WARNING:" + clrDesc + " setting this to less than 10 (and greater than 0) is not recommended. This can lead to nasty client glitches.");
}
}
}
}

View File

@ -0,0 +1,136 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.bukkit.Location;
import org.bukkit.World;
import com.wimbli.WorldBorder.*;
public class CmdSet extends WBCmd
{
public CmdSet()
{
name = permission = "set";
hasWorldNameInput = true;
consoleRequiresWorldName = false;
minParams = 1;
maxParams = 4;
addCmdExample(nameEmphasized() + "<radiusX> [radiusZ] - set border, centered on you.", true, false, true);
addCmdExample(nameEmphasizedW() + "<radiusX> [radiusZ] <x> <z> - use x/z coords.");
addCmdExample(nameEmphasizedW() + "<radiusX> [radiusZ] ^spawn - use spawn point.");
addCmdExample(nameEmphasized() + "<radiusX> [radiusZ] ^player <name> - center on player.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
// passsing a single parameter (radiusX) is only acceptable from player
if ((params.size() == 1) && player == null)
{
sendErrorAndHelp(sender, "You have not provided a sufficient number of arguments.");
return;
}
// "set" command from player or console, world specified
if (worldName != null)
{
if (params.size() == 2 && ! params.get(params.size() - 1).equalsIgnoreCase("spawn"))
{ // command can only be this short if "spawn" is specified rather than x + z or player name
sendErrorAndHelp(sender, "You have not provided a sufficient number of arguments.");
return;
}
World world = sender.getServer().getWorld(worldName);
if (world == null)
{
if (params.get(params.size() - 1).equalsIgnoreCase("spawn"))
{
sendErrorAndHelp(sender, "The world you specified (\"" + worldName + "\") could not be found on the server, so the spawn point cannot be determined.");
return;
}
sender.sendMessage("The world you specified (\"" + worldName + "\") could not be found on the server, but data for it will be stored anyway.");
}
}
// "set" command from player using current world since it isn't specified, or allowed from console only if player name is specified
else
{
if (player == null)
{
if (! params.get(params.size() - 2).equalsIgnoreCase("player"))
{ // command can only be called by console without world specified if player is specified instead
sendErrorAndHelp(sender, "You must specify a world name from console if not specifying a player name.");
return;
}
player = Bukkit.getPlayer(params.get(params.size() - 1));
if (player == null || ! player.isOnline())
{
sendErrorAndHelp(sender, "The player you specified (\"" + params.get(params.size() - 1) + "\") does not appear to be online.");
return;
}
}
worldName = player.getWorld().getName();
}
int radiusX, radiusZ;
double x, z;
int radiusCount = params.size();
try
{
if (params.get(params.size() - 1).equalsIgnoreCase("spawn"))
{ // "spawn" specified for x/z coordinates
Location loc = sender.getServer().getWorld(worldName).getSpawnLocation();
x = loc.getX();
z = loc.getZ();
radiusCount -= 1;
}
else if (params.get(params.size() - 2).equalsIgnoreCase("player"))
{ // player name specified for x/z coordinates
Player playerT = Bukkit.getPlayer(params.get(params.size() - 1));
if (playerT == null || ! playerT.isOnline())
{
sendErrorAndHelp(sender, "The player you specified (\"" + params.get(params.size() - 1) + "\") does not appear to be online.");
return;
}
worldName = playerT.getWorld().getName();
x = playerT.getLocation().getX();
z = playerT.getLocation().getZ();
radiusCount -= 2;
}
else
{
if (player == null || radiusCount > 2)
{ // x and z specified
x = Double.parseDouble(params.get(params.size() - 2));
z = Double.parseDouble(params.get(params.size() - 1));
radiusCount -= 2;
}
else
{ // using coordinates of command sender (player)
x = player.getLocation().getX();
z = player.getLocation().getZ();
}
}
radiusX = Integer.parseInt(params.get(0));
if (radiusCount < 2)
radiusZ = radiusX;
else
radiusZ = Integer.parseInt(params.get(1));
}
catch(NumberFormatException ex)
{
sendErrorAndHelp(sender, "The radius value(s) must be integers and the x and z values must be numerical.");
return;
}
Config.setBorder(worldName, radiusX, radiusZ, x, z);
sender.sendMessage("Border has been set. " + Config.BorderDescription(worldName));
}
}

View File

@ -0,0 +1,55 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.bukkit.World;
import com.wimbli.WorldBorder.*;
public class CmdSetcorners extends WBCmd
{
public CmdSetcorners()
{
name = "setcorners";
permission = "set";
hasWorldNameInput = true;
minParams = maxParams = 4;
addCmdExample(nameEmphasizedW() + "<x1> <z1> <x2> <z2> - corner coords.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
if (worldName == null)
{
worldName = player.getWorld().getName();
}
else
{
World worldTest = sender.getServer().getWorld(worldName);
if (worldTest == null)
sender.sendMessage("The world you specified (\"" + worldName + "\") could not be found on the server, but data for it will be stored anyway.");
}
try
{
double x1 = Double.parseDouble(params.get(0));
double z1 = Double.parseDouble(params.get(1));
double x2 = Double.parseDouble(params.get(2));
double z2 = Double.parseDouble(params.get(3));
Config.setBorderCorners(worldName, x1, z1, x2, z2);
}
catch(NumberFormatException ex)
{
sendErrorAndHelp(sender, "The x1, z1, x2, and z2 coordinate values must be numerical.");
return;
}
if(player != null)
sender.sendMessage("Border has been set. " + Config.BorderDescription(worldName));
}
}

View File

@ -0,0 +1,41 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdSetmsg extends WBCmd
{
public CmdSetmsg()
{
name = permission = "setmsg";
minParams = 1;
addCmdExample(nameEmphasized() + "<text> - set border message.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
StringBuilder message = new StringBuilder();
boolean first = true;
for (String param : params)
{
if (!first)
message.append(" ");
message.append(param);
first = false;
}
Config.setMessage(message.toString());
sender.sendMessage("Border message is now set to:");
sender.sendMessage(Config.MessageRaw());
sender.sendMessage("Formatted border message:");
sender.sendMessage(Config.Message());
}
}

View File

@ -0,0 +1,39 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdShape extends WBCmd
{
public CmdShape()
{
name = permission = "shape";
minParams = maxParams = 1;
addCmdExample(nameEmphasized() + "<round|square> - set the default border shape.");
addCmdExample(nameEmphasized() + "<elliptic|rectangular> - same as above.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
String shape = params.get(0).toLowerCase();
if (shape.equals("rectangular") || shape.equals("square"))
Config.setShape(false);
else if (shape.equals("elliptic") || shape.equals("round"))
Config.setShape(true);
else
{
sendErrorAndHelp(sender, "You must specify one of the 4 valid shape names as indicated below.");
return;
}
if (player != null)
sender.sendMessage("Default border shape for all worlds is now set to \"" + Config.ShapeName() + "\".");
}
}

View File

@ -0,0 +1,172 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdTrim extends WBCmd
{
public CmdTrim()
{
name = permission = "trim";
hasWorldNameInput = true;
consoleRequiresWorldName = false;
minParams = 0;
maxParams = 2;
addCmdExample(nameEmphasizedW() + "[freq] [pad] - trim world outside of border.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
boolean confirm = false;
// check for "cancel", "pause", or "confirm"
if (params.size() >= 1)
{
String check = params.get(0).toLowerCase();
if (check.equals("cancel") || check.equals("stop"))
{
if (!makeSureTrimIsRunning(sender))
return;
sender.sendMessage(clrHead + "Cancelling the world map trimming task.");
trimDefaults();
Config.StopTrimTask();
return;
}
else if (check.equals("pause"))
{
if (!makeSureTrimIsRunning(sender))
return;
Config.trimTask.pause();
sender.sendMessage(clrHead + "The world map trimming task is now " + (Config.trimTask.isPaused() ? "" : "un") + "paused.");
return;
}
confirm = check.equals("confirm");
}
// if not just confirming, make sure a world name is available
if (worldName == null && !confirm)
{
if (player != null)
worldName = player.getWorld().getName();
else
{
sendErrorAndHelp(sender, "You must specify a world!");
return;
}
}
// colorized "/wb trim "
String cmd = ((player == null) ? cmdC : cmdP) + nameEmphasized() + clrCmd;
// make sure Trim isn't already running
if (Config.trimTask != null && Config.trimTask.valid())
{
sender.sendMessage(clrErr + "The world map trimming task is already running.");
sender.sendMessage(clrDesc + "You can cancel at any time with " + cmd + "cancel" + clrDesc + ", or pause/unpause with " + cmd + "pause" + clrDesc + ".");
return;
}
// set frequency and/or padding if those were specified
try
{
if (params.size() >= 1 && !confirm)
trimFrequency = Math.abs(Integer.parseInt(params.get(0)));
if (params.size() >= 2 && !confirm)
trimPadding = Math.abs(Integer.parseInt(params.get(1)));
}
catch(NumberFormatException ex)
{
sendErrorAndHelp(sender, "The frequency and padding values must be integers.");
trimDefaults();
return;
}
if (trimFrequency <= 0)
{
sendErrorAndHelp(sender, "The frequency value must be greater than zero.");
trimDefaults();
return;
}
// set world if it was specified
if (worldName != null)
trimWorld = worldName;
if (confirm)
{ // command confirmed, go ahead with it
if (trimWorld.isEmpty())
{
sendErrorAndHelp(sender, "You must first use this command successfully without confirming.");
return;
}
if (player != null)
Config.log("Trimming world beyond border at the command of player \"" + player.getName() + "\".");
int ticks = 1, repeats = 1;
if (trimFrequency > 20)
repeats = trimFrequency / 20;
else
ticks = 20 / trimFrequency;
Config.trimTask = new WorldTrimTask(Bukkit.getServer(), player, trimWorld, trimPadding, repeats);
if (Config.trimTask.valid())
{
int task = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(WorldBorder.plugin, Config.trimTask, ticks, ticks);
Config.trimTask.setTaskID(task);
sender.sendMessage("WorldBorder map trimming task for world \"" + trimWorld + "\" started.");
}
else
sender.sendMessage(clrErr + "The world map trimming task failed to start.");
trimDefaults();
}
else
{
if (trimWorld.isEmpty())
{
sendErrorAndHelp(sender, "You must first specify a valid world.");
return;
}
sender.sendMessage(clrHead + "World trimming task is ready for world \"" + trimWorld + "\", attempting to process up to " + trimFrequency + " chunks per second (default 20). The map will be trimmed past " + trimPadding + " blocks beyond the border (default " + defaultPadding + ").");
sender.sendMessage(clrHead + "This process can take a very long time depending on the world's overall size. Also, depending on the chunk processing rate, players may experience lag for the duration.");
sender.sendMessage(clrDesc + "You should now use " + cmd + "confirm" + clrDesc + " to start the process.");
sender.sendMessage(clrDesc + "You can cancel at any time with " + cmd + "cancel" + clrDesc + ", or pause/unpause with " + cmd + "pause" + clrDesc + ".");
}
}
/* with "view-distance=10" in server.properties on a fast VM test server and "Render Distance: Far" in client,
* hitting border during testing was loading 11+ chunks beyond the border in a couple of directions (10 chunks in
* the other two directions). This could be worse on a more loaded or worse server, so:
*/
private final int defaultPadding = CoordXZ.chunkToBlock(13);
private String trimWorld = "";
private int trimFrequency = 5000;
private int trimPadding = defaultPadding;
private void trimDefaults()
{
trimWorld = "";
trimFrequency = 5000;
trimPadding = defaultPadding;
}
private boolean makeSureTrimIsRunning(CommandSender sender)
{
if (Config.trimTask != null && Config.trimTask.valid())
return true;
sendErrorAndHelp(sender, "The world map trimming task is not currently running.");
return false;
}
}

View File

@ -0,0 +1,32 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdWhoosh extends WBCmd
{
public CmdWhoosh()
{
name = permission = "whoosh";
minParams = maxParams = 1;
addCmdExample(nameEmphasized() + "<on|off> - turn knockback effect on or off.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
Config.setWhooshEffect(strAsBool(params.get(0)));
if (player != null)
{
Config.log((Config.whooshEffect() ? "Enabled" : "Disabled") + " \"whoosh\" knockback effect at the command of player \"" + player.getName() + "\".");
sender.sendMessage("\"Whoosh\" knockback effect " + enabledColored(Config.whooshEffect()) + ".");
}
}
}

View File

@ -0,0 +1,58 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdWrap extends WBCmd
{
public CmdWrap()
{
name = permission = "wrap";
minParams = 1;
maxParams = 2;
addCmdExample(nameEmphasized() + "{world} <on|off> - can make border crossings wrap.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
if (player == null && params.size() == 1)
{
sendErrorAndHelp(sender, "When running this command from console, you must specify a world.");
return;
}
boolean wrap = false;
// world and wrap on/off specified
if (params.size() == 2)
{
worldName = params.get(0);
wrap = strAsBool(params.get(1));
}
// no world specified, just wrap on/off
else
{
worldName = player.getWorld().getName();
wrap = strAsBool(params.get(0));
}
BorderData border = Config.Border(worldName);
if (border == null)
{
sendErrorAndHelp(sender, "This world (\"" + worldName + "\") does not have a border set.");
return;
}
border.setWrapping(wrap);
Config.setBorder(worldName, border, false);
sender.sendMessage("Border for world \"" + worldName + "\" is now set to " + (wrap ? "" : "not ") + "wrap around.");
}
}

View File

@ -0,0 +1,66 @@
package com.wimbli.WorldBorder.cmd;
import java.util.List;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import com.wimbli.WorldBorder.*;
public class CmdWshape extends WBCmd
{
public CmdWshape()
{
name = permission = "wshape";
minParams = 1;
maxParams = 2;
addCmdExample(nameEmphasized() + "{world} <elliptic|rectangular|default> - shape");
addCmdExample(clrDesc + " override for a single world.", true, true, false);
addCmdExample(nameEmphasized() + "{world} <round|square|default> - same as above.");
}
@Override
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
{
if (player == null && params.size() == 1)
{
sendErrorAndHelp(sender, "When running this command from console, you must specify a world.");
return;
}
String shapeName = "";
// world and shape specified
if (params.size() == 2)
{
worldName = params.get(0);
shapeName = params.get(1).toLowerCase();
}
// no world specified, just shape
else
{
worldName = player.getWorld().getName();
shapeName = params.get(0).toLowerCase();
}
BorderData border = Config.Border(worldName);
if (border == null)
{
sendErrorAndHelp(sender, "This world (\"" + worldName + "\") does not have a border set.");
return;
}
Boolean shape = null;
if (shapeName.equals("rectangular") || shapeName.equals("square"))
shape = false;
else if (shapeName.equals("elliptic") || shapeName.equals("round"))
shape = true;
border.setShape(shape);
Config.setBorder(worldName, border, false);
sender.sendMessage("Border shape for world \"" + worldName + "\" is now set to \"" + Config.ShapeName(shape) + "\".");
}
}

View File

@ -0,0 +1,130 @@
package com.wimbli.WorldBorder.cmd;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
public abstract class WBCmd
{
/*
* Primary variables, should be set as needed in constructors for the subclassed commands
*/
// command name, command permission; normally the same thing
public String name = "";
public String permission = null;
// whether command can accept a world name before itself
public boolean hasWorldNameInput = false;
public boolean consoleRequiresWorldName = true;
// minimum and maximum number of accepted parameters
public int minParams = 0;
public int maxParams = 9999;
/*
* The guts of the command run in here; needs to be overriden in the subclassed commands
*/
public abstract void execute(CommandSender sender, Player player, List<String> params, String worldName);
/*
* Helper variables and methods
*/
// color values for strings
public final static String clrCmd = ChatColor.AQUA.toString(); // main commands
public final static String clrDesc = ChatColor.WHITE.toString(); // command descriptions
public final static String clrErr = ChatColor.RED.toString(); // errors / notices
public final static String clrHead = ChatColor.YELLOW.toString(); // command listing header
public final static String clrOpt = ChatColor.DARK_GREEN.toString(); // optional values
public final static String clrReq = ChatColor.GREEN.toString(); // required values
// colorized root command, for console and for player
public final static String cmdC = clrCmd + "wb ";
public final static String cmdP = clrCmd + "/wb ";
// list of command examples for this command to be displayed as usage reference, separate between players and console
// ... these generally should be set indirectly using addCmdExample() within the constructor for each command class
public List<String> cmdExamplePlayer = new ArrayList<String>();
public List<String> cmdExampleConsole = new ArrayList<String>();
// much like the above, but used for displaying command list from root /wb command, listing all commands
public final static List<String> cmdExamplesConsole = new ArrayList<String>(48); // 48 command capacity, 6 full pages
public final static List<String> cmdExamplesPlayer = new ArrayList<String>(48); // still, could need to increase later
// add command examples for use the default "/wb" command list and for internal usage reference, formatted and colorized
public void addCmdExample(String example)
{
addCmdExample(example, true, true, true);
}
public void addCmdExample(String example, boolean forPlayer, boolean forConsole, boolean prefix)
{
// go ahead and colorize required "<>" and optional "[]" parameters, extra command words, and description
example = example.replace("<", clrReq+"<").replace("[", clrOpt+"[").replace("^", clrCmd).replace("- ", clrDesc+"- ");
// all "{}" are replaced by "[]" (optional) for player, "<>" (required) for console
if (forPlayer)
{
String exampleP = (prefix ? cmdP : "") + example.replace("{", clrOpt + "[").replace("}", "]");
cmdExamplePlayer.add(exampleP);
cmdExamplesPlayer.add(exampleP);
}
if (forConsole)
{
String exampleC = (prefix ? cmdC : "") + example.replace("{", clrReq + "<").replace("}", ">");
cmdExampleConsole.add(exampleC);
cmdExamplesConsole.add(exampleC);
}
}
// formatted and colorized text, intended for marking command name
public String commandEmphasized(String text)
{
return clrCmd + ChatColor.UNDERLINE + text + ChatColor.RESET + " ";
}
// returns green "enabled" or red "disabled" text
public String enabledColored(boolean enabled)
{
return enabled ? clrReq+"enabled" : clrErr+"disabled";
}
// formatted and colorized command name, optionally prefixed with "[world]" (for player) / "<world>" (for console)
public String nameEmphasized()
{
return commandEmphasized(name);
}
public String nameEmphasizedW()
{
return "{world} " + nameEmphasized();
}
// send command example message(s)
public void sendCmdHelp(CommandSender sender)
{
for (String example : ((sender instanceof Player) ? cmdExamplePlayer : cmdExampleConsole))
{
sender.sendMessage(example);
}
}
// send error message followed by command example message(s)
public void sendErrorAndHelp(CommandSender sender, String error)
{
sender.sendMessage(clrErr + error);
sendCmdHelp(sender);
}
// interpret string as boolean value (yes/no, true/false, on/off, +/-, 1/0)
public boolean strAsBool(String str)
{
str = str.toLowerCase();
return str.startsWith("y") || str.startsWith("t") || str.startsWith("on") || str.startsWith("+") || str.startsWith("1");
}
}

View File

@ -17,29 +17,30 @@ commands:
/<command> set <radiusX> [radiusZ] player <name> - center on player.
/<command> [world] setcorners <x1> <z1> <x2> <z2> - set border from corners.
/<command> [world] radius <radiusX> [radiusZ] - change border's radius.
/<command> shape <elliptic|rectangular> - set the default border shape.
/<command> shape <round|square> - same as above, backwards compatible.
/<command> [world] clear - remove border for this world.
/<command> clear all - remove border for all worlds.
/<command> list - show border information for all worlds.
/<command> shape <elliptic|rectangular> - set the default border shape.
/<command> shape <round|square> - same as above, backwards compatible.
/<command> getmsg - display border message.
/<command> setmsg <text> - set border message.
/<command> knockback <distance> - how far to move the player back.
/<command> whoosh <on/off> - turn knockback effect on or off.
/<command> portal <on/off> - turn portal redirection on or off.
/<command> delay <amount> - time between border checks.
/<command> wshape [world] <elliptic|rectangular|default> - override shape.
/<command> wshape [world] <round|square|default> - same as above values.
/<command> wrap [world] <on/off> - can make border crossings wrap around.
/<command> [world] fill [freq] [pad] [force] - generate world to border.
/<command> [world] trim [freq] [pad] - trim world outside of border.
/<command> bypass [player] [on/off] - let player go beyond border.
/<command> bypasslist - list players with border bypass enabled.
/<command> remount <amount> - delay before remounting after knockback.
/<command> fillautosave <seconds> - world save interval for Fill process.
/<command> denypearl <on/off> - stop ender pearls thrown past the border.
/<command> knockback <distance> - how far to move the player back.
/<command> wrap [world] <on/off> - can make border crossings wrap around.
/<command> whoosh <on/off> - turn knockback effect on or off.
/<command> getmsg - display border message.
/<command> setmsg <text> - set border message.
/<command> delay <amount> - time between border checks.
/<command> wshape [world] <elliptic|rectangular|default> - override shape.
/<command> wshape [world] <round|square|default> - same as above values.
/<command> dynmap <on/off> - turn DynMap border display on or off.
/<command> dynmapmsg <text> - DynMap border labels will show this.
/<command> remount <amount> - delay before remounting after knockback.
/<command> fillautosave <seconds> - world save interval for Fill process.
/<command> portal <on/off> - turn portal redirection on or off.
/<command> denypearl <on/off> - stop ender pearls thrown past the border.
/<command> reload - re-load data from config.yml.
/<command> debug <on/off> - turn debug mode on or off.
permissions:
worldborder.*: