diff --git a/pom.xml b/pom.xml
index f5a726c09..c0b25acae 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
UTF-8
PlotSquared
- 3.2.3
+ 3.2.4
PlotSquared
jar
diff --git a/src/main/java/com/intellectualcrafters/plot/commands/GenerateDocs.java b/src/main/java/com/intellectualcrafters/plot/commands/GenerateDocs.java
index 30e56feaa..d24a573bb 100644
--- a/src/main/java/com/intellectualcrafters/plot/commands/GenerateDocs.java
+++ b/src/main/java/com/intellectualcrafters/plot/commands/GenerateDocs.java
@@ -4,12 +4,16 @@ import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.object.PlotPlayer;
+import com.intellectualcrafters.plot.util.Permissions;
import com.intellectualcrafters.plot.util.StringMan;
import com.plotsquared.general.commands.Command;
@@ -91,10 +95,35 @@ public class GenerateDocs {
}
public static List getPerms(final String cmd, final List lines) {
- final ArrayList perms = new ArrayList();
+ final HashSet perms = new HashSet();
final Pattern p = Pattern.compile("\"([^\"]*)\"");
+ final Pattern p2 = Pattern.compile("C.PERMISSION_\\s*(\\w+)");
+ String last = null;
for (final String line : lines) {
+
+ Matcher m2 = p2.matcher(line);
+ while (m2.find()) {
+ perms.add(C.valueOf("PERMISSION_" + m2.group(1)).s());
+ }
+
if (line.contains("Permissions.hasPermission(")) {
+ String[] split = line.split("Permissions.hasPermission");
+ split = Arrays.copyOfRange(split, 1, split.length);
+ for (String method : split) {
+ String perm = method.split("[,|)]")[1].trim();
+ if (!perm.toLowerCase().equals(perm)) {
+ if (perm.startsWith("C.")) {
+ perm = C.valueOf(perm.split("\\.")[1]).s();
+ }
+ else {
+ continue;
+ }
+ }
+ else {
+ perm = perm.substring(1, perm.length() - 1);
+ }
+ perms.add(perm);
+ }
final Matcher m = p.matcher(line);
while (m.find()) {
String perm = m.group(1);
@@ -102,21 +131,42 @@ public class GenerateDocs {
perm += "";
}
if (perm.startsWith(".")) {
- perms.set(perms.size() - 1, perms.get(perms.size() - 1) + perm);
+ perms.remove(last);
+ perms.add(last + perm);
} else if (perm.contains(".")) {
+ last = perm;
perms.add(perm);
}
}
}
+ else if (line.contains("Permissions.hasPermissionRange")) {
+ String[] split = line.split("Permissions.hasPermissionRange");
+ split = Arrays.copyOfRange(split, 1, split.length);
+ for (String method : split) {
+ String perm = method.split("[,|)]")[1].trim();
+ if (!perm.toLowerCase().equals(perm)) {
+ if (perm.startsWith("C.")) {
+ perm = C.valueOf(perm.split("\\.")[1]).s();
+ }
+ else {
+ continue;
+ }
+ }
+ else {
+ perm = perm.substring(1, perm.length() - 1);
+ }
+ perms.add(perm + ".<#>");
+ }
+ }
}
switch (cmd.toLowerCase()) {
case "auto":
case "claim": {
- perms.add("plots.plot.#");
+ perms.add("plots.plot.<#>");
break;
}
}
- return perms;
+ return new ArrayList<>(perms);
}
public static String getComments(final List lines) {
diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Merge.java b/src/main/java/com/intellectualcrafters/plot/commands/Merge.java
index b2556e782..2f7173792 100644
--- a/src/main/java/com/intellectualcrafters/plot/commands/Merge.java
+++ b/src/main/java/com/intellectualcrafters/plot/commands/Merge.java
@@ -86,10 +86,15 @@ public class Merge extends SubCommand {
MainUtil.sendMessage(plr, C.PLOT_UNOWNED);
return false;
}
- final boolean admin = Permissions.hasPermission(plr, "plots.admin.command.merge");
- if (!plot.isOwner(plr.getUUID()) && !admin) {
- MainUtil.sendMessage(plr, C.NO_PLOT_PERMS);
- return false;
+ UUID uuid = plr.getUUID();
+ if (!plot.isOwner(uuid)) {
+ if (!Permissions.hasPermission(plr, "plots.admin.command.merge")) {
+ MainUtil.sendMessage(plr, C.NO_PLOT_PERMS);
+ return false;
+ }
+ else {
+ uuid = plot.owner;
+ }
}
final PlotWorld plotworld = PS.get().getPlotWorld(plot.world);
if ((EconHandler.manager != null) && plotworld.USE_ECONOMY && plotworld.MERGE_PRICE > 0d && EconHandler.manager.getMoney(plr) < plotworld.MERGE_PRICE) {
@@ -98,8 +103,8 @@ public class Merge extends SubCommand {
}
int direction = -1;
final int size = plot.getConnectedPlots().size();
- final int maxSize = Permissions.hasPermissionRange(plr, "plots.merge", Settings.MAX_PLOTS);
- if (size >= maxSize) {
+ final int maxSize = Permissions.hasPermissionRange(plr, "plots.merge", Settings.MAX_PLOTS);
+ if (size - 1> maxSize) {
MainUtil.sendMessage(plr, C.NO_PERMISSION, "plots.merge." + (size + 1));
return false;
}
@@ -120,7 +125,7 @@ public class Merge extends SubCommand {
// }
} else {
if (args[0].equalsIgnoreCase("all") || args[0].equalsIgnoreCase("auto")) {
- if (MainUtil.autoMerge(plot, -1, maxSize - size, plr.getUUID(), (args.length != 2) || !args[1].equalsIgnoreCase("false"))) {
+ if (MainUtil.autoMerge(plot, -1, maxSize - size, uuid, (args.length != 2) || !args[1].equalsIgnoreCase("false"))) {
if ((EconHandler.manager != null) && plotworld.USE_ECONOMY && plotworld.MERGE_PRICE > 0d) {
EconHandler.manager.withdrawMoney(plr, plotworld.MERGE_PRICE);
sendMessage(plr, C.REMOVED_BALANCE, plotworld.MERGE_PRICE + "");
@@ -144,7 +149,7 @@ public class Merge extends SubCommand {
MainUtil.sendMessage(plr, C.DIRECTION.s().replaceAll("%dir%", direction(loc.getYaw())));
return false;
}
- if (MainUtil.autoMerge(plot, direction, maxSize - size, plot.owner, (args.length != 2) || !args[1].equalsIgnoreCase("false"))) {
+ if (MainUtil.autoMerge(plot, direction, maxSize - size, uuid, (args.length != 2) || !args[1].equalsIgnoreCase("false"))) {
if ((EconHandler.manager != null) && plotworld.USE_ECONOMY && plotworld.MERGE_PRICE > 0d) {
EconHandler.manager.withdrawMoney(plr, plotworld.MERGE_PRICE);
sendMessage(plr, C.REMOVED_BALANCE, plotworld.MERGE_PRICE + "");
@@ -153,7 +158,7 @@ public class Merge extends SubCommand {
return true;
}
Plot adjacent = MainUtil.getPlotAbs(plot.world, MainUtil.getPlotIdRelative(plot.id, direction));
- if (adjacent == null || !adjacent.hasOwner() || adjacent.getMerged((direction + 2) % 4)) {
+ if (adjacent == null || !adjacent.hasOwner() || adjacent.getMerged((direction + 2) % 4) || adjacent.isOwner(uuid)) {
MainUtil.sendMessage(plr, C.NO_AVAILABLE_AUTOMERGE);
return false;
}
@@ -163,8 +168,8 @@ public class Merge extends SubCommand {
}
HashSet uuids = adjacent.getOwners();
boolean isOnline = false;
- for (final UUID uuid : uuids) {
- final PlotPlayer accepter = UUIDHandler.getPlayer(uuid);
+ for (final UUID owner : uuids) {
+ final PlotPlayer accepter = UUIDHandler.getPlayer(owner);
if (accepter == null) {
continue;
}
@@ -174,7 +179,7 @@ public class Merge extends SubCommand {
@Override
public void run() {
MainUtil.sendMessage(accepter, C.MERGE_ACCEPTED);
- MainUtil.autoMerge(plot, dir, maxSize - size, uuid, true);
+ MainUtil.autoMerge(plot, dir, maxSize - size, owner, true);
final PlotPlayer pp = UUIDHandler.getPlayer(plr.getUUID());
if (pp == null) {
sendMessage(accepter, C.MERGE_NOT_VALID);
diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Toggle.java b/src/main/java/com/intellectualcrafters/plot/commands/Toggle.java
index cc763dcb4..a63381f28 100644
--- a/src/main/java/com/intellectualcrafters/plot/commands/Toggle.java
+++ b/src/main/java/com/intellectualcrafters/plot/commands/Toggle.java
@@ -97,7 +97,7 @@ public class Toggle extends SubCommand {
return true;
}
});
- if (PS.get().worldedit != null) {
+ if (PS.get() != null && PS.get().worldedit != null) {
toggles.put("worldedit", new Command("worldedit", "/plot toggle worldedit", "Toggle worldedit bypass", C.PERMISSION_WORLDEDIT_BYPASS.s()) {
@Override
diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Visit.java b/src/main/java/com/intellectualcrafters/plot/commands/Visit.java
index 99ec231d2..884f634e4 100644
--- a/src/main/java/com/intellectualcrafters/plot/commands/Visit.java
+++ b/src/main/java/com/intellectualcrafters/plot/commands/Visit.java
@@ -21,6 +21,7 @@
package com.intellectualcrafters.plot.commands;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
@@ -44,7 +45,7 @@ import com.plotsquared.general.commands.CommandDeclaration;
command = "visit",
permission = "plots.visit",
description = "Visit someones plot",
-usage = "/plot visit [#]",
+usage = "/plot visit [#]",
aliases = { "v" },
requiredType = RequiredType.NONE,
category = CommandCategory.TELEPORT)
@@ -94,8 +95,7 @@ public class Visit extends SubCommand {
} else {
final Plot plot = MainUtil.getPlotFromString(player, args[0], true);
if (plot != null) {
- unsorted = new HashSet<>();
- unsorted.add(plot);
+ unsorted = new HashSet<>(Arrays.asList(plot.getBasePlot(false)));
}
}
break;
diff --git a/src/main/java/com/intellectualcrafters/plot/config/C.java b/src/main/java/com/intellectualcrafters/plot/config/C.java
index 5ea8a5ce0..61315b6a4 100644
--- a/src/main/java/com/intellectualcrafters/plot/config/C.java
+++ b/src/main/java/com/intellectualcrafters/plot/config/C.java
@@ -339,7 +339,7 @@ public enum C {
MERGE_REQUESTED("$2Successfully sent a merge request", "Merge"),
MERGE_REQUEST_CONFIRM("merge request from %s", "Permission"),
NO_PERM_MERGE("$2You are not the owner of the plot: $1%plot%", "Merge"),
- NO_AVAILABLE_AUTOMERGE("$2You do not own any adjacent plots in the specified direction.", "Merge"),
+ NO_AVAILABLE_AUTOMERGE("$2You do not own any adjacent plots in the specified direction or are not allowed to merge to the required size.", "Merge"),
UNLINK_REQUIRED("$2An unlink is required to do this.", "Merge"),
UNLINK_IMPOSSIBLE("$2You can only unlink a mega-plot", "Merge"),
UNLINK_SUCCESS("$2Successfully unlinked plots.", "Merge"),
diff --git a/src/main/java/com/intellectualcrafters/plot/object/Plot.java b/src/main/java/com/intellectualcrafters/plot/object/Plot.java
index 05433ca8e..003c131f3 100644
--- a/src/main/java/com/intellectualcrafters/plot/object/Plot.java
+++ b/src/main/java/com/intellectualcrafters/plot/object/Plot.java
@@ -429,25 +429,21 @@ public class Plot {
*/
public Plot getBasePlot(boolean recalculate) {
if ((origin != null && !recalculate)) {
- return origin;
+ if (this.equals(origin)) {
+ return this;
+ }
+ return origin.getBasePlot(false);
}
if (!isMerged()) {
origin = this;
return origin;
}
- int min = Integer.MAX_VALUE;
+ origin = this;
+ PlotId min = id;
for (Plot plot : MainUtil.getConnectedPlots(this)) {
- if (plot.temp != -1) {
- if (plot.temp < min) {
- min = plot.temp;
- origin = plot;
- }
- }
- else {
- if (plot.hashCode() < min) {
- origin = plot;
- min = plot.hashCode();
- }
+ if (plot.id.y < min.y || (plot.id.y == min.y && plot.id.x < min.x)) {
+ origin = plot;
+ min = plot.id;
}
}
for (Plot plot : MainUtil.getConnectedPlots(this)) {
@@ -772,15 +768,17 @@ public class Plot {
* @param alias
*/
public void setAlias(String alias) {
- final String name = getSettings().getAlias();
- if (alias == null) {
- alias = "";
+ for (Plot current : getConnectedPlots()) {
+ final String name = getSettings().getAlias();
+ if (alias == null) {
+ alias = "";
+ }
+ if (name.equals(alias)) {
+ return;
+ }
+ current.getSettings().setAlias(alias);
+ DBFunc.setAlias(current, alias);
}
- if (name.equals(alias)) {
- return;
- }
- getSettings().setAlias(alias);
- DBFunc.setAlias(this, alias);
}
/**
@@ -1120,6 +1118,9 @@ public class Plot {
}
public String getAlias() {
+ if (settings == null) {
+ return "";
+ }
return getSettings().getAlias();
}
@@ -1134,7 +1135,10 @@ public class Plot {
DBFunc.setMerged(this, merged);
MainUtil.connected_cache = null;
MainUtil.regions_cache = null;
- origin = null;
+ if (origin != null) {
+ origin.origin = null;
+ origin = null;
+ }
}
/**
@@ -1145,10 +1149,25 @@ public class Plot {
*/
public void setMerged(int direction, boolean value) {
if (getSettings().setMerged(direction, value)) {
+ if (value) {
+ Plot other = MainUtil.getPlotRelative(this, direction).getBasePlot(false);
+ if (!other.equals(getBasePlot(false))) {
+ Plot base = ((other.id.y < id.y) || ((other.id.y == id.y) && (other.id.x < id.x))) ? other : origin;
+ origin.origin = base;
+ other.origin = base;
+ origin = base;
+ MainUtil.connected_cache = null;
+ }
+ }
+ else {
+ if (origin != null) {
+ origin.origin = null;
+ origin = null;
+ }
+ MainUtil.connected_cache = null;
+ }
DBFunc.setMerged(this, getSettings().getMerged());
- MainUtil.connected_cache = null;
MainUtil.regions_cache = null;
- origin = null;
}
}
diff --git a/src/main/java/com/intellectualcrafters/plot/object/PlotSettings.java b/src/main/java/com/intellectualcrafters/plot/object/PlotSettings.java
index 533329c89..b0270a8cd 100644
--- a/src/main/java/com/intellectualcrafters/plot/object/PlotSettings.java
+++ b/src/main/java/com/intellectualcrafters/plot/object/PlotSettings.java
@@ -111,7 +111,10 @@ public class PlotSettings {
return position;
}
- public void setPosition(final BlockLoc position) {
+ public void setPosition(BlockLoc position) {
+ if (position != null && position.x == 0 && position.y == 0 && position.z == 0) {
+ position = null;
+ }
this.position = position;
}
diff --git a/src/main/java/com/intellectualcrafters/plot/util/MainUtil.java b/src/main/java/com/intellectualcrafters/plot/util/MainUtil.java
index 343f0f3d0..7f180d18d 100644
--- a/src/main/java/com/intellectualcrafters/plot/util/MainUtil.java
+++ b/src/main/java/com/intellectualcrafters/plot/util/MainUtil.java
@@ -424,7 +424,7 @@ public class MainUtil {
}
for (final Plot p : PS.get().getPlotsInWorld(worldname)) {
final String name = p.getAlias();
- if ((name.length() != 0) && name.equalsIgnoreCase(arg)) {
+ if ((name.length() != 0) && StringMan.isEqualIgnoreCase(name, arg)) {
return p;
}
}
@@ -631,22 +631,24 @@ public class MainUtil {
final PlotManager manager = PS.get().getPlotManager(plot.world);
final int x;
final int z;
- Location bot = plot.getBottomAbs();
if ((plotworld.DEFAULT_HOME.x == Integer.MAX_VALUE) && (plotworld.DEFAULT_HOME.z == Integer.MAX_VALUE)) {
- Location top = plot.getTopAbs();
- x = ((top.getX() - bot.getX()) / 2) + bot.getX();
- z = ((top.getZ() - bot.getZ()) / 2) + bot.getZ();
+ // center
+ RegionWrapper largest = getLargestRegion(plot);
+ x = ((largest.maxX - largest.minX) / 2) + largest.minX;
+ z = ((largest.maxZ - largest.minZ) / 2) + largest.minZ;
} else {
+ // specific
+ Location bot = plot.getBottomAbs();
x = bot.getX() + plotworld.DEFAULT_HOME.x;
z = bot.getZ() + plotworld.DEFAULT_HOME.z;
}
final int y = Math.max(getHeighestBlock(plot.world, x, z), manager.getSignLoc(PS.get().getPlotWorld(plot.world), plot).getY());
return new Location(plot.world, x, y + 1, z);
}
- Location bot = plot.getBottomAbs();
- Location top = plot.getTopAbs();
- final int x = ((top.getX() - bot.getX()) / 2) + bot.getX();
- final int z = bot.getZ() - 1;
+ // Side
+ RegionWrapper largest = getLargestRegion(plot);
+ final int x = ((largest.maxX - largest.minX) / 2) + largest.minX;
+ final int z = largest.minZ - 1;
final PlotManager manager = PS.get().getPlotManager(plot.world);
final int y = Math.max(getHeighestBlock(plot.world, x, z), manager.getSignLoc(PS.get().getPlotWorld(plot.world), plot).getY());
return new Location(plot.world, x, y + 1, z);
@@ -770,6 +772,18 @@ public class MainUtil {
return id;
}
+ /**
+ * direction 0 = north, 1 = south, etc:
+ *
+ * @param id
+ * @param direction
+ *
+ * @return Plot relative
+ */
+ public static Plot getPlotRelative(final Plot plot, final int direction) {
+ return getPlotAbs(plot.world, getPlotIdRelative(plot.id, direction));
+ }
+
/**
* Get a list of plot ids within a selection
* @param pos1
@@ -1019,13 +1033,18 @@ public class MainUtil {
a.setFlags(net);
b.setFlags(net);
}
+ if (a.getAlias().length() > 0) {
+ b.setAlias(a.getAlias());
+ }
+ else if (b.getAlias().length() > 0) {
+ a.setAlias(b.getAlias());
+ }
for (UUID uuid : a.getTrusted()) {
b.addTrusted(uuid);
}
for (UUID uuid : b.getTrusted()) {
a.addTrusted(uuid);
}
-
for (UUID uuid : a.getMembers()) {
b.addMember(uuid);
}
@@ -1174,62 +1193,58 @@ public class MainUtil {
}
HashSet visited = new HashSet<>();
HashSet merged = new HashSet<>();
+ for (Plot current : getConnectedPlots(plot)) {
+ merged.add(current.id);
+ }
ArrayDeque frontier = new ArrayDeque<>(getConnectedPlots(plot));
Plot current;
boolean toReturn = false;
- while ((current = frontier.poll()) != null && max > 0) {
+ Set plots;
+ while ((current = frontier.poll()) != null && max >= 0) {
if (visited.contains(current)) {
continue;
}
visited.add(current);
- if (max > 0 && (dir == -1 || dir == 0) && !current.getMerged(0)) {
- Plot other = getPlotAbs(current.world, getPlotIdRelative(current.id, 0));
- if (other.isOwner(uuid)) {
- frontier.addAll(other.getConnectedPlots());
+ if (max >= 0 && (dir == -1 || dir == 0) && !current.getMerged(0)) {
+ Plot other = getPlotRelative(current, 0);
+ if (other.isOwner(uuid) && (other.getBasePlot(false).equals(current.getBasePlot(false)) || ((plots = other.getConnectedPlots()).size() <= max && frontier.addAll(plots) && (max -= plots.size()) != -1))) {
mergePlot(current.world, current, other, removeRoads);
merged.add(current.id);
merged.add(other.id);
toReturn = true;
- max--;
}
}
- if (max > 0 && (dir == -1 || dir == 1) && !current.getMerged(1)) {
- Plot other = getPlotAbs(current.world, getPlotIdRelative(current.id, 1));
- if (other.isOwner(uuid)) {
- frontier.addAll(other.getConnectedPlots());
+ if (max >= 0 && (dir == -1 || dir == 1) && !current.getMerged(1)) {
+ Plot other = getPlotRelative(current, 1);
+ if (other.isOwner(uuid) && (other.getBasePlot(false).equals(current.getBasePlot(false)) || ((plots = other.getConnectedPlots()).size() <= max && frontier.addAll(plots) && (max -= plots.size()) != -1))) {
mergePlot(current.world, current, other, removeRoads);
merged.add(current.id);
merged.add(other.id);
toReturn = true;
- max--;
}
}
- if (max > 0 && (dir == -1 || dir == 2) && !current.getMerged(2)) {
- Plot other = getPlotAbs(current.world, getPlotIdRelative(current.id, 2));
- if (other.isOwner(uuid)) {
- frontier.addAll(other.getConnectedPlots());
+ if (max >= 0 && (dir == -1 || dir == 2) && !current.getMerged(2)) {
+ Plot other = getPlotRelative(current, 2);
+ if (other.isOwner(uuid) && (other.getBasePlot(false).equals(current.getBasePlot(false)) || ((plots = other.getConnectedPlots()).size() <= max && frontier.addAll(plots) && (max -= plots.size()) != -1))) {
mergePlot(current.world, current, other, removeRoads);
merged.add(current.id);
merged.add(other.id);
toReturn = true;
- max--;
}
}
- if (max > 0 && (dir == -1 || dir == 3) && !current.getMerged(3)) {
- Plot other = getPlotAbs(current.world, getPlotIdRelative(current.id, 3));
- if (other.isOwner(uuid)) {
- frontier.addAll(other.getConnectedPlots());
+ if (max >= 0 && (dir == -1 || dir == 3) && !current.getMerged(3)) {
+ Plot other = getPlotRelative(current, 3);
+ if (other.isOwner(uuid) && (other.getBasePlot(false).equals(current.getBasePlot(false)) || ((plots = other.getConnectedPlots()).size() <= max && frontier.addAll(plots) && (max -= plots.size()) != -1))) {
mergePlot(current.world, current, other, removeRoads);
merged.add(current.id);
merged.add(other.id);
toReturn = true;
- max--;
}
}
}
- PlotManager manager = PS.get().getPlotManager(plot.world);
- ArrayList ids = new ArrayList<>(merged);
- if (removeRoads) {
+ if (removeRoads && toReturn) {
+ PlotManager manager = PS.get().getPlotManager(plot.world);
+ ArrayList ids = new ArrayList<>(merged);
manager.finishPlotMerge(plot.getWorld(), ids);
}
return toReturn;
@@ -1548,7 +1563,7 @@ public class MainUtil {
* @return Home Location
*/
public static Location getPlotHome(final String w, final PlotId plotid) {
- final Plot plot = getPlotAbs(w, plotid).getBasePlot(false);
+ final Plot plot = getPlot(w, plotid);
final BlockLoc home = plot.getPosition();
PS.get().getPlotManager(w);
if ((home == null) || ((home.x == 0) && (home.z == 0))) {
@@ -2153,7 +2168,7 @@ public class MainUtil {
}
Plot current;
while ((current = frontier.poll()) != null) {
- if (current.settings == null) {
+ if (current.owner == null || current.settings == null) {
// Invalid plot
// merged onto unclaimed plot
PS.debug("Ignoring invalid merged plot: " + current + " | " + current.owner);
diff --git a/target/PlotSquared-Bukkit.jar b/target/PlotSquared-Bukkit.jar
index c32e9c3ce..d268e4acc 100644
Binary files a/target/PlotSquared-Bukkit.jar and b/target/PlotSquared-Bukkit.jar differ