From d37f5b9aa8547bbacbce1890d4eb0f00cfe2c690 Mon Sep 17 00:00:00 2001 From: Sauilitired Date: Mon, 21 Jan 2019 09:53:04 +0100 Subject: [PATCH 001/210] Fix schematic pasting offsets --- .../plotsquared/plot/config/Settings.java | 5 +++++ .../plotsquared/plot/generator/HybridGen.java | 8 +++++++- .../plotsquared/plot/generator/HybridPlotWorld.java | 4 ++-- .../intellectualsites/plotsquared/plot/object/Plot.java | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/config/Settings.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/config/Settings.java index f901744f8..0d5b74671 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/config/Settings.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/config/Settings.java @@ -225,6 +225,11 @@ public class Settings extends Config { @Comment("Display scientific numbers (4.2E8)") public static boolean SCIENTIFIC = false; } + @Comment("Schematic Settings") public static final class Schematics { + @Comment("Whether schematic based generation should paste schematic on top of plots, or from Y=1") + public static boolean PASTE_ON_TOP = true; + } + @Comment("Configure the paths that will be used") public static final class Paths { public static String SCHEMATICS = "schematics"; diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java index 886dd1125..f7e954a06 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java @@ -1,6 +1,7 @@ package com.github.intellectualsites.plotsquared.plot.generator; import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.Settings; import com.github.intellectualsites.plotsquared.plot.object.*; import com.github.intellectualsites.plotsquared.plot.util.MathMan; import com.github.intellectualsites.plotsquared.plot.util.block.ScopedLocalBlockQueue; @@ -16,7 +17,12 @@ public class HybridGen extends IndependentPlotGenerator { private void placeSchem(HybridPlotWorld world, ScopedLocalBlockQueue result, short relativeX, short relativeZ, int x, int z) { - int minY = Math.min(world.PLOT_HEIGHT, world.ROAD_HEIGHT); + int minY; // Math.min(world.PLOT_HEIGHT, world.ROAD_HEIGHT); + if (Settings.Schematics.PASTE_ON_TOP) { + minY = Math.min(world.PLOT_HEIGHT, world.ROAD_HEIGHT); + } else { + minY = 1; + } BaseBlock[] blocks = world.G_SCH.get(MathMan.pair(relativeX, relativeZ)); if (blocks != null) { for (int y = 0; y < blocks.length; y++) { diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotWorld.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotWorld.java index 4bed2c97a..0a722b4d6 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotWorld.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotWorld.java @@ -156,13 +156,13 @@ public class HybridPlotWorld extends ClassicPlotWorld { if (w3 > PLOT_WIDTH || h3 > PLOT_WIDTH) { this.ROAD_SCHEMATIC_ENABLED = true; } - int centerShiftZ = 0; + int centerShiftZ; if (l3 < this.PLOT_WIDTH) { centerShiftZ = (this.PLOT_WIDTH - l3) / 2; } else { centerShiftZ = (PLOT_WIDTH - l3) / 2; } - int centerShiftX = 0; + int centerShiftX; if (w3 < this.PLOT_WIDTH) { centerShiftX = (this.PLOT_WIDTH - w3) / 2; } else { diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Plot.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Plot.java index c57299bd8..83af645cf 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Plot.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Plot.java @@ -1443,7 +1443,7 @@ public class Plot { e.printStackTrace(); return true; } - SchematicHandler.manager.paste(sch, this, 0, 1, 0, false, new RunnableVal() { + SchematicHandler.manager.paste(sch, this, 0, 1, 0, Settings.Schematics.PASTE_ON_TOP, new RunnableVal() { @Override public void run(Boolean value) { if (value) { MainUtil.sendMessage(player, C.SCHEMATIC_PASTE_SUCCESS); From 7edfc313d672c98a3b7e0609d8c632826f9b62f3 Mon Sep 17 00:00:00 2001 From: Sauilitired Date: Mon, 21 Jan 2019 12:24:34 +0100 Subject: [PATCH 002/210] I did an oopsie --- .../plotsquared/bukkit/util/BukkitHybridUtils.java | 8 +++++++- .../plotsquared/plot/commands/Delete.java | 1 - .../plotsquared/plot/generator/HybridPlotManager.java | 7 ++++++- .../plotsquared/plot/generator/HybridUtils.java | 8 +++++++- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitHybridUtils.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitHybridUtils.java index b7eebcc04..68b845e58 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitHybridUtils.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitHybridUtils.java @@ -2,6 +2,7 @@ package com.github.intellectualsites.plotsquared.bukkit.util; import com.github.intellectualsites.plotsquared.bukkit.generator.BukkitPlotGenerator; import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.Settings; import com.github.intellectualsites.plotsquared.plot.generator.HybridPlotWorld; import com.github.intellectualsites.plotsquared.plot.generator.HybridUtils; import com.github.intellectualsites.plotsquared.plot.object.*; @@ -107,7 +108,12 @@ public class BukkitHybridUtils extends HybridUtils { } rz[i] = v; } - int minY = Math.min(hpw.PLOT_HEIGHT, hpw.ROAD_HEIGHT); + int minY; + if ( Settings.Schematics.PASTE_ON_TOP) { + minY = Math.min(hpw.PLOT_HEIGHT, hpw.ROAD_HEIGHT); + } else { + minY = 1; + } for (short x = 0; x < 16; x++) { for (short z = 0; z < 16; z++) { BaseBlock[] blocks = hpw.G_SCH.get(MathMan.pair(rx[x], rz[z])); diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Delete.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Delete.java index ede1f14cd..b399f5752 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Delete.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Delete.java @@ -16,7 +16,6 @@ import com.github.intellectualsites.plotsquared.plot.util.*; // The syntax also works with any command: /plot @Override public boolean onCommand(final PlotPlayer player, String[] args) { - Location loc = player.getLocation(); final Plot plot = loc.getPlotAbs(); if (plot == null) { diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotManager.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotManager.java index 1f6429dbd..071af627c 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotManager.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotManager.java @@ -79,7 +79,12 @@ public class HybridPlotManager extends ClassicPlotManager { private void createSchemAbs(HybridPlotWorld hpw, LocalBlockQueue queue, Location pos1, Location pos2, boolean clear) { int size = hpw.SIZE; - int minY = Math.min(hpw.PLOT_HEIGHT, hpw.ROAD_HEIGHT); + int minY; + if (Settings.Schematics.PASTE_ON_TOP) { + minY = Math.min(hpw.PLOT_HEIGHT, hpw.ROAD_HEIGHT); + } else { + minY = 1; + } for (int x = pos1.getX(); x <= pos2.getX(); x++) { short absX = (short) ((x - hpw.ROAD_OFFSET_X) % size); if (absX < 0) { diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridUtils.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridUtils.java index 4d46205ad..80b8b0f99 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridUtils.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridUtils.java @@ -2,6 +2,7 @@ package com.github.intellectualsites.plotsquared.plot.generator; import com.github.intellectualsites.plotsquared.plot.PlotSquared; import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; import com.github.intellectualsites.plotsquared.plot.flag.FlagManager; import com.github.intellectualsites.plotsquared.plot.flag.Flags; import com.github.intellectualsites.plotsquared.plot.listener.WEExtent; @@ -347,7 +348,12 @@ public abstract class HybridUtils { } if (condition) { BaseBlock[] blocks = plotWorld.G_SCH.get(MathMan.pair(absX, absZ)); - int minY = Math.min(plotWorld.PLOT_HEIGHT, plotWorld.ROAD_HEIGHT); + int minY; + if (Settings.Schematics.PASTE_ON_TOP) { + minY = Math.min(plotWorld.PLOT_HEIGHT, plotWorld.ROAD_HEIGHT); + } else { + minY = 1; + } int maxY = Math.max(extend, blocks.length); if (blocks != null) { for (int y = 0; y < maxY; y++) { From 7e56e47046d97d1a750e648347d312658f123e57 Mon Sep 17 00:00:00 2001 From: Sauilitired Date: Mon, 21 Jan 2019 17:49:36 +0100 Subject: [PATCH 003/210] Fix block list flag permissions --- .../plotsquared/plot/commands/FlagCmd.java | 37 ++++++++++++++----- .../plot/flag/PlotBlockListFlag.java | 8 ++-- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java index d1e8c9d04..b33f672ca 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java @@ -8,6 +8,7 @@ import com.github.intellectualsites.plotsquared.plot.database.DBFunc; import com.github.intellectualsites.plotsquared.plot.flag.*; import com.github.intellectualsites.plotsquared.plot.object.Location; import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotBlock; import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; import com.github.intellectualsites.plotsquared.plot.util.*; @@ -30,13 +31,37 @@ import java.util.*; int checkRange = PlotSquared.get().getPlatform().equalsIgnoreCase("bukkit") ? numeric : Settings.Limit.MAX_PLOTS; - return player.hasPermissionRange(perm, checkRange) >= numeric; + final boolean result = player.hasPermissionRange(perm, checkRange) >= numeric; + if (!result) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_SET_FLAG_KEY_VALUE + .f(key.toLowerCase(), value.toLowerCase())); + } + return result; } } catch (NumberFormatException ignore) { } + } else if (flag instanceof PlotBlockListFlag) { + final PlotBlockListFlag blockListFlag = (PlotBlockListFlag) flag; + final HashSet parsedBlocks = blockListFlag.parseValue(value); + for (final PlotBlock block : parsedBlocks) { + final String permission = C.PERMISSION_SET_FLAG_KEY_VALUE.f(key.toLowerCase(), + block.getRawId().toString().toLowerCase()); + final boolean result = Permissions.hasPermission(player, permission); + if (!result) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_SET_FLAG_KEY_VALUE + .f(key.toLowerCase(), value.toLowerCase())); + return false; + } + } + return true; } - return Permissions.hasPermission(player, perm); + final boolean result = Permissions.hasPermission(player, perm); + if (!result) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_SET_FLAG_KEY_VALUE + .f(key.toLowerCase(), value.toLowerCase())); + } + return result; } @Override public boolean onCommand(PlotPlayer player, String[] args) { @@ -116,8 +141,6 @@ import java.util.*; } String value = StringMan.join(Arrays.copyOfRange(args, 2, args.length), " "); if (!checkPermValue(player, flag, args[1], value)) { - MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_SET_FLAG_KEY_VALUE - .f(args[1].toLowerCase(), value.toLowerCase())); return false; } Object parsed = flag.parseValue(value); @@ -152,8 +175,6 @@ import java.util.*; } for (String entry : args[2].split(",")) { if (!checkPermValue(player, flag, args[1], entry)) { - MainUtil.sendMessage(player, C.NO_PERMISSION, - C.PERMISSION_SET_FLAG_KEY_VALUE.f(args[1].toLowerCase(), entry)); return false; } } @@ -200,8 +221,6 @@ import java.util.*; } for (String entry : args[2].split(",")) { if (!checkPermValue(player, flag, args[1], entry)) { - MainUtil.sendMessage(player, C.NO_PERMISSION, - C.PERMISSION_SET_FLAG_KEY_VALUE.f(args[1].toLowerCase(), entry)); return false; } } @@ -246,7 +265,7 @@ import java.util.*; for (Flag flag1 : Flags.getFlags()) { String type = flag1.getClass().getSimpleName(); if (!flags.containsKey(type)) { - flags.put(type, new ArrayList()); + flags.put(type, new ArrayList<>()); } flags.get(type).add(flag1.getName()); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/PlotBlockListFlag.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/PlotBlockListFlag.java index 96499d703..56cd0e901 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/PlotBlockListFlag.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/PlotBlockListFlag.java @@ -16,10 +16,10 @@ public class PlotBlockListFlag extends ListFlag> { return StringMan.join((HashSet) value, ","); } - @Override public HashSet parseValue(String value) { - HashSet list = new HashSet<>(); - for (String item : value.split(",")) { - PlotBlock block = PlotSquared.get().IMP.getLegacyMappings().fromAny(item); + @Override public HashSet parseValue(final String value) { + final HashSet list = new HashSet<>(); + for (final String item : value.split(",")) { + final PlotBlock block = PlotSquared.get().IMP.getLegacyMappings().fromAny(item); if (block != null) { list.add(block); } From 8733dc6daba3175a28fcac57c6799caa54b7aa7b Mon Sep 17 00:00:00 2001 From: Sauilitired Date: Tue, 22 Jan 2019 10:43:29 +0100 Subject: [PATCH 004/210] Fix deny-teleport flag: Fixes #2128 --- .../bukkit/listeners/PlayerEvents.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/PlayerEvents.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/PlayerEvents.java index 8e4ea13a0..6b172f49e 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/PlayerEvents.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/PlayerEvents.java @@ -619,8 +619,8 @@ import java.util.regex.Pattern; public void onTeleport(PlayerTeleportEvent event) { if (event.getTo() == null || event.getFrom() == null || !event.getFrom().getWorld() .equals(event.getTo().getWorld())) { - BukkitUtil.getPlayer(event.getPlayer()).deleteMeta(PlotPlayer.META_LOCATION); - BukkitUtil.getPlayer(event.getPlayer()).deleteMeta(PlotPlayer.META_LAST_PLOT); + final Object lastLoc = BukkitUtil.getPlayer(event.getPlayer()).deleteMeta(PlotPlayer.META_LOCATION); + final Object lastPlot = BukkitUtil.getPlayer(event.getPlayer()).deleteMeta(PlotPlayer.META_LAST_PLOT); org.bukkit.Location to = event.getTo(); if (to != null) { Player player = event.getPlayer(); @@ -632,7 +632,19 @@ import java.util.regex.Pattern; } Plot plot = area.getPlot(loc); if (plot != null) { - plotEntry(pp, plot); + final boolean result = Flags.DENY_TELEPORT.allowsTeleport(pp, plot); + if (!result) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_ENTRY_DENIED); + event.setCancelled(true); + if (lastLoc != null) { + pp.setMeta(PlotPlayer.META_LOCATION, lastLoc); + } + if (lastPlot != null) { + pp.setMeta(PlotPlayer.META_LAST_PLOT, lastPlot); + } + } else { + plotEntry(pp, plot); + } } } return; From e54f964eca6fc4904bdf70205a9361502f9ca3e2 Mon Sep 17 00:00:00 2001 From: Sauilitired Date: Tue, 22 Jan 2019 18:51:13 +0100 Subject: [PATCH 005/210] Fix #2009 --- .../plotsquared/plot/commands/FlagCmd.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java index b33f672ca..a3d3e5b85 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java @@ -186,7 +186,17 @@ import java.util.*; if (flag1.isPresent()) { boolean o = flag1.get().removeAll((Collection) flag.parseValue(value)); if (o) { - MainUtil.sendMessage(player, C.FLAG_REMOVED); + if (flag1.get().isEmpty()) { + final boolean result = plot.removeFlag(flag); + if (result) { + MainUtil.sendMessage(player, C.FLAG_REMOVED); + } else { + MainUtil.sendMessage(player, C.FLAG_NOT_REMOVED); + } + return true; + } else { + MainUtil.sendMessage(player, C.FLAG_REMOVED); + } } else { MainUtil.sendMessage(player, C.FLAG_NOT_REMOVED); return false; From 344a2afeffc9357d519ba772e4fce92b63724339 Mon Sep 17 00:00:00 2001 From: Sauilitired Date: Tue, 22 Jan 2019 19:54:31 +0100 Subject: [PATCH 006/210] Use StringBuilder, like a sane person --- .../plotsquared/plot/commands/FlagCmd.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java index a3d3e5b85..c875f44b9 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java @@ -279,16 +279,17 @@ import java.util.*; } flags.get(type).add(flag1.getName()); } - String message = ""; + StringBuilder message = new StringBuilder(); String prefix = ""; for (Map.Entry> entry : flags.entrySet()) { String category = entry.getKey(); List flagNames = entry.getValue(); Collections.sort(flagNames); - message += prefix + "&6" + category + ": &7" + StringMan.join(flagNames, ", "); + message.append(prefix).append("&6").append(category).append(": &7") + .append(StringMan.join(flagNames, ", ")); prefix = "\n"; } - MainUtil.sendMessage(player, message); + MainUtil.sendMessage(player, message.toString()); return true; } MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot flag "); From c96a1afaedbda34fadf787aa810267c6559e2e41 Mon Sep 17 00:00:00 2001 From: Sauilitired Date: Tue, 22 Jan 2019 21:32:24 +0100 Subject: [PATCH 007/210] Don't fuck up road schematics, I guess --- .../plotsquared/plot/generator/HybridGen.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java index f7e954a06..82b76f0c9 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java @@ -16,9 +16,9 @@ public class HybridGen extends IndependentPlotGenerator { } private void placeSchem(HybridPlotWorld world, ScopedLocalBlockQueue result, short relativeX, - short relativeZ, int x, int z) { + short relativeZ, int x, int z, boolean isRoad) { int minY; // Math.min(world.PLOT_HEIGHT, world.ROAD_HEIGHT); - if (Settings.Schematics.PASTE_ON_TOP) { + if (isRoad || Settings.Schematics.PASTE_ON_TOP) { minY = Math.min(world.PLOT_HEIGHT, world.ROAD_HEIGHT); } else { minY = 1; @@ -131,7 +131,7 @@ public class HybridGen extends IndependentPlotGenerator { result.setBlock(x, y, z, hpw.ROAD_BLOCK.getBlock()); } if (hpw.ROAD_SCHEMATIC_ENABLED) { - placeSchem(hpw, result, rx[x], rz[z], x, z); + placeSchem(hpw, result, rx[x], rz[z], x, z, true); } } } else if (wx[x]) { @@ -142,7 +142,7 @@ public class HybridGen extends IndependentPlotGenerator { result.setBlock(x, y, z, hpw.ROAD_BLOCK.getBlock()); } if (hpw.ROAD_SCHEMATIC_ENABLED) { - placeSchem(hpw, result, rx[x], rz[z], x, z); + placeSchem(hpw, result, rx[x], rz[z], x, z, true); } } else { // wall @@ -152,7 +152,7 @@ public class HybridGen extends IndependentPlotGenerator { if (!hpw.ROAD_SCHEMATIC_ENABLED) { result.setBlock(x, hpw.WALL_HEIGHT + 1, z, hpw.WALL_BLOCK.getBlock()); } else { - placeSchem(hpw, result, rx[x], rz[z], x, z); + placeSchem(hpw, result, rx[x], rz[z], x, z, true); } } } @@ -164,7 +164,7 @@ public class HybridGen extends IndependentPlotGenerator { result.setBlock(x, y, z, hpw.ROAD_BLOCK.getBlock()); } if (hpw.ROAD_SCHEMATIC_ENABLED) { - placeSchem(hpw, result, rx[x], rz[z], x, z); + placeSchem(hpw, result, rx[x], rz[z], x, z, true); } } else if (wz[z]) { // wall @@ -174,7 +174,7 @@ public class HybridGen extends IndependentPlotGenerator { if (!hpw.ROAD_SCHEMATIC_ENABLED) { result.setBlock(x, hpw.WALL_HEIGHT + 1, z, hpw.WALL_BLOCK.getBlock()); } else { - placeSchem(hpw, result, rx[x], rz[z], x, z); + placeSchem(hpw, result, rx[x], rz[z], x, z, true); } } else { // plot @@ -183,7 +183,7 @@ public class HybridGen extends IndependentPlotGenerator { } result.setBlock(x, hpw.PLOT_HEIGHT, z, hpw.TOP_BLOCK.getBlock()); if (hpw.PLOT_SCHEMATIC) { - placeSchem(hpw, result, rx[x], rz[z], x, z); + placeSchem(hpw, result, rx[x], rz[z], x, z, false); } } } From 25ed9d279821e074467b0a81822fc7d9eca570b5 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Wed, 23 Jan 2019 12:23:05 +0000 Subject: [PATCH 008/210] Fix road schematic pasting height --- .../plotsquared/plot/generator/HybridPlotManager.java | 7 +------ .../plotsquared/plot/generator/HybridUtils.java | 8 +------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotManager.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotManager.java index 071af627c..1f6429dbd 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotManager.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotManager.java @@ -79,12 +79,7 @@ public class HybridPlotManager extends ClassicPlotManager { private void createSchemAbs(HybridPlotWorld hpw, LocalBlockQueue queue, Location pos1, Location pos2, boolean clear) { int size = hpw.SIZE; - int minY; - if (Settings.Schematics.PASTE_ON_TOP) { - minY = Math.min(hpw.PLOT_HEIGHT, hpw.ROAD_HEIGHT); - } else { - minY = 1; - } + int minY = Math.min(hpw.PLOT_HEIGHT, hpw.ROAD_HEIGHT); for (int x = pos1.getX(); x <= pos2.getX(); x++) { short absX = (short) ((x - hpw.ROAD_OFFSET_X) % size); if (absX < 0) { diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridUtils.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridUtils.java index 80b8b0f99..4d46205ad 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridUtils.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridUtils.java @@ -2,7 +2,6 @@ package com.github.intellectualsites.plotsquared.plot.generator; import com.github.intellectualsites.plotsquared.plot.PlotSquared; import com.github.intellectualsites.plotsquared.plot.config.C; -import com.github.intellectualsites.plotsquared.plot.config.Settings; import com.github.intellectualsites.plotsquared.plot.flag.FlagManager; import com.github.intellectualsites.plotsquared.plot.flag.Flags; import com.github.intellectualsites.plotsquared.plot.listener.WEExtent; @@ -348,12 +347,7 @@ public abstract class HybridUtils { } if (condition) { BaseBlock[] blocks = plotWorld.G_SCH.get(MathMan.pair(absX, absZ)); - int minY; - if (Settings.Schematics.PASTE_ON_TOP) { - minY = Math.min(plotWorld.PLOT_HEIGHT, plotWorld.ROAD_HEIGHT); - } else { - minY = 1; - } + int minY = Math.min(plotWorld.PLOT_HEIGHT, plotWorld.ROAD_HEIGHT); int maxY = Math.max(extend, blocks.length); if (blocks != null) { for (int y = 0; y < maxY; y++) { From fd4a5f2aaac52461b5e8d252a381e49720b64d3b Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Wed, 23 Jan 2019 13:34:23 +0000 Subject: [PATCH 009/210] Fix item despawning on plots --- .../intellectualsites/plotsquared/bukkit/BukkitMain.java | 3 ++- .../plotsquared/bukkit/listeners/EntitySpawnListener.java | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java index ae95bd371..e2eb005c2 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java @@ -431,7 +431,8 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain case FIREBALL: case DRAGON_FIREBALL: case DROPPED_ITEM: - if (Settings.Enabled_Components.KILL_ROAD_ITEMS) { + if (Settings.Enabled_Components.KILL_ROAD_ITEMS + && BukkitUtil.getPlot(entity.getLocation()) == null) { entity.remove(); } // dropped item diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/EntitySpawnListener.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/EntitySpawnListener.java index 9f787297d..443e07025 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/EntitySpawnListener.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/EntitySpawnListener.java @@ -75,6 +75,7 @@ import java.util.List; switch (type) { case DROPPED_ITEM: if (Settings.Enabled_Components.KILL_ROAD_ITEMS) { + event.setCancelled(true); break; } case PLAYER: From a4c3fb26c79f5f3e8fe35e47e8247877beb8a93b Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Wed, 23 Jan 2019 14:02:18 +0000 Subject: [PATCH 010/210] Check for road or unowned plot --- .../intellectualsites/plotsquared/bukkit/BukkitMain.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java index e2eb005c2..a2e6a6cb9 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java @@ -431,8 +431,9 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain case FIREBALL: case DRAGON_FIREBALL: case DROPPED_ITEM: - if (Settings.Enabled_Components.KILL_ROAD_ITEMS - && BukkitUtil.getPlot(entity.getLocation()) == null) { + if (Settings.Enabled_Components.KILL_ROAD_ITEMS || plotArea + .getOwnedPlotAbs( + BukkitUtil.getLocation(entity.getLocation())) == null) { entity.remove(); } // dropped item From cd8a1a0816472e967c39d6feae1a84552a39bed3 Mon Sep 17 00:00:00 2001 From: NotMyFault Date: Sun, 27 Jan 2019 00:48:03 +0100 Subject: [PATCH 011/210] Fixed some translation mismatches --- Core/src/main/resources/de-DE.yml | 112 +++++++++++++++--------------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/Core/src/main/resources/de-DE.yml b/Core/src/main/resources/de-DE.yml index 57a22a38a..8a52ce9a6 100644 --- a/Core/src/main/resources/de-DE.yml +++ b/Core/src/main/resources/de-DE.yml @@ -1,11 +1,11 @@ # Translated by: Krauti2 / EvilOlaf # Adjusted and updated by: NotMyFault -BORDER: $2Du befindest dich außerhalb der aktuellen Weltengrenze +BORDER: $2Du befindest dich außerhalb der aktuellen Weltengrenze. confirm: failed_confirm: $2Es gibt keine zur Bestätigung ausstehenden Befehle! requires_confirm: '$2Bist du sicher, dass du diesen Befehl ausführen willst: $1%s$2?&-$2Die Änderung ist unwiderruflich! Wenn du sicher bist: $1/plot confirm' - expired_confirm: $2Bestätigung abgelaufgen, führe den Befehl nochmal aus! + expired_confirm: $2Bestätigung abgelaufgen, führe den Befehl erneut aus! move: move_success: $4Plot erfolgreich verschoben. copy_success: $4Plot erfolgreich kopiert. @@ -38,7 +38,7 @@ cluster: cluster_teleporting: $4Teleportiere... cluster_info: '$1Aktueller Cluster: $2%id%&-$1Name: $2%name%&-$1Besitzer: $2%owner%&-$1Größe: $2%size%&-$1Rechte: $2%rights%' - cluster_outside: '$2Der Vorgeschlagene Bereich liegt außerhalb der Plot Grenze: %s0' + cluster_outside: '$2Der vorgeschlagene Bereich liegt außerhalb der Plot Grenze: %s0' unclaim: unclaim_success: $4Dieser Plot gehört dir jetzt nicht mehr. unclaim_failed: $2Plot konnte nicht enteignet werden. @@ -52,9 +52,9 @@ worldedit masks: worldedit_unsafe: $2Der Zugriff auf diesen Befehl wurde verwehrt. worldedit_bypass: $2&oUm die Beschränkung außer Kraft zu setzen, verwende $4/plot wea - worldedit_unmasked: $1Dein WorldEdit ist jetzt nicht mehr begrenzt. - worldedit_restricted: $1Dein WorldEdit ist jetzt begrenzt. - worldedit_delayed: $2Bitte warte, während deine WorldEdit Aktion verarbeitet wird... + worldedit_unmasked: $1Dein WorldEdit-Bereich ist jetzt nicht mehr begrenzt. + worldedit_restricted: $1Dein WorldEdit-Bereich ist jetzt begrenzt. + worldedit_delayed: $2Bitte warte während deine WorldEdit Aktion verarbeitet wird... worldedit_run: '$2Sorry für die Wartezeit. Starte jetzt: %s' worldedit_bypassed: $2Beschränkungen werden nun ignoriert. records: @@ -65,7 +65,7 @@ swap: swap_overlap: $2Der geplante Bereich darf nicht überlappen. swap_dimensions: $2Die geplanten Bereiche müssen vergleichbare Dimensionen aufweisen. swap_syntax: $2/plot swap - swap_success: $4Plots erfolgreich getauscht + swap_success: $4Plots erfolgreich getauscht. started_swap: $2Plot swap Aufgabe gestartet. Du erhälst eine Meldung wenn sie beendet ist. comment: @@ -73,21 +73,21 @@ comment: inbox_item: $2 - $4%s comment_syntax: $2Verwende /plot comment [X;Z] <%s> invalid_inbox: '$2Dieses Postfach ist ungültig.&-$1Akzeptierte Werte: %s' - no_perm_inbox: $2Du hast keine Berechtigung für dieses Postfach - no_perm_inbox_modify: $2Du hast keine Berechtigung + no_perm_inbox: $2Du hast keine Berechtigung für dieses Postfach. + no_perm_inbox_modify: $2Du hast keine Berechtigung. no_plot_inbox: $2Du musst an einem Plot stehen oder einen solchen angeben. comment_removed: $4Kommentar/e n$2 - '$3%s$2' erfolgreich gelöscht. comment_added: $4Ein Kommentar wurde hinterlassen. comment_header: $2------ Kommentare ------ - inbox_notification: '%s unread messages. Use /plot inbox' - inbox_empty: $2Keine Kommentare + inbox_notification: '%s ungelesene Nachrichten. Öffne sie mit /plot inbox' + inbox_empty: $2Keine Kommentare. console: not_console: $2Aus Sicherheitsgründen kann dieser Befehl nur von der Konsole ausgeführt werden. is_console: $2Dieser Befehl kann nur von einem Spieler ausgeführt werden. clipboard: clipboard_set: $2Der aktuelle Plot wird in die Zwischenablage kopiert. Benutze $1/plot - paste$2 um es einzufügen. + paste$2 um ihn einzufügen. pasted: $4Die Plotauswahl wurde erfolgreich eingefügt. Die Zwischenablage wurde geleert. paste_failed: '$2Einfügen fehlgeschlagen: $2%s' @@ -100,28 +100,28 @@ ratings: rating_applied: '$4Du hast diesen Plot erfolgreich bewertet: $2%s' rating_not_your_own: $2Du kannst deinen eigenen Plot nicht selbst bewerten. rating_not_owned: $2Plots ohne Besitzer können nicht bewertet werden. - ratings_purged: $2Bewertungen für diesen Plot wurden gelöscht + ratings_purged: $2Bewertungen für diesen Plot wurden gelöscht. rating_not_done: $2Du kannst nur beendete Plots bewerten. economy: econ_disabled: $2Ökonomie ist nicht aktiviert. cannot_afford_plot: $2Du kannst dir diesen Plot nicht leisten. Er kostet $1%s not_for_sale: $2Dieser Plot steht nicht zum Verkauf. cannot_buy_own: $2Du kannst deinen eigenen Plot nicht kaufen. - plot_sold: $4Dein Plot $1%s$4, wurde an $1%s$4 für $1$%s$4 verkauft. + plot_sold: $4Dein Plot $1%s$4 wurde an $1%s$4 für $1$%s$4 verkauft. cannot_afford_merge: $2Du kannst dir das Zusammenfügen der Plots nicht leisten. Es kostet $1%s added_balance: $1%s $2wurden deinem Guthaben hinzugefügt. removed_balance: $1%s $2wurden von deinem Guthaben abgezogen. - removed_granted_plot: $2You used %s plot grant(s), you've got $1%s $2left + removed_granted_plot: $2Du hast %s plot grant(s) benutzt, du hast $1%s $2übrig. setup: setup_init: '$1Verwendung: $2/plot setup ' setup_step: '$3[$1Schritt %s$3] $1%s $2- $1Erwarte: $2%s $1Standard: $2%s' setup_invalid_arg: '$2%s ist kein gültiger Wert für Schritt %s. Um Setup abzubrechen verwende: $1/plot setup cancel' setup_valid_arg: $2Wert $1%s $2gesetzt auf %s - setup_finished: $3Falls du MULTIVERSE oder MULTIWORLD verwendest sollte die Welt + setup_finished: $3Falls du MULTIVERSE oder MULTIWORLD verwendest, sollte die Welt generiert worden sein. Andernfalls musst du die Welt manuell über bukkit.yml hinzufügen. - setup_world_taken: $2%s ist bereits eine bekannte Plotwelt + setup_world_taken: $2%s ist bereits eine bekannte Plotwelt. setup_missing_world: $2Du musst einen Namen für die Welt vergeben ($1/plot setup &l$1 $2)&-$1Zusätzliche Befehle:&-$2 - $1/plot setup &-$2 - $1/plot setup backn$2 - $1/plot setup cancel @@ -134,9 +134,9 @@ schematics: , $1save$2 , $1paste $2, $1exportall' schematic_invalid: '$2Diese Schematic ist ungültig: $2%s' schematic_valid: $2Diese Schematic ist gültig. - schematic_paste_failed: $2Einfügen der Schematic fehlgeschlagen + schematic_paste_failed: $2Einfügen der Schematic fehlgeschlagen. schematic_paste_success: $4Einfügen der Schematic erfolgreich. - schematic_too_large: $2The plot is too large for this action! + schematic_too_large: $2Der Plot ist zu groß für diese Aktion. titles: title_entered_plot: Du betrittst Plot %world%;%x%;%z% title_entered_plot_sub: 'Besitzer: %s' @@ -147,32 +147,32 @@ core: enabled: $1PlotSquared wurde aktiviert task_start: Starte Aufgabe... reload: - reloaded_configs: $1Übersetzungen und Welteneinstellungen wurden neu geladen - reload_failed: $2Erneutes Laden der Konfiguration fehlgeschlagen + reloaded_configs: $1Übersetzungen und Welteneinstellungen wurden neu geladen. + reload_failed: $2Erneutes Laden der Konfiguration fehlgeschlagen. alias: - alias_set_to: $2Plot Alias auf $1%alias% gesetzt - missing_alias: $2Du musst einen Alias angeben - alias_too_long: $2Der Alias darf nicht länger als 50 Zeichen sein - alias_is_taken: $2Dieser Alias wird bereits verwendet - alias_removed: $2Der Alias wurde gelöscht + alias_set_to: $2Plot Alias auf $1%alias% gesetzt. + missing_alias: $2Du musst einen Alias angeben. + alias_too_long: $2Der Alias darf nicht länger als 50 Zeichen sein. + alias_is_taken: $2Dieser Alias wird bereits verwendet. + alias_removed: $2Der Alias wurde gelöscht. position: - missing_position: '$2Du musst eine Position angeben. Mögliche Werte: $1none' - position_set: $1Der Plot Spawn wurde auf deinen aktuellen Standort gesetzt + missing_position: '$2Du musst eine Position angeben. Mögliche Werte sind: $1none' + position_set: $1Der Plot Spawn wurde auf deinen aktuellen Standort gesetzt. home_argument: $2Verwende /plot set home [none] - invalid_position: $2Dies ist eine ungültige Position - position_unset: $1Home Position zurückgesetzt auf standard Wert + invalid_position: $2Dies ist eine ungültige Position. + position_unset: $1Home Position zurückgesetzt auf standard Wert. time: time_format: $1%hours%, %min%, %sec% permission: - no_schematic_permission: '$2Du hast keine Berechtigung Schematics zu verwenden: + no_schematic_permission: '$2Du hast keine Berechtigung um Schematics zu verwenden: $1%s' no_permission: '$2Dir fehlt folgende Berechtigung: $1%s' - no_plot_perms: $2Diese Aktion kann nur der Besitzer des Plots + no_plot_perms: $2Diese Aktion kann nur der Besitzer des Plots ausführen. cant_claim_more_plots: $2Du kannst keine weiteren Plots besitzen. - cant_transfer_more_plots: $2Du kannst keine weiteren Plots diesem Spieler schicken. + cant_transfer_more_plots: $2Du kannst keine weiteren Plots diesem Spieler übergeben. cant_claim_more_plots_num: $2Du kannst nicht mehr als $1%s $2Plots auf einmal einnehmen. you_be_denied: $2Es ist dir nicht gestattet diesen Plot zu betreten. - merge_request_confirm: Zusammenführanfrage von %s + merge_request_confirm: '%s möchte sein Plot mit deinem verbinden.' no_permission_event: '$2Dir fehlt folgende Berechtigung: $1%s' cant_claim_more_clusters: $2Du kannst nicht mehr Cluster besitzen. merge: @@ -180,14 +180,14 @@ merge: unlink_required: $2Die Plots müssen vorher getrennt (unlink) werden. unlink_impossible: $2Die Trennung (unlink) funktioniert nur auf Megaplots. unlink_success: $2Trennung erfolgreich. - merge_not_valid: $2Diese Zusammenführanfrage ist nicht länger gültig. - merge_accepted: $2Die Zusammenführanfrage wurde akzeptiert. + merge_not_valid: $2Diese Anfrage ist nicht länger gültig. + merge_accepted: $2Die Anfrage wurde akzeptiert. success_merge: $2Plots wurden zusammengeführt. - merge_requested: $2Zusammenführanfrage erfolgreich verschickt. + merge_requested: $2Anfrage erfolgreich verschickt. no_available_automerge: $2Dir gehören keine benachbarten Plots oder du darfst die Plot Zusammenführungsgröße nicht überschreiten. commandconfig: not_valid_subcommand: $2Das ist kein gültiger Parameter. - did_you_mean: '$2Meinst du: $1%s' + did_you_mean: '$2Meintest du: $1%s' name_little: $2%s Name ist zu kurz, $1%s$2<$1%s no_commands: $2Du hast für keinen Befehl eine Berechtigung. subcommand_set_options_header: '$2Mögliche Werte: ' @@ -205,7 +205,7 @@ errors: not_valid_world: $2Das ist keine gültige Welt (Groß- / Kleinschreibung beachten) not_valid_plot_world: $2Das ist keine gültige Plotwelt (Groß- / Kleinschreibung beachten) - no_plots: $2Du hast keine Plots + no_plots: $2Du hast keine Plots. wait_for_timer: $2Ein Zeitgeber wurde an den Plot oder an dich gebunden. Bitte warte bis die Zeit abgelaufen ist. invalid_player_wait: '$2Spieler nicht gefunden: $1%s$2. Versuche es später nochmal.' @@ -234,6 +234,7 @@ debug: debug_section: $2>> $1&l%val% debug_line: $2>> $1%var%$2:$1 %val%&- debug_header: $1Debug Information&- + requires_unmerged: Diser Plot kann nicht verbunden werden. invalid: not_valid_data: $2Das ist kein gültiger Datenwert. not_valid_block: $2Das ist kein gültiger Block. @@ -244,8 +245,8 @@ invalid: no_such_plot: $2Ein solcher Plot existiert nicht. player_has_not_been_on: $2Dieser Spieler war nicht in der Plotwelt. found_no_plots: $2Dein Suchmuster ergab keine Treffer. - not_allowed_block: '$2That block is not allowed: %s' - found_no_plots_for_player: '$2No plots found for player: %s' + not_allowed_block: '$2Dieser Block ist nicht erlaubt: %s' + found_no_plots_for_player: '$2Keine Grundstücke für %s gefunden.' camera: camera_started: $2Du verwendest den Kameramodus für Plot $1%s camera_stopped: $2Der Kameramodus wurde abeschaltet. @@ -292,13 +293,13 @@ working: deleting_done: $4Löschung in %sms abgeschlossen. list: plot_list_header_paged: $2(Seite $1%von$2/$1%max$2) $1Liste Plots nach %word% - plot_list_header: $1Liste aller %word% Plots + plot_list_header: $1Liste aller %word% Plots. plot_list_item: $2>> $1%id$2:$1%Welt $2- $1%owner plot_list_item_ordered: $2[$1%in$2] >> $1%id$2:$1%Welt $2- $1%owner plot_list_footer: $2>> $1%word% umfasst insgesamt $2%num% $1Plots %plot%. - comment_list_header_paged: $2(Page $1%cur$2/$1%max$2) $1List of %amount% comments + comment_list_header_paged: $2(Seite $1%cur$2/$1%max$2) $1Liste %amount% Kommentare auf. clickable: ' (interactive)' - area_list_header_paged: $2(Page $1%cur$2/$1%max$2) $1List of %amount% areas + area_list_header_paged: $2(Seite $1%cur$2/$1%max$2) $1Liste %amount% of Plot-Areas auf. left: left_plot: $2Du hast einen Plot verlassen. chat: @@ -345,6 +346,7 @@ member: owner: set_owner: $4Plotbesitzer erfolgreich gesetzt. now_owner: $4Du bist jetzt Besitzer des Plots %s + set_owner_cancelled: Die Plotübergabe wurde abgebrochen. signs: owner_sign_line_1: '$1ID: $1%id%' owner_sign_line_2: '$1Besitzer:' @@ -355,7 +357,7 @@ help: help_info_item: $1/plot help %category% $3- $2%category_desc% help_item: $1%usage% [%alias%]&- $3- $2%desc%&- direction: '$1Aktuelle Himmelsrichtung: %dir%' - help_page_header: '$1Category: $2%category%$2,$1 Page: $2%current%$3/$2%max%$2' + help_page_header: '$1Kategorie: $2%category%$2,$1 Seite: $2%current%$3/$2%max%$2' help_footer: $3&m---------&r $1Plot² Hilfe $3&m--------- '-': custom_string: '-' @@ -364,15 +366,15 @@ set: web: generating_link: $1Lade Plot hoch... generating_link_failed: $2Es konnte kein Download Link erstellt werden! - save_failed: $2Konnte Plot nicht speichern - load_null: $2Benutze $4/plot load $2um eine Liste der Schematics zu bekommen - load_failed: $2Fehler beim Laden des Plots - load_list: '$2Um eine Schematic zu laden, benutze $1/plot load #' + save_failed: $2Konnte Plot nicht speichern. + load_null: $2Benutze $4/plot load $2um eine Liste der Schematics zu bekommen. + load_failed: $2Fehler beim Laden des Plots. + load_list: '$2Um eine Schematic zu laden benutze $1/plot load #' save_success: $1Gespeichert! gamemode: - gamemode_was_bypassed: $1Du ignorierst Spielmodus ($2{gamemode}$1) $1im Plot $2{plot} + gamemode_was_bypassed: $1Du ignorierst den Spielmodus ($2{gamemode}$1) $1im Plot $2{plot} height limit: - height_limit: $1Diese Plot Region hat ein Höhenlimit vonf $2{limit} + height_limit: $1Diese Plot Region hat ein Höhenlimit von $2{limit} inventory: inventory_usage: '&cBenutzung: &6{usage}' inventory_desc: '&cBeschreibung: &6{desc}' @@ -385,18 +387,18 @@ blocked command: done: done_already_done: $2Dieses Plot ist bereits als fertig markiert. done_not_done: $2Dieses Plot ist nicht als fertig markiert. - done_insufficient_complexity: $2Dieses Plot ist zu simpel. Füge mehr Struktur und Terrain hinzu befor du den Befehlt erneut benutzt. + done_insufficient_complexity: $2Dieses Plot ist zu simpel. Füge mehr Struktur und Terrain hinzu bevor du den Befehl erneut benutzt. done_success: $1Plot als fertig markiert. - done_removed: $1Vielleicht möchtest du hier weiterbauen. + done_removed: $1Du kannst nun weiterbauen. tutorial: - rate_this: $2Bewerte dieses Plot! + rate_this: $2Bewerte dieses Plot. comment_this: '$2Hinterlasse deine Meinung über das Plot: %s' desc: desc_set: $2Plot Beschreibung gesetzt. desc_unset: $2Plot Beschreibung gelöscht. missing_desc: $2Du musst eine Beschreibung angeben. cap: - entity_cap: $2Du darfst hier keine Mobs spawnen + entity_cap: $2Du darfst hier keine Mobs spawnen. paste: debug_report_created: '$1Debug-Log hochgeladen: $1%url%' unsafe: From 8ac9b862f8610b02947bf25435024b2a58c30725 Mon Sep 17 00:00:00 2001 From: matt <4009945+MattBDev@users.noreply.github.com> Date: Thu, 31 Jan 2019 14:20:48 -0500 Subject: [PATCH 012/210] Major cleanup. Added todo comments to many 1.13 issues still lingering. Changed access to some methods to be weaker. Removed cluster flags (most of it). Java 8 stuff added. Hid more PlotSetting methods. etc. Signed-off-by: matt <4009945+MattBDev@users.noreply.github.com> --- .../plotsquared/bukkit/BukkitMain.java | 12 +- .../plotsquared/bukkit/chat/FancyMessage.java | 28 - .../bukkit/events/ClusterFlagRemoveEvent.java | 63 - .../bukkit/listeners/ChunkListener.java | 129 +- .../bukkit/listeners/ForceFieldListener.java | 153 +- .../bukkit/listeners/PlayerEvents.java | 5253 +++++++------- .../bukkit/listeners/PlotPlusListener.java | 73 +- .../bukkit/listeners/SingleWorldListener.java | 13 +- .../entity/ReplicatingEntityWrapper.java | 1320 ++-- .../bukkit/object/schematic/StateWrapper.java | 3 +- .../bukkit/titles/TitleManager.java | 6 +- .../bukkit/titles/TitleManager_1_11.java | 2 +- .../bukkit/util/BukkitEventUtil.java | 4 - .../bukkit/util/BukkitInventoryUtil.java | 4 +- .../plotsquared/bukkit/util/SendChunk.java | 157 +- .../bukkit/util/block/BukkitLocalQueue.java | 3 +- .../bukkit/uuid/DefaultUUIDWrapper.java | 10 +- .../bukkit/uuid/FileUUIDHandler.java | 356 +- .../bukkit/uuid/OfflineUUIDWrapper.java | 25 +- .../bukkit/uuid/SQLUUIDHandler.java | 244 +- .../configuration/Configuration.java | 3 +- .../configuration/ConfigurationOptions.java | 4 +- .../configuration/ConfigurationSection.java | 9 +- .../configuration/MemoryConfiguration.java | 3 +- .../configuration/MemorySection.java | 1448 ++-- .../configuration/file/FileConfiguration.java | 3 +- .../configuration/file/YamlConfiguration.java | 2 +- .../file/YamlConfigurationOptions.java | 2 +- .../configuration/file/YamlConstructor.java | 2 +- .../plotsquared/plot/IPlotMain.java | 4 +- .../plotsquared/plot/Platform.java | 2 +- .../plotsquared/plot/PlotSquared.java | 3883 +++++----- .../plotsquared/plot/commands/Area.java | 112 +- .../plotsquared/plot/commands/Claim.java | 22 +- .../plotsquared/plot/commands/Cluster.java | 7 +- .../plotsquared/plot/commands/Condense.java | 13 +- .../plotsquared/plot/commands/Database.java | 319 +- .../plotsquared/plot/commands/Help.java | 4 +- .../plotsquared/plot/commands/Inbox.java | 5 +- .../plotsquared/plot/commands/Merge.java | 4 +- .../plotsquared/plot/commands/Purge.java | 30 +- .../plotsquared/plot/commands/Rate.java | 70 +- .../plotsquared/plot/database/AbstractDB.java | 8 - .../plotsquared/plot/database/DBFunc.java | 67 +- .../plotsquared/plot/database/Database.java | 16 +- .../plotsquared/plot/database/MySQL.java | 2 +- .../plotsquared/plot/database/SQLManager.java | 6326 +++++++++-------- .../plotsquared/plot/database/SQLite.java | 2 +- .../plotsquared/plot/flag/FlagManager.java | 36 +- .../plot/generator/HybridPlotWorld.java | 6 +- .../plotsquared/plot/logger/ILogger.java | 1 + .../plotsquared/plot/object/Expression.java | 3 + .../plotsquared/plot/object/Plot.java | 5606 +++++++-------- .../plotsquared/plot/object/PlotArea.java | 3 + .../plotsquared/plot/object/PlotCluster.java | 15 +- .../plotsquared/plot/object/PlotMessage.java | 1 + .../plotsquared/plot/object/PlotPlayer.java | 1177 ++- .../plotsquared/plot/object/PlotSettings.java | 9 +- .../stream/AbstractDelegateOutputStream.java | 41 +- .../object/worlds/DefaultPlotAreaManager.java | 16 +- .../plot/object/worlds/PlotAreaManager.java | 20 +- .../plot/object/worlds/SinglePlot.java | 2 + .../object/worlds/SinglePlotAreaManager.java | 3 +- .../plot/object/worlds/SinglePlotManager.java | 10 +- .../plotsquared/plot/util/AbstractTitle.java | 2 +- .../plotsquared/plot/util/ChunkManager.java | 78 +- .../plotsquared/plot/util/CmdConfirm.java | 8 +- .../plotsquared/plot/util/CommentManager.java | 48 +- .../plotsquared/plot/util/EventUtil.java | 8 +- .../plotsquared/plot/util/MainUtil.java | 69 +- .../plot/util/SchematicHandler.java | 2 +- .../plot/util/block/GlobalBlockQueue.java | 530 +- .../plot/util/expiry/ExpireManager.java | 839 ++- .../plot/util/expiry/ExpiryTask.java | 1 - .../plot/util/expiry/PlotAnalysis.java | 31 +- .../plotsquared/plot/uuid/UUIDWrapper.java | 14 +- .../plot/database/AbstractDBTest.java | 5 +- .../plotsquared/plot/util/EventUtilTest.java | 6 +- 78 files changed, 14311 insertions(+), 14509 deletions(-) delete mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/events/ClusterFlagRemoveEvent.java diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java index a2e6a6cb9..ab1894a9d 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/BukkitMain.java @@ -134,7 +134,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain private final BlockRegistry blockRegistry = new BukkitBlockRegistry(Material.values()); private int[] version; - @Getter private String pluginName; + private String pluginName; @Getter private SingleWorldListener singleWorldListener; private Method methodUnloadChunk0; private boolean methodUnloadSetup = false; @@ -165,9 +165,9 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain return Bukkit.getVersion(); } + @Override public void onEnable() { this.pluginName = getDescription().getName(); - getServer().getName(); PlotPlayer.registerConverter(Player.class, BukkitUtil::getPlayer); @@ -319,6 +319,11 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain return getDescription().getVersion(); } + @Override + public String getPluginName() { + return pluginName; + } + @Override public void registerCommands() { final BukkitCommand bukkitCommand = new BukkitCommand(); final PluginCommand plotCommand = getCommand("plots"); @@ -586,6 +591,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain @Override @Nullable public final ChunkGenerator getDefaultWorldGenerator(final String world, final String id) { + PlotSquared.log("DEFAULT WORLD GENERATOR RUN"); final IndependentPlotGenerator result; if (id != null && id.equalsIgnoreCase("single")) { result = new SingleWorldGenerator(); @@ -802,7 +808,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain } ChunkGenerator gen = world.getGenerator(); if (gen instanceof BukkitPlotGenerator) { - PlotSquared.get().loadWorld(worldName, (BukkitPlotGenerator) gen); + PlotSquared.get().loadWorld(worldName, (GeneratorWrapper) gen); } else if (gen != null) { PlotSquared.get().loadWorld(worldName, new BukkitPlotGenerator(worldName, gen)); } else if (PlotSquared.get().worlds.contains("worlds." + worldName)) { diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/chat/FancyMessage.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/chat/FancyMessage.java index 41ec91e49..69b168b3d 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/chat/FancyMessage.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/chat/FancyMessage.java @@ -320,34 +320,6 @@ public class FancyMessage return this; } - /** - * Set the behavior of the current editing component to display information about an achievement when the client hovers over the text. - *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

- * - * @param which The achievement to display. - * @return This builder instance. - */ - public FancyMessage achievementTooltip(final Achievement which) { - try { - Object achievement = Reflection - .getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSAchievement", - Achievement.class).invoke(null, which); - return achievementTooltip( - (String) Reflection.getField(Reflection.getNMSClass("Achievement"), "name") - .get(achievement)); - } catch (IllegalAccessException e) { - Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e); - return this; - } catch (IllegalArgumentException e) { - Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e); - return this; - } catch (InvocationTargetException e) { - Bukkit.getLogger() - .log(Level.WARNING, "A error has occurred during invoking of method.", e); - return this; - } - } - /** * Set the behavior of the current editing component to display information about a parameterless statistic when the client hovers over the text. *

Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.

diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/events/ClusterFlagRemoveEvent.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/events/ClusterFlagRemoveEvent.java deleted file mode 100644 index 40acef111..000000000 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/events/ClusterFlagRemoveEvent.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.github.intellectualsites.plotsquared.bukkit.events; - -import com.github.intellectualsites.plotsquared.plot.flag.Flag; -import com.github.intellectualsites.plotsquared.plot.object.PlotCluster; -import org.bukkit.event.Cancellable; -import org.bukkit.event.Event; -import org.bukkit.event.HandlerList; - -/** - * Called when a flag is removed from a plot. - */ -public class ClusterFlagRemoveEvent extends Event implements Cancellable { - - private static final HandlerList handlers = new HandlerList(); - private final PlotCluster cluster; - private final Flag flag; - private boolean cancelled; - - /** - * PlotFlagRemoveEvent: Called when a flag is removed from a plot. - * - * @param flag Flag that was removed - * @param cluster PlotCluster from which the flag was removed - */ - public ClusterFlagRemoveEvent(Flag flag, PlotCluster cluster) { - this.cluster = cluster; - this.flag = flag; - } - - public static HandlerList getHandlerList() { - return handlers; - } - - /** - * Get the cluster involved. - * - * @return PlotCluster - */ - public PlotCluster getCluster() { - return this.cluster; - } - - /** - * Get the flag involved. - * - * @return Flag - */ - public Flag getFlag() { - return this.flag; - } - - @Override public HandlerList getHandlers() { - return handlers; - } - - @Override public boolean isCancelled() { - return this.cancelled; - } - - @Override public void setCancelled(boolean b) { - this.cancelled = b; - } -} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/ChunkListener.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/ChunkListener.java index da1bb49c3..7b56cabfd 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/ChunkListener.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/ChunkListener.java @@ -1,5 +1,7 @@ package com.github.intellectualsites.plotsquared.bukkit.listeners; +import static com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils.getRefClass; + import com.github.intellectualsites.plotsquared.plot.PlotSquared; import com.github.intellectualsites.plotsquared.plot.config.C; import com.github.intellectualsites.plotsquared.plot.config.Settings; @@ -9,6 +11,8 @@ import com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils.RefCla import com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils.RefField; import com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils.RefMethod; import com.github.intellectualsites.plotsquared.plot.util.TaskManager; +import java.lang.reflect.Method; +import java.util.HashSet; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Material; @@ -27,11 +31,6 @@ import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; -import java.lang.reflect.Method; -import java.util.HashSet; - -import static com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils.getRefClass; - @SuppressWarnings("unused") public class ChunkListener implements Listener { @@ -60,48 +59,46 @@ public class ChunkListener implements Listener { for (World world : Bukkit.getWorlds()) { world.setAutoSave(false); } - TaskManager.runTaskRepeat(new Runnable() { - @Override public void run() { - try { - HashSet toUnload = new HashSet<>(); - for (World world : Bukkit.getWorlds()) { - String worldName = world.getName(); - if (!PlotSquared.get().hasPlotArea(worldName)) { + TaskManager.runTaskRepeat(() -> { + try { + HashSet toUnload = new HashSet<>(); + for (World world : Bukkit.getWorlds()) { + String worldName = world.getName(); + if (!PlotSquared.get().hasPlotArea(worldName)) { + continue; + } + Object w = world.getClass().getDeclaredMethod("getHandle").invoke(world); + Object chunkMap = + w.getClass().getDeclaredMethod("getPlayerChunkMap").invoke(w); + Method methodIsChunkInUse = chunkMap.getClass() + .getDeclaredMethod("isChunkInUse", int.class, int.class); + Chunk[] chunks = world.getLoadedChunks(); + for (Chunk chunk : chunks) { + if ((boolean) methodIsChunkInUse + .invoke(chunkMap, chunk.getX(), chunk.getZ())) { continue; } - Object w = world.getClass().getDeclaredMethod("getHandle").invoke(world); - Object chunkMap = - w.getClass().getDeclaredMethod("getPlayerChunkMap").invoke(w); - Method methodIsChunkInUse = chunkMap.getClass() - .getDeclaredMethod("isChunkInUse", int.class, int.class); - Chunk[] chunks = world.getLoadedChunks(); - for (Chunk chunk : chunks) { - if ((boolean) methodIsChunkInUse - .invoke(chunkMap, chunk.getX(), chunk.getZ())) { - continue; - } - int x = chunk.getX(); - int z = chunk.getZ(); - if (!shouldSave(worldName, x, z)) { - unloadChunk(worldName, chunk, false); - continue; - } - toUnload.add(chunk); + int x = chunk.getX(); + int z = chunk.getZ(); + if (!shouldSave(worldName, x, z)) { + unloadChunk(worldName, chunk, false); + continue; } + toUnload.add(chunk); } - if (toUnload.isEmpty()) { + } + if (toUnload.isEmpty()) { + return; + } + long start = System.currentTimeMillis(); + for (Chunk chunk : toUnload) { + if (System.currentTimeMillis() - start > 5) { return; } - long start = System.currentTimeMillis(); - for (Chunk chunk : toUnload) { - if (System.currentTimeMillis() - start > 5) { - return; - } - chunk.unload(true, false); - } - } catch (Throwable e) { - e.printStackTrace(); + chunk.unload(true, false); } + } catch (Throwable e) { + e.printStackTrace(); } }, 1); } @@ -112,7 +109,7 @@ public class ChunkListener implements Listener { } Object c = this.methodGetHandleChunk.of(chunk).call(); RefField.RefExecutor field = this.mustSave.of(c); - if ((Boolean) field.get() == true) { + if ((Boolean) field.get()) { field.set(false); if (chunk.isLoaded()) { ignoreUnload = true; @@ -226,18 +223,28 @@ public class ChunkListener implements Listener { private void cleanChunk(final Chunk chunk) { TaskManager.index.incrementAndGet(); final Integer currentIndex = TaskManager.index.get(); - Integer task = TaskManager.runTaskRepeat(new Runnable() { - @Override public void run() { - if (!chunk.isLoaded()) { - Bukkit.getScheduler().cancelTask(TaskManager.tasks.get(currentIndex)); - TaskManager.tasks.remove(currentIndex); - PlotSquared - .debug(C.PREFIX.s() + "&aSuccessfully processed and unloaded chunk!"); - chunk.unload(true, true); - return; - } - BlockState[] tiles = chunk.getTileEntities(); - if (tiles.length == 0) { + Integer task = TaskManager.runTaskRepeat(() -> { + if (!chunk.isLoaded()) { + Bukkit.getScheduler().cancelTask(TaskManager.tasks.get(currentIndex)); + TaskManager.tasks.remove(currentIndex); + PlotSquared + .debug(C.PREFIX.s() + "&aSuccessfully processed and unloaded chunk!"); + chunk.unload(true, true); + return; + } + BlockState[] tiles = chunk.getTileEntities(); + if (tiles.length == 0) { + Bukkit.getScheduler().cancelTask(TaskManager.tasks.get(currentIndex)); + TaskManager.tasks.remove(currentIndex); + PlotSquared + .debug(C.PREFIX.s() + "&aSuccessfully processed and unloaded chunk!"); + chunk.unload(true, true); + return; + } + long start = System.currentTimeMillis(); + int i = 0; + while (System.currentTimeMillis() - start < 250) { + if (i >= tiles.length) { Bukkit.getScheduler().cancelTask(TaskManager.tasks.get(currentIndex)); TaskManager.tasks.remove(currentIndex); PlotSquared @@ -245,20 +252,8 @@ public class ChunkListener implements Listener { chunk.unload(true, true); return; } - long start = System.currentTimeMillis(); - int i = 0; - while (System.currentTimeMillis() - start < 250) { - if (i >= tiles.length) { - Bukkit.getScheduler().cancelTask(TaskManager.tasks.get(currentIndex)); - TaskManager.tasks.remove(currentIndex); - PlotSquared - .debug(C.PREFIX.s() + "&aSuccessfully processed and unloaded chunk!"); - chunk.unload(true, true); - return; - } - tiles[i].getBlock().setType(Material.AIR, false); - i++; - } + tiles[i].getBlock().setType(Material.AIR, false); + i++; } }, 5); TaskManager.tasks.put(currentIndex, task); diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/ForceFieldListener.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/ForceFieldListener.java index 97d1bb7d7..bf33577a1 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/ForceFieldListener.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/ForceFieldListener.java @@ -16,89 +16,90 @@ import java.util.HashSet; import java.util.Set; import java.util.UUID; -@SuppressWarnings("unused") public class ForceFieldListener { +@SuppressWarnings("unused") +public class ForceFieldListener { - private static Set getNearbyPlayers(Player player, Plot plot) { - Set players = new HashSet<>(); - for (Player nearPlayer : Iterables - .filter(player.getNearbyEntities(5d, 5d, 5d), Player.class)) { - PlotPlayer plotPlayer; - if ((plotPlayer = BukkitUtil.getPlayer(nearPlayer)) == null || !plot - .equals(plotPlayer.getCurrentPlot())) { - continue; - } - if (!plot.isAdded(plotPlayer.getUUID())) { - players.add(plotPlayer); - } - } - return players; + private static Set getNearbyPlayers(Player player, Plot plot) { + Set players = new HashSet<>(); + for (Player nearPlayer : Iterables + .filter(player.getNearbyEntities(5d, 5d, 5d), Player.class)) { + PlotPlayer plotPlayer; + if ((plotPlayer = BukkitUtil.getPlayer(nearPlayer)) == null || !plot + .equals(plotPlayer.getCurrentPlot())) { + continue; + } + if (!plot.isAdded(plotPlayer.getUUID())) { + players.add(plotPlayer); + } } + return players; + } - private static PlotPlayer hasNearbyPermitted(Player player, Plot plot) { - for (Player nearPlayer : Iterables - .filter(player.getNearbyEntities(5d, 5d, 5d), Player.class)) { - PlotPlayer plotPlayer; - if ((plotPlayer = BukkitUtil.getPlayer(nearPlayer)) == null || !plot - .equals(plotPlayer.getCurrentPlot())) { - continue; - } - if (plot.isAdded(plotPlayer.getUUID())) { - return plotPlayer; - } - } - return null; + private static PlotPlayer hasNearbyPermitted(Player player, Plot plot) { + for (Player nearPlayer : Iterables + .filter(player.getNearbyEntities(5d, 5d, 5d), Player.class)) { + PlotPlayer plotPlayer; + if ((plotPlayer = BukkitUtil.getPlayer(nearPlayer)) == null || !plot + .equals(plotPlayer.getCurrentPlot())) { + continue; + } + if (plot.isAdded(plotPlayer.getUUID())) { + return plotPlayer; + } } + return null; + } - private static Vector calculateVelocity(PlotPlayer player, PlotPlayer e) { - Location playerLocation = player.getLocationFull(); - Location oPlayerLocation = e.getLocation(); - double playerX = playerLocation.getX(); - double playerY = playerLocation.getY(); - double playerZ = playerLocation.getZ(); - double oPlayerX = oPlayerLocation.getX(); - double oPlayerY = oPlayerLocation.getY(); - double oPlayerZ = oPlayerLocation.getZ(); - double x = 0d; - if (playerX < oPlayerX) { - x = 1.0d; - } else if (playerX > oPlayerX) { - x = -1.0d; - } - double y = 0d; - if (playerY < oPlayerY) { - y = 0.5d; - } else if (playerY > oPlayerY) { - y = -0.5d; - } - double z = 0d; - if (playerZ < oPlayerZ) { - z = 1.0d; - } else if (playerZ > oPlayerZ) { - z = -1.0d; - } - return new Vector(x, y, z); + private static Vector calculateVelocity(PlotPlayer player, PlotPlayer e) { + Location playerLocation = player.getLocationFull(); + Location oPlayerLocation = e.getLocation(); + double playerX = playerLocation.getX(); + double playerY = playerLocation.getY(); + double playerZ = playerLocation.getZ(); + double oPlayerX = oPlayerLocation.getX(); + double oPlayerY = oPlayerLocation.getY(); + double oPlayerZ = oPlayerLocation.getZ(); + double x = 0d; + if (playerX < oPlayerX) { + x = 1.0d; + } else if (playerX > oPlayerX) { + x = -1.0d; } + double y = 0d; + if (playerY < oPlayerY) { + y = 0.5d; + } else if (playerY > oPlayerY) { + y = -0.5d; + } + double z = 0d; + if (playerZ < oPlayerZ) { + z = 1.0d; + } else if (playerZ > oPlayerZ) { + z = -1.0d; + } + return new Vector(x, y, z); + } - public static void handleForcefield(Player player, PlotPlayer plotPlayer, Plot plot) { - if (Flags.FORCEFIELD.isTrue(plot)) { - UUID uuid = plotPlayer.getUUID(); - if (plot.isAdded(uuid)) { - Set players = getNearbyPlayers(player, plot); - for (PlotPlayer oPlayer : players) { - if (!Permissions.hasPermission(oPlayer, C.PERMISSION_ADMIN_ENTRY_FORCEFIELD)) { - ((BukkitPlayer) oPlayer).player - .setVelocity(calculateVelocity(plotPlayer, oPlayer)); - } - } - } else { - PlotPlayer oPlayer = hasNearbyPermitted(player, plot); - if (oPlayer == null) { - return; - } - if (!Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_ENTRY_FORCEFIELD)) { - player.setVelocity(calculateVelocity(oPlayer, plotPlayer)); - } - } + public static void handleForcefield(Player player, PlotPlayer plotPlayer, Plot plot) { + if (Flags.FORCEFIELD.isTrue(plot)) { + UUID uuid = plotPlayer.getUUID(); + if (plot.isAdded(uuid)) { + Set players = getNearbyPlayers(player, plot); + for (PlotPlayer oPlayer : players) { + if (!Permissions.hasPermission(oPlayer, C.PERMISSION_ADMIN_ENTRY_FORCEFIELD)) { + ((BukkitPlayer) oPlayer).player + .setVelocity(calculateVelocity(plotPlayer, oPlayer)); + } } + } else { + PlotPlayer oPlayer = hasNearbyPermitted(player, plot); + if (oPlayer == null) { + return; + } + if (!Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_ENTRY_FORCEFIELD)) { + player.setVelocity(calculateVelocity(oPlayer, plotPlayer)); + } + } } + } } diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/PlayerEvents.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/PlayerEvents.java index 6b172f49e..ecb6b50ef 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/PlayerEvents.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/PlayerEvents.java @@ -42,6 +42,7 @@ import org.bukkit.help.HelpTopic; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.material.Directional; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; @@ -57,186 +58,188 @@ import java.util.regex.Pattern; /** * Player Events involving plots. */ -@SuppressWarnings("unused") public class PlayerEvents extends PlotListener implements Listener { +@SuppressWarnings("unused") +public class PlayerEvents extends PlotListener implements Listener { - private boolean pistonBlocks = true; - private float lastRadius; - // To prevent recursion - private boolean tmpTeleport = true; - private Field fieldPlayer; - private PlayerMoveEvent moveTmp; + private boolean pistonBlocks = true; + private float lastRadius; + // To prevent recursion + private boolean tmpTeleport = true; + private Field fieldPlayer; + private PlayerMoveEvent moveTmp; - { - try { - fieldPlayer = PlayerEvent.class.getDeclaredField("player"); - fieldPlayer.setAccessible(true); - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } + { + try { + fieldPlayer = PlayerEvent.class.getDeclaredField("player"); + fieldPlayer.setAccessible(true); + } catch (NoSuchFieldException e) { + e.printStackTrace(); } + } - public static void sendBlockChange(final org.bukkit.Location bloc, final BlockData data) { - TaskManager.runTaskLater(() -> { - String world = bloc.getWorld().getName(); - int x = bloc.getBlockX(); - int z = bloc.getBlockZ(); - int distance = Bukkit.getViewDistance() * 16; - for (Entry entry : UUIDHandler.getPlayers().entrySet()) { - PlotPlayer player = entry.getValue(); - Location loc = player.getLocation(); - if (loc.getWorld().equals(world)) { - if (16 * Math.abs(loc.getX() - x) / 16 > distance - || 16 * Math.abs(loc.getZ() - z) / 16 > distance) { - continue; - } - ((BukkitPlayer) player).player.sendBlockChange(bloc, data); - } - } - }, 3); - } - - public static boolean checkEntity(Entity entity, Plot plot) { - if (plot == null || !plot.hasOwner() || plot.getFlags().isEmpty() && plot - .getArea().DEFAULT_FLAGS.isEmpty()) { - return false; + public static void sendBlockChange(final org.bukkit.Location bloc, final BlockData data) { + TaskManager.runTaskLater(() -> { + String world = bloc.getWorld().getName(); + int x = bloc.getBlockX(); + int z = bloc.getBlockZ(); + int distance = Bukkit.getViewDistance() * 16; + for (Entry entry : UUIDHandler.getPlayers().entrySet()) { + PlotPlayer player = entry.getValue(); + Location loc = player.getLocation(); + if (loc.getWorld().equals(world)) { + if (16 * Math.abs(loc.getX() - x) / 16 > distance + || 16 * Math.abs(loc.getZ() - z) / 16 > distance) { + continue; + } + ((BukkitPlayer) player).player.sendBlockChange(bloc, data); } - switch (entity.getType()) { - case PLAYER: - return false; - case ARROW: - case DRAGON_FIREBALL: - case DROPPED_ITEM: - case EGG: - case ENDER_PEARL: - case FIREBALL: - case LINGERING_POTION: - case LLAMA_SPIT: - case SHULKER_BULLET: - case SMALL_FIREBALL: - case SNOWBALL: - case SPECTRAL_ARROW: - case SPLASH_POTION: - case THROWN_EXP_BOTTLE: - case TIPPED_ARROW: - // projectile - case FALLING_BLOCK: - case PRIMED_TNT: - // Block entities - case AREA_EFFECT_CLOUD: - case COMPLEX_PART: - case ENDER_CRYSTAL: - case ENDER_SIGNAL: - case EVOKER_FANGS: - case EXPERIENCE_ORB: - case FIREWORK: - case FISHING_HOOK: - case LEASH_HITCH: - case LIGHTNING: - case UNKNOWN: - case WEATHER: - case WITHER_SKULL: - // non moving / unmovable - return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP); - case ARMOR_STAND: - case ITEM_FRAME: - case PAINTING: - return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP, Flags.MISC_CAP); - // misc - case BOAT: - case MINECART: - case MINECART_CHEST: - case MINECART_COMMAND: - case MINECART_FURNACE: - case MINECART_HOPPER: - case MINECART_MOB_SPAWNER: - case MINECART_TNT: - return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP, Flags.VEHICLE_CAP); - case BAT: - case CHICKEN: - case COD: - case COW: - case DOLPHIN: - case DONKEY: - case HORSE: - case IRON_GOLEM: - case LLAMA: - case MULE: - case MUSHROOM_COW: - case OCELOT: - case PARROT: - case PIG: - case POLAR_BEAR: - case PUFFERFISH: - case RABBIT: - case SALMON: - case SHEEP: - case SKELETON_HORSE: - case SNOWMAN: - case SQUID: - case TROPICAL_FISH: - case TURTLE: - case VILLAGER: - case WOLF: - case ZOMBIE_HORSE: - // animal - return EntityUtil - .checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP, Flags.ANIMAL_CAP); - case BLAZE: - case CAVE_SPIDER: - case CREEPER: - case DROWNED: - case ELDER_GUARDIAN: - case ENDERMAN: - case ENDERMITE: - case ENDER_DRAGON: - case EVOKER: - case GHAST: - case GIANT: - case GUARDIAN: - case HUSK: - case ILLUSIONER: - case MAGMA_CUBE: - case PIG_ZOMBIE: - case SHULKER: - case SILVERFISH: - case SKELETON: - case SLIME: - case SPIDER: - case STRAY: - case VEX: - case VINDICATOR: - case WITCH: - case WITHER: - case WITHER_SKELETON: - case ZOMBIE: - case ZOMBIE_VILLAGER: - // monster - return EntityUtil - .checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP, Flags.HOSTILE_CAP); - default: - if (entity instanceof LivingEntity) { - if (entity instanceof Animals || entity instanceof WaterMob) { - return EntityUtil - .checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP, Flags.ANIMAL_CAP); - } else if (entity instanceof Monster) { - return EntityUtil - .checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP, Flags.HOSTILE_CAP); - } else { - return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP); - } - } - if (entity instanceof Vehicle) { - return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP, Flags.VEHICLE_CAP); - } - if (entity instanceof Hanging) { - return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP, Flags.MISC_CAP); - } - return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP); - } - } + } + }, 3); + } - @EventHandler public void onRedstoneEvent(BlockRedstoneEvent event) { - Block block = event.getBlock(); + public static boolean checkEntity(Entity entity, Plot plot) { + if (plot == null || !plot.hasOwner() || plot.getFlags().isEmpty() && plot + .getArea().DEFAULT_FLAGS.isEmpty()) { + return false; + } + switch (entity.getType()) { + case PLAYER: + return false; + case ARROW: + case DRAGON_FIREBALL: + case DROPPED_ITEM: + case EGG: + case ENDER_PEARL: + case FIREBALL: + case LINGERING_POTION: + case LLAMA_SPIT: + case SHULKER_BULLET: + case SMALL_FIREBALL: + case SNOWBALL: + case SPECTRAL_ARROW: + case SPLASH_POTION: + case THROWN_EXP_BOTTLE: + case TIPPED_ARROW: + // projectile + case FALLING_BLOCK: + case PRIMED_TNT: + // Block entities + case AREA_EFFECT_CLOUD: + case COMPLEX_PART: + case ENDER_CRYSTAL: + case ENDER_SIGNAL: + case EVOKER_FANGS: + case EXPERIENCE_ORB: + case FIREWORK: + case FISHING_HOOK: + case LEASH_HITCH: + case LIGHTNING: + case UNKNOWN: + case WEATHER: + case WITHER_SKULL: + // non moving / unmovable + return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP); + case ARMOR_STAND: + case ITEM_FRAME: + case PAINTING: + return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP, Flags.MISC_CAP); + // misc + case BOAT: + case MINECART: + case MINECART_CHEST: + case MINECART_COMMAND: + case MINECART_FURNACE: + case MINECART_HOPPER: + case MINECART_MOB_SPAWNER: + case MINECART_TNT: + return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP, Flags.VEHICLE_CAP); + case BAT: + case CHICKEN: + case COD: + case COW: + case DOLPHIN: + case DONKEY: + case HORSE: + case IRON_GOLEM: + case LLAMA: + case MULE: + case MUSHROOM_COW: + case OCELOT: + case PARROT: + case PIG: + case POLAR_BEAR: + case PUFFERFISH: + case RABBIT: + case SALMON: + case SHEEP: + case SKELETON_HORSE: + case SNOWMAN: + case SQUID: + case TROPICAL_FISH: + case TURTLE: + case VILLAGER: + case WOLF: + case ZOMBIE_HORSE: + // animal + return EntityUtil + .checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP, Flags.ANIMAL_CAP); + case BLAZE: + case CAVE_SPIDER: + case CREEPER: + case DROWNED: + case ELDER_GUARDIAN: + case ENDERMAN: + case ENDERMITE: + case ENDER_DRAGON: + case EVOKER: + case GHAST: + case GIANT: + case GUARDIAN: + case HUSK: + case ILLUSIONER: + case MAGMA_CUBE: + case PIG_ZOMBIE: + case SHULKER: + case SILVERFISH: + case SKELETON: + case SLIME: + case SPIDER: + case STRAY: + case VEX: + case VINDICATOR: + case WITCH: + case WITHER: + case WITHER_SKELETON: + case ZOMBIE: + case ZOMBIE_VILLAGER: + // monster + return EntityUtil + .checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP, Flags.HOSTILE_CAP); + default: + if (entity instanceof LivingEntity) { + if (entity instanceof Animals || entity instanceof WaterMob) { + return EntityUtil + .checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP, Flags.ANIMAL_CAP); + } else if (entity instanceof Monster) { + return EntityUtil + .checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP, Flags.HOSTILE_CAP); + } else { + return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP); + } + } + if (entity instanceof Vehicle) { + return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP, Flags.VEHICLE_CAP); + } + if (entity instanceof Hanging) { + return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP, Flags.MISC_CAP); + } + return EntityUtil.checkEntity(plot, Flags.ENTITY_CAP); + } + } + + @EventHandler + public void onRedstoneEvent(BlockRedstoneEvent event) { + Block block = event.getBlock(); /* switch (block.getType()) { case OBSERVER: case REDSTONE: @@ -284,2561 +287,2575 @@ import java.util.regex.Pattern; case POWERED_RAIL: return; default:*/ + Location loc = BukkitUtil.getLocation(block.getLocation()); + PlotArea area = loc.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlot(loc); + if (plot == null) { + return; + } + if (Flags.REDSTONE.isFalse(plot)) { + event.setNewCurrent(0); + return; + } + if (Settings.Redstone.DISABLE_OFFLINE) { + boolean disable; + if (plot.isMerged()) { + disable = true; + for (UUID owner : plot.getOwners()) { + if (UUIDHandler.getPlayer(owner) != null) { + disable = false; + break; + } + } + } else { + disable = UUIDHandler.getPlayer(plot.guessOwner()) == null; + } + if (disable) { + for (UUID trusted : plot.getTrusted()) { + if (UUIDHandler.getPlayer(trusted) != null) { + disable = false; + break; + } + } + if (disable) { + event.setNewCurrent(0); + return; + } + } + } + if (Settings.Redstone.DISABLE_UNOCCUPIED) { + for (Entry entry : UUIDHandler.getPlayers().entrySet()) { + if (plot.equals(entry.getValue().getCurrentPlot())) { + return; + } + } + event.setNewCurrent(0); + } + //} + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onPhysicsEvent(BlockPhysicsEvent event) { + switch (event.getChangedType()) { + case COMPARATOR: { + Block block = event.getBlock(); Location loc = BukkitUtil.getLocation(block.getLocation()); PlotArea area = loc.getPlotArea(); if (area == null) { - return; + return; } - Plot plot = area.getOwnedPlot(loc); + Plot plot = area.getOwnedPlotAbs(loc); if (plot == null) { - return; + return; } if (Flags.REDSTONE.isFalse(plot)) { - event.setNewCurrent(0); - return; - } - if (Settings.Redstone.DISABLE_OFFLINE) { - boolean disable; - if (plot.isMerged()) { - disable = true; - for (UUID owner : plot.getOwners()) { - if (UUIDHandler.getPlayer(owner) != null) { - disable = false; - break; - } - } - } else { - disable = UUIDHandler.getPlayer(plot.guessOwner()) == null; - } - if (disable) { - for (UUID trusted : plot.getTrusted()) { - if (UUIDHandler.getPlayer(trusted) != null) { - disable = false; - break; - } - } - if (disable) { - event.setNewCurrent(0); - return; - } - } - } - if (Settings.Redstone.DISABLE_UNOCCUPIED) { - for (Entry entry : UUIDHandler.getPlayers().entrySet()) { - if (plot.equals(entry.getValue().getCurrentPlot())) { - return; - } - } - event.setNewCurrent(0); - } - //} - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) - public void onPhysicsEvent(BlockPhysicsEvent event) { - switch (event.getChangedType()) { - case COMPARATOR: { - Block block = event.getBlock(); - Location loc = BukkitUtil.getLocation(block.getLocation()); - PlotArea area = loc.getPlotArea(); - if (area == null) { - return; - } - Plot plot = area.getOwnedPlotAbs(loc); - if (plot == null) { - return; - } - if (Flags.REDSTONE.isFalse(plot)) { - event.setCancelled(true); - } - return; - } - case ANVIL: - case DRAGON_EGG: - case GRAVEL: - case SAND: - case TURTLE_EGG: - case TURTLE_HELMET: - case TURTLE_SPAWN_EGG: { - Block block = event.getBlock(); - Location loc = BukkitUtil.getLocation(block.getLocation()); - PlotArea area = loc.getPlotArea(); - if (area == null) { - return; - } - Plot plot = area.getOwnedPlotAbs(loc); - if (plot == null) { - return; - } - if (Flags.DISABLE_PHYSICS.isFalse(plot)) { - event.setCancelled(true); - } - return; - } - default: - if (Settings.Redstone.DETECT_INVALID_EDGE_PISTONS) { - Block block = event.getBlock(); - switch (block.getType()) { - case PISTON: - case STICKY_PISTON: - Piston piston = (Piston) block.getBlockData(); - Location loc = BukkitUtil.getLocation(block.getLocation()); - PlotArea area = loc.getPlotArea(); - if (area == null) { - return; - } - Plot plot = area.getOwnedPlotAbs(loc); - if (plot == null) { - return; - } - switch (piston.getFacing()) { - case EAST: - loc.setX(loc.getX() + 1); - break; - case SOUTH: - loc.setX(loc.getX() - 1); - break; - case WEST: - loc.setZ(loc.getZ() + 1); - break; - case NORTH: - loc.setZ(loc.getZ() - 1); - break; - } - Plot newPlot = area.getOwnedPlotAbs(loc); - if (!plot.equals(newPlot)) { - event.setCancelled(true); - return; - } - } - } - break; - } - } - - @EventHandler public void onProjectileLaunch(ProjectileLaunchEvent event) { - Projectile entity = event.getEntity(); - if (!(entity instanceof ThrownPotion)) { - return; - } - ProjectileSource shooter = entity.getShooter(); - if (!(shooter instanceof Player)) { - return; - } - Location l = BukkitUtil.getLocation(entity); - if (!PlotSquared.get().hasPlotArea(l.getWorld())) { - return; - } - PlotPlayer pp = BukkitUtil.getPlayer((Player) shooter); - Plot plot = l.getOwnedPlot(); - if (plot != null && !plot.isAdded(pp.getUUID())) { - entity.remove(); - event.setCancelled(true); - } - } - - @EventHandler public boolean onProjectileHit(ProjectileHitEvent event) { - Projectile entity = event.getEntity(); - Location loc = BukkitUtil.getLocation(entity); - if (!PlotSquared.get().hasPlotArea(loc.getWorld())) { - return true; + event.setCancelled(true); } + return; + } + case ANVIL: + case DRAGON_EGG: + case GRAVEL: + case SAND: + case TURTLE_EGG: + case TURTLE_HELMET: + case TURTLE_SPAWN_EGG: { + Block block = event.getBlock(); + Location loc = BukkitUtil.getLocation(block.getLocation()); PlotArea area = loc.getPlotArea(); if (area == null) { - return true; + return; } - Plot plot = area.getPlot(loc); - ProjectileSource shooter = entity.getShooter(); - if (shooter instanceof Player) { - PlotPlayer pp = BukkitUtil.getPlayer((Player) shooter); - if (plot == null) { - if (!Permissions.hasPermission(pp, C.PERMISSION_PROJECTILE_UNOWNED)) { - entity.remove(); - return false; - } - return true; - } - if (plot.isAdded(pp.getUUID()) || Permissions - .hasPermission(pp, C.PERMISSION_PROJECTILE_OTHER)) { - return true; - } - entity.remove(); - return false; + Plot plot = area.getOwnedPlotAbs(loc); + if (plot == null) { + return; } - if (!(shooter instanceof Entity) && shooter != null) { - if (plot == null) { - entity.remove(); - return false; - } - Location sLoc = - BukkitUtil.getLocation(((BlockProjectileSource) shooter).getBlock().getLocation()); - if (!area.contains(sLoc.getX(), sLoc.getZ())) { - entity.remove(); - return false; - } - Plot sPlot = area.getOwnedPlotAbs(sLoc); - if (sPlot == null || !PlotHandler.sameOwners(plot, sPlot)) { - entity.remove(); - return false; - } + if (Flags.DISABLE_PHYSICS.isFalse(plot)) { + event.setCancelled(true); + } + return; + } + default: + if (Settings.Redstone.DETECT_INVALID_EDGE_PISTONS) { + Block block = event.getBlock(); + switch (block.getType()) { + case PISTON: + case STICKY_PISTON: + Piston piston = (Piston) block.getBlockData(); + Location loc = BukkitUtil.getLocation(block.getLocation()); + PlotArea area = loc.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlotAbs(loc); + if (plot == null) { + return; + } + switch (piston.getFacing()) { + case EAST: + loc.setX(loc.getX() + 1); + break; + case SOUTH: + loc.setX(loc.getX() - 1); + break; + case WEST: + loc.setZ(loc.getZ() + 1); + break; + case NORTH: + loc.setZ(loc.getZ() - 1); + break; + } + Plot newPlot = area.getOwnedPlotAbs(loc); + if (!plot.equals(newPlot)) { + event.setCancelled(true); + return; + } + } + } + break; + } + } + + @EventHandler + public void onProjectileLaunch(ProjectileLaunchEvent event) { + Projectile entity = event.getEntity(); + if (!(entity instanceof ThrownPotion)) { + return; + } + ProjectileSource shooter = entity.getShooter(); + if (!(shooter instanceof Player)) { + return; + } + Location l = BukkitUtil.getLocation(entity); + if (!PlotSquared.get().hasPlotArea(l.getWorld())) { + return; + } + PlotPlayer pp = BukkitUtil.getPlayer((Player) shooter); + Plot plot = l.getOwnedPlot(); + if (plot != null && !plot.isAdded(pp.getUUID())) { + entity.remove(); + event.setCancelled(true); + } + } + + @EventHandler + public boolean onProjectileHit(ProjectileHitEvent event) { + Projectile entity = event.getEntity(); + Location loc = BukkitUtil.getLocation(entity); + if (!PlotSquared.get().hasPlotArea(loc.getWorld())) { + return true; + } + PlotArea area = loc.getPlotArea(); + if (area == null) { + return true; + } + Plot plot = area.getPlot(loc); + ProjectileSource shooter = entity.getShooter(); + if (shooter instanceof Player) { + PlotPlayer pp = BukkitUtil.getPlayer((Player) shooter); + if (plot == null) { + if (!Permissions.hasPermission(pp, C.PERMISSION_PROJECTILE_UNOWNED)) { + entity.remove(); + return false; } return true; + } + if (plot.isAdded(pp.getUUID()) || Permissions + .hasPermission(pp, C.PERMISSION_PROJECTILE_OTHER)) { + return true; + } + entity.remove(); + return false; } + if (!(shooter instanceof Entity) && shooter != null) { + if (plot == null) { + entity.remove(); + return false; + } + Location sLoc = + BukkitUtil.getLocation(((BlockProjectileSource) shooter).getBlock().getLocation()); + if (!area.contains(sLoc.getX(), sLoc.getZ())) { + entity.remove(); + return false; + } + Plot sPlot = area.getOwnedPlotAbs(sLoc); + if (sPlot == null || !PlotHandler.sameOwners(plot, sPlot)) { + entity.remove(); + return false; + } + } + return true; + } - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) - public void playerCommand(PlayerCommandPreprocessEvent event) { - String msg = event.getMessage().toLowerCase().replaceAll("/", "").trim(); - if (msg.isEmpty()) { + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void playerCommand(PlayerCommandPreprocessEvent event) { + String msg = event.getMessage().toLowerCase().replaceAll("/", "").trim(); + if (msg.isEmpty()) { + return; + } + Player player = event.getPlayer(); + PlotPlayer pp = BukkitUtil.getPlayer(player); + Location loc = pp.getLocation(); + PlotArea area = loc.getPlotArea(); + if (area == null) { + return; + } + String[] parts = msg.split(" "); + Plot plot = pp.getCurrentPlot(); + if (BukkitMain.getWorldEdit() != null) { // Check WorldEdit + switch (parts[0].toLowerCase()) { + case "up": + case "/up": + case "worldedit:up": + case "worldedit:/up": + if (plot == null || (!plot.isAdded(pp.getUUID()) && !Permissions + .hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER, true))) { + event.setCancelled(true); return; + } + } + } + if (plot == null) { + return; + } + Optional> flag = plot.getFlag(Flags.BLOCKED_CMDS); + if (flag.isPresent() && !Permissions + .hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_BLOCKED_CMDS)) { + List blocked_cmds = flag.get(); + String c = parts[0]; + if (parts[0].contains(":")) { + c = parts[0].split(":")[1]; + msg = msg.replace(parts[0].split(":")[0] + ':', ""); + } + String l = c; + List aliases = new ArrayList<>(); + for (HelpTopic cmdLabel : Bukkit.getServer().getHelpMap().getHelpTopics()) { + if (c.equals(cmdLabel.getName())) { + break; } + String label = cmdLabel.getName().replaceFirst("/", ""); + if (aliases.contains(label)) { + continue; + } + PluginCommand p; + if ((p = Bukkit.getPluginCommand(label)) != null) { + for (String a : p.getAliases()) { + if (aliases.contains(a)) { + continue; + } + aliases.add(a); + a = a.replaceFirst("/", ""); + if (!a.equals(label) && a.equals(c)) { + c = label; + break; + } + } + } + } + if (!l.equals(c)) { + msg = msg.replace(l, c); + } + for (String s : blocked_cmds) { + Pattern pattern; + if (!RegExUtil.compiledPatterns.containsKey(s)) { + RegExUtil.compiledPatterns.put(s, pattern = Pattern.compile(s)); + } else { + pattern = RegExUtil.compiledPatterns.get(s); + } + if (pattern.matcher(msg).matches()) { + String perm; + if (plot.isAdded(pp.getUUID())) { + perm = "plots.admin.command.blocked-cmds.shared"; + } else { + perm = "plots.admin.command.blocked-cmds.other"; + } + if (!Permissions.hasPermission(pp, perm)) { + MainUtil.sendMessage(pp, C.COMMAND_BLOCKED); + event.setCancelled(true); + } + return; + } + } + } + } + + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + public void onConnect(PlayerJoinEvent event) { + final Player player = event.getPlayer(); + UUIDHandler.getPlayers().remove(player.getName()); + BukkitUtil.removePlayer(player.getName()); + final PlotPlayer pp = BukkitUtil.getPlayer(player); + // Now + String name = pp.getName(); + StringWrapper sw = new StringWrapper(name); + UUID uuid = pp.getUUID(); + UUIDHandler.add(sw, uuid); + + Location loc = pp.getLocation(); + PlotArea area = loc.getPlotArea(); + if (area != null) { + Plot plot = area.getPlot(loc); + if (plot != null) { + plotEntry(pp, plot); + } + } + // Delayed + + // Async + TaskManager.runTaskLaterAsync(() -> { + if (!player.hasPlayedBefore() && player.isOnline()) { + player.saveData(); + } + EventUtil.manager.doJoinTask(pp); + }, 20); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void playerRespawn(PlayerRespawnEvent event) { + Player player = event.getPlayer(); + PlotPlayer pp = BukkitUtil.getPlayer(player); + EventUtil.manager.doRespawnTask(pp); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onTeleport(PlayerTeleportEvent event) { + if (event.getTo() == null || event.getFrom() == null || !event.getFrom().getWorld() + .equals(event.getTo().getWorld())) { + final Object lastLoc = BukkitUtil.getPlayer(event.getPlayer()) + .deleteMeta(PlotPlayer.META_LOCATION); + final Object lastPlot = BukkitUtil.getPlayer(event.getPlayer()) + .deleteMeta(PlotPlayer.META_LAST_PLOT); + org.bukkit.Location to = event.getTo(); + if (to != null) { Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); - Location loc = pp.getLocation(); - PlotArea area = loc.getPlotArea(); - if (area == null) { - return; - } - String[] parts = msg.split(" "); - Plot plot = pp.getCurrentPlot(); - if (BukkitMain.getWorldEdit() != null) { // Check WorldEdit - switch (parts[0].toLowerCase()) { - case "up": - case "/up": - case "worldedit:up": - case "worldedit:/up": - if (plot == null || (!plot.isAdded(pp.getUUID()) && !Permissions - .hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER, true))) { - event.setCancelled(true); - return; - } - } - } - if (plot == null) { - return; - } - Optional> flag = plot.getFlag(Flags.BLOCKED_CMDS); - if (flag.isPresent() && !Permissions - .hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_BLOCKED_CMDS)) { - List blocked_cmds = flag.get(); - String c = parts[0]; - if (parts[0].contains(":")) { - c = parts[0].split(":")[1]; - msg = msg.replace(parts[0].split(":")[0] + ':', ""); - } - String l = c; - List aliases = new ArrayList<>(); - for (HelpTopic cmdLabel : Bukkit.getServer().getHelpMap().getHelpTopics()) { - if (c.equals(cmdLabel.getName())) { - break; - } - String label = cmdLabel.getName().replaceFirst("/", ""); - if (aliases.contains(label)) { - continue; - } - PluginCommand p; - if ((p = Bukkit.getPluginCommand(label)) != null) { - for (String a : p.getAliases()) { - if (aliases.contains(a)) { - continue; - } - aliases.add(a); - a = a.replaceFirst("/", ""); - if (!a.equals(label) && a.equals(c)) { - c = label; - break; - } - } - } - } - if (!l.equals(c)) { - msg = msg.replace(l, c); - } - for (String s : blocked_cmds) { - Pattern pattern; - if (!RegExUtil.compiledPatterns.containsKey(s)) { - RegExUtil.compiledPatterns.put(s, pattern = Pattern.compile(s)); - } else { - pattern = RegExUtil.compiledPatterns.get(s); - } - if (pattern.matcher(msg).matches()) { - String perm; - if (plot.isAdded(pp.getUUID())) { - perm = "plots.admin.command.blocked-cmds.shared"; - } else { - perm = "plots.admin.command.blocked-cmds.other"; - } - if (!Permissions.hasPermission(pp, perm)) { - MainUtil.sendMessage(pp, C.COMMAND_BLOCKED); - event.setCancelled(true); - } - return; - } - } - } - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onConnect(PlayerJoinEvent event) { - final Player player = event.getPlayer(); - UUIDHandler.getPlayers().remove(player.getName()); - BukkitUtil.removePlayer(player.getName()); - final PlotPlayer pp = BukkitUtil.getPlayer(player); - // Now - String name = pp.getName(); - StringWrapper sw = new StringWrapper(name); - UUID uuid = pp.getUUID(); - UUIDHandler.add(sw, uuid); - - Location loc = pp.getLocation(); - PlotArea area = loc.getPlotArea(); - if (area != null) { - Plot plot = area.getPlot(loc); - if (plot != null) { - plotEntry(pp, plot); - } - } - // Delayed - - // Async - TaskManager.runTaskLaterAsync(() -> { - if (!player.hasPlayedBefore() && player.isOnline()) { - player.saveData(); - } - EventUtil.manager.doJoinTask(pp); - }, 20); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void playerRespawn(PlayerRespawnEvent event) { - Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); - EventUtil.manager.doRespawnTask(pp); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onTeleport(PlayerTeleportEvent event) { - if (event.getTo() == null || event.getFrom() == null || !event.getFrom().getWorld() - .equals(event.getTo().getWorld())) { - final Object lastLoc = BukkitUtil.getPlayer(event.getPlayer()).deleteMeta(PlotPlayer.META_LOCATION); - final Object lastPlot = BukkitUtil.getPlayer(event.getPlayer()).deleteMeta(PlotPlayer.META_LAST_PLOT); - org.bukkit.Location to = event.getTo(); - if (to != null) { - Player player = event.getPlayer(); - PlotPlayer pp = PlotPlayer.wrap(player); - Location loc = BukkitUtil.getLocation(to); - PlotArea area = PlotSquared.get().getPlotAreaAbs(loc); - if (area == null) { - return; - } - Plot plot = area.getPlot(loc); - if (plot != null) { - final boolean result = Flags.DENY_TELEPORT.allowsTeleport(pp, plot); - if (!result) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_ENTRY_DENIED); - event.setCancelled(true); - if (lastLoc != null) { - pp.setMeta(PlotPlayer.META_LOCATION, lastLoc); - } - if (lastPlot != null) { - pp.setMeta(PlotPlayer.META_LAST_PLOT, lastPlot); - } - } else { - plotEntry(pp, plot); - } - } - } - return; - } - playerMove(event); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void vehicleMove(VehicleMoveEvent event) throws IllegalAccessException { - final org.bukkit.Location from = event.getFrom(); - final org.bukkit.Location to = event.getTo(); - - int toX, toZ; - if ((toX = MathMan.roundInt(to.getX())) != MathMan.roundInt(from.getX()) - | (toZ = MathMan.roundInt(to.getZ())) != MathMan.roundInt(from.getZ())) { - Vehicle vehicle = event.getVehicle(); - - // Check allowed - if (!vehicle.getPassengers().isEmpty()) { - Entity passenger = vehicle.getPassengers().get(0); - - if (passenger instanceof Player) { - final Player player = (Player) passenger; - // reset - if (moveTmp == null) - moveTmp = new PlayerMoveEvent(null, from, to); - moveTmp.setFrom(from); - moveTmp.setTo(to); - moveTmp.setCancelled(false); - fieldPlayer.set(moveTmp, player); - - List passengers = vehicle.getPassengers(); - - this.playerMove(moveTmp); - org.bukkit.Location dest; - if (moveTmp.isCancelled()) { - dest = from; - } else if (MathMan.roundInt(moveTmp.getTo().getX()) != toX - || MathMan.roundInt(moveTmp.getTo().getZ()) != toZ) { - dest = to; - } else { - dest = null; - } - if (dest != null) { - if (passengers != null) { - vehicle.eject(); - vehicle.setVelocity(new Vector(0d, 0d, 0d)); - vehicle.teleport(dest); - passengers.forEach(vehicle::addPassenger); - } else { - vehicle.eject(); - vehicle.setVelocity(new Vector(0d, 0d, 0d)); - vehicle.teleport(dest); - vehicle.setPassenger(player); - } - return; - } - } - if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) { - switch (vehicle.getType()) { - case BOAT: - case ENDER_CRYSTAL: - case MINECART: - case MINECART_CHEST: - case MINECART_COMMAND: - case MINECART_FURNACE: - case MINECART_HOPPER: - case MINECART_MOB_SPAWNER: - case MINECART_TNT: { - List meta = vehicle.getMetadata("plot"); - Plot toPlot = BukkitUtil.getLocation(to).getPlot(); - if (!meta.isEmpty()) { - Plot origin = (Plot) meta.get(0).value(); - if (!origin.getBasePlot(false).equals(toPlot)) { - vehicle.remove(); - } - } else if (toPlot != null) { - vehicle.setMetadata("plot", - new FixedMetadataValue((Plugin) PlotSquared.get().IMP, toPlot)); - } - } - } - } - } - - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void playerMove(PlayerMoveEvent event) { - org.bukkit.Location from = event.getFrom(); - org.bukkit.Location to = event.getTo(); - int x2; - if (MathMan.roundInt(from.getX()) != (x2 = MathMan.roundInt(to.getX()))) { - Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); - // Cancel teleport - TaskManager.TELEPORT_QUEUE.remove(pp.getName()); - // Set last location - Location loc = BukkitUtil.getLocation(to); - pp.setMeta(PlotPlayer.META_LOCATION, loc); - PlotArea area = loc.getPlotArea(); - if (area == null) { - pp.deleteMeta(PlotPlayer.META_LAST_PLOT); - return; - } - Plot now = area.getPlot(loc); - Plot lastPlot = pp.getMeta(PlotPlayer.META_LAST_PLOT); - if (now == null) { - if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport && !pp - .getMeta("kick", false)) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_EXIT_DENIED); - this.tmpTeleport = false; - if (lastPlot.equals(BukkitUtil.getLocation(from).getPlot())) { - player.teleport(from); - } else { - player.teleport(player.getWorld().getSpawnLocation()); - } - this.tmpTeleport = true; - event.setCancelled(true); - return; - } - } else if (now.equals(lastPlot)) { - ForceFieldListener.handleForcefield(player, pp, now); - return; - } else if (!plotEntry(pp, now) && this.tmpTeleport) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_ENTRY_DENIED); - this.tmpTeleport = false; - to.setX(from.getBlockX()); - to.setY(from.getBlockY()); - to.setZ(from.getBlockZ()); - player.teleport(event.getTo()); - this.tmpTeleport = true; - return; - } - Integer border = area.getBorder(); - if (x2 > border && this.tmpTeleport) { - to.setX(x2 - 1); - this.tmpTeleport = false; - player.teleport(event.getTo()); - this.tmpTeleport = true; - MainUtil.sendMessage(pp, C.BORDER); - return; - } - if (x2 < -border && this.tmpTeleport) { - to.setX(x2 + 1); - this.tmpTeleport = false; - player.teleport(event.getTo()); - this.tmpTeleport = true; - MainUtil.sendMessage(pp, C.BORDER); - return; - } - return; - } - int z2; - if (MathMan.roundInt(from.getZ()) != (z2 = MathMan.roundInt(to.getZ()))) { - Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); - // Cancel teleport - TaskManager.TELEPORT_QUEUE.remove(pp.getName()); - // Set last location - Location loc = BukkitUtil.getLocation(to); - pp.setMeta(PlotPlayer.META_LOCATION, loc); - PlotArea area = loc.getPlotArea(); - if (area == null) { - pp.deleteMeta(PlotPlayer.META_LAST_PLOT); - return; - } - Plot now = area.getPlot(loc); - Plot lastPlot = pp.getMeta(PlotPlayer.META_LAST_PLOT); - if (now == null) { - if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport && !pp - .getMeta("kick", false)) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_EXIT_DENIED); - this.tmpTeleport = false; - if (lastPlot.equals(BukkitUtil.getLocation(from).getPlot())) { - player.teleport(from); - } else { - player.teleport(player.getWorld().getSpawnLocation()); - } - this.tmpTeleport = true; - event.setCancelled(true); - return; - } - } else if (now.equals(lastPlot)) { - ForceFieldListener.handleForcefield(player, pp, now); - return; - } else if (!plotEntry(pp, now) && this.tmpTeleport) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_ENTRY_DENIED); - this.tmpTeleport = false; - player.teleport(from); - to.setX(from.getBlockX()); - to.setY(from.getBlockY()); - to.setZ(from.getBlockZ()); - player.teleport(event.getTo()); - this.tmpTeleport = true; - return; - } - Integer border = area.getBorder(); - if (z2 > border && this.tmpTeleport) { - to.setZ(z2 - 1); - this.tmpTeleport = false; - player.teleport(event.getTo()); - this.tmpTeleport = true; - MainUtil.sendMessage(pp, C.BORDER); - } else if (z2 < -border && this.tmpTeleport) { - to.setZ(z2 + 1); - this.tmpTeleport = false; - player.teleport(event.getTo()); - this.tmpTeleport = true; - MainUtil.sendMessage(pp, C.BORDER); - } - } - } - - @EventHandler(priority = EventPriority.LOW) public void onChat(AsyncPlayerChatEvent event) { - if (event.isCancelled()) - return; - - PlotPlayer plotPlayer = BukkitUtil.getPlayer(event.getPlayer()); - Location location = plotPlayer.getLocation(); - PlotArea area = location.getPlotArea(); - if (area == null || (area.PLOT_CHAT == plotPlayer.getAttribute("chat"))) { - return; - } - Plot plot = area.getPlot(location); - if (plot == null) { - return; - } - event.setCancelled(true); - String message = event.getMessage(); - String format = C.PLOT_CHAT_FORMAT.s(); - String sender = event.getPlayer().getDisplayName(); - PlotId id = plot.getId(); - Set recipients = event.getRecipients(); - Set spies = new HashSet<>(); - recipients.clear(); - for (Entry entry : UUIDHandler.getPlayers().entrySet()) { - PlotPlayer pp = entry.getValue(); - if (pp.getAttribute("chatspy")) { - spies.add(((BukkitPlayer) pp).player); - } else { - Plot current = pp.getCurrentPlot(); - if (current != null && current.getBasePlot(false).equals(plot)) { - recipients.add(((BukkitPlayer) pp).player); - } - } - } - String partial = ChatColor.translateAlternateColorCodes('&', - format.replace("%plot_id%", id.x + ";" + id.y).replace("%sender%", sender)); - if (plotPlayer.hasPermission("plots.chat.color")) { - message = C.color(message); - } - String full = partial.replace("%msg%", message); - for (Player receiver : recipients) { - receiver.sendMessage(full); - } - if (!spies.isEmpty()) { - String spyMessage = C.PLOT_CHAT_SPY_FORMAT.s().replace("%plot_id%", id.x + ";" + id.y) - .replace("%sender%", sender).replace("%msg%", message); - for (Player player : spies) { - player.sendMessage(spyMessage); - } - } - PlotSquared.debug(full); - } - - @EventHandler(priority = EventPriority.LOWEST) public void blockDestroy(BlockBreakEvent event) { - Player player = event.getPlayer(); - Location location = BukkitUtil.getLocation(event.getBlock().getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Plot plot = area.getPlot(location); - if (plot != null) { - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); - if (event.getBlock().getY() == 0) { - if (!Permissions - .hasPermission(plotPlayer, C.PERMISSION_ADMIN_DESTROY_GROUNDLEVEL)) { - MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, - C.PERMISSION_ADMIN_DESTROY_GROUNDLEVEL); - event.setCancelled(true); - return; - } - } else if ( - (location.getY() > area.MAX_BUILD_HEIGHT || location.getY() < area.MIN_BUILD_HEIGHT) - && !Permissions - .hasPermission(plotPlayer, C.PERMISSION_ADMIN_BUILD_HEIGHTLIMIT)) { - event.setCancelled(true); - MainUtil.sendMessage(plotPlayer, - C.HEIGHT_LIMIT.s().replace("{limit}", String.valueOf(area.MAX_BUILD_HEIGHT))); - } - if (!plot.hasOwner()) { - if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_DESTROY_UNOWNED)) { - return; - } - MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, - C.PERMISSION_ADMIN_DESTROY_UNOWNED); - event.setCancelled(true); - return; - } - if (!plot.isAdded(plotPlayer.getUUID())) { - Optional> destroy = plot.getFlag(Flags.BREAK); - Block block = event.getBlock(); - if (destroy.isPresent() && destroy.get() - .contains(PlotBlock.get(block.getType().name()))) { - return; - } - if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_DESTROY_OTHER)) { - return; - } - MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, - C.PERMISSION_ADMIN_DESTROY_OTHER); - event.setCancelled(true); - } else if (Settings.Done.RESTRICT_BUILDING && plot.getFlags().containsKey(Flags.DONE)) { - if (!Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_BUILD_OTHER)) { - MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, - C.PERMISSION_ADMIN_BUILD_OTHER); - event.setCancelled(true); - return; - } - } - return; - } - PlotPlayer pp = BukkitUtil.getPlayer(player); - if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_DESTROY_ROAD)) { - return; - } - if (PlotSquared.get().worldedit != null && pp.getAttribute("worldedit")) { - if (player.getInventory().getItemInMainHand().getType() == Material - .getMaterial(PlotSquared.get().worldedit.getConfiguration().wandItem)) { - return; - } - } - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_DESTROY_ROAD); - event.setCancelled(true); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBigBoom(EntityExplodeEvent event) { - Location location = BukkitUtil.getLocation(event.getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - if (!PlotSquared.get().hasPlotArea(location.getWorld())) { - return; - } - Iterator iterator = event.blockList().iterator(); - while (iterator.hasNext()) { - iterator.next(); - if (location.getPlotArea() != null) { - iterator.remove(); - } - } - return; - } - Plot plot = area.getOwnedPlot(location); - if (plot != null) { - if (Flags.EXPLOSION.isTrue(plot)) { - List meta = event.getEntity().getMetadata("plot"); - Plot origin; - if (meta.isEmpty()) { - origin = plot; - } else { - origin = (Plot) meta.get(0).value(); - } - if (this.lastRadius != 0) { - List nearby = event.getEntity() - .getNearbyEntities(this.lastRadius, this.lastRadius, this.lastRadius); - for (Entity near : nearby) { - if (near instanceof TNTPrimed || near.getType() - .equals(EntityType.MINECART_TNT)) { - if (!near.hasMetadata("plot")) { - near.setMetadata("plot", - new FixedMetadataValue((Plugin) PlotSquared.get().IMP, plot)); - } - } - } - this.lastRadius = 0; - } - Iterator iterator = event.blockList().iterator(); - while (iterator.hasNext()) { - Block block = iterator.next(); - location = BukkitUtil.getLocation(block.getLocation()); - if (!area.contains(location.getX(), location.getZ()) || !origin - .equals(area.getOwnedPlot(location))) { - iterator.remove(); - } - } - return; - } - } - event.setCancelled(true); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onWorldChanged(PlayerChangedWorldEvent event) { - Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); - // Delete last location - pp.deleteMeta(PlotPlayer.META_LOCATION); - Plot plot = (Plot) pp.deleteMeta(PlotPlayer.META_LAST_PLOT); - if (plot != null) { - plotExit(pp, plot); - } - if (PlotSquared.get().worldedit != null) { - if (!Permissions.hasPermission(pp, C.PERMISSION_WORLDEDIT_BYPASS)) { - if (pp.getAttribute("worldedit")) { - pp.removeAttribute("worldedit"); - } - } - } - if (Settings.Enabled_Components.PERMISSION_CACHE) { - pp.deleteMeta("perm"); - } - Location loc = pp.getLocation(); + PlotPlayer pp = PlotPlayer.wrap(player); + Location loc = BukkitUtil.getLocation(to); PlotArea area = PlotSquared.get().getPlotAreaAbs(loc); if (area == null) { - return; + return; } - plot = area.getPlot(loc); + Plot plot = area.getPlot(loc); if (plot != null) { + final boolean result = Flags.DENY_TELEPORT.allowsTeleport(pp, plot); + if (!result) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_ENTRY_DENIED); + event.setCancelled(true); + if (lastLoc != null) { + pp.setMeta(PlotPlayer.META_LOCATION, lastLoc); + } + if (lastPlot != null) { + pp.setMeta(PlotPlayer.META_LAST_PLOT, lastPlot); + } + } else { plotEntry(pp, plot); + } } + } + return; } + playerMove(event); + } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onPeskyMobsChangeTheWorldLikeWTFEvent(EntityChangeBlockEvent event) { - Entity e = event.getEntity(); - if (!(e instanceof FallingBlock)) { - Location location = BukkitUtil.getLocation(event.getBlock().getLocation()); - PlotArea area = location.getPlotArea(); - if (area != null) { - Plot plot = area.getOwnedPlot(location); - if (plot != null && Flags.MOB_BREAK.isTrue(plot)) - return; - event.setCancelled(true); + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void vehicleMove(VehicleMoveEvent event) throws IllegalAccessException { + final org.bukkit.Location from = event.getFrom(); + final org.bukkit.Location to = event.getTo(); + + int toX, toZ; + if ((toX = MathMan.roundInt(to.getX())) != MathMan.roundInt(from.getX()) + | (toZ = MathMan.roundInt(to.getZ())) != MathMan.roundInt(from.getZ())) { + Vehicle vehicle = event.getVehicle(); + + // Check allowed + if (!vehicle.getPassengers().isEmpty()) { + Entity passenger = vehicle.getPassengers().get(0); + + if (passenger instanceof Player) { + final Player player = (Player) passenger; + // reset + if (moveTmp == null) { + moveTmp = new PlayerMoveEvent(null, from, to); + } + moveTmp.setFrom(from); + moveTmp.setTo(to); + moveTmp.setCancelled(false); + fieldPlayer.set(moveTmp, player); + + List passengers = vehicle.getPassengers(); + + this.playerMove(moveTmp); + org.bukkit.Location dest; + if (moveTmp.isCancelled()) { + dest = from; + } else if (MathMan.roundInt(moveTmp.getTo().getX()) != toX + || MathMan.roundInt(moveTmp.getTo().getZ()) != toZ) { + dest = to; + } else { + dest = null; + } + if (dest != null) { + if (passengers != null) { + vehicle.eject(); + vehicle.setVelocity(new Vector(0d, 0d, 0d)); + vehicle.teleport(dest); + passengers.forEach(vehicle::addPassenger); + } else { + vehicle.eject(); + vehicle.setVelocity(new Vector(0d, 0d, 0d)); + vehicle.teleport(dest); + vehicle.addPassenger(player); } - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onEntityBlockForm(EntityBlockFormEvent event) { - String world = event.getBlock().getWorld().getName(); - if (!PlotSquared.get().hasPlotArea(world)) { return; + } } - Location location = BukkitUtil.getLocation(event.getBlock().getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Plot plot = area.getOwnedPlot(location); - if (plot == null) { - event.setCancelled(true); - return; - } - Entity entity = event.getEntity(); - if (entity instanceof Player) { - Player player = (Player) entity; - if (!plot.hasOwner()) { - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); - if (Flags.ICE_FORM.isTrue(plot)) { - return; + if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) { + switch (vehicle.getType()) { + case BOAT: + case ENDER_CRYSTAL: + case MINECART: + case MINECART_CHEST: + case MINECART_COMMAND: + case MINECART_FURNACE: + case MINECART_HOPPER: + case MINECART_MOB_SPAWNER: + case MINECART_TNT: { + List meta = vehicle.getMetadata("plot"); + Plot toPlot = BukkitUtil.getLocation(to).getPlot(); + if (!meta.isEmpty()) { + Plot origin = (Plot) meta.get(0).value(); + if (!origin.getBasePlot(false).equals(toPlot)) { + vehicle.remove(); } - event.setCancelled(true); - return; + } else if (toPlot != null) { + vehicle.setMetadata("plot", + new FixedMetadataValue((Plugin) PlotSquared.get().IMP, toPlot)); + } } - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); - if (!plot.isAdded(plotPlayer.getUUID())) { - if (Flags.ICE_FORM.isTrue(plot)) { - return; - } - event.setCancelled(true); - return; - } - return; + } } - if (!Flags.ICE_FORM.isTrue(plot)) { - event.setCancelled(true); + } + + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void playerMove(PlayerMoveEvent event) { + org.bukkit.Location from = event.getFrom(); + org.bukkit.Location to = event.getTo(); + int x2; + if (MathMan.roundInt(from.getX()) != (x2 = MathMan.roundInt(to.getX()))) { + Player player = event.getPlayer(); + PlotPlayer pp = BukkitUtil.getPlayer(player); + // Cancel teleport + TaskManager.TELEPORT_QUEUE.remove(pp.getName()); + // Set last location + Location loc = BukkitUtil.getLocation(to); + pp.setMeta(PlotPlayer.META_LOCATION, loc); + PlotArea area = loc.getPlotArea(); + if (area == null) { + pp.deleteMeta(PlotPlayer.META_LAST_PLOT); + return; + } + Plot now = area.getPlot(loc); + Plot lastPlot = pp.getMeta(PlotPlayer.META_LAST_PLOT); + if (now == null) { + if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport && !pp + .getMeta("kick", false)) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_EXIT_DENIED); + this.tmpTeleport = false; + if (lastPlot.equals(BukkitUtil.getLocation(from).getPlot())) { + player.teleport(from); + } else { + player.teleport(player.getWorld().getSpawnLocation()); + } + this.tmpTeleport = true; + event.setCancelled(true); + return; } + } else if (now.equals(lastPlot)) { + ForceFieldListener.handleForcefield(player, pp, now); + return; + } else if (!plotEntry(pp, now) && this.tmpTeleport) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_ENTRY_DENIED); + this.tmpTeleport = false; + to.setX(from.getBlockX()); + to.setY(from.getBlockY()); + to.setZ(from.getBlockZ()); + player.teleport(event.getTo()); + this.tmpTeleport = true; + return; + } + int border = area.getBorder(); + if (x2 > border && this.tmpTeleport) { + to.setX(x2 - 1); + this.tmpTeleport = false; + player.teleport(event.getTo()); + this.tmpTeleport = true; + MainUtil.sendMessage(pp, C.BORDER); + return; + } + if (x2 < -border && this.tmpTeleport) { + to.setX(x2 + 1); + this.tmpTeleport = false; + player.teleport(event.getTo()); + this.tmpTeleport = true; + MainUtil.sendMessage(pp, C.BORDER); + return; + } + return; + } + int z2; + if (MathMan.roundInt(from.getZ()) != (z2 = MathMan.roundInt(to.getZ()))) { + Player player = event.getPlayer(); + PlotPlayer pp = BukkitUtil.getPlayer(player); + // Cancel teleport + TaskManager.TELEPORT_QUEUE.remove(pp.getName()); + // Set last location + Location loc = BukkitUtil.getLocation(to); + pp.setMeta(PlotPlayer.META_LOCATION, loc); + PlotArea area = loc.getPlotArea(); + if (area == null) { + pp.deleteMeta(PlotPlayer.META_LAST_PLOT); + return; + } + Plot now = area.getPlot(loc); + Plot lastPlot = pp.getMeta(PlotPlayer.META_LAST_PLOT); + if (now == null) { + if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport && !pp + .getMeta("kick", false)) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_EXIT_DENIED); + this.tmpTeleport = false; + if (lastPlot.equals(BukkitUtil.getLocation(from).getPlot())) { + player.teleport(from); + } else { + player.teleport(player.getWorld().getSpawnLocation()); + } + this.tmpTeleport = true; + event.setCancelled(true); + return; + } + } else if (now.equals(lastPlot)) { + ForceFieldListener.handleForcefield(player, pp, now); + return; + } else if (!plotEntry(pp, now) && this.tmpTeleport) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_ENTRY_DENIED); + this.tmpTeleport = false; + player.teleport(from); + to.setX(from.getBlockX()); + to.setY(from.getBlockY()); + to.setZ(from.getBlockZ()); + player.teleport(event.getTo()); + this.tmpTeleport = true; + return; + } + int border = area.getBorder(); + if (z2 > border && this.tmpTeleport) { + to.setZ(z2 - 1); + this.tmpTeleport = false; + player.teleport(event.getTo()); + this.tmpTeleport = true; + MainUtil.sendMessage(pp, C.BORDER); + } else if (z2 < -border && this.tmpTeleport) { + to.setZ(z2 + 1); + this.tmpTeleport = false; + player.teleport(event.getTo()); + this.tmpTeleport = true; + MainUtil.sendMessage(pp, C.BORDER); + } + } + } + + @EventHandler(priority = EventPriority.LOW) + public void onChat(AsyncPlayerChatEvent event) { + if (event.isCancelled()) { + return; } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockSpread(BlockSpreadEvent event) { + PlotPlayer plotPlayer = BukkitUtil.getPlayer(event.getPlayer()); + Location location = plotPlayer.getLocation(); + PlotArea area = location.getPlotArea(); + if (area == null || (area.PLOT_CHAT == plotPlayer.getAttribute("chat"))) { + return; + } + Plot plot = area.getPlot(location); + if (plot == null) { + return; + } + event.setCancelled(true); + String message = event.getMessage(); + String format = C.PLOT_CHAT_FORMAT.s(); + String sender = event.getPlayer().getDisplayName(); + PlotId id = plot.getId(); + Set recipients = event.getRecipients(); + Set spies = new HashSet<>(); + recipients.clear(); + for (Entry entry : UUIDHandler.getPlayers().entrySet()) { + PlotPlayer pp = entry.getValue(); + if (pp.getAttribute("chatspy")) { + spies.add(((BukkitPlayer) pp).player); + } else { + Plot current = pp.getCurrentPlot(); + if (current != null && current.getBasePlot(false).equals(plot)) { + recipients.add(((BukkitPlayer) pp).player); + } + } + } + String partial = ChatColor.translateAlternateColorCodes('&', + format.replace("%plot_id%", id.x + ";" + id.y).replace("%sender%", sender)); + if (plotPlayer.hasPermission("plots.chat.color")) { + message = C.color(message); + } + String full = partial.replace("%msg%", message); + for (Player receiver : recipients) { + receiver.sendMessage(full); + } + if (!spies.isEmpty()) { + String spyMessage = C.PLOT_CHAT_SPY_FORMAT.s().replace("%plot_id%", id.x + ";" + id.y) + .replace("%sender%", sender).replace("%msg%", message); + for (Player player : spies) { + player.sendMessage(spyMessage); + } + } + PlotSquared.debug(full); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void blockDestroy(BlockBreakEvent event) { + Player player = event.getPlayer(); + Location location = BukkitUtil.getLocation(event.getBlock().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getPlot(location); + if (plot != null) { + PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + if (event.getBlock().getY() == 0) { + if (!Permissions + .hasPermission(plotPlayer, C.PERMISSION_ADMIN_DESTROY_GROUNDLEVEL)) { + MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, + C.PERMISSION_ADMIN_DESTROY_GROUNDLEVEL); + event.setCancelled(true); + return; + } + } else if ( + (location.getY() > area.MAX_BUILD_HEIGHT || location.getY() < area.MIN_BUILD_HEIGHT) + && !Permissions + .hasPermission(plotPlayer, C.PERMISSION_ADMIN_BUILD_HEIGHTLIMIT)) { + event.setCancelled(true); + MainUtil.sendMessage(plotPlayer, + C.HEIGHT_LIMIT.s().replace("{limit}", String.valueOf(area.MAX_BUILD_HEIGHT))); + } + if (!plot.hasOwner()) { + if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_DESTROY_UNOWNED)) { + return; + } + MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, + C.PERMISSION_ADMIN_DESTROY_UNOWNED); + event.setCancelled(true); + return; + } + if (!plot.isAdded(plotPlayer.getUUID())) { + Optional> destroy = plot.getFlag(Flags.BREAK); Block block = event.getBlock(); - Location location = BukkitUtil.getLocation(block.getLocation()); - if (location.isPlotRoad()) { - event.setCancelled(true); - return; + if (destroy.isPresent() && destroy.get() + .contains(PlotBlock.get(block.getType().name()))) { + return; } - PlotArea area = location.getPlotArea(); - if (area == null) { - return; + if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_DESTROY_OTHER)) { + return; } - Plot plot = area.getOwnedPlot(location); - if (plot == null) { - return; - } - switch (event.getSource().getType()) { - case GRASS: - if (Flags.GRASS_GROW.isFalse(plot)) { - event.setCancelled(true); - } - break; - case MYCELIUM: - if (Flags.MYCEL_GROW.isFalse(plot)) { - event.setCancelled(true); - } - break; - case VINE: - if (Flags.VINE_GROW.isFalse(plot)) { - event.setCancelled(true); - } - break; + MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, + C.PERMISSION_ADMIN_DESTROY_OTHER); + event.setCancelled(true); + } else if (Settings.Done.RESTRICT_BUILDING && plot.getFlags().containsKey(Flags.DONE)) { + if (!Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_BUILD_OTHER)) { + MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, + C.PERMISSION_ADMIN_BUILD_OTHER); + event.setCancelled(true); + return; } + } + return; } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockForm(BlockFormEvent event) { - Block block = event.getBlock(); - Location location = BukkitUtil.getLocation(block.getLocation()); - if (location.isPlotRoad()) { - event.setCancelled(true); - return; - } - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Plot plot = area.getOwnedPlot(location); - if (plot == null) { - return; - } - switch (event.getNewState().getType()) { - case SNOW: - case SNOW_BLOCK: - if (Flags.SNOW_FORM.isFalse(plot)) { - event.setCancelled(true); - } - return; - case ICE: - case FROSTED_ICE: - case PACKED_ICE: - if (Flags.ICE_FORM.isFalse(plot)) { - event.setCancelled(true); - } - return; - case STONE: - case OBSIDIAN: - case COBBLESTONE: - // TODO event ? - return; - } + PlotPlayer pp = BukkitUtil.getPlayer(player); + if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_DESTROY_ROAD)) { + return; } + if (PlotSquared.get().worldedit != null && pp.getAttribute("worldedit")) { + if (player.getInventory().getItemInMainHand().getType() == Material + .getMaterial(PlotSquared.get().worldedit.getConfiguration().wandItem)) { + return; + } + } + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_DESTROY_ROAD); + event.setCancelled(true); + } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockDamage(BlockDamageEvent event) { - Player player = event.getPlayer(); - Location location = BukkitUtil.getLocation(event.getBlock().getLocation()); - if (player == null) { - if (location.isPlotRoad()) { - event.setCancelled(true); - return; - } + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBigBoom(EntityExplodeEvent event) { + Location location = BukkitUtil.getLocation(event.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + if (!PlotSquared.get().hasPlotArea(location.getWorld())) { + return; + } + Iterator iterator = event.blockList().iterator(); + while (iterator.hasNext()) { + iterator.next(); + if (location.getPlotArea() != null) { + iterator.remove(); } - PlotArea area = location.getPlotArea(); - if (area == null) { - return; + } + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot != null) { + if (Flags.EXPLOSION.isTrue(plot)) { + List meta = event.getEntity().getMetadata("plot"); + Plot origin; + if (meta.isEmpty()) { + origin = plot; + } else { + origin = (Plot) meta.get(0).value(); } - Plot plot = area.getPlot(location); - if (plot != null) { - if (location.getY() == 0) { - event.setCancelled(true); - return; + if (this.lastRadius != 0) { + List nearby = event.getEntity() + .getNearbyEntities(this.lastRadius, this.lastRadius, this.lastRadius); + for (Entity near : nearby) { + if (near instanceof TNTPrimed || near.getType() + .equals(EntityType.MINECART_TNT)) { + if (!near.hasMetadata("plot")) { + near.setMetadata("plot", + new FixedMetadataValue((Plugin) PlotSquared.get().IMP, plot)); + } } - if (!plot.hasOwner()) { - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); - if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_DESTROY_UNOWNED)) { - return; - } - event.setCancelled(true); - return; - } - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); - if (!plot.isAdded(plotPlayer.getUUID())) { - Optional> destroy = plot.getFlag(Flags.BREAK); - Block block = event.getBlock(); - if (destroy.isPresent() && destroy.get() - .contains(PlotBlock.get(block.getType().name())) || Permissions - .hasPermission(plotPlayer, C.PERMISSION_ADMIN_DESTROY_OTHER)) { - return; - } - event.setCancelled(true); - return; - } - return; + } + this.lastRadius = 0; } - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); - if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_DESTROY_ROAD)) { - return; + Iterator iterator = event.blockList().iterator(); + while (iterator.hasNext()) { + Block block = iterator.next(); + location = BukkitUtil.getLocation(block.getLocation()); + if (!area.contains(location.getX(), location.getZ()) || !origin + .equals(area.getOwnedPlot(location))) { + iterator.remove(); + } + } + return; + } + } + event.setCancelled(true); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onWorldChanged(PlayerChangedWorldEvent event) { + Player player = event.getPlayer(); + PlotPlayer pp = BukkitUtil.getPlayer(player); + // Delete last location + pp.deleteMeta(PlotPlayer.META_LOCATION); + Plot plot = (Plot) pp.deleteMeta(PlotPlayer.META_LAST_PLOT); + if (plot != null) { + plotExit(pp, plot); + } + if (PlotSquared.get().worldedit != null) { + if (!Permissions.hasPermission(pp, C.PERMISSION_WORLDEDIT_BYPASS)) { + if (pp.getAttribute("worldedit")) { + pp.removeAttribute("worldedit"); + } + } + } + if (Settings.Enabled_Components.PERMISSION_CACHE) { + pp.deleteMeta("perm"); + } + Location loc = pp.getLocation(); + PlotArea area = PlotSquared.get().getPlotAreaAbs(loc); + if (area == null) { + return; + } + plot = area.getPlot(loc); + if (plot != null) { + plotEntry(pp, plot); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPeskyMobsChangeTheWorldLikeWTFEvent(EntityChangeBlockEvent event) { + Entity e = event.getEntity(); + if (!(e instanceof FallingBlock)) { + Location location = BukkitUtil.getLocation(event.getBlock().getLocation()); + PlotArea area = location.getPlotArea(); + if (area != null) { + Plot plot = area.getOwnedPlot(location); + if (plot != null && Flags.MOB_BREAK.isTrue(plot)) { + return; } event.setCancelled(true); + } } + } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onFade(BlockFadeEvent event) { - Block b = event.getBlock(); - Location location = BukkitUtil.getLocation(b.getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Plot plot = area.getOwnedPlot(location); - if (plot == null) { - event.setCancelled(true); - return; - } - switch (b.getType()) { - case ICE: - if (Flags.ICE_MELT.isFalse(plot)) { - event.setCancelled(true); - } - break; - case SNOW: - if (Flags.SNOW_MELT.isFalse(plot)) { - event.setCancelled(true); - } - break; - case FARMLAND: - if (Flags.SOIL_DRY.isFalse(plot)) { - event.setCancelled(true); - } - break; - } + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onEntityBlockForm(EntityBlockFormEvent event) { + String world = event.getBlock().getWorld().getName(); + if (!PlotSquared.get().hasPlotArea(world)) { + return; } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onChange(BlockFromToEvent event) { - Block from = event.getBlock(); - Block to = event.getToBlock(); - Location tLocation = BukkitUtil.getLocation(to.getLocation()); - PlotArea area = tLocation.getPlotArea(); - if (area == null) { - return; - } - Plot plot = area.getOwnedPlot(tLocation); - Location fLocation = BukkitUtil.getLocation(from.getLocation()); - if (plot != null) { - if (Flags.DISABLE_PHYSICS.isFalse(plot)) { - event.setCancelled(true); - return; - } else if (!area.contains(fLocation.getX(), fLocation.getZ()) || !Objects - .equals(plot, area.getOwnedPlot(fLocation))) { - event.setCancelled(true); - return; - } - if (Flags.LIQUID_FLOW.isFalse(plot)) { - switch (to.getType()) { - case WATER: - case LAVA: - event.setCancelled(true); - } - } - } else if (!area.contains(fLocation.getX(), fLocation.getZ()) || !Objects - .equals(null, area.getOwnedPlot(fLocation))) { - event.setCancelled(true); - } + Location location = BukkitUtil.getLocation(event.getBlock().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onGrow(BlockGrowEvent event) { - Block b = event.getBlock(); - Location location = BukkitUtil.getLocation(b.getLocation()); - if (location.isUnownedPlotArea()) { - event.setCancelled(true); - } + Plot plot = area.getOwnedPlot(location); + if (plot == null) { + event.setCancelled(true); + return; } + Entity entity = event.getEntity(); + if (entity instanceof Player) { + Player player = (Player) entity; + if (!plot.hasOwner()) { + PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + if (Flags.ICE_FORM.isTrue(plot)) { + return; + } + event.setCancelled(true); + return; + } + PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + if (!plot.isAdded(plotPlayer.getUUID())) { + if (Flags.ICE_FORM.isTrue(plot)) { + return; + } + event.setCancelled(true); + return; + } + return; + } + if (!Flags.ICE_FORM.isTrue(plot)) { + event.setCancelled(true); + } + } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockPistonExtend(BlockPistonExtendEvent event) { + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockSpread(BlockSpreadEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.getLocation(block.getLocation()); + if (location.isPlotRoad()) { + event.setCancelled(true); + return; + } + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot == null) { + return; + } + switch (event.getSource().getType()) { + case GRASS: + if (Flags.GRASS_GROW.isFalse(plot)) { + event.setCancelled(true); + } + break; + case MYCELIUM: + if (Flags.MYCEL_GROW.isFalse(plot)) { + event.setCancelled(true); + } + break; + case VINE: + if (Flags.VINE_GROW.isFalse(plot)) { + event.setCancelled(true); + } + break; + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockForm(BlockFormEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.getLocation(block.getLocation()); + if (location.isPlotRoad()) { + event.setCancelled(true); + return; + } + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot == null) { + return; + } + switch (event.getNewState().getType()) { + case SNOW: + case SNOW_BLOCK: + if (Flags.SNOW_FORM.isFalse(plot)) { + event.setCancelled(true); + } + return; + case ICE: + case FROSTED_ICE: + case PACKED_ICE: + if (Flags.ICE_FORM.isFalse(plot)) { + event.setCancelled(true); + } + return; + case STONE: + case OBSIDIAN: + case COBBLESTONE: + // TODO event ? + return; + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockDamage(BlockDamageEvent event) { + Player player = event.getPlayer(); + Location location = BukkitUtil.getLocation(event.getBlock().getLocation()); + if (player == null) { + if (location.isPlotRoad()) { + event.setCancelled(true); + return; + } + } + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getPlot(location); + if (plot != null) { + if (location.getY() == 0) { + event.setCancelled(true); + return; + } + if (!plot.hasOwner()) { + PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_DESTROY_UNOWNED)) { + return; + } + event.setCancelled(true); + return; + } + PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + if (!plot.isAdded(plotPlayer.getUUID())) { + Optional> destroy = plot.getFlag(Flags.BREAK); Block block = event.getBlock(); - Location location = BukkitUtil.getLocation(block.getLocation()); - BlockFace face = event.getDirection(); - Vector relative = new Vector(face.getModX(), face.getModY(), face.getModZ()); - PlotArea area = location.getPlotArea(); - if (area == null) { - if (!PlotSquared.get().hasPlotArea(location.getWorld())) { - return; - } - for (Block b : event.getBlocks()) { - if (BukkitUtil.getLocation(b.getLocation().add(relative)).getPlotArea() != null) { - event.setCancelled(true); - return; - } - } - return; - } - Plot plot = area.getOwnedPlot(location); - if (plot == null) { - event.setCancelled(true); - return; - } - List blocks = event.getBlocks(); - for (Block b : blocks) { - Location bloc = BukkitUtil.getLocation(b.getLocation()); - if (!area.contains(bloc.getX(), bloc.getZ()) || !area - .contains(bloc.getX() + relative.getBlockX(), bloc.getZ() + relative.getBlockZ())) { - event.setCancelled(true); - return; - } - if (!plot.equals(area.getOwnedPlot(bloc)) || !plot.equals(area.getOwnedPlot( - bloc.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ())))) { - event.setCancelled(true); - return; - } + if (destroy.isPresent() && destroy.get() + .contains(PlotBlock.get(block.getType().name())) || Permissions + .hasPermission(plotPlayer, C.PERMISSION_ADMIN_DESTROY_OTHER)) { + return; } + event.setCancelled(true); + return; + } + return; } + PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_DESTROY_ROAD)) { + return; + } + event.setCancelled(true); + } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockPistonRetract(BlockPistonRetractEvent event) { - Block block = event.getBlock(); - Location location = BukkitUtil.getLocation(block.getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - if (!PlotSquared.get().hasPlotArea(location.getWorld())) { - return; - } - if (this.pistonBlocks) { - try { - for (Block pulled : event.getBlocks()) { - location = BukkitUtil.getLocation(pulled.getLocation()); - if (location.getPlotArea() != null) { - event.setCancelled(true); - return; - } - } - } catch (Throwable ignored) { - this.pistonBlocks = false; - } - } - if (!this.pistonBlocks && !block.getType().toString().contains("PISTON")) { - BlockFace dir = event.getDirection(); - location = BukkitUtil.getLocation(block.getLocation() - .add(dir.getModX() * 2, dir.getModY() * 2, dir.getModZ() * 2)); - if (location.getPlotArea() != null) { - event.setCancelled(true); - return; - } - } - return; + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onFade(BlockFadeEvent event) { + Block b = event.getBlock(); + Location location = BukkitUtil.getLocation(b.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot == null) { + event.setCancelled(true); + return; + } + switch (b.getType()) { + case ICE: + if (Flags.ICE_MELT.isFalse(plot)) { + event.setCancelled(true); } - Plot plot = area.getOwnedPlot(location); + break; + case SNOW: + if (Flags.SNOW_MELT.isFalse(plot)) { + event.setCancelled(true); + } + break; + case FARMLAND: + if (Flags.SOIL_DRY.isFalse(plot)) { + event.setCancelled(true); + } + break; + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onChange(BlockFromToEvent event) { + Block from = event.getBlock(); + Block to = event.getToBlock(); + Location tLocation = BukkitUtil.getLocation(to.getLocation()); + PlotArea area = tLocation.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlot(tLocation); + Location fLocation = BukkitUtil.getLocation(from.getLocation()); + if (plot != null) { + if (Flags.DISABLE_PHYSICS.isFalse(plot)) { + event.setCancelled(true); + return; + } else if (!area.contains(fLocation.getX(), fLocation.getZ()) || !Objects + .equals(plot, area.getOwnedPlot(fLocation))) { + event.setCancelled(true); + return; + } + if (Flags.LIQUID_FLOW.isFalse(plot)) { + switch (to.getType()) { + case WATER: + case LAVA: + event.setCancelled(true); + } + } + } else if (!area.contains(fLocation.getX(), fLocation.getZ()) || !Objects + .equals(null, area.getOwnedPlot(fLocation))) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onGrow(BlockGrowEvent event) { + Block b = event.getBlock(); + Location location = BukkitUtil.getLocation(b.getLocation()); + if (location.isUnownedPlotArea()) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockPistonExtend(BlockPistonExtendEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.getLocation(block.getLocation()); + BlockFace face = event.getDirection(); + Vector relative = new Vector(face.getModX(), face.getModY(), face.getModZ()); + PlotArea area = location.getPlotArea(); + if (area == null) { + if (!PlotSquared.get().hasPlotArea(location.getWorld())) { + return; + } + for (Block b : event.getBlocks()) { + if (BukkitUtil.getLocation(b.getLocation().add(relative)).getPlotArea() != null) { + event.setCancelled(true); + return; + } + } + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot == null) { + event.setCancelled(true); + return; + } + List blocks = event.getBlocks(); + for (Block b : blocks) { + Location bloc = BukkitUtil.getLocation(b.getLocation()); + if (!area.contains(bloc.getX(), bloc.getZ()) || !area + .contains(bloc.getX() + relative.getBlockX(), bloc.getZ() + relative.getBlockZ())) { + event.setCancelled(true); + return; + } + if (!plot.equals(area.getOwnedPlot(bloc)) || !plot.equals(area.getOwnedPlot( + bloc.add(relative.getBlockX(), relative.getBlockY(), relative.getBlockZ())))) { + event.setCancelled(true); + return; + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockPistonRetract(BlockPistonRetractEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.getLocation(block.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + if (!PlotSquared.get().hasPlotArea(location.getWorld())) { + return; + } + if (this.pistonBlocks) { + try { + for (Block pulled : event.getBlocks()) { + location = BukkitUtil.getLocation(pulled.getLocation()); + if (location.getPlotArea() != null) { + event.setCancelled(true); + return; + } + } + } catch (Throwable ignored) { + this.pistonBlocks = false; + } + } + if (!this.pistonBlocks && !block.getType().toString().contains("PISTON")) { BlockFace dir = event.getDirection(); - // Location head = location.add(-dir.getModX(), -dir.getModY(), -dir.getModZ()); - // - // if (!Objects.equals(plot, area.getOwnedPlot(head))) { - // // FIXME: cancelling the event doesn't work here. See issue #1484 - // event.setCancelled(true); - // return; - // } - if (this.pistonBlocks) { - try { - for (Block pulled : event.getBlocks()) { - Location from = BukkitUtil.getLocation( - pulled.getLocation().add(dir.getModX(), dir.getModY(), dir.getModZ())); - Location to = BukkitUtil.getLocation(pulled.getLocation()); - if (!area.contains(to.getX(), to.getZ())) { - event.setCancelled(true); - return; - } - Plot fromPlot = area.getOwnedPlot(from); - Plot toPlot = area.getOwnedPlot(to); - if (!Objects.equals(fromPlot, toPlot)) { - event.setCancelled(true); - return; - } - } - } catch (Throwable ignored) { - this.pistonBlocks = false; - } - } - if (!this.pistonBlocks && !block.getType().toString().contains("PISTON")) { - location = BukkitUtil.getLocation( - block.getLocation().add(dir.getModX() * 2, dir.getModY() * 2, dir.getModZ() * 2)); - if (!area.contains(location)) { - event.setCancelled(true); - return; - } - Plot newPlot = area.getOwnedPlot(location); - if (!Objects.equals(plot, newPlot)) { - event.setCancelled(true); - } + location = BukkitUtil.getLocation(block.getLocation() + .add(dir.getModX() * 2, dir.getModY() * 2, dir.getModZ() * 2)); + if (location.getPlotArea() != null) { + event.setCancelled(true); + return; } + } + return; } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockDispense(BlockDispenseEvent event) { - Material type = event.getItem().getType(); - switch (type) { - case WATER_BUCKET: - case LAVA_BUCKET: { - if (event.getBlock().getType() == Material.DROPPER) - return; - BlockFace targetFace = - ((org.bukkit.material.Dispenser) event.getBlock().getState().getData()) - .getFacing(); - Location location = - BukkitUtil.getLocation(event.getBlock().getRelative(targetFace).getLocation()); - if (location.isPlotRoad()) { - event.setCancelled(true); - } - } - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onStructureGrow(StructureGrowEvent event) { - if (!PlotSquared.get().hasPlotArea(event.getWorld().getName())) { - return; - } - List blocks = event.getBlocks(); - if (blocks.isEmpty()) { - return; - } - Location location = BukkitUtil.getLocation(blocks.get(0).getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - for (int i = blocks.size() - 1; i >= 0; i--) { - location = BukkitUtil.getLocation(blocks.get(i).getLocation()); - if (location.getPlotArea() != null) { - blocks.remove(i); - } - } - return; - } else { - Plot origin = area.getOwnedPlot(location); - if (origin == null) { - event.setCancelled(true); - return; - } - for (int i = blocks.size() - 1; i >= 0; i--) { - location = BukkitUtil.getLocation(blocks.get(i).getLocation()); - if (!area.contains(location.getX(), location.getZ())) { - blocks.remove(i); - continue; - } - Plot plot = area.getOwnedPlot(location); - if (!Objects.equals(plot, origin)) { - event.getBlocks().remove(i); - } - } - } - Plot origin = area.getPlot(location); - if (origin == null) { + Plot plot = area.getOwnedPlot(location); + BlockFace dir = event.getDirection(); + // Location head = location.add(-dir.getModX(), -dir.getModY(), -dir.getModZ()); + // + // if (!Objects.equals(plot, area.getOwnedPlot(head))) { + // // FIXME: cancelling the event doesn't work here. See issue #1484 + // event.setCancelled(true); + // return; + // } + if (this.pistonBlocks) { + try { + for (Block pulled : event.getBlocks()) { + Location from = BukkitUtil.getLocation( + pulled.getLocation().add(dir.getModX(), dir.getModY(), dir.getModZ())); + Location to = BukkitUtil.getLocation(pulled.getLocation()); + if (!area.contains(to.getX(), to.getZ())) { event.setCancelled(true); return; + } + Plot fromPlot = area.getOwnedPlot(from); + Plot toPlot = area.getOwnedPlot(to); + if (!Objects.equals(fromPlot, toPlot)) { + event.setCancelled(true); + return; + } } - for (int i = blocks.size() - 1; i >= 0; i--) { - location = BukkitUtil.getLocation(blocks.get(i).getLocation()); - Plot plot = area.getOwnedPlot(location); - /* - * plot -> the base plot of the merged area - * origin -> the plot where the event gets called - */ - - // Are plot and origin not the same AND are both plots merged - if (!Objects.equals(plot, origin) && (!plot.isMerged() && !origin.isMerged())) { - event.getBlocks().remove(i); - } - } + } catch (Throwable ignored) { + this.pistonBlocks = false; + } } + if (!this.pistonBlocks && !block.getType().toString().contains("PISTON")) { + location = BukkitUtil.getLocation( + block.getLocation().add(dir.getModX() * 2, dir.getModY() * 2, dir.getModZ() * 2)); + if (!area.contains(location)) { + event.setCancelled(true); + return; + } + Plot newPlot = area.getOwnedPlot(location); + if (!Objects.equals(plot, newPlot)) { + event.setCancelled(true); + } + } + } - @SuppressWarnings("deprecation") - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onInventoryClick(InventoryClickEvent event) { + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockDispense(BlockDispenseEvent event) { + Material type = event.getItem().getType(); + switch (type) { + case WATER_BUCKET: + case LAVA_BUCKET: { + if (event.getBlock().getType() == Material.DROPPER) { + return; + } + BlockFace targetFace = + ((Directional) event.getBlock().getState().getData()).getFacing(); + Location location = + BukkitUtil.getLocation(event.getBlock().getRelative(targetFace).getLocation()); + if (location.isPlotRoad()) { + event.setCancelled(true); + } + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onStructureGrow(StructureGrowEvent event) { + if (!PlotSquared.get().hasPlotArea(event.getWorld().getName())) { + return; + } + List blocks = event.getBlocks(); + if (blocks.isEmpty()) { + return; + } + Location location = BukkitUtil.getLocation(blocks.get(0).getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + for (int i = blocks.size() - 1; i >= 0; i--) { + location = BukkitUtil.getLocation(blocks.get(i).getLocation()); + if (location.getPlotArea() != null) { + blocks.remove(i); + } + } + return; + } else { + Plot origin = area.getOwnedPlot(location); + if (origin == null) { + event.setCancelled(true); + return; + } + for (int i = blocks.size() - 1; i >= 0; i--) { + location = BukkitUtil.getLocation(blocks.get(i).getLocation()); + if (!area.contains(location.getX(), location.getZ())) { + blocks.remove(i); + continue; + } + Plot plot = area.getOwnedPlot(location); + if (!Objects.equals(plot, origin)) { + event.getBlocks().remove(i); + } + } + } + Plot origin = area.getPlot(location); + if (origin == null) { + event.setCancelled(true); + return; + } + for (int i = blocks.size() - 1; i >= 0; i--) { + location = BukkitUtil.getLocation(blocks.get(i).getLocation()); + Plot plot = area.getOwnedPlot(location); + /* + * plot -> the base plot of the merged area + * origin -> the plot where the event gets called + */ + + // Are plot and origin not the same AND are both plots merged + if (!Objects.equals(plot, origin) && (!plot.isMerged() && !origin.isMerged())) { + event.getBlocks().remove(i); + } + } + } + + @SuppressWarnings("deprecation") + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onInventoryClick(InventoryClickEvent event) { /*if (!event.isLeftClick() || (event.getAction() != InventoryAction.PLACE_ALL) || event .isShiftClick()) { return; }*/ - HumanEntity entity = event.getWhoClicked(); - if (!(entity instanceof Player) || !PlotSquared.get() - .hasPlotArea(entity.getWorld().getName())) { - return; - } + HumanEntity entity = event.getWhoClicked(); + if (!(entity instanceof Player) || !PlotSquared.get() + .hasPlotArea(entity.getWorld().getName())) { + return; + } - HumanEntity clicker = event.getWhoClicked(); - if (!(clicker instanceof Player)) { - return; + HumanEntity clicker = event.getWhoClicked(); + if (!(clicker instanceof Player)) { + return; + } + Player player = (Player) clicker; + PlotPlayer pp = BukkitUtil.getPlayer(player); + final PlotInventory inventory = PlotInventory.getOpenPlotInventory(pp); + if (inventory != null && event.getRawSlot() == event.getSlot()) { + if (!inventory.onClick(event.getSlot())) { + event.setResult(Event.Result.DENY); + event.setCancelled(true); + inventory.close(); + } + } + PlayerInventory inv = player.getInventory(); + int slot = inv.getHeldItemSlot(); + if ((slot > 8) || !event.getEventName().equals("InventoryCreativeEvent")) { + return; + } + ItemStack current = inv.getItemInHand(); + ItemStack newItem = event.getCursor(); + ItemMeta newMeta = newItem.getItemMeta(); + ItemMeta oldMeta = newItem.getItemMeta(); + String newLore = ""; + if (newMeta != null) { + List lore = newMeta.getLore(); + if (lore != null) { + newLore = lore.toString(); + } + } + String oldLore = ""; + if (oldMeta != null) { + List lore = oldMeta.getLore(); + if (lore != null) { + oldLore = lore.toString(); + } + } + if (!"[(+NBT)]".equals(newLore) || (current.equals(newItem) && newLore.equals(oldLore))) { + switch (newItem.getType()) { + case LEGACY_BANNER: + case PLAYER_HEAD: + if (newMeta != null) { + break; + } + default: + return; + } + } + Block block = player.getTargetBlock(null, 7); + BlockState state = block.getState(); + if (state == null) { + return; + } + Material stateType = state.getType(); + Material itemType = newItem.getType(); + if (stateType != itemType) { + switch (stateType) { + case LEGACY_STANDING_BANNER: + case LEGACY_WALL_BANNER: + if (itemType == Material.LEGACY_BANNER) { + break; + } + case LEGACY_SKULL: + if (itemType == Material.LEGACY_SKULL_ITEM) { + break; + } + default: + return; + } + } + Location l = BukkitUtil.getLocation(state.getLocation()); + PlotArea area = l.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getPlotAbs(l); + boolean cancelled = false; + if (plot == null) { + if (!Permissions.hasPermission(pp, "plots.admin.interact.road")) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.road"); + cancelled = true; + } + } else if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, "plots.admin.interact.unowned")) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.unowned"); + cancelled = true; + } + } else { + UUID uuid = pp.getUUID(); + if (!plot.isAdded(uuid)) { + if (!Permissions.hasPermission(pp, "plots.admin.interact.other")) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.other"); + cancelled = true; } - Player player = (Player) clicker; - PlotPlayer pp = BukkitUtil.getPlayer(player); - final PlotInventory inventory = PlotInventory.getOpenPlotInventory(pp); - if (inventory != null && event.getRawSlot() == event.getSlot()) { - if (!inventory.onClick(event.getSlot())) { - event.setResult(Event.Result.DENY); - event.setCancelled(true); - inventory.close(); + } + } + if (cancelled) { + if ((current.getType() == newItem.getType()) && (current.getDurability() == newItem + .getDurability())) { + event.setCursor( + new ItemStack(newItem.getType(), newItem.getAmount(), newItem.getDurability())); + event.setCancelled(true); + return; + } + event.setCursor( + new ItemStack(newItem.getType(), newItem.getAmount(), newItem.getDurability())); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPotionSplash(LingeringPotionSplashEvent event) { + LingeringPotion entity = event.getEntity(); + Location l = BukkitUtil.getLocation(entity); + if (!PlotSquared.get().hasPlotArea(l.getWorld())) { + return; + } + if (!this.onProjectileHit(event)) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onInteract(PlayerInteractAtEntityEvent e) { + Entity entity = e.getRightClicked(); + if (!(entity instanceof ArmorStand)) { + return; + } + Location l = BukkitUtil.getLocation(e.getRightClicked().getLocation()); + PlotArea area = l.getPlotArea(); + if (area == null) { + return; + } + + EntitySpawnListener.test(entity); + + Plot plot = area.getPlotAbs(l); + PlotPlayer pp = BukkitUtil.getPlayer(e.getPlayer()); + if (plot == null) { + if (!Permissions.hasPermission(pp, "plots.admin.interact.road")) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.road"); + e.setCancelled(true); + } + } else if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, "plots.admin.interact.unowned")) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.unowned"); + e.setCancelled(true); + } + } else { + UUID uuid = pp.getUUID(); + if (!plot.isAdded(uuid)) { + if (Flags.MISC_INTERACT.isTrue(plot)) { + return; + } + if (!Permissions.hasPermission(pp, "plots.admin.interact.other")) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.other"); + e.setCancelled(true); + } + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBigBoom(BlockExplodeEvent event) { + Block block = event.getBlock(); + Location location = BukkitUtil.getLocation(block.getLocation()); + String world = location.getWorld(); + if (!PlotSquared.get().hasPlotArea(world)) { + return; + } + PlotArea area = location.getPlotArea(); + if (area == null) { + Iterator iterator = event.blockList().iterator(); + while (iterator.hasNext()) { + location = BukkitUtil.getLocation(iterator.next().getLocation()); + if (location.getPlotArea() != null) { + iterator.remove(); + } + } + return; + } + Plot plot = area.getOwnedPlot(location); + if (plot == null || !plot.getFlag(Flags.EXPLOSION).orElse(false)) { + event.setCancelled(true); + } + event.blockList().removeIf( + b -> !plot.equals(area.getOwnedPlot(BukkitUtil.getLocation(b.getLocation())))); + } + + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onInteract(PlayerInteractEvent event) { + Player player = event.getPlayer(); + PlotPlayer pp = BukkitUtil.getPlayer(player); + PlotArea area = pp.getPlotAreaAbs(); + if (area == null) { + return; + } + PlayerBlockEventType eventType = null; + BukkitLazyBlock lb; + Location location; + Action action = event.getAction(); + switch (action) { + case PHYSICAL: { + eventType = PlayerBlockEventType.TRIGGER_PHYSICAL; + Block block = event.getClickedBlock(); + lb = new BukkitLazyBlock(block); + location = BukkitUtil.getLocation(block.getLocation()); + break; + } + case RIGHT_CLICK_BLOCK: { + Block block = event.getClickedBlock(); + location = BukkitUtil.getLocation(block.getLocation()); + Material blockType = block.getType(); + switch (blockType) { + case ACACIA_DOOR: + case BIRCH_DOOR: + case DARK_OAK_DOOR: + case IRON_DOOR: + case JUNGLE_DOOR: + case OAK_DOOR: + case SPRUCE_DOOR: + + case ACACIA_TRAPDOOR: + case BIRCH_TRAPDOOR: + case DARK_OAK_TRAPDOOR: + case IRON_TRAPDOOR: + case JUNGLE_TRAPDOOR: + case OAK_TRAPDOOR: + case SPRUCE_TRAPDOOR: + + case CHEST: + case ENDER_CHEST: + case TRAPPED_CHEST: + + case ACACIA_FENCE_GATE: + case BIRCH_FENCE_GATE: + case DARK_OAK_FENCE_GATE: + case OAK_FENCE_GATE: + case JUNGLE_FENCE_GATE: + case SPRUCE_FENCE_GATE: + + case ACACIA_BUTTON: + case BIRCH_BUTTON: + case DARK_OAK_BUTTON: + case JUNGLE_BUTTON: + case OAK_BUTTON: + case SPRUCE_BUTTON: + case STONE_BUTTON: + + case BLACK_BED: + case BLUE_BED: + case BROWN_BED: + case CYAN_BED: + case GRAY_BED: + case GREEN_BED: + case LIGHT_BLUE_BED: + case LIGHT_GRAY_BED: + case LIME_BED: + case MAGENTA_BED: + case ORANGE_BED: + case PINK_BED: + case PURPLE_BED: + case RED_BED: + case WHITE_BED: + case YELLOW_BED: + + case BLACK_BANNER: + case BLACK_WALL_BANNER: + case BLUE_BANNER: + case BLUE_WALL_BANNER: + case BROWN_BANNER: + case BROWN_WALL_BANNER: + case CYAN_BANNER: + case CYAN_WALL_BANNER: + case GRAY_BANNER: + case GRAY_WALL_BANNER: + case GREEN_BANNER: + case GREEN_WALL_BANNER: + case LIGHT_BLUE_BANNER: + case LIGHT_BLUE_WALL_BANNER: + case LIGHT_GRAY_BANNER: + case LIGHT_GRAY_WALL_BANNER: + case LIME_BANNER: + case LIME_WALL_BANNER: + case MAGENTA_BANNER: + case MAGENTA_WALL_BANNER: + case ORANGE_BANNER: + case ORANGE_WALL_BANNER: + case PINK_BANNER: + case PINK_WALL_BANNER: + case PURPLE_BANNER: + case PURPLE_WALL_BANNER: + case RED_BANNER: + case RED_WALL_BANNER: + case WHITE_BANNER: + case WHITE_WALL_BANNER: + case YELLOW_BANNER: + case YELLOW_WALL_BANNER: + + case BLACK_SHULKER_BOX: + case BLUE_SHULKER_BOX: + case BROWN_SHULKER_BOX: + case CYAN_SHULKER_BOX: + case GRAY_SHULKER_BOX: + case GREEN_SHULKER_BOX: + case LIGHT_BLUE_SHULKER_BOX: + case LIGHT_GRAY_SHULKER_BOX: + case LIME_SHULKER_BOX: + case MAGENTA_SHULKER_BOX: + case ORANGE_SHULKER_BOX: + case PINK_SHULKER_BOX: + case PURPLE_SHULKER_BOX: + case RED_SHULKER_BOX: + case WHITE_SHULKER_BOX: + case YELLOW_SHULKER_BOX: + + case CHAIN_COMMAND_BLOCK: + case REPEATING_COMMAND_BLOCK: + + case SIGN: + case WALL_SIGN: + + case REDSTONE_TORCH: + case REDSTONE_WALL_TORCH: + + case TURTLE_EGG: + case TURTLE_HELMET: + case TURTLE_SPAWN_EGG: + + case ANVIL: + case BEACON: + case BREWING_STAND: + case CAKE: + case COMMAND_BLOCK: + case COMPARATOR: + case CRAFTING_TABLE: + case DISPENSER: + case DROPPER: + case ENCHANTING_TABLE: + case FURNACE: + case HOPPER: + case JUKEBOX: + case LEVER: + case NOTE_BLOCK: + case REDSTONE_ORE: + eventType = PlayerBlockEventType.INTERACT_BLOCK; + break; + case DRAGON_EGG: + eventType = PlayerBlockEventType.TELEPORT_OBJECT; + break; + default: + int blockId = ((LegacyPlotBlock) PlotSquared.get().IMP.getLegacyMappings() + .fromStringToLegacy(blockType.name())).id; + if (blockId > 197) { + eventType = PlayerBlockEventType.INTERACT_BLOCK; } + break; } - PlayerInventory inv = player.getInventory(); - int slot = inv.getHeldItemSlot(); - if ((slot > 8) || !event.getEventName().equals("InventoryCreativeEvent")) { - return; + lb = new BukkitLazyBlock(PlotBlock.get(block.getType().toString())); + ItemStack hand = player.getInventory().getItemInMainHand(); + if (eventType != null && (eventType != PlayerBlockEventType.INTERACT_BLOCK + || !player.isSneaking())) { + break; } - ItemStack current = inv.getItemInHand(); - ItemStack newItem = event.getCursor(); - ItemMeta newMeta = newItem.getItemMeta(); - ItemMeta oldMeta = newItem.getItemMeta(); - String newLore = ""; - if (newMeta != null) { - List lore = newMeta.getLore(); - if (lore != null) { - newLore = lore.toString(); - } + Material type = (hand == null) ? null : hand.getType(); + if (type == Material.AIR) { + eventType = PlayerBlockEventType.INTERACT_BLOCK; + break; } - String oldLore = ""; - if (oldMeta != null) { - List lore = oldMeta.getLore(); - if (lore != null) { - oldLore = lore.toString(); - } + if (type == null || type.isBlock()) { + location = BukkitUtil + .getLocation(block.getRelative(event.getBlockFace()).getLocation()); + eventType = PlayerBlockEventType.PLACE_BLOCK; + break; } - if (!"[(+NBT)]".equals(newLore) || (current.equals(newItem) && newLore.equals(oldLore))) { - switch (newItem.getType()) { - case LEGACY_BANNER: - case PLAYER_HEAD: - if (newMeta != null) - break; - default: - return; - } - } - Block block = player.getTargetBlock(null, 7); - BlockState state = block.getState(); - if (state == null) { - return; - } - Material stateType = state.getType(); - Material itemType = newItem.getType(); - if (stateType != itemType) { - switch (stateType) { - case LEGACY_STANDING_BANNER: - case LEGACY_WALL_BANNER: - if (itemType == Material.LEGACY_BANNER) - break; - case LEGACY_SKULL: - if (itemType == Material.LEGACY_SKULL_ITEM) - break; - default: - return; - } - } - Location l = BukkitUtil.getLocation(state.getLocation()); - PlotArea area = l.getPlotArea(); - if (area == null) { - return; - } - Plot plot = area.getPlotAbs(l); - boolean cancelled = false; - if (plot == null) { - if (!Permissions.hasPermission(pp, "plots.admin.interact.road")) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.road"); - cancelled = true; - } - } else if (!plot.hasOwner()) { - if (!Permissions.hasPermission(pp, "plots.admin.interact.unowned")) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.unowned"); - cancelled = true; - } + Material handType = hand.getType(); + lb = new BukkitLazyBlock(PlotBlock.get(handType.toString())); + if (handType.toString().endsWith("egg")) { + eventType = PlayerBlockEventType.SPAWN_MOB; } else { - UUID uuid = pp.getUUID(); - if (!plot.isAdded(uuid)) { - if (!Permissions.hasPermission(pp, "plots.admin.interact.other")) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.other"); - cancelled = true; - } - } - } - if (cancelled) { - if ((current.getType() == newItem.getType()) && (current.getDurability() == newItem - .getDurability())) { - event.setCursor( - new ItemStack(newItem.getType(), newItem.getAmount(), newItem.getDurability())); - event.setCancelled(true); - return; - } - event.setCursor( - new ItemStack(newItem.getType(), newItem.getAmount(), newItem.getDurability())); - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onPotionSplash(LingeringPotionSplashEvent event) { - LingeringPotion entity = event.getEntity(); - Location l = BukkitUtil.getLocation(entity); - if (!PlotSquared.get().hasPlotArea(l.getWorld())) { - return; - } - if (!this.onProjectileHit(event)) { - event.setCancelled(true); - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onInteract(PlayerInteractAtEntityEvent e) { - Entity entity = e.getRightClicked(); - if (!(entity instanceof ArmorStand)) { - return; - } - Location l = BukkitUtil.getLocation(e.getRightClicked().getLocation()); - PlotArea area = l.getPlotArea(); - if (area == null) { - return; - } - - EntitySpawnListener.test(entity); - - Plot plot = area.getPlotAbs(l); - PlotPlayer pp = BukkitUtil.getPlayer(e.getPlayer()); - if (plot == null) { - if (!Permissions.hasPermission(pp, "plots.admin.interact.road")) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.road"); - e.setCancelled(true); - } - } else if (!plot.hasOwner()) { - if (!Permissions.hasPermission(pp, "plots.admin.interact.unowned")) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.unowned"); - e.setCancelled(true); - } - } else { - UUID uuid = pp.getUUID(); - if (!plot.isAdded(uuid)) { - if (Flags.MISC_INTERACT.isTrue(plot)) { - return; - } - if (!Permissions.hasPermission(pp, "plots.admin.interact.other")) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.interact.other"); - e.setCancelled(true); - } - } - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBigBoom(BlockExplodeEvent event) { - Block block = event.getBlock(); - Location location = BukkitUtil.getLocation(block.getLocation()); - String world = location.getWorld(); - if (!PlotSquared.get().hasPlotArea(world)) { - return; - } - PlotArea area = location.getPlotArea(); - if (area == null) { - Iterator iterator = event.blockList().iterator(); - while (iterator.hasNext()) { - location = BukkitUtil.getLocation(iterator.next().getLocation()); - if (location.getPlotArea() != null) { - iterator.remove(); - } - } - return; - } - Plot plot = area.getOwnedPlot(location); - if (plot == null || !plot.getFlag(Flags.EXPLOSION).orElse(false)) { - event.setCancelled(true); - } - event.blockList().removeIf( - b -> !plot.equals(area.getOwnedPlot(BukkitUtil.getLocation(b.getLocation())))); - } - - @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) - public void onInteract(PlayerInteractEvent event) { - Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); - PlotArea area = pp.getPlotAreaAbs(); - if (area == null) { - return; - } - PlayerBlockEventType eventType = null; - BukkitLazyBlock lb; - Location location; - Action action = event.getAction(); - switch (action) { - case PHYSICAL: { - eventType = PlayerBlockEventType.TRIGGER_PHYSICAL; - Block block = event.getClickedBlock(); - lb = new BukkitLazyBlock(block); - location = BukkitUtil.getLocation(block.getLocation()); - break; - } - case RIGHT_CLICK_BLOCK: { - Block block = event.getClickedBlock(); - location = BukkitUtil.getLocation(block.getLocation()); - Material blockType = block.getType(); - switch (blockType) { - case ACACIA_DOOR: - case BIRCH_DOOR: - case DARK_OAK_DOOR: - case IRON_DOOR: - case JUNGLE_DOOR: - case OAK_DOOR: - case SPRUCE_DOOR: - - case ACACIA_TRAPDOOR: - case BIRCH_TRAPDOOR: - case DARK_OAK_TRAPDOOR: - case IRON_TRAPDOOR: - case JUNGLE_TRAPDOOR: - case OAK_TRAPDOOR: - case SPRUCE_TRAPDOOR: - - case CHEST: - case ENDER_CHEST: - case TRAPPED_CHEST: - - case ACACIA_FENCE_GATE: - case BIRCH_FENCE_GATE: - case DARK_OAK_FENCE_GATE: - case OAK_FENCE_GATE: - case JUNGLE_FENCE_GATE: - case SPRUCE_FENCE_GATE: - - case ACACIA_BUTTON: - case BIRCH_BUTTON: - case DARK_OAK_BUTTON: - case JUNGLE_BUTTON: - case OAK_BUTTON: - case SPRUCE_BUTTON: - case STONE_BUTTON: - - case BLACK_BED: - case BLUE_BED: - case BROWN_BED: - case CYAN_BED: - case GRAY_BED: - case GREEN_BED: - case LIGHT_BLUE_BED: - case LIGHT_GRAY_BED: - case LIME_BED: - case MAGENTA_BED: - case ORANGE_BED: - case PINK_BED: - case PURPLE_BED: - case RED_BED: - case WHITE_BED: - case YELLOW_BED: - - case BLACK_BANNER: - case BLACK_WALL_BANNER: - case BLUE_BANNER: - case BLUE_WALL_BANNER: - case BROWN_BANNER: - case BROWN_WALL_BANNER: - case CYAN_BANNER: - case CYAN_WALL_BANNER: - case GRAY_BANNER: - case GRAY_WALL_BANNER: - case GREEN_BANNER: - case GREEN_WALL_BANNER: - case LIGHT_BLUE_BANNER: - case LIGHT_BLUE_WALL_BANNER: - case LIGHT_GRAY_BANNER: - case LIGHT_GRAY_WALL_BANNER: - case LIME_BANNER: - case LIME_WALL_BANNER: - case MAGENTA_BANNER: - case MAGENTA_WALL_BANNER: - case ORANGE_BANNER: - case ORANGE_WALL_BANNER: - case PINK_BANNER: - case PINK_WALL_BANNER: - case PURPLE_BANNER: - case PURPLE_WALL_BANNER: - case RED_BANNER: - case RED_WALL_BANNER: - case WHITE_BANNER: - case WHITE_WALL_BANNER: - case YELLOW_BANNER: - case YELLOW_WALL_BANNER: - - case BLACK_SHULKER_BOX: - case BLUE_SHULKER_BOX: - case BROWN_SHULKER_BOX: - case CYAN_SHULKER_BOX: - case GRAY_SHULKER_BOX: - case GREEN_SHULKER_BOX: - case LIGHT_BLUE_SHULKER_BOX: - case LIGHT_GRAY_SHULKER_BOX: - case LIME_SHULKER_BOX: - case MAGENTA_SHULKER_BOX: - case ORANGE_SHULKER_BOX: - case PINK_SHULKER_BOX: - case PURPLE_SHULKER_BOX: - case RED_SHULKER_BOX: - case WHITE_SHULKER_BOX: - case YELLOW_SHULKER_BOX: - - case CHAIN_COMMAND_BLOCK: - case REPEATING_COMMAND_BLOCK: - - case SIGN: - case WALL_SIGN: - - case REDSTONE_TORCH: - case REDSTONE_WALL_TORCH: - - case TURTLE_EGG: - case TURTLE_HELMET: - case TURTLE_SPAWN_EGG: - - case ANVIL: - case BEACON: - case BREWING_STAND: - case CAKE: - case COMMAND_BLOCK: - case COMPARATOR: - case CRAFTING_TABLE: - case DISPENSER: - case DROPPER: - case ENCHANTING_TABLE: - case FURNACE: - case HOPPER: - case JUKEBOX: - case LEVER: - case NOTE_BLOCK: - case REDSTONE_ORE: - eventType = PlayerBlockEventType.INTERACT_BLOCK; - break; - case DRAGON_EGG: - eventType = PlayerBlockEventType.TELEPORT_OBJECT; - break; - default: - int blockId = ((LegacyPlotBlock) PlotSquared.get().IMP.getLegacyMappings() - .fromStringToLegacy(blockType.name())).id; - if (blockId > 197) { - eventType = PlayerBlockEventType.INTERACT_BLOCK; - } - break; - } - lb = new BukkitLazyBlock(PlotBlock.get(block.getType().toString())); - ItemStack hand = player.getInventory().getItemInMainHand(); - if (eventType != null && (eventType != PlayerBlockEventType.INTERACT_BLOCK - || !player.isSneaking())) { - break; - } - Material type = (hand == null) ? null : hand.getType(); - if (type == Material.AIR) { - eventType = PlayerBlockEventType.INTERACT_BLOCK; - break; - } - if (type == null || type.isBlock()) { - location = BukkitUtil - .getLocation(block.getRelative(event.getBlockFace()).getLocation()); - eventType = PlayerBlockEventType.PLACE_BLOCK; - break; - } - Material handType = hand.getType(); - lb = new BukkitLazyBlock(PlotBlock.get(handType.toString())); - if (handType.toString().endsWith("egg")) { - eventType = PlayerBlockEventType.SPAWN_MOB; - } else { - switch (handType) { - case FIREWORK_ROCKET: - case FIREWORK_STAR: - eventType = PlayerBlockEventType.SPAWN_MOB; - break; - case ARMOR_STAND: - location = BukkitUtil - .getLocation(block.getRelative(event.getBlockFace()).getLocation()); - eventType = PlayerBlockEventType.PLACE_MISC; - break; - case BOOK: - case ENCHANTED_BOOK: - case KNOWLEDGE_BOOK: - case WRITABLE_BOOK: - case WRITTEN_BOOK: - eventType = PlayerBlockEventType.READ; - break; - case APPLE: - case BAKED_POTATO: - case BEEF: - case BREAD: - case CARROT: - case CHICKEN: - case COD: - case COOKED_BEEF: - case COOKED_CHICKEN: - case COOKED_COD: - case COOKED_MUTTON: - case COOKED_PORKCHOP: - case COOKED_RABBIT: - case COOKED_SALMON: - case COOKIE: - case GOLDEN_CARROT: - case MUSHROOM_STEW: - case MUTTON: - case POISONOUS_POTATO: - case PORKCHOP: - case POTATO: - case POTION: - case PUFFERFISH: - case PUMPKIN_PIE: - case RABBIT: - case RABBIT_FOOT: - case RABBIT_STEW: - case SALMON: - case TROPICAL_FISH: - eventType = PlayerBlockEventType.EAT; - break; - case ACACIA_BOAT: - case BIRCH_BOAT: - case CHEST_MINECART: - case COMMAND_BLOCK_MINECART: - case DARK_OAK_BOAT: - case FURNACE_MINECART: - case HOPPER_MINECART: - case JUNGLE_BOAT: - case MINECART: - case OAK_BOAT: - case SPRUCE_BOAT: - case TNT_MINECART: - eventType = PlayerBlockEventType.PLACE_VEHICLE; - break; - case ITEM_FRAME: - case PAINTING: - location = BukkitUtil - .getLocation(block.getRelative(event.getBlockFace()).getLocation()); - eventType = PlayerBlockEventType.PLACE_HANGING; - break; - default: - eventType = PlayerBlockEventType.INTERACT_BLOCK; - break; - } - } - break; - } - case LEFT_CLICK_BLOCK: - Block block = event.getClickedBlock(); - location = BukkitUtil.getLocation(block.getLocation()); - eventType = PlayerBlockEventType.BREAK_BLOCK; - lb = new BukkitLazyBlock(block); - break; + switch (handType) { + case FIREWORK_ROCKET: + case FIREWORK_STAR: + eventType = PlayerBlockEventType.SPAWN_MOB; + break; + case ARMOR_STAND: + location = BukkitUtil + .getLocation(block.getRelative(event.getBlockFace()).getLocation()); + eventType = PlayerBlockEventType.PLACE_MISC; + break; + case BOOK: + case ENCHANTED_BOOK: + case KNOWLEDGE_BOOK: + case WRITABLE_BOOK: + case WRITTEN_BOOK: + eventType = PlayerBlockEventType.READ; + break; + case APPLE: + case BAKED_POTATO: + case BEEF: + case BREAD: + case CARROT: + case CHICKEN: + case COD: + case COOKED_BEEF: + case COOKED_CHICKEN: + case COOKED_COD: + case COOKED_MUTTON: + case COOKED_PORKCHOP: + case COOKED_RABBIT: + case COOKED_SALMON: + case COOKIE: + case GOLDEN_CARROT: + case MUSHROOM_STEW: + case MUTTON: + case POISONOUS_POTATO: + case PORKCHOP: + case POTATO: + case POTION: + case PUFFERFISH: + case PUMPKIN_PIE: + case RABBIT: + case RABBIT_FOOT: + case RABBIT_STEW: + case SALMON: + case TROPICAL_FISH: + eventType = PlayerBlockEventType.EAT; + break; + case ACACIA_BOAT: + case BIRCH_BOAT: + case CHEST_MINECART: + case COMMAND_BLOCK_MINECART: + case DARK_OAK_BOAT: + case FURNACE_MINECART: + case HOPPER_MINECART: + case JUNGLE_BOAT: + case MINECART: + case OAK_BOAT: + case SPRUCE_BOAT: + case TNT_MINECART: + eventType = PlayerBlockEventType.PLACE_VEHICLE; + break; + case ITEM_FRAME: + case PAINTING: + location = BukkitUtil + .getLocation(block.getRelative(event.getBlockFace()).getLocation()); + eventType = PlayerBlockEventType.PLACE_HANGING; + break; default: - return; + eventType = PlayerBlockEventType.INTERACT_BLOCK; + break; + } } - if (PlotSquared.get().worldedit != null && pp.getAttribute("worldedit")) { - if (player.getInventory().getItemInMainHand().getType() == Material - .getMaterial(PlotSquared.get().worldedit.getConfiguration().wandItem)) { - return; - } + break; + } + case LEFT_CLICK_BLOCK: + Block block = event.getClickedBlock(); + location = BukkitUtil.getLocation(block.getLocation()); + eventType = PlayerBlockEventType.BREAK_BLOCK; + lb = new BukkitLazyBlock(block); + break; + default: + return; + } + if (PlotSquared.get().worldedit != null && pp.getAttribute("worldedit")) { + if (player.getInventory().getItemInMainHand().getType() == Material + .getMaterial(PlotSquared.get().worldedit.getConfiguration().wandItem)) { + return; + } + } + if (!EventUtil.manager.checkPlayerBlockEvent(pp, eventType, location, lb, true)) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void creatureSpawnEvent(CreatureSpawnEvent event) { + Entity entity = event.getEntity(); + Location location = BukkitUtil.getLocation(entity.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + CreatureSpawnEvent.SpawnReason reason = event.getSpawnReason(); + //TODO needs an overhaul for the increased number of spawn reasons added to this event. + //I can't believe they waited so damn long to expand this API set. + switch (reason) { + case DISPENSE_EGG: + case EGG: + case OCELOT_BABY: + case SPAWNER_EGG: + if (!area.SPAWN_EGGS) { + event.setCancelled(true); + return; } - if (!EventUtil.manager.checkPlayerBlockEvent(pp, eventType, location, lb, true)) { - event.setCancelled(true); + break; + case REINFORCEMENTS: + case NATURAL: + case CHUNK_GEN: + if (!area.MOB_SPAWNING) { + event.setCancelled(true); + return; } + case BREEDING: + if (!area.SPAWN_BREEDING) { + event.setCancelled(true); + return; + } + break; + case BUILD_IRONGOLEM: + case BUILD_SNOWMAN: + case BUILD_WITHER: + case CUSTOM: + if (!area.SPAWN_CUSTOM && entity.getType() != EntityType.ARMOR_STAND) { + event.setCancelled(true); + return; + } + break; + case SPAWNER: + if (!area.MOB_SPAWNER_SPAWNING) { + event.setCancelled(true); + return; + } + break; + } + Plot plot = area.getOwnedPlotAbs(location); + if (plot == null) { + if (!area.MOB_SPAWNING) { + event.setCancelled(true); + } + return; + } + if (checkEntity(entity, plot)) { + event.setCancelled(true); + } + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) + public void onEntityFall(EntityChangeBlockEvent event) { + if (event.getEntityType() != EntityType.FALLING_BLOCK) { + return; + } + Block block = event.getBlock(); + World world = block.getWorld(); + String worldName = world.getName(); + if (!PlotSquared.get().hasPlotArea(worldName)) { + return; + } + Location location = BukkitUtil.getLocation(block.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlotAbs(location); + if (plot == null || plot.getFlag(Flags.DISABLE_PHYSICS, false)) { + event.setCancelled(true); + return; + } + if (event.getTo().hasGravity()) { + Entity entity = event.getEntity(); + List meta = entity.getMetadata("plot"); + if (meta.isEmpty()) { + return; + } + Plot origin = (Plot) meta.get(0).value(); + if (origin != null && !origin.equals(plot)) { + event.setCancelled(true); + entity.remove(); + } + } else if (event.getTo() == Material.AIR) { + event.getEntity() + .setMetadata("plot", new FixedMetadataValue((Plugin) PlotSquared.get().IMP, plot)); + } + } + + @EventHandler + public void onPrime(ExplosionPrimeEvent event) { + this.lastRadius = event.getRadius() + 1; + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockBurn(BlockBurnEvent event) { + Block b = event.getBlock(); + Location location = BukkitUtil.getLocation(b.getLocation()); + + PlotArea area = location.getPlotArea(); + if (area == null) { + return; } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void creatureSpawnEvent(CreatureSpawnEvent event) { - Entity entity = event.getEntity(); - Location location = BukkitUtil.getLocation(entity.getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - CreatureSpawnEvent.SpawnReason reason = event.getSpawnReason(); - //TODO needs an overhaul for the increased number of spawn reasons added to this event. - //I can't believe they waited so damn long to expand this API set. - switch (reason) { - case DISPENSE_EGG: - case EGG: - case OCELOT_BABY: - case SPAWNER_EGG: - if (!area.SPAWN_EGGS) { - event.setCancelled(true); - return; - } - break; - case REINFORCEMENTS: - case NATURAL: - case CHUNK_GEN: - if (!area.MOB_SPAWNING) { - event.setCancelled(true); - return; - } - case BREEDING: - if (!area.SPAWN_BREEDING) { - event.setCancelled(true); - return; - } - break; - case BUILD_IRONGOLEM: - case BUILD_SNOWMAN: - case BUILD_WITHER: - case CUSTOM: - if (!area.SPAWN_CUSTOM && entity.getType() != EntityType.ARMOR_STAND) { - event.setCancelled(true); - return; - } - break; - case SPAWNER: - if (!area.MOB_SPAWNER_SPAWNING) { - event.setCancelled(true); - return; - } - break; - } - Plot plot = area.getOwnedPlotAbs(location); - if (plot == null) { - if (!area.MOB_SPAWNING) { - event.setCancelled(true); - } - return; - } - if (checkEntity(entity, plot)) { - event.setCancelled(true); - } + Plot plot = location.getOwnedPlot(); + if (plot == null || !plot.getFlag(Flags.BLOCK_BURN, false)) { + event.setCancelled(true); + return; } - @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) - public void onEntityFall(EntityChangeBlockEvent event) { - if (event.getEntityType() != EntityType.FALLING_BLOCK) { - return; - } - Block block = event.getBlock(); - World world = block.getWorld(); - String worldName = world.getName(); - if (!PlotSquared.get().hasPlotArea(worldName)) { - return; - } - Location location = BukkitUtil.getLocation(block.getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Plot plot = area.getOwnedPlotAbs(location); - if (plot == null || plot.getFlag(Flags.DISABLE_PHYSICS, false)) { - event.setCancelled(true); - return; - } - if (event.getTo().hasGravity()) { - Entity entity = event.getEntity(); - List meta = entity.getMetadata("plot"); - if (meta.isEmpty()) { - return; - } - Plot origin = (Plot) meta.get(0).value(); - if (origin != null && !origin.equals(plot)) { - event.setCancelled(true); - entity.remove(); - } - } else if (event.getTo() == Material.AIR) { - event.getEntity() - .setMetadata("plot", new FixedMetadataValue((Plugin) PlotSquared.get().IMP, plot)); - } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockIgnite(BlockIgniteEvent event) { + Player player = event.getPlayer(); + Entity ignitingEntity = event.getIgnitingEntity(); + Block block = event.getBlock(); + BlockIgniteEvent.IgniteCause igniteCause = event.getCause(); + Location loc; + if (block != null) { + loc = BukkitUtil.getLocation(block.getLocation()); + } else if (ignitingEntity != null) { + loc = BukkitUtil.getLocation(ignitingEntity); + } else if (player != null) { + loc = BukkitUtil.getLocation(player); + } else { + return; + } + PlotArea area = loc.getPlotArea(); + if (area == null) { + return; + } + if (igniteCause == BlockIgniteEvent.IgniteCause.LIGHTNING) { + event.setCancelled(true); + return; } - @EventHandler public void onPrime(ExplosionPrimeEvent event) { - this.lastRadius = event.getRadius() + 1; + Plot plot = area.getOwnedPlotAbs(loc); + if (player != null) { + PlotPlayer pp = BukkitUtil.getPlayer(player); + if (plot == null) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_ROAD)) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_ROAD); + event.setCancelled(true); + } + } else if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_UNOWNED)) { + MainUtil + .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_UNOWNED); + event.setCancelled(true); + } + } else if (!plot.isAdded(pp.getUUID())) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); + event.setCancelled(true); + } + } else if (Flags.BLOCK_IGNITION.isFalse(plot)) { + event.setCancelled(true); + } + } else { + if (plot == null) { + event.setCancelled(true); + return; + } + if (ignitingEntity != null) { + if (!plot.getFlag(Flags.BLOCK_IGNITION, false)) { + event.setCancelled(true); + return; + } + if (igniteCause == BlockIgniteEvent.IgniteCause.FIREBALL) { + if (ignitingEntity instanceof Fireball) { + Projectile fireball = (Projectile) ignitingEntity; + Location location = null; + if (fireball.getShooter() instanceof Entity) { + Entity shooter = (Entity) fireball.getShooter(); + location = BukkitUtil.getLocation(shooter.getLocation()); + } else if (fireball.getShooter() instanceof BlockProjectileSource) { + Block shooter = + ((BlockProjectileSource) fireball.getShooter()).getBlock(); + location = BukkitUtil.getLocation(shooter.getLocation()); + } + if (location != null && !plot.equals(location.getPlot())) { + event.setCancelled(true); + } + } + } + + } else if (event.getIgnitingBlock() != null) { + Block ignitingBlock = event.getIgnitingBlock(); + Plot plotIgnited = BukkitUtil.getLocation(ignitingBlock.getLocation()).getPlot(); + if (igniteCause == BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL && ( + !plot.getFlag(Flags.BLOCK_IGNITION, false) || plotIgnited == null + || !plotIgnited.equals(plot)) || + (igniteCause == BlockIgniteEvent.IgniteCause.SPREAD + || igniteCause == BlockIgniteEvent.IgniteCause.LAVA) && ( + !plot.getFlag(Flags.BLOCK_IGNITION).orElse(false) || plotIgnited == null + || !plotIgnited.equals(plot))) { + event.setCancelled(true); + } + } } + } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockBurn(BlockBurnEvent event) { - Block b = event.getBlock(); - Location location = BukkitUtil.getLocation(b.getLocation()); - - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - - Plot plot = location.getOwnedPlot(); - if (plot == null || !plot.getFlag(Flags.BLOCK_BURN, false)) { - event.setCancelled(true); - return; - } - + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBucketEmpty(PlayerBucketEmptyEvent event) { + BlockFace bf = event.getBlockFace(); + Block b = + event.getBlockClicked().getLocation().add(bf.getModX(), bf.getModY(), bf.getModZ()) + .getBlock(); + Location location = BukkitUtil.getLocation(b.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockIgnite(BlockIgniteEvent event) { - Player player = event.getPlayer(); - Entity ignitingEntity = event.getIgnitingEntity(); - Block block = event.getBlock(); - BlockIgniteEvent.IgniteCause igniteCause = event.getCause(); - Location loc; - if (block != null) { - loc = BukkitUtil.getLocation(block.getLocation()); - } else if (ignitingEntity != null) { - loc = BukkitUtil.getLocation(ignitingEntity); - } else if (player != null) { - loc = BukkitUtil.getLocation(player); - } else { - return; - } - PlotArea area = loc.getPlotArea(); - if (area == null) { - return; - } - if (igniteCause == BlockIgniteEvent.IgniteCause.LIGHTNING) { - event.setCancelled(true); - return; - } - - Plot plot = area.getOwnedPlotAbs(loc); - if (player != null) { - PlotPlayer pp = BukkitUtil.getPlayer(player); - if (plot == null) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_ROAD)) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_ROAD); - event.setCancelled(true); - } - } else if (!plot.hasOwner()) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_UNOWNED)) { - MainUtil - .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_UNOWNED); - event.setCancelled(true); - } - } else if (!plot.isAdded(pp.getUUID())) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); - event.setCancelled(true); - } - } else if (Flags.BLOCK_IGNITION.isFalse(plot)) { - event.setCancelled(true); - } - } else { - if (plot == null) { - event.setCancelled(true); - return; - } - if (ignitingEntity != null) { - if (!plot.getFlag(Flags.BLOCK_IGNITION, false)) { - event.setCancelled(true); - return; - } - if (igniteCause == BlockIgniteEvent.IgniteCause.FIREBALL) { - if (ignitingEntity instanceof Fireball) { - Projectile fireball = (Projectile) ignitingEntity; - Location location = null; - if (fireball.getShooter() instanceof Entity) { - Entity shooter = (Entity) fireball.getShooter(); - location = BukkitUtil.getLocation(shooter.getLocation()); - } else if (fireball.getShooter() instanceof BlockProjectileSource) { - Block shooter = - ((BlockProjectileSource) fireball.getShooter()).getBlock(); - location = BukkitUtil.getLocation(shooter.getLocation()); - } - if (location != null && !plot.equals(location.getPlot())) { - event.setCancelled(true); - } - } - } - - } else if (event.getIgnitingBlock() != null) { - Block ignitingBlock = event.getIgnitingBlock(); - Plot plotIgnited = BukkitUtil.getLocation(ignitingBlock.getLocation()).getPlot(); - if (igniteCause == BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL && ( - !plot.getFlag(Flags.BLOCK_IGNITION, false) || plotIgnited == null - || !plotIgnited.equals(plot)) || - (igniteCause == BlockIgniteEvent.IgniteCause.SPREAD - || igniteCause == BlockIgniteEvent.IgniteCause.LAVA) && ( - !plot.getFlag(Flags.BLOCK_IGNITION).orElse(false) || plotIgnited == null - || !plotIgnited.equals(plot))) { - event.setCancelled(true); - } - } - } + PlotPlayer pp = BukkitUtil.getPlayer(event.getPlayer()); + Plot plot = area.getPlot(location); + if (plot == null) { + if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_ROAD)) { + return; + } + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_ROAD); + event.setCancelled(true); + } else if (!plot.hasOwner()) { + if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_UNOWNED)) { + return; + } + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_UNOWNED); + event.setCancelled(true); + } else if (!plot.isAdded(pp.getUUID())) { + if (Flags.USE.contains(plot, PlotBlock.get(event.getBucket().getId(), 0))) { + return; + } + if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) { + return; + } + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); + event.setCancelled(true); + } else if (Settings.Done.RESTRICT_BUILDING && plot.getFlags().containsKey(Flags.DONE)) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); + event.setCancelled(true); + } } + } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBucketEmpty(PlayerBucketEmptyEvent event) { - BlockFace bf = event.getBlockFace(); - Block b = - event.getBlockClicked().getLocation().add(bf.getModX(), bf.getModY(), bf.getModZ()) - .getBlock(); - Location location = BukkitUtil.getLocation(b.getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - PlotPlayer pp = BukkitUtil.getPlayer(event.getPlayer()); - Plot plot = area.getPlot(location); - if (plot == null) { - if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_ROAD)) { - return; - } - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_ROAD); - event.setCancelled(true); - } else if (!plot.hasOwner()) { - if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_UNOWNED)) { - return; - } - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_UNOWNED); - event.setCancelled(true); - } else if (!plot.isAdded(pp.getUUID())) { - if (Flags.USE.contains(plot, PlotBlock.get(event.getBucket().getId(), 0))) { - return; - } - if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) { - return; - } - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); - event.setCancelled(true); - } else if (Settings.Done.RESTRICT_BUILDING && plot.getFlags().containsKey(Flags.DONE)) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); - event.setCancelled(true); - } - } + @EventHandler(priority = EventPriority.HIGHEST) + public void onInventoryClose(InventoryCloseEvent event) { + HumanEntity closer = event.getPlayer(); + if (!(closer instanceof Player)) { + return; } + Player player = (Player) closer; + PlotInventory.removePlotInventoryOpen(BukkitUtil.getPlayer(player)); + } - @EventHandler(priority = EventPriority.HIGHEST) - public void onInventoryClose(InventoryCloseEvent event) { - HumanEntity closer = event.getPlayer(); - if (!(closer instanceof Player)) { - return; - } - Player player = (Player) closer; - PlotInventory.removePlotInventoryOpen(BukkitUtil.getPlayer(player)); + @EventHandler(priority = EventPriority.MONITOR) + public void onLeave(PlayerQuitEvent event) { + TaskManager.TELEPORT_QUEUE.remove(event.getPlayer().getName()); + PlotPlayer pp = BukkitUtil.getPlayer(event.getPlayer()); + pp.unregister(); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBucketFill(PlayerBucketFillEvent event) { + Block b = event.getBlockClicked(); + Location location = BukkitUtil.getLocation(b.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; } - - @EventHandler(priority = EventPriority.MONITOR) public void onLeave(PlayerQuitEvent event) { - TaskManager.TELEPORT_QUEUE.remove(event.getPlayer().getName()); - PlotPlayer pp = BukkitUtil.getPlayer(event.getPlayer()); - pp.unregister(); + Player player = event.getPlayer(); + PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + Plot plot = area.getPlot(location); + if (plot == null) { + if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_BUILD_ROAD)) { + return; + } + MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_ROAD); + event.setCancelled(true); + } else if (!plot.hasOwner()) { + if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_BUILD_UNOWNED)) { + return; + } + MainUtil + .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_UNOWNED); + event.setCancelled(true); + } else if (!plot.isAdded(plotPlayer.getUUID())) { + Optional> use = plot.getFlag(Flags.USE); + Block block = event.getBlockClicked(); + if (use.isPresent() && use.get().contains(PlotBlock.get(block.getType().name()))) { + return; + } + if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_BUILD_OTHER)) { + return; + } + MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); + event.setCancelled(true); + } else if (Settings.Done.RESTRICT_BUILDING && plot.getFlags().containsKey(Flags.DONE)) { + if (!Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_BUILD_OTHER)) { + MainUtil + .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); + event.setCancelled(true); + } } + } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBucketFill(PlayerBucketFillEvent event) { - Block b = event.getBlockClicked(); - Location location = BukkitUtil.getLocation(b.getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onVehicleCreate(VehicleCreateEvent event) { + Vehicle entity = event.getVehicle(); + Location location = BukkitUtil.getLocation(entity); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Plot plot = area.getOwnedPlotAbs(location); + if (plot == null || checkEntity(entity, plot)) { + entity.remove(); + return; + } + if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) { + entity + .setMetadata("plot", new FixedMetadataValue((Plugin) PlotSquared.get().IMP, plot)); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onHangingPlace(HangingPlaceEvent event) { + Block b = event.getBlock().getRelative(event.getBlockFace()); + Location location = BukkitUtil.getLocation(b.getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Player p = event.getPlayer(); + PlotPlayer pp = BukkitUtil.getPlayer(p); + Plot plot = area.getPlot(location); + if (plot == null) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_ROAD)) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_ROAD); + event.setCancelled(true); + } + } else { + if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_UNOWNED)) { + MainUtil + .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_UNOWNED); + event.setCancelled(true); } - Player player = event.getPlayer(); - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); - Plot plot = area.getPlot(location); - if (plot == null) { - if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_BUILD_ROAD)) { - return; - } - MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_ROAD); - event.setCancelled(true); - } else if (!plot.hasOwner()) { - if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_BUILD_UNOWNED)) { - return; - } + return; + } + if (!plot.isAdded(pp.getUUID())) { + if (!plot.getFlag(Flags.HANGING_PLACE, false)) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) { MainUtil - .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_UNOWNED); + .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); event.setCancelled(true); - } else if (!plot.isAdded(plotPlayer.getUUID())) { - Optional> use = plot.getFlag(Flags.USE); - Block block = event.getBlockClicked(); - if (use.isPresent() && use.get().contains(PlotBlock.get(block.getType().name()))) { - return; - } - if (Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_BUILD_OTHER)) { - return; - } - MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); - event.setCancelled(true); - } else if (Settings.Done.RESTRICT_BUILDING && plot.getFlags().containsKey(Flags.DONE)) { - if (!Permissions.hasPermission(plotPlayer, C.PERMISSION_ADMIN_BUILD_OTHER)) { - MainUtil - .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); - event.setCancelled(true); - } + } + return; } - } + } + if (checkEntity(event.getEntity(), plot)) { + event.setCancelled(true); + } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onVehicleCreate(VehicleCreateEvent event) { - Vehicle entity = event.getVehicle(); - Location location = BukkitUtil.getLocation(entity); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onHangingBreakByEntity(HangingBreakByEntityEvent event) { + Entity remover = event.getRemover(); + if (remover instanceof Player) { + Player p = (Player) remover; + Location location = BukkitUtil.getLocation(event.getEntity()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + PlotPlayer pp = BukkitUtil.getPlayer(p); + Plot plot = area.getPlot(location); + if (plot == null) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_DESTROY_ROAD)) { + MainUtil + .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_DESTROY_ROAD); + event.setCancelled(true); + } + } else if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_DESTROY_UNOWNED)) { + MainUtil + .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_DESTROY_UNOWNED); + event.setCancelled(true); + } + } else if (!plot.isAdded(pp.getUUID())) { + if (plot.getFlag(Flags.HANGING_BREAK, false)) { + return; + } + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_DESTROY_OTHER)) { + MainUtil + .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_DESTROY_OTHER); + event.setCancelled(true); + } + } + } else if (remover instanceof Projectile) { + Projectile p = (Projectile) remover; + if (p.getShooter() instanceof Player) { + Player shooter = (Player) p.getShooter(); + Location location = BukkitUtil.getLocation(event.getEntity()); PlotArea area = location.getPlotArea(); if (area == null) { - return; + return; } - Plot plot = area.getOwnedPlotAbs(location); - if (plot == null || checkEntity(entity, plot)) { - entity.remove(); - return; - } - if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) { - entity - .setMetadata("plot", new FixedMetadataValue((Plugin) PlotSquared.get().IMP, plot)); - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onHangingPlace(HangingPlaceEvent event) { - Block b = event.getBlock().getRelative(event.getBlockFace()); - Location location = BukkitUtil.getLocation(b.getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Player p = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(p); - Plot plot = area.getPlot(location); - if (plot == null) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_ROAD)) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_ROAD); - event.setCancelled(true); - } - } else { - if (!plot.hasOwner()) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_UNOWNED)) { - MainUtil - .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_UNOWNED); - event.setCancelled(true); - } - return; - } - if (!plot.isAdded(pp.getUUID())) { - if (!plot.getFlag(Flags.HANGING_PLACE, false)) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) { - MainUtil - .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); - event.setCancelled(true); - } - return; - } - } - if (checkEntity(event.getEntity(), plot)) { - event.setCancelled(true); - } - - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onHangingBreakByEntity(HangingBreakByEntityEvent event) { - Entity remover = event.getRemover(); - if (remover instanceof Player) { - Player p = (Player) remover; - Location location = BukkitUtil.getLocation(event.getEntity()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - PlotPlayer pp = BukkitUtil.getPlayer(p); - Plot plot = area.getPlot(location); - if (plot == null) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_DESTROY_ROAD)) { - MainUtil - .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_DESTROY_ROAD); - event.setCancelled(true); - } - } else if (!plot.hasOwner()) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_DESTROY_UNOWNED)) { - MainUtil - .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_DESTROY_UNOWNED); - event.setCancelled(true); - } - } else if (!plot.isAdded(pp.getUUID())) { - if (plot.getFlag(Flags.HANGING_BREAK, false)) { - return; - } - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_DESTROY_OTHER)) { - MainUtil - .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_DESTROY_OTHER); - event.setCancelled(true); - } - } - } else if (remover instanceof Projectile) { - Projectile p = (Projectile) remover; - if (p.getShooter() instanceof Player) { - Player shooter = (Player) p.getShooter(); - Location location = BukkitUtil.getLocation(event.getEntity()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - PlotPlayer player = BukkitUtil.getPlayer(shooter); - Plot plot = area.getPlot(BukkitUtil.getLocation(event.getEntity())); - if (plot != null) { - if (!plot.hasOwner()) { - if (!Permissions - .hasPermission(player, C.PERMISSION_ADMIN_DESTROY_UNOWNED)) { - MainUtil.sendMessage(player, C.NO_PERMISSION_EVENT, - C.PERMISSION_ADMIN_DESTROY_UNOWNED); - event.setCancelled(true); - } - } else if (!plot.isAdded(player.getUUID())) { - if (!plot.getFlag(Flags.HANGING_BREAK, false)) { - if (!Permissions - .hasPermission(player, C.PERMISSION_ADMIN_DESTROY_OTHER)) { - MainUtil.sendMessage(player, C.NO_PERMISSION_EVENT, - C.PERMISSION_ADMIN_DESTROY_OTHER); - event.setCancelled(true); - } - } - } - } - } - } else { - event.setCancelled(true); - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { - Location location = BukkitUtil.getLocation(event.getRightClicked().getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Player p = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(p); - Plot plot = area.getPlot(location); - if (plot == null) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_ROAD)) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_INTERACT_ROAD); - event.setCancelled(true); - } - } else if (!plot.hasOwner()) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_UNOWNED)) { - MainUtil - .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_INTERACT_UNOWNED); - event.setCancelled(true); - } - } else if (!plot.isAdded(pp.getUUID())) { - Entity entity = event.getRightClicked(); - if (entity instanceof Monster && plot.getFlag(Flags.HOSTILE_INTERACT, false)) { - return; - } - if (entity instanceof Animals && plot.getFlag(Flags.ANIMAL_INTERACT, false)) { - return; - } - if (entity instanceof Tameable && ((Tameable) entity).isTamed() && plot - .getFlag(Flags.TAMED_INTERACT, false)) { - return; - } - if (entity instanceof Vehicle && plot.getFlag(Flags.VEHICLE_USE, false)) { - return; - } - if (entity instanceof Player && plot.getFlag(Flags.PLAYER_INTERACT, false)) { - return; - } - if (entity instanceof Villager && plot.getFlag(Flags.VILLAGER_INTERACT, false)) { - return; - } - if (entity instanceof ItemFrame && plot.getFlag(Flags.MISC_INTERACT, false)) { - return; - } - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_OTHER)) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_INTERACT_OTHER); - event.setCancelled(true); - } - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onVehicleDestroy(VehicleDestroyEvent event) { - Location l = BukkitUtil.getLocation(event.getVehicle()); - PlotArea area = l.getPlotArea(); - if (area == null) { - return; - } - Entity d = event.getAttacker(); - if (d instanceof Player) { - Player p = (Player) d; - PlotPlayer pp = BukkitUtil.getPlayer(p); - Plot plot = area.getPlot(l); - if (plot == null) { - if (!Permissions.hasPermission(pp, "plots.admin.vehicle.break.road")) { - MainUtil - .sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.vehicle.break.road"); - event.setCancelled(true); - } - } else { - if (!plot.hasOwner()) { - if (!Permissions.hasPermission(pp, "plots.admin.vehicle.break.unowned")) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, - "plots.admin.vehicle.break.unowned"); - event.setCancelled(true); - return; - } - return; - } - if (!plot.isAdded(pp.getUUID())) { - if (plot.getFlag(Flags.VEHICLE_BREAK, false)) { - return; - } - if (!Permissions.hasPermission(pp, "plots.admin.vehicle.break.other")) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, - "plots.admin.vehicle.break.other"); - event.setCancelled(true); - } - } - } - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onPotionSplash(PotionSplashEvent event) { - ThrownPotion damager = event.getPotion(); - Location l = BukkitUtil.getLocation(damager); - if (!PlotSquared.get().hasPlotArea(l.getWorld())) { - return; - } - int count = 0; - for (LivingEntity victim : event.getAffectedEntities()) { - if (!entityDamage(damager, victim)) { - event.setIntensity(victim, 0); - count++; - } - } - if ((count > 0 && count == event.getAffectedEntities().size()) || !onProjectileHit(event)) { - event.setCancelled(true); - } - } - - @SuppressWarnings("deprecation") @EventHandler(priority = EventPriority.HIGHEST) - public void onEntityCombustByEntity(EntityCombustByEntityEvent event) { - EntityDamageByEntityEvent eventChange = null; - eventChange = new EntityDamageByEntityEvent(event.getCombuster(), event.getEntity(), - EntityDamageEvent.DamageCause.FIRE_TICK, (double) event.getDuration()); - onEntityDamageByEntityEvent(eventChange); - if (eventChange.isCancelled()) { - event.setCancelled(true); - } - } - - @EventHandler(priority = EventPriority.HIGHEST) - public void onEntityDamageByEntityEvent(EntityDamageByEntityEvent event) { - Entity damager = event.getDamager(); - Location l = BukkitUtil.getLocation(damager); - if (!PlotSquared.get().hasPlotArea(l.getWorld())) { - return; - } - Entity victim = event.getEntity(); - if (!entityDamage(damager, victim)) { - if (event.isCancelled()) { - if (victim instanceof Ageable) { - Ageable ageable = (Ageable) victim; - if (ageable.getAge() == -24000) { - ageable.setAge(0); - ageable.setAdult(); - } - } - } - event.setCancelled(true); - } - } - - public boolean entityDamage(Entity damager, Entity victim) { - Location dloc = BukkitUtil.getLocation(damager); - Location vloc = BukkitUtil.getLocation(victim); - PlotArea dArea = dloc.getPlotArea(); - PlotArea vArea = - dArea != null && dArea.contains(vloc.getX(), vloc.getZ()) ? dArea : vloc.getPlotArea(); - if (dArea == null && vArea == null) { - return true; - } - - Plot dplot = dArea != null ? dArea.getPlot(dloc) : null; - Plot vplot = vArea != null ? vArea.getPlot(vloc) : null; - - Plot plot; - String stub; - if (dplot == null && vplot == null) { - if (dArea == null) { - return true; - } - plot = null; - stub = "road"; - } else { - // Prioritize plots for close to seamless pvp zones - if (victim.getTicksLived() > damager.getTicksLived()) { - if (dplot == null || !(victim instanceof Player)) { - if (vplot == null) { - plot = dplot; - } else { - plot = vplot; - } - } else { - plot = dplot; - } - } else if (dplot == null || !(victim instanceof Player)) { - if (vplot == null) { - plot = dplot; - } else { - plot = vplot; - } - } else if (vplot == null) { - plot = dplot; - } else { - plot = vplot; - } - if (plot.hasOwner()) { - stub = "other"; - } else { - stub = "unowned"; - } - } - - Player player; - if (damager instanceof Player) { // attacker is player - player = (Player) damager; - } else if (damager instanceof Projectile) { - Projectile projectile = (Projectile) damager; - ProjectileSource shooter = projectile.getShooter(); - if (shooter instanceof Player) { // shooter is player - player = (Player) shooter; - } else { // shooter is not player - if (shooter instanceof BlockProjectileSource) { - Location sLoc = BukkitUtil - .getLocation(((BlockProjectileSource) shooter).getBlock().getLocation()); - dplot = dArea.getPlot(sLoc); - } - player = null; - } - } else { // Attacker is not player - player = null; - } - if (player != null) { - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); - if (victim instanceof Hanging) { // hanging - if (plot != null && (plot.getFlag(Flags.HANGING_BREAK, false) || plot - .isAdded(plotPlayer.getUUID()))) { - return true; - } - if (!Permissions.hasPermission(plotPlayer, "plots.admin.destroy." + stub)) { - MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, - "plots.admin.destroy." + stub); - return false; - } - } else if (victim.getEntityId() == 30) { - if (plot != null && (plot.getFlag(Flags.MISC_BREAK, false) || plot - .isAdded(plotPlayer.getUUID()))) { - return true; - } - if (!Permissions.hasPermission(plotPlayer, "plots.admin.destroy." + stub)) { - MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, - "plots.admin.destroy." + stub); - return false; - } - } else if (victim instanceof Monster - || victim instanceof EnderDragon) { // victim is monster - if (plot != null && (plot.getFlag(Flags.HOSTILE_ATTACK, false) || plot - .getFlag(Flags.PVE, false) || plot.isAdded(plotPlayer.getUUID()))) { - return true; - } - if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { - MainUtil - .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.pve." + stub); - return false; - } - } else if (victim instanceof Tameable) { // victim is tameable - if (plot != null && (plot.getFlag(Flags.TAMED_ATTACK, false) || plot - .getFlag(Flags.PVE, false) || plot.isAdded(plotPlayer.getUUID()))) { - return true; - } - if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { - MainUtil - .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.pve." + stub); - return false; - } - } else if (victim instanceof Player) { - if (plot != null) { - if (Flags.PVP.isFalse(plot) && !Permissions - .hasPermission(plotPlayer, "plots.admin.pvp." + stub)) { - MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, - "plots.admin.pvp." + stub); - return false; - } else { - return true; - } - } - if (!Permissions.hasPermission(plotPlayer, "plots.admin.pvp." + stub)) { - MainUtil - .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.pvp." + stub); - return false; - } - } else if (victim instanceof Creature) { // victim is animal - if (plot != null && (plot.getFlag(Flags.ANIMAL_ATTACK, false) || plot - .getFlag(Flags.PVE, false) || plot.isAdded(plotPlayer.getUUID()))) { - return true; - } - if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { - MainUtil - .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.pve." + stub); - return false; - } - } else if (victim instanceof Vehicle) { // Vehicles are managed in vehicle destroy event - return true; - } else { // victim is something else - if (plot != null && (plot.getFlag(Flags.PVE, false) || plot - .isAdded(plotPlayer.getUUID()))) { - return true; - } - if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { - MainUtil - .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.pve." + stub); - return false; - } - } - return true; - } else if (dplot != null && (!dplot.equals(vplot) || Objects - .equals(dplot.guessOwner(), vplot.guessOwner()))) { - return vplot != null && Flags.PVE.isTrue(vplot); - } - return ((vplot != null && Flags.PVE.isTrue(vplot)) || !(damager instanceof Arrow - && !(victim instanceof Creature))); - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onPlayerEggThrow(PlayerEggThrowEvent event) { - Location l = BukkitUtil.getLocation(event.getEgg().getLocation()); - PlotArea area = l.getPlotArea(); - if (area == null) { - return; - } - Player player = event.getPlayer(); - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); - Plot plot = area.getPlot(l); - if (plot == null) { - if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.road")) { - MainUtil - .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.projectile.road"); - event.setHatching(false); - } - } else if (!plot.hasOwner()) { - if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.unowned")) { - MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, - "plots.admin.projectile.unowned"); - event.setHatching(false); - } - } else if (!plot.isAdded(plotPlayer.getUUID())) { - if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.other")) { - MainUtil - .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.projectile.other"); - event.setHatching(false); - } - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void blockCreate(BlockPlaceEvent event) { - Location location = BukkitUtil.getLocation(event.getBlock().getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); - Plot plot = area.getPlot(location); + PlotPlayer player = BukkitUtil.getPlayer(shooter); + Plot plot = area.getPlot(BukkitUtil.getLocation(event.getEntity())); if (plot != null) { - if ((location.getY() > area.MAX_BUILD_HEIGHT || location.getY() < area.MIN_BUILD_HEIGHT) - && !Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_HEIGHTLIMIT)) { + if (!plot.hasOwner()) { + if (!Permissions + .hasPermission(player, C.PERMISSION_ADMIN_DESTROY_UNOWNED)) { + MainUtil.sendMessage(player, C.NO_PERMISSION_EVENT, + C.PERMISSION_ADMIN_DESTROY_UNOWNED); + event.setCancelled(true); + } + } else if (!plot.isAdded(player.getUUID())) { + if (!plot.getFlag(Flags.HANGING_BREAK, false)) { + if (!Permissions + .hasPermission(player, C.PERMISSION_ADMIN_DESTROY_OTHER)) { + MainUtil.sendMessage(player, C.NO_PERMISSION_EVENT, + C.PERMISSION_ADMIN_DESTROY_OTHER); event.setCancelled(true); - MainUtil.sendMessage(pp, - C.HEIGHT_LIMIT.s().replace("{limit}", String.valueOf(area.MAX_BUILD_HEIGHT))); + } } - if (!plot.hasOwner()) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_UNOWNED)) { - MainUtil - .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_UNOWNED); - event.setCancelled(true); - return; - } - } else if (!plot.isAdded(pp.getUUID())) { - Set place = plot.getFlag(Flags.PLACE, null); - if (place != null) { - Block block = event.getBlock(); - if (place.contains(PlotBlock.get(block.getType().name()))) { - return; - } - } - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); - event.setCancelled(true); - return; - } - } else if (Settings.Done.RESTRICT_BUILDING && plot.getFlags().containsKey(Flags.DONE)) { - if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); - event.setCancelled(true); - return; - } - } - if (plot.getFlag(Flags.DISABLE_PHYSICS, false)) { - Block block = event.getBlockPlaced(); - if (block.getType().hasGravity()) { - sendBlockChange(block.getLocation(), block.getBlockData()); - } - } - } else if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_ROAD)) { - MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_ROAD); - event.setCancelled(true); + } } + } + } else { + event.setCancelled(true); } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { + Location location = BukkitUtil.getLocation(event.getRightClicked().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Player p = event.getPlayer(); + PlotPlayer pp = BukkitUtil.getPlayer(p); + Plot plot = area.getPlot(location); + if (plot == null) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_ROAD)) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_INTERACT_ROAD); + event.setCancelled(true); + } + } else if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_UNOWNED)) { + MainUtil + .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_INTERACT_UNOWNED); + event.setCancelled(true); + } + } else if (!plot.isAdded(pp.getUUID())) { + Entity entity = event.getRightClicked(); + if (entity instanceof Monster && plot.getFlag(Flags.HOSTILE_INTERACT, false)) { + return; + } + if (entity instanceof Animals && plot.getFlag(Flags.ANIMAL_INTERACT, false)) { + return; + } + if (entity instanceof Tameable && ((Tameable) entity).isTamed() && plot + .getFlag(Flags.TAMED_INTERACT, false)) { + return; + } + if (entity instanceof Vehicle && plot.getFlag(Flags.VEHICLE_USE, false)) { + return; + } + if (entity instanceof Player && plot.getFlag(Flags.PLAYER_INTERACT, false)) { + return; + } + if (entity instanceof Villager && plot.getFlag(Flags.VILLAGER_INTERACT, false)) { + return; + } + if (entity instanceof ItemFrame && plot.getFlag(Flags.MISC_INTERACT, false)) { + return; + } + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_OTHER)) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_INTERACT_OTHER); + event.setCancelled(true); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onVehicleDestroy(VehicleDestroyEvent event) { + Location l = BukkitUtil.getLocation(event.getVehicle()); + PlotArea area = l.getPlotArea(); + if (area == null) { + return; + } + Entity d = event.getAttacker(); + if (d instanceof Player) { + Player p = (Player) d; + PlotPlayer pp = BukkitUtil.getPlayer(p); + Plot plot = area.getPlot(l); + if (plot == null) { + if (!Permissions.hasPermission(pp, "plots.admin.vehicle.break.road")) { + MainUtil + .sendMessage(pp, C.NO_PERMISSION_EVENT, "plots.admin.vehicle.break.road"); + event.setCancelled(true); + } + } else { + if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, "plots.admin.vehicle.break.unowned")) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, + "plots.admin.vehicle.break.unowned"); + event.setCancelled(true); + return; + } + return; + } + if (!plot.isAdded(pp.getUUID())) { + if (plot.getFlag(Flags.VEHICLE_BREAK, false)) { + return; + } + if (!Permissions.hasPermission(pp, "plots.admin.vehicle.break.other")) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, + "plots.admin.vehicle.break.other"); + event.setCancelled(true); + } + } + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPotionSplash(PotionSplashEvent event) { + ThrownPotion damager = event.getPotion(); + Location l = BukkitUtil.getLocation(damager); + if (!PlotSquared.get().hasPlotArea(l.getWorld())) { + return; + } + int count = 0; + for (LivingEntity victim : event.getAffectedEntities()) { + if (!entityDamage(damager, victim)) { + event.setIntensity(victim, 0); + count++; + } + } + if ((count > 0 && count == event.getAffectedEntities().size()) || !onProjectileHit(event)) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onEntityCombustByEntity(EntityCombustByEntityEvent event) { + EntityDamageByEntityEvent eventChange = new EntityDamageByEntityEvent(event.getCombuster(), + event.getEntity(), + EntityDamageEvent.DamageCause.FIRE_TICK, (double) event.getDuration()); + onEntityDamageByEntityEvent(eventChange); + if (eventChange.isCancelled()) { + event.setCancelled(true); + } + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void onEntityDamageByEntityEvent(EntityDamageByEntityEvent event) { + Entity damager = event.getDamager(); + Location l = BukkitUtil.getLocation(damager); + if (!PlotSquared.get().hasPlotArea(l.getWorld())) { + return; + } + Entity victim = event.getEntity(); + if (!entityDamage(damager, victim)) { + if (event.isCancelled()) { + if (victim instanceof Ageable) { + Ageable ageable = (Ageable) victim; + if (ageable.getAge() == -24000) { + ageable.setAge(0); + ageable.setAdult(); + } + } + } + event.setCancelled(true); + } + } + + public boolean entityDamage(Entity damager, Entity victim) { + Location dloc = BukkitUtil.getLocation(damager); + Location vloc = BukkitUtil.getLocation(victim); + PlotArea dArea = dloc.getPlotArea(); + PlotArea vArea = + dArea != null && dArea.contains(vloc.getX(), vloc.getZ()) ? dArea : vloc.getPlotArea(); + if (dArea == null && vArea == null) { + return true; + } + + Plot dplot = dArea != null ? dArea.getPlot(dloc) : null; + Plot vplot = vArea != null ? vArea.getPlot(vloc) : null; + + Plot plot; + String stub; + if (dplot == null && vplot == null) { + if (dArea == null) { + return true; + } + plot = null; + stub = "road"; + } else { + // Prioritize plots for close to seamless pvp zones + if (victim.getTicksLived() > damager.getTicksLived()) { + if (dplot == null || !(victim instanceof Player)) { + if (vplot == null) { + plot = dplot; + } else { + plot = vplot; + } + } else { + plot = dplot; + } + } else if (dplot == null || !(victim instanceof Player)) { + if (vplot == null) { + plot = dplot; + } else { + plot = vplot; + } + } else if (vplot == null) { + plot = dplot; + } else { + plot = vplot; + } + if (plot.hasOwner()) { + stub = "other"; + } else { + stub = "unowned"; + } + } + + Player player; + if (damager instanceof Player) { // attacker is player + player = (Player) damager; + } else if (damager instanceof Projectile) { + Projectile projectile = (Projectile) damager; + ProjectileSource shooter = projectile.getShooter(); + if (shooter instanceof Player) { // shooter is player + player = (Player) shooter; + } else { // shooter is not player + if (shooter instanceof BlockProjectileSource) { + Location sLoc = BukkitUtil + .getLocation(((BlockProjectileSource) shooter).getBlock().getLocation()); + dplot = dArea.getPlot(sLoc); + } + player = null; + } + } else { // Attacker is not player + player = null; + } + if (player != null) { + PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + if (victim instanceof Hanging) { // hanging + if (plot != null && (plot.getFlag(Flags.HANGING_BREAK, false) || plot + .isAdded(plotPlayer.getUUID()))) { + return true; + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.destroy." + stub)) { + MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, + "plots.admin.destroy." + stub); + return false; + } + } else if (victim.getEntityId() == 30) { + if (plot != null && (plot.getFlag(Flags.MISC_BREAK, false) || plot + .isAdded(plotPlayer.getUUID()))) { + return true; + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.destroy." + stub)) { + MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, + "plots.admin.destroy." + stub); + return false; + } + } else if (victim instanceof Monster + || victim instanceof EnderDragon) { // victim is monster + if (plot != null && (plot.getFlag(Flags.HOSTILE_ATTACK, false) || plot + .getFlag(Flags.PVE, false) || plot.isAdded(plotPlayer.getUUID()))) { + return true; + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { + MainUtil + .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.pve." + stub); + return false; + } + } else if (victim instanceof Tameable) { // victim is tameable + if (plot != null && (plot.getFlag(Flags.TAMED_ATTACK, false) || plot + .getFlag(Flags.PVE, false) || plot.isAdded(plotPlayer.getUUID()))) { + return true; + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { + MainUtil + .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.pve." + stub); + return false; + } + } else if (victim instanceof Player) { + if (plot != null) { + if (Flags.PVP.isFalse(plot) && !Permissions + .hasPermission(plotPlayer, "plots.admin.pvp." + stub)) { + MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, + "plots.admin.pvp." + stub); + return false; + } else { + return true; + } + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.pvp." + stub)) { + MainUtil + .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.pvp." + stub); + return false; + } + } else if (victim instanceof Creature) { // victim is animal + if (plot != null && (plot.getFlag(Flags.ANIMAL_ATTACK, false) || plot + .getFlag(Flags.PVE, false) || plot.isAdded(plotPlayer.getUUID()))) { + return true; + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { + MainUtil + .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.pve." + stub); + return false; + } + } else if (victim instanceof Vehicle) { // Vehicles are managed in vehicle destroy event + return true; + } else { // victim is something else + if (plot != null && (plot.getFlag(Flags.PVE, false) || plot + .isAdded(plotPlayer.getUUID()))) { + return true; + } + if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { + MainUtil + .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.pve." + stub); + return false; + } + } + return true; + } else if (dplot != null && (!dplot.equals(vplot) || Objects + .equals(dplot.guessOwner(), vplot.guessOwner()))) { + return vplot != null && Flags.PVE.isTrue(vplot); + } + return ((vplot != null && Flags.PVE.isTrue(vplot)) || !(damager instanceof Arrow + && !(victim instanceof Creature))); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPlayerEggThrow(PlayerEggThrowEvent event) { + Location l = BukkitUtil.getLocation(event.getEgg().getLocation()); + PlotArea area = l.getPlotArea(); + if (area == null) { + return; + } + Player player = event.getPlayer(); + PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + Plot plot = area.getPlot(l); + if (plot == null) { + if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.road")) { + MainUtil + .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.projectile.road"); + event.setHatching(false); + } + } else if (!plot.hasOwner()) { + if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.unowned")) { + MainUtil.sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, + "plots.admin.projectile.unowned"); + event.setHatching(false); + } + } else if (!plot.isAdded(plotPlayer.getUUID())) { + if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.other")) { + MainUtil + .sendMessage(plotPlayer, C.NO_PERMISSION_EVENT, "plots.admin.projectile.other"); + event.setHatching(false); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void blockCreate(BlockPlaceEvent event) { + Location location = BukkitUtil.getLocation(event.getBlock().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Player player = event.getPlayer(); + PlotPlayer pp = BukkitUtil.getPlayer(player); + Plot plot = area.getPlot(location); + if (plot != null) { + if ((location.getY() > area.MAX_BUILD_HEIGHT || location.getY() < area.MIN_BUILD_HEIGHT) + && !Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_HEIGHTLIMIT)) { + event.setCancelled(true); + MainUtil.sendMessage(pp, + C.HEIGHT_LIMIT.s().replace("{limit}", String.valueOf(area.MAX_BUILD_HEIGHT))); + } + if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_UNOWNED)) { + MainUtil + .sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_UNOWNED); + event.setCancelled(true); + return; + } + } else if (!plot.isAdded(pp.getUUID())) { + Set place = plot.getFlag(Flags.PLACE, null); + if (place != null) { + Block block = event.getBlock(); + if (place.contains(PlotBlock.get(block.getType().name()))) { + return; + } + } + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); + event.setCancelled(true); + return; + } + } else if (Settings.Done.RESTRICT_BUILDING && plot.getFlags().containsKey(Flags.DONE)) { + if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_OTHER); + event.setCancelled(true); + return; + } + } + if (plot.getFlag(Flags.DISABLE_PHYSICS, false)) { + Block block = event.getBlockPlaced(); + if (block.getType().hasGravity()) { + sendBlockChange(block.getLocation(), block.getBlockData()); + } + } + } else if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_ROAD)) { + MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_ROAD); + event.setCancelled(true); + } + } } diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/PlotPlusListener.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/PlotPlusListener.java index a4df7c6b3..19cd4c554 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/PlotPlusListener.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/PlotPlusListener.java @@ -10,6 +10,7 @@ import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.block.Block; +import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; @@ -37,45 +38,43 @@ public class PlotPlusListener extends PlotListener implements Listener { private static final HashMap healRunnable = new HashMap<>(); public static void startRunnable(JavaPlugin plugin) { - plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() { - @Override public void run() { - if (!healRunnable.isEmpty()) { - for (Iterator> iterator = - healRunnable.entrySet().iterator(); iterator.hasNext(); ) { - Entry entry = iterator.next(); - Interval value = entry.getValue(); - ++value.count; - if (value.count == value.interval) { - value.count = 0; - Player player = Bukkit.getPlayer(entry.getKey()); - if (player == null) { - iterator.remove(); - continue; - } - double level = player.getHealth(); - if (level != value.max) { - player.setHealth(Math.min(level + value.amount, value.max)); - } + plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, () -> { + if (!healRunnable.isEmpty()) { + for (Iterator> iterator = + healRunnable.entrySet().iterator(); iterator.hasNext(); ) { + Entry entry = iterator.next(); + Interval value = entry.getValue(); + ++value.count; + if (value.count == value.interval) { + value.count = 0; + Player player = Bukkit.getPlayer(entry.getKey()); + if (player == null) { + iterator.remove(); + continue; + } + double level = player.getHealth(); + if (level != value.max) { + player.setHealth(Math.min(level + value.amount, value.max)); } } } - if (!feedRunnable.isEmpty()) { - for (Iterator> iterator = - feedRunnable.entrySet().iterator(); iterator.hasNext(); ) { - Entry entry = iterator.next(); - Interval value = entry.getValue(); - ++value.count; - if (value.count == value.interval) { - value.count = 0; - Player player = Bukkit.getPlayer(entry.getKey()); - if (player == null) { - iterator.remove(); - continue; - } - int level = player.getFoodLevel(); - if (level != value.max) { - player.setFoodLevel(Math.min(level + value.amount, value.max)); - } + } + if (!feedRunnable.isEmpty()) { + for (Iterator> iterator = + feedRunnable.entrySet().iterator(); iterator.hasNext(); ) { + Entry entry = iterator.next(); + Interval value = entry.getValue(); + ++value.count; + if (value.count == value.interval) { + value.count = 0; + Player player = Bukkit.getPlayer(entry.getKey()); + if (player == null) { + iterator.remove(); + continue; + } + int level = player.getFoodLevel(); + if (level != value.max) { + player.setFoodLevel(Math.min(level + value.amount, value.max)); } } } @@ -108,7 +107,7 @@ public class PlotPlusListener extends PlotListener implements Listener { if (event.getEntityType() != EntityType.PLAYER) { return; } - Player player = (Player) event.getEntity(); + Entity player = event.getEntity(); Plot plot = BukkitUtil.getLocation(player).getOwnedPlot(); if (plot == null) { return; diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/SingleWorldListener.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/SingleWorldListener.java index 6a3e26d59..321dde939 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/SingleWorldListener.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/listeners/SingleWorldListener.java @@ -1,9 +1,13 @@ package com.github.intellectualsites.plotsquared.bukkit.listeners; +import static com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils.getRefClass; + import com.github.intellectualsites.plotsquared.plot.PlotSquared; import com.github.intellectualsites.plotsquared.plot.object.worlds.PlotAreaManager; import com.github.intellectualsites.plotsquared.plot.object.worlds.SinglePlotAreaManager; import com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; @@ -14,11 +18,6 @@ import org.bukkit.event.world.ChunkEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.plugin.Plugin; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -import static com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils.getRefClass; - @SuppressWarnings("unused") public class SingleWorldListener implements Listener { private Method methodGetHandleChunk; @@ -33,8 +32,8 @@ import static com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils this.done = classChunk.getField("done").getRealField(); this.lit = classChunk.getField("lit").getRealField(); this.s = classChunk.getField("s").getRealField(); - } catch (Throwable ignore) { - ignore.printStackTrace(); + } catch (NoSuchFieldException exception) { + exception.printStackTrace(); } Bukkit.getPluginManager().registerEvents(this, plugin); } diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/object/entity/ReplicatingEntityWrapper.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/object/entity/ReplicatingEntityWrapper.java index e71373771..c06b66b71 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/object/entity/ReplicatingEntityWrapper.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/object/entity/ReplicatingEntityWrapper.java @@ -12,685 +12,697 @@ import org.bukkit.util.Vector; public final class ReplicatingEntityWrapper extends EntityWrapper { - private final short depth; - private final int hash; - private final EntityBaseStats base = new EntityBaseStats(); + private final short depth; + private final int hash; + private final EntityBaseStats base = new EntityBaseStats(); - public ItemStack[] inventory; - // Extended - private ItemStack stack; - private byte dataByte; - private byte dataByte2; - private String dataString; - private LivingEntityStats lived; - private AgeableStats aged; - private TameableStats tamed; - private ArmorStandStats stand; - private HorseStats horse; - private boolean noGravity; + public ItemStack[] inventory; + // Extended + private ItemStack stack; + private byte dataByte; + private byte dataByte2; + private String dataString; + private LivingEntityStats lived; + private AgeableStats aged; + private TameableStats tamed; + private ArmorStandStats stand; + private HorseStats horse; + private boolean noGravity; - public ReplicatingEntityWrapper(Entity entity, short depth) { - super(entity); + public ReplicatingEntityWrapper(Entity entity, short depth) { + super(entity); - this.hash = entity.getEntityId(); - this.depth = depth; + this.hash = entity.getEntityId(); + this.depth = depth; - if (depth == 0) { - return; - } - Entity passenger = entity.getPassenger(); - if (passenger != null) { - this.base.passenger = new ReplicatingEntityWrapper(passenger, depth); - } - this.base.fall = entity.getFallDistance(); - this.base.fire = (short) entity.getFireTicks(); - this.base.age = entity.getTicksLived(); - Vector velocity = entity.getVelocity(); - this.base.vX = velocity.getX(); - this.base.vY = velocity.getY(); - this.base.vZ = velocity.getZ(); - if (depth == 1) { - return; - } - if (!entity.hasGravity()) { - this.noGravity = true; - } - switch (entity.getType()) { - case BOAT: - Boat boat = (Boat) entity; - this.dataByte = getOrdinal(TreeSpecies.values(), boat.getWoodType()); - return; - case ARROW: - case COMPLEX_PART: - case EGG: - case ENDER_CRYSTAL: - case ENDER_PEARL: - case ENDER_SIGNAL: - case EXPERIENCE_ORB: - case FALLING_BLOCK: - case FIREBALL: - case FIREWORK: - case FISHING_HOOK: - case LEASH_HITCH: - case LIGHTNING: - case MINECART: - case MINECART_COMMAND: - case MINECART_MOB_SPAWNER: - case MINECART_TNT: - case PLAYER: - case PRIMED_TNT: - case SLIME: - case SMALL_FIREBALL: - case SNOWBALL: - case MINECART_FURNACE: - case SPLASH_POTION: - case THROWN_EXP_BOTTLE: - case WEATHER: - case WITHER_SKULL: - case UNKNOWN: - case TIPPED_ARROW: - case SPECTRAL_ARROW: - case SHULKER_BULLET: - case DRAGON_FIREBALL: - case LINGERING_POTION: - case AREA_EFFECT_CLOUD: - // Do this stuff later - return; - // MISC // - case DROPPED_ITEM: - Item item = (Item) entity; - this.stack = item.getItemStack(); - return; - case ITEM_FRAME: - this.x = Math.floor(this.x); - this.y = Math.floor(this.y); - this.z = Math.floor(this.z); - ItemFrame itemFrame = (ItemFrame) entity; - this.dataByte = getOrdinal(Rotation.values(), itemFrame.getRotation()); - this.stack = itemFrame.getItem().clone(); - return; - case PAINTING: - this.x = Math.floor(this.x); - this.y = Math.floor(this.y); - this.z = Math.floor(this.z); - Painting painting = (Painting) entity; - Art art = painting.getArt(); - this.dataByte = getOrdinal(BlockFace.values(), painting.getFacing()); - int h = art.getBlockHeight(); - if (h % 2 == 0) { - this.y -= 1; - } - this.dataString = art.name(); - return; - // END MISC // - // INVENTORY HOLDER // - case MINECART_CHEST: - case MINECART_HOPPER: - storeInventory((InventoryHolder) entity); - return; - // START LIVING ENTITY // - // START AGEABLE // - // START TAMEABLE // - case HORSE: - Horse horse = (Horse) entity; - this.horse = new HorseStats(); - this.horse.jump = horse.getJumpStrength(); - this.horse.chest = horse.isCarryingChest(); - this.horse.variant = horse.getVariant(); - this.horse.style = horse.getStyle(); - this.horse.color = horse.getColor(); - storeTameable(horse); - storeAgeable(horse); - storeLiving(horse); - storeInventory(horse); - return; - // END INVENTORY HOLDER // - case WOLF: - case OCELOT: - storeTameable((Tameable) entity); - storeAgeable((Ageable) entity); - storeLiving((LivingEntity) entity); - return; - // END TAMEABLE // - case SHEEP: - Sheep sheep = (Sheep) entity; - this.dataByte = (byte) (sheep.isSheared() ? 1 : 0); - this.dataByte2 = sheep.getColor().getDyeData(); - storeAgeable(sheep); - storeLiving(sheep); - return; - case VILLAGER: - case CHICKEN: - case COW: - case MUSHROOM_COW: - case PIG: - case POLAR_BEAR: - storeAgeable((Ageable) entity); - storeLiving((LivingEntity) entity); - return; - case RABBIT: - this.dataByte = getOrdinal(Rabbit.Type.values(), ((Rabbit) entity).getRabbitType()); - storeAgeable((Ageable) entity); - storeLiving((LivingEntity) entity); - return; - // END AGEABLE // - case GUARDIAN: - this.dataByte = (byte) (((Guardian) entity).isElder() ? 1 : 0); - storeLiving((LivingEntity) entity); - return; - case SKELETON: - this.dataByte = getOrdinal(Skeleton.SkeletonType.values(), - ((Skeleton) entity).getSkeletonType()); - storeLiving((LivingEntity) entity); - return; - case ARMOR_STAND: - ArmorStand stand = (ArmorStand) entity; - this.inventory = - new ItemStack[] {stand.getItemInHand().clone(), stand.getHelmet().clone(), - stand.getChestplate().clone(), stand.getLeggings().clone(), - stand.getBoots().clone()}; - storeLiving(stand); - this.stand = new ArmorStandStats(); - - EulerAngle head = stand.getHeadPose(); - this.stand.head[0] = (float) head.getX(); - this.stand.head[1] = (float) head.getY(); - this.stand.head[2] = (float) head.getZ(); - - EulerAngle body = stand.getBodyPose(); - this.stand.body[0] = (float) body.getX(); - this.stand.body[1] = (float) body.getY(); - this.stand.body[2] = (float) body.getZ(); - - EulerAngle leftLeg = stand.getLeftLegPose(); - this.stand.leftLeg[0] = (float) leftLeg.getX(); - this.stand.leftLeg[1] = (float) leftLeg.getY(); - this.stand.leftLeg[2] = (float) leftLeg.getZ(); - - EulerAngle rightLeg = stand.getRightLegPose(); - this.stand.rightLeg[0] = (float) rightLeg.getX(); - this.stand.rightLeg[1] = (float) rightLeg.getY(); - this.stand.rightLeg[2] = (float) rightLeg.getZ(); - - EulerAngle leftArm = stand.getLeftArmPose(); - this.stand.leftArm[0] = (float) leftArm.getX(); - this.stand.leftArm[1] = (float) leftArm.getY(); - this.stand.leftArm[2] = (float) leftArm.getZ(); - - EulerAngle rightArm = stand.getRightArmPose(); - this.stand.rightArm[0] = (float) rightArm.getX(); - this.stand.rightArm[1] = (float) rightArm.getY(); - this.stand.rightArm[2] = (float) rightArm.getZ(); - - if (stand.hasArms()) { - this.stand.arms = true; - } - if (!stand.hasBasePlate()) { - this.stand.noPlate = true; - } - if (!stand.isVisible()) { - this.stand.invisible = true; - } - if (stand.isSmall()) { - this.stand.small = true; - } - return; - case ENDERMITE: - return; - case BAT: - if (((Bat) entity).isAwake()) { - this.dataByte = (byte) 1; - } else { - this.dataByte = (byte) 0; - } - return; - case ENDER_DRAGON: - EnderDragon entity1 = (EnderDragon) entity; - this.dataByte = (byte) entity1.getPhase().ordinal(); - return; - case GHAST: - case MAGMA_CUBE: - case SQUID: - case PIG_ZOMBIE: - case ZOMBIE: - case WITHER: - case WITCH: - case SPIDER: - case CAVE_SPIDER: - case SILVERFISH: - case GIANT: - case ENDERMAN: - case CREEPER: - case BLAZE: - case SHULKER: - case SNOWMAN: - storeLiving((LivingEntity) entity); - return; - case IRON_GOLEM: - if (((IronGolem) entity).isPlayerCreated()) { - this.dataByte = (byte) 1; - } else { - this.dataByte = (byte) 0; - } - storeLiving((LivingEntity) entity); - // END LIVING // - default: - PlotSquared.debug("&cCOULD NOT IDENTIFY ENTITY: " + entity.getType()); - } + if (depth == 0) { + return; } - - @Override public boolean equals(Object obj) { - return this.hash == obj.hashCode(); + Entity passenger = entity.getPassenger(); + if (passenger != null) { + this.base.passenger = new ReplicatingEntityWrapper(passenger, depth); } - - @Override public int hashCode() { - return this.hash; + this.base.fall = entity.getFallDistance(); + this.base.fire = (short) entity.getFireTicks(); + this.base.age = entity.getTicksLived(); + Vector velocity = entity.getVelocity(); + this.base.vX = velocity.getX(); + this.base.vY = velocity.getY(); + this.base.vZ = velocity.getZ(); + if (depth == 1) { + return; } - - public void storeInventory(InventoryHolder held) { - this.inventory = held.getInventory().getContents().clone(); + if (!entity.hasGravity()) { + this.noGravity = true; } + switch (entity.getType()) { + case BOAT: + Boat boat = (Boat) entity; + this.dataByte = getOrdinal(TreeSpecies.values(), boat.getWoodType()); + return; + case ARROW: + case COMPLEX_PART: + case EGG: + case ENDER_CRYSTAL: + case ENDER_PEARL: + case ENDER_SIGNAL: + case EXPERIENCE_ORB: + case FALLING_BLOCK: + case FIREBALL: + case FIREWORK: + case FISHING_HOOK: + case LEASH_HITCH: + case LIGHTNING: + case MINECART: + case MINECART_COMMAND: + case MINECART_MOB_SPAWNER: + case MINECART_TNT: + case PLAYER: + case PRIMED_TNT: + case SLIME: + case SMALL_FIREBALL: + case SNOWBALL: + case MINECART_FURNACE: + case SPLASH_POTION: + case THROWN_EXP_BOTTLE: + case WEATHER: + case WITHER_SKULL: + case UNKNOWN: + case TIPPED_ARROW: + case SPECTRAL_ARROW: + case SHULKER_BULLET: + case DRAGON_FIREBALL: + case LINGERING_POTION: + case AREA_EFFECT_CLOUD: + // Do this stuff later + return; + // MISC // + case DROPPED_ITEM: + Item item = (Item) entity; + this.stack = item.getItemStack(); + return; + case ITEM_FRAME: + this.x = Math.floor(this.x); + this.y = Math.floor(this.y); + this.z = Math.floor(this.z); + ItemFrame itemFrame = (ItemFrame) entity; + this.dataByte = getOrdinal(Rotation.values(), itemFrame.getRotation()); + this.stack = itemFrame.getItem().clone(); + return; + case PAINTING: + this.x = Math.floor(this.x); + this.y = Math.floor(this.y); + this.z = Math.floor(this.z); + Painting painting = (Painting) entity; + Art art = painting.getArt(); + this.dataByte = getOrdinal(BlockFace.values(), painting.getFacing()); + int h = art.getBlockHeight(); + if (h % 2 == 0) { + this.y -= 1; + } + this.dataString = art.name(); + return; + // END MISC // + // INVENTORY HOLDER // + case MINECART_CHEST: + case MINECART_HOPPER: + storeInventory((InventoryHolder) entity); + return; + // START LIVING ENTITY // + // START AGEABLE // + // START TAMEABLE // + case HORSE: + Horse horse = (Horse) entity; + this.horse = new HorseStats(); + this.horse.jump = horse.getJumpStrength(); + if (horse instanceof ChestedHorse) { + this.horse.chest = ((ChestedHorse) horse).isCarryingChest(); + } else { + this.horse.chest = false; + } + this.horse.variant = horse.getVariant(); + this.horse.style = horse.getStyle(); + this.horse.color = horse.getColor(); + storeTameable(horse); + storeAgeable(horse); + storeLiving(horse); + storeInventory(horse); + return; + // END INVENTORY HOLDER // + case WOLF: + case OCELOT: + storeTameable((Tameable) entity); + storeAgeable((Ageable) entity); + storeLiving((LivingEntity) entity); + return; + // END TAMEABLE // + case SHEEP: + Sheep sheep = (Sheep) entity; + this.dataByte = (byte) (sheep.isSheared() ? 1 : 0); + this.dataByte2 = sheep.getColor().getDyeData(); + storeAgeable(sheep); + storeLiving(sheep); + return; + case VILLAGER: + case CHICKEN: + case COW: + case MUSHROOM_COW: + case PIG: + case POLAR_BEAR: + storeAgeable((Ageable) entity); + storeLiving((LivingEntity) entity); + return; + case RABBIT: + this.dataByte = getOrdinal(Rabbit.Type.values(), ((Rabbit) entity).getRabbitType()); + storeAgeable((Ageable) entity); + storeLiving((LivingEntity) entity); + return; + // END AGEABLE // + case GUARDIAN: + //todo no longer works (possible exception thrown) + this.dataByte = (byte) (((Guardian) entity).isElder() ? 1 : 0); + storeLiving((LivingEntity) entity); + return; + case SKELETON: + //todo no longer works (possible exception thrown) + this.dataByte = getOrdinal(Skeleton.SkeletonType.values(), + ((Skeleton) entity).getSkeletonType()); + storeLiving((LivingEntity) entity); + return; + case ARMOR_STAND: + ArmorStand stand = (ArmorStand) entity; + this.inventory = + new ItemStack[]{stand.getItemInHand().clone(), stand.getHelmet().clone(), + stand.getChestplate().clone(), stand.getLeggings().clone(), + stand.getBoots().clone()}; + storeLiving(stand); + this.stand = new ArmorStandStats(); - void restoreLiving(LivingEntity entity) { - entity.setCanPickupItems(this.lived.loot); - if (this.lived.name != null) { - entity.setCustomName(this.lived.name); - entity.setCustomNameVisible(this.lived.visible); - } - if (this.lived.potions != null && !this.lived.potions.isEmpty()) { - entity.addPotionEffects(this.lived.potions); - } - entity.setRemainingAir(this.lived.air); - entity.setRemoveWhenFarAway(this.lived.persistent); - if (this.lived.equipped) { - this.restoreEquipment(entity); - } - if (this.lived.leashed) { - // TODO leashes - // World world = entity.getWorld(); - // Entity leash = world.spawnEntity(new Location(world, Math.floor(x) + lived.leashX, Math.floor(y) + lived.leashY, Math - // .floor(z) + lived.leashZ), EntityType.LEASH_HITCH); - // entity.setLeashHolder(leash); - } - } + EulerAngle head = stand.getHeadPose(); + this.stand.head[0] = (float) head.getX(); + this.stand.head[1] = (float) head.getY(); + this.stand.head[2] = (float) head.getZ(); - void restoreEquipment(LivingEntity entity) { - EntityEquipment equipment = entity.getEquipment(); - equipment.setItemInMainHand(this.lived.mainHand); - equipment.setItemInOffHand(this.lived.offHand); - equipment.setHelmet(this.lived.helmet); - equipment.setChestplate(this.lived.chestplate); - equipment.setLeggings(this.lived.leggings); - equipment.setBoots(this.lived.boots); - } + EulerAngle body = stand.getBodyPose(); + this.stand.body[0] = (float) body.getX(); + this.stand.body[1] = (float) body.getY(); + this.stand.body[2] = (float) body.getZ(); - private void restoreInventory(InventoryHolder entity) { - try { - entity.getInventory().setContents(this.inventory); - } catch (IllegalArgumentException e) { - PlotSquared.debug("&c[WARN] Failed to restore inventory.\n Reason: " + e.getMessage()); - } - } + EulerAngle leftLeg = stand.getLeftLegPose(); + this.stand.leftLeg[0] = (float) leftLeg.getX(); + this.stand.leftLeg[1] = (float) leftLeg.getY(); + this.stand.leftLeg[2] = (float) leftLeg.getZ(); - public void storeLiving(LivingEntity lived) { - this.lived = new LivingEntityStats(); - this.lived.potions = lived.getActivePotionEffects(); - this.lived.loot = lived.getCanPickupItems(); - this.lived.name = lived.getCustomName(); - this.lived.visible = lived.isCustomNameVisible(); - this.lived.health = (float) lived.getHealth(); - this.lived.air = (short) lived.getRemainingAir(); - this.lived.persistent = lived.getRemoveWhenFarAway(); - this.lived.leashed = lived.isLeashed(); - if (this.lived.leashed) { - Location location = lived.getLeashHolder().getLocation(); - this.lived.leashX = (short) (this.x - location.getBlockX()); - this.lived.leashY = (short) (this.y - location.getBlockY()); - this.lived.leashZ = (short) (this.z - location.getBlockZ()); - } - EntityEquipment equipment = lived.getEquipment(); - this.lived.equipped = equipment != null; - if (this.lived.equipped) { - storeEquipment(equipment); - } - } + EulerAngle rightLeg = stand.getRightLegPose(); + this.stand.rightLeg[0] = (float) rightLeg.getX(); + this.stand.rightLeg[1] = (float) rightLeg.getY(); + this.stand.rightLeg[2] = (float) rightLeg.getZ(); - void storeEquipment(EntityEquipment equipment) { - this.lived.mainHand = equipment.getItemInMainHand().clone(); - this.lived.offHand = equipment.getItemInOffHand().clone(); - this.lived.boots = equipment.getBoots().clone(); - this.lived.leggings = equipment.getLeggings().clone(); - this.lived.chestplate = equipment.getChestplate().clone(); - this.lived.helmet = equipment.getHelmet().clone(); - } + EulerAngle leftArm = stand.getLeftArmPose(); + this.stand.leftArm[0] = (float) leftArm.getX(); + this.stand.leftArm[1] = (float) leftArm.getY(); + this.stand.leftArm[2] = (float) leftArm.getZ(); - private void restoreTameable(Tameable entity) { - if (this.tamed.tamed) { - if (this.tamed.owner != null) { - entity.setTamed(true); - entity.setOwner(this.tamed.owner); - } - } - } + EulerAngle rightArm = stand.getRightArmPose(); + this.stand.rightArm[0] = (float) rightArm.getX(); + this.stand.rightArm[1] = (float) rightArm.getY(); + this.stand.rightArm[2] = (float) rightArm.getZ(); - private void restoreAgeable(Ageable entity) { - if (!this.aged.adult) { - entity.setBaby(); + if (stand.hasArms()) { + this.stand.arms = true; } - entity.setAgeLock(this.aged.locked); - if (this.aged.age > 0) { - entity.setAge(this.aged.age); + if (!stand.hasBasePlate()) { + this.stand.noPlate = true; } + if (!stand.isVisible()) { + this.stand.invisible = true; + } + if (stand.isSmall()) { + this.stand.small = true; + } + return; + case ENDERMITE: + return; + case BAT: + if (((Bat) entity).isAwake()) { + this.dataByte = (byte) 1; + } else { + this.dataByte = (byte) 0; + } + return; + case ENDER_DRAGON: + EnderDragon entity1 = (EnderDragon) entity; + this.dataByte = (byte) entity1.getPhase().ordinal(); + return; + case GHAST: + case MAGMA_CUBE: + case SQUID: + case PIG_ZOMBIE: + case ZOMBIE: + case WITHER: + case WITCH: + case SPIDER: + case CAVE_SPIDER: + case SILVERFISH: + case GIANT: + case ENDERMAN: + case CREEPER: + case BLAZE: + case SHULKER: + case SNOWMAN: + storeLiving((LivingEntity) entity); + return; + case IRON_GOLEM: + if (((IronGolem) entity).isPlayerCreated()) { + this.dataByte = (byte) 1; + } else { + this.dataByte = (byte) 0; + } + storeLiving((LivingEntity) entity); + // END LIVING // + default: + PlotSquared.debug("&cCOULD NOT IDENTIFY ENTITY: " + entity.getType()); } + } - public void storeAgeable(Ageable aged) { - this.aged = new AgeableStats(); - this.aged.age = aged.getAge(); - this.aged.locked = aged.getAgeLock(); - this.aged.adult = aged.isAdult(); - } + @Override + public boolean equals(Object obj) { + return this.hash == obj.hashCode(); + } - public void storeTameable(Tameable tamed) { - this.tamed = new TameableStats(); - this.tamed.owner = tamed.getOwner(); - this.tamed.tamed = tamed.isTamed(); - } + @Override + public int hashCode() { + return this.hash; + } - @Override public Entity spawn(World world, int xOffset, int zOffset) { - Location location = new Location(world, this.x + xOffset, this.y, this.z + zOffset); - location.setYaw(this.yaw); - location.setPitch(this.pitch); - if (!this.getType().isSpawnable()) { - return null; - } - Entity entity; - switch (this.getType()) { - case DROPPED_ITEM: - return world.dropItem(location, this.stack); - case PLAYER: - case LEASH_HITCH: - return null; - case ITEM_FRAME: - entity = world.spawn(location, ItemFrame.class); - break; - case PAINTING: - entity = world.spawn(location, Painting.class); - break; - default: - entity = world.spawnEntity(location, this.getType()); - break; - } - if (this.depth == 0) { - return entity; - } - if (this.base.passenger != null) { - try { - entity.setPassenger(this.base.passenger.spawn(world, xOffset, zOffset)); - } catch (Exception ignored) { - } - } - if (this.base.fall != 0) { - entity.setFallDistance(this.base.fall); - } - if (this.base.fire != 0) { - entity.setFireTicks(this.base.fire); - } - if (this.base.age != 0) { - entity.setTicksLived(this.base.age); - } - entity.setVelocity(new Vector(this.base.vX, this.base.vY, this.base.vZ)); - if (this.depth == 1) { - return entity; - } - if (this.noGravity) { - entity.setGravity(false); - } - switch (entity.getType()) { - case BOAT: - Boat boat = (Boat) entity; - boat.setWoodType(TreeSpecies.values()[dataByte]); - return entity; - case SLIME: - ((Slime) entity).setSize(this.dataByte); - return entity; - case ARROW: - case COMPLEX_PART: - case EGG: - case ENDER_CRYSTAL: - case ENDER_PEARL: - case ENDER_SIGNAL: - case DROPPED_ITEM: - case EXPERIENCE_ORB: - case FALLING_BLOCK: - case FIREBALL: - case FIREWORK: - case FISHING_HOOK: - case LEASH_HITCH: - case LIGHTNING: - case MINECART: - case MINECART_COMMAND: - case MINECART_MOB_SPAWNER: - case MINECART_TNT: - case PLAYER: - case PRIMED_TNT: - case SMALL_FIREBALL: - case SNOWBALL: - case SPLASH_POTION: - case THROWN_EXP_BOTTLE: - case WEATHER: - case TIPPED_ARROW: - case SPECTRAL_ARROW: - case SHULKER_BULLET: - case LINGERING_POTION: - case AREA_EFFECT_CLOUD: - case DRAGON_FIREBALL: - case WITHER_SKULL: - case MINECART_FURNACE: - case UNKNOWN: - // Do this stuff later - return entity; - // MISC // - case ITEM_FRAME: - ItemFrame itemframe = (ItemFrame) entity; - itemframe.setRotation(Rotation.values()[this.dataByte]); - itemframe.setItem(this.stack); - return entity; - case PAINTING: - Painting painting = (Painting) entity; - painting.setFacingDirection(BlockFace.values()[this.dataByte], true); - painting.setArt(Art.getByName(this.dataString), true); - return entity; - // END MISC // - // INVENTORY HOLDER // - case MINECART_CHEST: - case MINECART_HOPPER: - restoreInventory((InventoryHolder) entity); - return entity; - // START LIVING ENTITY // - // START AGEABLE // - // START TAMEABLE // - case HORSE: - Horse horse = (Horse) entity; - horse.setJumpStrength(this.horse.jump); - horse.setCarryingChest(this.horse.chest); - horse.setVariant(this.horse.variant); - horse.setStyle(this.horse.style); - horse.setColor(this.horse.color); - restoreTameable(horse); - restoreAgeable(horse); - restoreLiving(horse); - restoreInventory(horse); - return entity; - // END INVENTORY HOLDER // - case WOLF: - case OCELOT: - restoreTameable((Tameable) entity); - restoreAgeable((Ageable) entity); - restoreLiving((LivingEntity) entity); - return entity; - // END AGEABLE // - case SHEEP: - Sheep sheep = (Sheep) entity; - if (this.dataByte == 1) { - sheep.setSheared(true); - } - if (this.dataByte2 != 0) { - sheep.setColor(DyeColor.getByDyeData(this.dataByte2)); - } - restoreAgeable(sheep); - restoreLiving(sheep); - return sheep; - case VILLAGER: - case CHICKEN: - case COW: - case POLAR_BEAR: - case MUSHROOM_COW: - case PIG: - restoreAgeable((Ageable) entity); - restoreLiving((LivingEntity) entity); - return entity; - // END AGEABLE // - case RABBIT: - if (this.dataByte != 0) { - ((Rabbit) entity).setRabbitType(Rabbit.Type.values()[this.dataByte]); - } - restoreAgeable((Ageable) entity); - restoreLiving((LivingEntity) entity); - return entity; - case GUARDIAN: - if (this.dataByte != 0) { - ((Guardian) entity).setElder(true); - } - restoreLiving((LivingEntity) entity); - return entity; - case SKELETON: - if (this.dataByte != 0) { - ((Skeleton) entity) - .setSkeletonType(Skeleton.SkeletonType.values()[this.dataByte]); - } - storeLiving((LivingEntity) entity); - return entity; - case ARMOR_STAND: - // CHECK positions - ArmorStand stand = (ArmorStand) entity; - if (this.inventory[0] != null) { - stand.setItemInHand(this.inventory[0]); - } - if (this.inventory[1] != null) { - stand.setHelmet(this.inventory[1]); - } - if (this.inventory[2] != null) { - stand.setChestplate(this.inventory[2]); - } - if (this.inventory[3] != null) { - stand.setLeggings(this.inventory[3]); - } - if (this.inventory[4] != null) { - stand.setBoots(this.inventory[4]); - } - if (this.stand.head[0] != 0 || this.stand.head[1] != 0 || this.stand.head[2] != 0) { - EulerAngle pose = - new EulerAngle(this.stand.head[0], this.stand.head[1], this.stand.head[2]); - stand.setHeadPose(pose); - } - if (this.stand.body[0] != 0 || this.stand.body[1] != 0 || this.stand.body[2] != 0) { - EulerAngle pose = - new EulerAngle(this.stand.body[0], this.stand.body[1], this.stand.body[2]); - stand.setBodyPose(pose); - } - if (this.stand.leftLeg[0] != 0 || this.stand.leftLeg[1] != 0 - || this.stand.leftLeg[2] != 0) { - EulerAngle pose = new EulerAngle(this.stand.leftLeg[0], this.stand.leftLeg[1], - this.stand.leftLeg[2]); - stand.setLeftLegPose(pose); - } - if (this.stand.rightLeg[0] != 0 || this.stand.rightLeg[1] != 0 - || this.stand.rightLeg[2] != 0) { - EulerAngle pose = new EulerAngle(this.stand.rightLeg[0], this.stand.rightLeg[1], - this.stand.rightLeg[2]); - stand.setRightLegPose(pose); - } - if (this.stand.leftArm[0] != 0 || this.stand.leftArm[1] != 0 - || this.stand.leftArm[2] != 0) { - EulerAngle pose = new EulerAngle(this.stand.leftArm[0], this.stand.leftArm[1], - this.stand.leftArm[2]); - stand.setLeftArmPose(pose); - } - if (this.stand.rightArm[0] != 0 || this.stand.rightArm[1] != 0 - || this.stand.rightArm[2] != 0) { - EulerAngle pose = new EulerAngle(this.stand.rightArm[0], this.stand.rightArm[1], - this.stand.rightArm[2]); - stand.setRightArmPose(pose); - } - if (this.stand.invisible) { - stand.setVisible(false); - } - if (this.stand.arms) { - stand.setArms(true); - } - if (this.stand.noPlate) { - stand.setBasePlate(false); - } - if (this.stand.small) { - stand.setSmall(true); - } - restoreLiving(stand); - return stand; - case BAT: - if (this.dataByte != 0) { - ((Bat) entity).setAwake(true); - } - restoreLiving((LivingEntity) entity); - return entity; - case ENDER_DRAGON: - if (this.dataByte != 0) { - ((EnderDragon) entity).setPhase(EnderDragon.Phase.values()[this.dataByte]); - } - restoreLiving((LivingEntity) entity); - return entity; - case ENDERMITE: - case GHAST: - case MAGMA_CUBE: - case SQUID: - case PIG_ZOMBIE: - case ZOMBIE: - case WITHER: - case WITCH: - case SPIDER: - case CAVE_SPIDER: - case SILVERFISH: - case GIANT: - case ENDERMAN: - case CREEPER: - case BLAZE: - case SNOWMAN: - case SHULKER: - restoreLiving((LivingEntity) entity); - return entity; - case IRON_GOLEM: - if (this.dataByte != 0) { - ((IronGolem) entity).setPlayerCreated(true); - } - restoreLiving((LivingEntity) entity); - return entity; - default: - PlotSquared.debug("&cCOULD NOT IDENTIFY ENTITY: " + entity.getType()); - return entity; - // END LIVING - } - } + public void storeInventory(InventoryHolder held) { + this.inventory = held.getInventory().getContents().clone(); + } - public void saveEntity() { + void restoreLiving(LivingEntity entity) { + entity.setCanPickupItems(this.lived.loot); + if (this.lived.name != null) { + entity.setCustomName(this.lived.name); + entity.setCustomNameVisible(this.lived.visible); } + if (this.lived.potions != null && !this.lived.potions.isEmpty()) { + entity.addPotionEffects(this.lived.potions); + } + entity.setRemainingAir(this.lived.air); + entity.setRemoveWhenFarAway(this.lived.persistent); + if (this.lived.equipped) { + this.restoreEquipment(entity); + } + if (this.lived.leashed) { + // TODO leashes + // World world = entity.getWorld(); + // Entity leash = world.spawnEntity(new Location(world, Math.floor(x) + lived.leashX, Math.floor(y) + lived.leashY, Math + // .floor(z) + lived.leashZ), EntityType.LEASH_HITCH); + // entity.setLeashHolder(leash); + } + } - private byte getOrdinal(Object[] list, Object value) { - for (byte i = 0; i < list.length; i++) { - if (list[i].equals(value)) { - return i; - } - } - return 0; + void restoreEquipment(LivingEntity entity) { + EntityEquipment equipment = entity.getEquipment(); + equipment.setItemInMainHand(this.lived.mainHand); + equipment.setItemInOffHand(this.lived.offHand); + equipment.setHelmet(this.lived.helmet); + equipment.setChestplate(this.lived.chestplate); + equipment.setLeggings(this.lived.leggings); + equipment.setBoots(this.lived.boots); + } + + private void restoreInventory(InventoryHolder entity) { + try { + entity.getInventory().setContents(this.inventory); + } catch (IllegalArgumentException e) { + PlotSquared.debug("&c[WARN] Failed to restore inventory.\n Reason: " + e.getMessage()); } + } + + public void storeLiving(LivingEntity lived) { + this.lived = new LivingEntityStats(); + this.lived.potions = lived.getActivePotionEffects(); + this.lived.loot = lived.getCanPickupItems(); + this.lived.name = lived.getCustomName(); + this.lived.visible = lived.isCustomNameVisible(); + this.lived.health = (float) lived.getHealth(); + this.lived.air = (short) lived.getRemainingAir(); + this.lived.persistent = lived.getRemoveWhenFarAway(); + this.lived.leashed = lived.isLeashed(); + if (this.lived.leashed) { + Location location = lived.getLeashHolder().getLocation(); + this.lived.leashX = (short) (this.x - location.getBlockX()); + this.lived.leashY = (short) (this.y - location.getBlockY()); + this.lived.leashZ = (short) (this.z - location.getBlockZ()); + } + EntityEquipment equipment = lived.getEquipment(); + this.lived.equipped = equipment != null; + if (this.lived.equipped) { + storeEquipment(equipment); + } + } + + void storeEquipment(EntityEquipment equipment) { + this.lived.mainHand = equipment.getItemInMainHand().clone(); + this.lived.offHand = equipment.getItemInOffHand().clone(); + this.lived.boots = equipment.getBoots().clone(); + this.lived.leggings = equipment.getLeggings().clone(); + this.lived.chestplate = equipment.getChestplate().clone(); + this.lived.helmet = equipment.getHelmet().clone(); + } + + private void restoreTameable(Tameable entity) { + if (this.tamed.tamed) { + if (this.tamed.owner != null) { + entity.setTamed(true); + entity.setOwner(this.tamed.owner); + } + } + } + + private void restoreAgeable(Ageable entity) { + if (!this.aged.adult) { + entity.setBaby(); + } + entity.setAgeLock(this.aged.locked); + if (this.aged.age > 0) { + entity.setAge(this.aged.age); + } + } + + public void storeAgeable(Ageable aged) { + this.aged = new AgeableStats(); + this.aged.age = aged.getAge(); + this.aged.locked = aged.getAgeLock(); + this.aged.adult = aged.isAdult(); + } + + public void storeTameable(Tameable tamed) { + this.tamed = new TameableStats(); + this.tamed.owner = tamed.getOwner(); + this.tamed.tamed = tamed.isTamed(); + } + + @Override + public Entity spawn(World world, int xOffset, int zOffset) { + Location location = new Location(world, this.x + xOffset, this.y, this.z + zOffset); + location.setYaw(this.yaw); + location.setPitch(this.pitch); + if (!this.getType().isSpawnable()) { + return null; + } + Entity entity; + switch (this.getType()) { + case DROPPED_ITEM: + return world.dropItem(location, this.stack); + case PLAYER: + case LEASH_HITCH: + return null; + case ITEM_FRAME: + entity = world.spawn(location, ItemFrame.class); + break; + case PAINTING: + entity = world.spawn(location, Painting.class); + break; + default: + entity = world.spawnEntity(location, this.getType()); + break; + } + if (this.depth == 0) { + return entity; + } + if (this.base.passenger != null) { + entity.addPassenger(this.base.passenger.spawn(world, xOffset, zOffset)); + } + if (this.base.fall != 0) { + entity.setFallDistance(this.base.fall); + } + if (this.base.fire != 0) { + entity.setFireTicks(this.base.fire); + } + if (this.base.age != 0) { + entity.setTicksLived(this.base.age); + } + entity.setVelocity(new Vector(this.base.vX, this.base.vY, this.base.vZ)); + if (this.depth == 1) { + return entity; + } + if (this.noGravity) { + entity.setGravity(false); + } + switch (entity.getType()) { + case BOAT: + Boat boat = (Boat) entity; + boat.setWoodType(TreeSpecies.values()[dataByte]); + return entity; + case SLIME: + ((Slime) entity).setSize(this.dataByte); + return entity; + case ARROW: + case COMPLEX_PART: + case EGG: + case ENDER_CRYSTAL: + case ENDER_PEARL: + case ENDER_SIGNAL: + case DROPPED_ITEM: + case EXPERIENCE_ORB: + case FALLING_BLOCK: + case FIREBALL: + case FIREWORK: + case FISHING_HOOK: + case LEASH_HITCH: + case LIGHTNING: + case MINECART: + case MINECART_COMMAND: + case MINECART_MOB_SPAWNER: + case MINECART_TNT: + case PLAYER: + case PRIMED_TNT: + case SMALL_FIREBALL: + case SNOWBALL: + case SPLASH_POTION: + case THROWN_EXP_BOTTLE: + case WEATHER: + case TIPPED_ARROW: + case SPECTRAL_ARROW: + case SHULKER_BULLET: + case LINGERING_POTION: + case AREA_EFFECT_CLOUD: + case DRAGON_FIREBALL: + case WITHER_SKULL: + case MINECART_FURNACE: + case UNKNOWN: + // Do this stuff later + return entity; + // MISC // + case ITEM_FRAME: + ItemFrame itemframe = (ItemFrame) entity; + itemframe.setRotation(Rotation.values()[this.dataByte]); + itemframe.setItem(this.stack); + return entity; + case PAINTING: + Painting painting = (Painting) entity; + painting.setFacingDirection(BlockFace.values()[this.dataByte], true); + painting.setArt(Art.getByName(this.dataString), true); + return entity; + // END MISC // + // INVENTORY HOLDER // + case MINECART_CHEST: + case MINECART_HOPPER: + restoreInventory((InventoryHolder) entity); + return entity; + // START LIVING ENTITY // + // START AGEABLE // + // START TAMEABLE // + case HORSE: + Horse horse = (Horse) entity; + horse.setJumpStrength(this.horse.jump); + if (horse instanceof ChestedHorse && this.horse.chest) { + ((ChestedHorse) horse).setCarryingChest(true); + } + //todo broken in 1.13 possible exception thrown + horse.setVariant(this.horse.variant); + horse.setStyle(this.horse.style); + horse.setColor(this.horse.color); + restoreTameable(horse); + restoreAgeable(horse); + restoreLiving(horse); + restoreInventory(horse); + return entity; + // END INVENTORY HOLDER // + case WOLF: + case OCELOT: + restoreTameable((Tameable) entity); + restoreAgeable((Ageable) entity); + restoreLiving((LivingEntity) entity); + return entity; + // END AGEABLE // + case SHEEP: + Sheep sheep = (Sheep) entity; + if (this.dataByte == 1) { + sheep.setSheared(true); + } + if (this.dataByte2 != 0) { + sheep.setColor(DyeColor.getByDyeData(this.dataByte2)); + } + restoreAgeable(sheep); + restoreLiving(sheep); + return sheep; + case VILLAGER: + case CHICKEN: + case COW: + case POLAR_BEAR: + case MUSHROOM_COW: + case PIG: + restoreAgeable((Ageable) entity); + restoreLiving((LivingEntity) entity); + return entity; + // END AGEABLE // + case RABBIT: + if (this.dataByte != 0) { + ((Rabbit) entity).setRabbitType(Rabbit.Type.values()[this.dataByte]); + } + restoreAgeable((Ageable) entity); + restoreLiving((LivingEntity) entity); + return entity; + case GUARDIAN: + if (this.dataByte != 0) { + //todo broken in 1.13 possible exception thrown + + ((Guardian) entity).setElder(true); + } + restoreLiving((LivingEntity) entity); + return entity; + case SKELETON: + if (this.dataByte != 0) { + //todo broken in 1.13 possible exception thrown + ((Skeleton) entity) + .setSkeletonType(Skeleton.SkeletonType.values()[this.dataByte]); + } + storeLiving((LivingEntity) entity); + return entity; + case ARMOR_STAND: + // CHECK positions + ArmorStand stand = (ArmorStand) entity; + if (this.inventory[0] != null) { + stand.setItemInHand(this.inventory[0]); + } + if (this.inventory[1] != null) { + stand.setHelmet(this.inventory[1]); + } + if (this.inventory[2] != null) { + stand.setChestplate(this.inventory[2]); + } + if (this.inventory[3] != null) { + stand.setLeggings(this.inventory[3]); + } + if (this.inventory[4] != null) { + stand.setBoots(this.inventory[4]); + } + if (this.stand.head[0] != 0 || this.stand.head[1] != 0 || this.stand.head[2] != 0) { + EulerAngle pose = + new EulerAngle(this.stand.head[0], this.stand.head[1], this.stand.head[2]); + stand.setHeadPose(pose); + } + if (this.stand.body[0] != 0 || this.stand.body[1] != 0 || this.stand.body[2] != 0) { + EulerAngle pose = + new EulerAngle(this.stand.body[0], this.stand.body[1], this.stand.body[2]); + stand.setBodyPose(pose); + } + if (this.stand.leftLeg[0] != 0 || this.stand.leftLeg[1] != 0 + || this.stand.leftLeg[2] != 0) { + EulerAngle pose = new EulerAngle(this.stand.leftLeg[0], this.stand.leftLeg[1], + this.stand.leftLeg[2]); + stand.setLeftLegPose(pose); + } + if (this.stand.rightLeg[0] != 0 || this.stand.rightLeg[1] != 0 + || this.stand.rightLeg[2] != 0) { + EulerAngle pose = new EulerAngle(this.stand.rightLeg[0], this.stand.rightLeg[1], + this.stand.rightLeg[2]); + stand.setRightLegPose(pose); + } + if (this.stand.leftArm[0] != 0 || this.stand.leftArm[1] != 0 + || this.stand.leftArm[2] != 0) { + EulerAngle pose = new EulerAngle(this.stand.leftArm[0], this.stand.leftArm[1], + this.stand.leftArm[2]); + stand.setLeftArmPose(pose); + } + if (this.stand.rightArm[0] != 0 || this.stand.rightArm[1] != 0 + || this.stand.rightArm[2] != 0) { + EulerAngle pose = new EulerAngle(this.stand.rightArm[0], this.stand.rightArm[1], + this.stand.rightArm[2]); + stand.setRightArmPose(pose); + } + if (this.stand.invisible) { + stand.setVisible(false); + } + if (this.stand.arms) { + stand.setArms(true); + } + if (this.stand.noPlate) { + stand.setBasePlate(false); + } + if (this.stand.small) { + stand.setSmall(true); + } + restoreLiving(stand); + return stand; + case BAT: + if (this.dataByte != 0) { + ((Bat) entity).setAwake(true); + } + restoreLiving((LivingEntity) entity); + return entity; + case ENDER_DRAGON: + if (this.dataByte != 0) { + ((EnderDragon) entity).setPhase(EnderDragon.Phase.values()[this.dataByte]); + } + restoreLiving((LivingEntity) entity); + return entity; + case ENDERMITE: + case GHAST: + case MAGMA_CUBE: + case SQUID: + case PIG_ZOMBIE: + case ZOMBIE: + case WITHER: + case WITCH: + case SPIDER: + case CAVE_SPIDER: + case SILVERFISH: + case GIANT: + case ENDERMAN: + case CREEPER: + case BLAZE: + case SNOWMAN: + case SHULKER: + restoreLiving((LivingEntity) entity); + return entity; + case IRON_GOLEM: + if (this.dataByte != 0) { + ((IronGolem) entity).setPlayerCreated(true); + } + restoreLiving((LivingEntity) entity); + return entity; + default: + PlotSquared.debug("&cCOULD NOT IDENTIFY ENTITY: " + entity.getType()); + return entity; + // END LIVING + } + } + + public void saveEntity() { + } + + private byte getOrdinal(Object[] list, Object value) { + for (byte i = 0; i < list.length; i++) { + if (list[i].equals(value)) { + return i; + } + } + return 0; + } } diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/object/schematic/StateWrapper.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/object/schematic/StateWrapper.java index 3557f33af..d1eaa9081 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/object/schematic/StateWrapper.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/object/schematic/StateWrapper.java @@ -20,6 +20,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import org.bukkit.inventory.meta.Damageable; public class StateWrapper { @@ -241,7 +242,7 @@ public class StateWrapper { public Map serializeItem(ItemStack item) { Map data = new HashMap<>(); data.put("id", new StringTag(item.getType().name())); - data.put("Damage", new ShortTag(item.getDurability())); + data.put("Damage", new ShortTag((short) ((Damageable)item.getItemMeta()).getDamage())); data.put("Count", new ByteTag((byte) item.getAmount())); if (!item.getEnchantments().isEmpty()) { List enchantmentList = new ArrayList<>(); diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/titles/TitleManager.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/titles/TitleManager.java index f4c249f97..df16d07a2 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/titles/TitleManager.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/titles/TitleManager.java @@ -187,11 +187,7 @@ public abstract class TitleManager { throws IllegalArgumentException, ReflectiveOperationException, SecurityException; private Class getPrimitiveType(Class clazz) { - if (CORRESPONDING_TYPES.containsKey(clazz)) { - return CORRESPONDING_TYPES.get(clazz); - } else { - return clazz; - } + return CORRESPONDING_TYPES.getOrDefault(clazz, clazz); } private Class[] toPrimitiveTypeArray(Class[] classes) { diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/titles/TitleManager_1_11.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/titles/TitleManager_1_11.java index 92155ba45..817417087 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/titles/TitleManager_1_11.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/titles/TitleManager_1_11.java @@ -335,7 +335,7 @@ public class TitleManager_1_11 { } private Class getPrimitiveType(Class clazz) { - return CORRESPONDING_TYPES.containsKey(clazz) ? CORRESPONDING_TYPES.get(clazz) : clazz; + return CORRESPONDING_TYPES.getOrDefault(clazz, clazz); } private Class[] toPrimitiveTypeArray(Class[] classes) { diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitEventUtil.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitEventUtil.java index 808dabb7a..34e392a27 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitEventUtil.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitEventUtil.java @@ -99,10 +99,6 @@ public final class BukkitEventUtil extends EventUtil { new PlotChangeOwnerEvent(getPlayer(initiator), plot, oldOwner, newOwner, hasOldOwner)); } - @Override public boolean callFlagRemove(Flag flag, Object object, PlotCluster cluster) { - return callEvent(new ClusterFlagRemoveEvent(flag, cluster)); - } - @Override @Nullable public Rating callRating(PlotPlayer player, Plot plot, Rating rating) { PlotRateEvent event = new PlotRateEvent(player, rating, plot); Bukkit.getServer().getPluginManager().callEvent(event); diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitInventoryUtil.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitInventoryUtil.java index c40e13d09..d855f9e39 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitInventoryUtil.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitInventoryUtil.java @@ -83,7 +83,7 @@ public class BukkitInventoryUtil extends InventoryUtil { } // int id = item.getTypeId(); Material id = item.getType(); - short data = item.getDurability(); + //short data = item.getDurability(); int amount = item.getAmount(); String name = null; String[] lore = null; @@ -94,7 +94,7 @@ public class BukkitInventoryUtil extends InventoryUtil { } if (meta.hasLore()) { List itemLore = meta.getLore(); - lore = itemLore.toArray(new String[itemLore.size()]); + lore = itemLore.toArray(new String[0]); } } return new PlotItemStack(id.name(), amount, name, lore); diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/SendChunk.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/SendChunk.java index f0987b219..41e515cc7 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/SendChunk.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/SendChunk.java @@ -1,5 +1,7 @@ package com.github.intellectualsites.plotsquared.bukkit.util; +import static com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils.getRefClass; + import com.github.intellectualsites.plotsquared.bukkit.object.BukkitPlayer; import com.github.intellectualsites.plotsquared.plot.PlotSquared; import com.github.intellectualsites.plotsquared.plot.object.ChunkLoc; @@ -12,52 +14,49 @@ import com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils.RefFie import com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils.RefMethod; import com.github.intellectualsites.plotsquared.plot.util.TaskManager; import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.entity.Player; - import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map.Entry; - -import static com.github.intellectualsites.plotsquared.plot.util.ReflectionUtils.getRefClass; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.entity.Player; /** - * An utility that can be used to send chunks, rather than using bukkit code - * to do so (uses heavy NMS). + * An utility that can be used to send chunks, rather than using bukkit code to do so (uses heavy + * NMS). */ public class SendChunk { - private final RefMethod methodGetHandlePlayer; - private final RefMethod methodGetHandleChunk; - private final RefConstructor mapChunk; - private final RefField connection; - private final RefMethod send; - private final RefMethod methodInitLighting; + private final RefMethod methodGetHandlePlayer; + private final RefMethod methodGetHandleChunk; + private final RefConstructor mapChunk; + private final RefField connection; + private final RefMethod send; + private final RefMethod methodInitLighting; - /** - * Constructor. - */ - public SendChunk() throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException { - RefConstructor tempMapChunk; - RefClass classCraftPlayer = getRefClass("{cb}.entity.CraftPlayer"); - this.methodGetHandlePlayer = classCraftPlayer.getMethod("getHandle"); - RefClass classCraftChunk = getRefClass("{cb}.CraftChunk"); - this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle"); - RefClass classChunk = getRefClass("{nms}.Chunk"); - this.methodInitLighting = classChunk.getMethod("initLighting"); - RefClass classMapChunk = getRefClass("{nms}.PacketPlayOutMapChunk"); - tempMapChunk = classMapChunk.getConstructor(classChunk.getRealClass(), int.class); - this.mapChunk = tempMapChunk; - RefClass classEntityPlayer = getRefClass("{nms}.EntityPlayer"); - this.connection = classEntityPlayer.getField("playerConnection"); - RefClass classPacket = getRefClass("{nms}.Packet"); - RefClass classConnection = getRefClass("{nms}.PlayerConnection"); - this.send = classConnection.getMethod("sendPacket", classPacket.getRealClass()); - } + /** + * Constructor. + */ + public SendChunk() throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException { + RefConstructor tempMapChunk; + RefClass classCraftPlayer = getRefClass("{cb}.entity.CraftPlayer"); + this.methodGetHandlePlayer = classCraftPlayer.getMethod("getHandle"); + RefClass classCraftChunk = getRefClass("{cb}.CraftChunk"); + this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle"); + RefClass classChunk = getRefClass("{nms}.Chunk"); + this.methodInitLighting = classChunk.getMethod("initLighting"); + RefClass classMapChunk = getRefClass("{nms}.PacketPlayOutMapChunk"); + tempMapChunk = classMapChunk.getConstructor(classChunk.getRealClass(), int.class); + this.mapChunk = tempMapChunk; + RefClass classEntityPlayer = getRefClass("{nms}.EntityPlayer"); + this.connection = classEntityPlayer.getField("playerConnection"); + RefClass classPacket = getRefClass("{nms}.Packet"); + RefClass classConnection = getRefClass("{nms}.PlayerConnection"); + this.send = classConnection.getMethod("sendPacket", classPacket.getRealClass()); + } public void sendChunk(Collection input) { HashSet chunks = new HashSet<>(input); @@ -97,54 +96,52 @@ public class SendChunk { Player player = ((BukkitPlayer) pp).player; Object entity = this.methodGetHandlePlayer.of(player).call(); - for (Chunk chunk : list) { - int dx = Math.abs(cx - chunk.getX()); - int dz = Math.abs(cz - chunk.getZ()); - if ((dx > view) || (dz > view)) { - continue; - } - Object c = this.methodGetHandleChunk.of(chunk).call(); - chunks.remove(chunk); - Object con = this.connection.of(entity).get(); - Object packet = null; - try { - packet = this.mapChunk.create(c, 65535); - } catch (Exception ignored) { - } - if (packet == null) { - PlotSquared.debug("Error with PacketPlayOutMapChunk reflection."); - } - this.send.of(con).call(packet); - } + for (Chunk chunk : list) { + int dx = Math.abs(cx - chunk.getX()); + int dz = Math.abs(cz - chunk.getZ()); + if ((dx > view) || (dz > view)) { + continue; } - for (final Chunk chunk : chunks) { - TaskManager.runTask(new Runnable() { - @Override public void run() { - try { - chunk.unload(true, false); - } catch (Throwable ignored) { - String worldName = chunk.getWorld().getName(); - PlotSquared.debug( - "$4Could not save chunk: " + worldName + ';' + chunk.getX() + ";" - + chunk.getZ()); - PlotSquared - .debug("$3 - $4File may be open in another process (e.g. MCEdit)"); - PlotSquared.debug("$3 - $4" + worldName + "/level.dat or " + worldName - + "/level_old.dat may be corrupt (try repairing or removing these)"); - } - } - }); + Object c = this.methodGetHandleChunk.of(chunk).call(); + chunks.remove(chunk); + Object con = this.connection.of(entity).get(); + Object packet = null; + try { + packet = this.mapChunk.create(c, 65535); + } catch (Exception ignored) { } + if (packet == null) { + PlotSquared.debug("Error with PacketPlayOutMapChunk reflection."); + } + this.send.of(con).call(packet); + } } + for (final Chunk chunk : chunks) { + TaskManager.runTask(() -> { + try { + chunk.unload(true, false); + } catch (Throwable ignored) { + String worldName = chunk.getWorld().getName(); + PlotSquared.debug( + "$4Could not save chunk: " + worldName + ';' + chunk.getX() + ";" + + chunk.getZ()); + PlotSquared + .debug("$3 - $4File may be open in another process (e.g. MCEdit)"); + PlotSquared.debug("$3 - $4" + worldName + "/level.dat or " + worldName + + "/level_old.dat may be corrupt (try repairing or removing these)"); + } + }); + } + } - public void sendChunk(String worldName, Collection chunkLocations) { - World myWorld = Bukkit.getWorld(worldName); - ArrayList chunks = new ArrayList<>(); - for (ChunkLoc loc : chunkLocations) { - if (myWorld.isChunkLoaded(loc.x, loc.z)) { - chunks.add(myWorld.getChunkAt(loc.x, loc.z)); - } - } - sendChunk(chunks); + public void sendChunk(String worldName, Collection chunkLocations) { + World myWorld = Bukkit.getWorld(worldName); + ArrayList chunks = new ArrayList<>(); + for (ChunkLoc loc : chunkLocations) { + if (myWorld.isChunkLoaded(loc.x, loc.z)) { + chunks.add(myWorld.getChunkAt(loc.x, loc.z)); + } } + sendChunk(chunks); + } } diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/block/BukkitLocalQueue.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/block/BukkitLocalQueue.java index 77518690d..eee467db1 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/block/BukkitLocalQueue.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/block/BukkitLocalQueue.java @@ -192,8 +192,7 @@ public class BukkitLocalQueue extends BasicLocalBlockQueue { for (int x = 0; x < lc.biomes.length; x++) { String[] biomes2 = lc.biomes[x]; if (biomes2 != null) { - for (int y = 0; y < biomes2.length; y++) { - String biomeStr = biomes2[y]; + for (String biomeStr : biomes2) { if (biomeStr != null) { if (last == null || !StringMan.isEqual(last, biomeStr)) { biome = Biome.valueOf(biomeStr.toUpperCase()); diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/DefaultUUIDWrapper.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/DefaultUUIDWrapper.java index 3660bef92..aaa94dbeb 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/DefaultUUIDWrapper.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/DefaultUUIDWrapper.java @@ -5,12 +5,13 @@ import com.github.intellectualsites.plotsquared.bukkit.object.BukkitPlayer; import com.github.intellectualsites.plotsquared.plot.object.OfflinePlotPlayer; import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; import com.github.intellectualsites.plotsquared.plot.uuid.UUIDWrapper; +import java.util.Arrays; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import java.util.UUID; -public class DefaultUUIDWrapper extends UUIDWrapper { +public class DefaultUUIDWrapper implements UUIDWrapper { @Override public UUID getUUID(PlotPlayer player) { return ((BukkitPlayer) player).player.getUniqueId(); @@ -30,11 +31,8 @@ public class DefaultUUIDWrapper extends UUIDWrapper { @Override public OfflinePlotPlayer[] getOfflinePlayers() { OfflinePlayer[] ops = Bukkit.getOfflinePlayers(); - BukkitOfflinePlayer[] toReturn = new BukkitOfflinePlayer[ops.length]; - for (int i = 0; i < ops.length; i++) { - toReturn[i] = new BukkitOfflinePlayer(ops[i]); - } - return toReturn; + return Arrays.stream(ops).map(BukkitOfflinePlayer::new) + .toArray(BukkitOfflinePlayer[]::new); } @Override public OfflinePlotPlayer getOfflinePlayer(String name) { diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/FileUUIDHandler.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/FileUUIDHandler.java index 2223feceb..a8e2278b4 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/FileUUIDHandler.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/FileUUIDHandler.java @@ -47,204 +47,200 @@ public class FileUUIDHandler extends UUIDHandlerImplementation { } else { world = worlds.get(0).getName(); } - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - PlotSquared.debug(C.PREFIX + "&6Starting player data caching for: " + world); - File uuidFile = new File(PlotSquared.get().IMP.getDirectory(), "uuids.txt"); - if (uuidFile.exists()) { - try { - List lines = - Files.readAllLines(uuidFile.toPath(), StandardCharsets.UTF_8); - for (String line : lines) { - try { - line = line.trim(); - if (line.isEmpty()) { - continue; - } - line = line.replaceAll("[\\|][0-9]+[\\|][0-9]+[\\|]", ""); - String[] split = line.split("\\|"); - String name = split[0]; - if (name.isEmpty() || (name.length() > 16) || !StringMan - .isAlphanumericUnd(name)) { - continue; - } - UUID uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name); - if (uuid == null) { - continue; - } - UUIDHandler.add(new StringWrapper(name), uuid); - } catch (Exception e2) { - e2.printStackTrace(); + TaskManager.runTaskAsync(() -> { + PlotSquared.debug(C.PREFIX + "&6Starting player data caching for: " + world); + File uuidFile = new File(PlotSquared.get().IMP.getDirectory(), "uuids.txt"); + if (uuidFile.exists()) { + try { + List lines = + Files.readAllLines(uuidFile.toPath(), StandardCharsets.UTF_8); + for (String line : lines) { + try { + line = line.trim(); + if (line.isEmpty()) { + continue; } + line = line.replaceAll("[\\|][0-9]+[\\|][0-9]+[\\|]", ""); + String[] split = line.split("\\|"); + String name = split[0]; + if (name.isEmpty() || (name.length() > 16) || !StringMan + .isAlphanumericUnd(name)) { + continue; + } + UUID uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name); + if (uuid == null) { + continue; + } + UUIDHandler.add(new StringWrapper(name), uuid); + } catch (Exception e2) { + e2.printStackTrace(); } - } catch (IOException e) { - e.printStackTrace(); } + } catch (IOException e) { + e.printStackTrace(); } - HashBiMap toAdd = - HashBiMap.create(new HashMap()); - if (Settings.UUID.NATIVE_UUID_PROVIDER) { - HashSet all = UUIDHandler.getAllUUIDS(); - PlotSquared.debug("&aFast mode UUID caching enabled!"); - File playerDataFolder = - new File(container, world + File.separator + "playerdata"); - String[] dat = playerDataFolder.list(new DatFileFilter()); - boolean check = all.isEmpty(); - if (dat != null) { - for (String current : dat) { - String s = current.replaceAll(".dat$", ""); - try { - UUID uuid = UUID.fromString(s); - if (check || all.remove(uuid)) { - File file = new File(playerDataFolder, current); - NbtFactory.NbtCompound compound = NbtFactory - .fromStream(new FileInputStream(file), - NbtFactory.StreamOptions.GZIP_COMPRESSION); - if (!compound.containsKey("bukkit")) { - PlotSquared.debug("ERROR: Player data (" + uuid.toString() - + ".dat) does not contain the the key \"bukkit\""); - } else { - NbtFactory.NbtCompound bukkit = - (NbtFactory.NbtCompound) compound.get("bukkit"); - String name = (String) bukkit.get("lastKnownName"); - long last = (long) bukkit.get("lastPlayed"); - long first = (long) bukkit.get("firstPlayed"); - if (ExpireManager.IMP != null) { - ExpireManager.IMP.storeDate(uuid, last); - ExpireManager.IMP.storeAccountAge(uuid, last - first); - } - toAdd.put(new StringWrapper(name), uuid); + } + HashBiMap toAdd = + HashBiMap.create(new HashMap<>()); + if (Settings.UUID.NATIVE_UUID_PROVIDER) { + HashSet all = UUIDHandler.getAllUUIDS(); + PlotSquared.debug("&aFast mode UUID caching enabled!"); + File playerDataFolder = + new File(container, world + File.separator + "playerdata"); + String[] dat = playerDataFolder.list(new DatFileFilter()); + boolean check = all.isEmpty(); + if (dat != null) { + for (String current : dat) { + String s = current.replaceAll(".dat$", ""); + try { + UUID uuid = UUID.fromString(s); + if (check || all.remove(uuid)) { + File file = new File(playerDataFolder, current); + NbtFactory.NbtCompound compound = NbtFactory + .fromStream(new FileInputStream(file), + NbtFactory.StreamOptions.GZIP_COMPRESSION); + if (!compound.containsKey("bukkit")) { + PlotSquared.debug("ERROR: Player data (" + uuid.toString() + + ".dat) does not contain the the key \"bukkit\""); + } else { + NbtFactory.NbtCompound bukkit = + (NbtFactory.NbtCompound) compound.get("bukkit"); + String name = (String) bukkit.get("lastKnownName"); + long last = (long) bukkit.get("lastPlayed"); + long first = (long) bukkit.get("firstPlayed"); + if (ExpireManager.IMP != null) { + ExpireManager.IMP.storeDate(uuid, last); + ExpireManager.IMP.storeAccountAge(uuid, last - first); } - } - } catch (Exception e) { - e.printStackTrace(); - PlotSquared.debug(C.PREFIX + "Invalid playerdata: " + current); - } - } - } - add(toAdd); - if (all.isEmpty()) { - if (whenDone != null) { - whenDone.run(); - } - return; - } else { - PlotSquared.debug("Failed to cache: " + all.size() - + " uuids - slowly processing all files"); - } - } - HashSet worlds = Sets.newHashSet(world, "world"); - HashSet uuids = new HashSet<>(); - HashSet names = new HashSet<>(); - File playerDataFolder = null; - for (String worldName : worlds) { - // Getting UUIDs - playerDataFolder = - new File(container, worldName + File.separator + "playerdata"); - String[] dat = playerDataFolder.list(new DatFileFilter()); - if ((dat != null) && (dat.length != 0)) { - for (String current : dat) { - String s = current.replaceAll(".dat$", ""); - try { - UUID uuid = UUID.fromString(s); - uuids.add(uuid); - } catch (Exception ignored) { - PlotSquared.debug(C.PREFIX + "Invalid PlayerData: " + current); - } - } - break; - } - // Getting names - File playersFolder = new File(worldName + File.separator + "players"); - dat = playersFolder.list(new DatFileFilter()); - if ((dat != null) && (dat.length != 0)) { - for (String current : dat) { - names.add(current.replaceAll(".dat$", "")); - } - break; - } - } - for (UUID uuid : uuids) { - try { - File file = - new File(playerDataFolder + File.separator + uuid.toString() + ".dat"); - if (!file.exists()) { - continue; - } - NbtFactory.NbtCompound compound = NbtFactory - .fromStream(new FileInputStream(file), - NbtFactory.StreamOptions.GZIP_COMPRESSION); - if (!compound.containsKey("bukkit")) { - PlotSquared.debug("ERROR: Player data (" + uuid.toString() - + ".dat) does not contain the the key \"bukkit\""); - } else { - NbtFactory.NbtCompound bukkit = - (NbtFactory.NbtCompound) compound.get("bukkit"); - String name = (String) bukkit.get("lastKnownName"); - StringWrapper wrap = new StringWrapper(name); - if (!toAdd.containsKey(wrap)) { - long last = (long) bukkit.get("lastPlayed"); - long first = (long) bukkit.get("firstPlayed"); - if (Settings.UUID.OFFLINE) { - if (Settings.UUID.FORCE_LOWERCASE && !name.toLowerCase() - .equals(name)) { - uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name); - } else { - long most = (long) compound.get("UUIDMost"); - long least = (long) compound.get("UUIDLeast"); - uuid = new UUID(most, least); - } - } - if (ExpireManager.IMP != null) { - ExpireManager.IMP.storeDate(uuid, last); - ExpireManager.IMP.storeAccountAge(uuid, last - first); - } - toAdd.put(wrap, uuid); - } - } - } catch (Exception ignored) { - PlotSquared - .debug(C.PREFIX + "&6Invalid PlayerData: " + uuid.toString() + ".dat"); - } - } - for (String name : names) { - UUID uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name); - StringWrapper nameWrap = new StringWrapper(name); - toAdd.put(nameWrap, uuid); - } - - if (getUUIDMap().isEmpty()) { - for (OfflinePlotPlayer op : FileUUIDHandler.this.uuidWrapper - .getOfflinePlayers()) { - long last = op.getLastPlayed(); - if (last != 0) { - String name = op.getName(); - StringWrapper wrap = new StringWrapper(name); - if (!toAdd.containsKey(wrap)) { - UUID uuid = FileUUIDHandler.this.uuidWrapper.getUUID(op); - toAdd.put(wrap, uuid); - if (ExpireManager.IMP != null) { - ExpireManager.IMP.storeDate(uuid, last); + toAdd.put(new StringWrapper(name), uuid); } } + } catch (Exception e) { + e.printStackTrace(); + PlotSquared.debug(C.PREFIX + "Invalid playerdata: " + current); } } } add(toAdd); - if (whenDone != null) { - whenDone.run(); + if (all.isEmpty()) { + if (whenDone != null) { + whenDone.run(); + } + return; + } else { + PlotSquared.debug("Failed to cache: " + all.size() + + " uuids - slowly processing all files"); } } + HashSet worlds1 = Sets.newHashSet(world, "world"); + HashSet uuids = new HashSet<>(); + HashSet names = new HashSet<>(); + File playerDataFolder = null; + for (String worldName : worlds1) { + // Getting UUIDs + playerDataFolder = + new File(container, worldName + File.separator + "playerdata"); + String[] dat = playerDataFolder.list(new DatFileFilter()); + if ((dat != null) && (dat.length != 0)) { + for (String current : dat) { + String s = current.replaceAll(".dat$", ""); + try { + UUID uuid = UUID.fromString(s); + uuids.add(uuid); + } catch (Exception ignored) { + PlotSquared.debug(C.PREFIX + "Invalid PlayerData: " + current); + } + } + break; + } + // Getting names + File playersFolder = new File(worldName + File.separator + "players"); + dat = playersFolder.list(new DatFileFilter()); + if ((dat != null) && (dat.length != 0)) { + for (String current : dat) { + names.add(current.replaceAll(".dat$", "")); + } + break; + } + } + for (UUID uuid : uuids) { + try { + File file = + new File(playerDataFolder + File.separator + uuid.toString() + ".dat"); + if (!file.exists()) { + continue; + } + NbtFactory.NbtCompound compound = NbtFactory + .fromStream(new FileInputStream(file), + NbtFactory.StreamOptions.GZIP_COMPRESSION); + if (!compound.containsKey("bukkit")) { + PlotSquared.debug("ERROR: Player data (" + uuid.toString() + + ".dat) does not contain the the key \"bukkit\""); + } else { + NbtFactory.NbtCompound bukkit = + (NbtFactory.NbtCompound) compound.get("bukkit"); + String name = (String) bukkit.get("lastKnownName"); + StringWrapper wrap = new StringWrapper(name); + if (!toAdd.containsKey(wrap)) { + long last = (long) bukkit.get("lastPlayed"); + long first = (long) bukkit.get("firstPlayed"); + if (Settings.UUID.OFFLINE) { + if (Settings.UUID.FORCE_LOWERCASE && !name.toLowerCase() + .equals(name)) { + uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name); + } else { + long most = (long) compound.get("UUIDMost"); + long least = (long) compound.get("UUIDLeast"); + uuid = new UUID(most, least); + } + } + if (ExpireManager.IMP != null) { + ExpireManager.IMP.storeDate(uuid, last); + ExpireManager.IMP.storeAccountAge(uuid, last - first); + } + toAdd.put(wrap, uuid); + } + } + } catch (Exception ignored) { + PlotSquared + .debug(C.PREFIX + "&6Invalid PlayerData: " + uuid.toString() + ".dat"); + } + } + for (String name : names) { + UUID uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name); + StringWrapper nameWrap = new StringWrapper(name); + toAdd.put(nameWrap, uuid); + } + + if (getUUIDMap().isEmpty()) { + for (OfflinePlotPlayer op : FileUUIDHandler.this.uuidWrapper + .getOfflinePlayers()) { + long last = op.getLastPlayed(); + if (last != 0) { + String name = op.getName(); + StringWrapper wrap = new StringWrapper(name); + if (!toAdd.containsKey(wrap)) { + UUID uuid = FileUUIDHandler.this.uuidWrapper.getUUID(op); + toAdd.put(wrap, uuid); + if (ExpireManager.IMP != null) { + ExpireManager.IMP.storeDate(uuid, last); + } + } + } + } + } + add(toAdd); + if (whenDone != null) { + whenDone.run(); + } }); return true; } @Override public void fetchUUID(final String name, final RunnableVal ifFetch) { - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - ifFetch.value = FileUUIDHandler.this.uuidWrapper.getUUID(name); - TaskManager.runTask(ifFetch); - } + TaskManager.runTaskAsync(() -> { + ifFetch.value = FileUUIDHandler.this.uuidWrapper.getUUID(name); + TaskManager.runTask(ifFetch); }); } } diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/OfflineUUIDWrapper.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/OfflineUUIDWrapper.java index c44fa6e72..c06c7a3cc 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/OfflineUUIDWrapper.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/OfflineUUIDWrapper.java @@ -9,6 +9,7 @@ import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; import com.github.intellectualsites.plotsquared.plot.uuid.UUIDWrapper; import com.google.common.base.Charsets; import com.google.common.collect.BiMap; +import java.util.Arrays; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.Server; @@ -19,7 +20,7 @@ import java.lang.reflect.Method; import java.util.Collection; import java.util.UUID; -public class OfflineUUIDWrapper extends UUIDWrapper { +public class OfflineUUIDWrapper implements UUIDWrapper { private final Object[] arg = new Object[0]; private Method getOnline = null; @@ -59,18 +60,15 @@ public class OfflineUUIDWrapper extends UUIDWrapper { return new BukkitOfflinePlayer(op); } } - for (OfflinePlayer player : Bukkit.getOfflinePlayers()) { - if (getUUID(player).equals(uuid)) { - return new BukkitOfflinePlayer(player); - } - } - return null; + return Arrays.stream(Bukkit.getOfflinePlayers()) + .filter(player -> getUUID(player).equals(uuid)).findFirst() + .map(BukkitOfflinePlayer::new).orElse(null); } public Player[] getOnlinePlayers() { if (this.getOnline == null) { Collection onlinePlayers = Bukkit.getOnlinePlayers(); - return onlinePlayers.toArray(new Player[onlinePlayers.size()]); + return onlinePlayers.toArray(new Player[0]); } try { Object players = this.getOnline.invoke(Bukkit.getServer(), this.arg); @@ -79,13 +77,13 @@ public class OfflineUUIDWrapper extends UUIDWrapper { } else { @SuppressWarnings("unchecked") Collection p = (Collection) players; - return p.toArray(new Player[p.size()]); + return p.toArray(new Player[0]); } } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException ignored) { PlotSquared.debug("Failed to resolve online players"); this.getOnline = null; Collection onlinePlayers = Bukkit.getOnlinePlayers(); - return onlinePlayers.toArray(new Player[onlinePlayers.size()]); + return onlinePlayers.toArray(new Player[0]); } } @@ -95,11 +93,8 @@ public class OfflineUUIDWrapper extends UUIDWrapper { @Override public OfflinePlotPlayer[] getOfflinePlayers() { OfflinePlayer[] ops = Bukkit.getOfflinePlayers(); - BukkitOfflinePlayer[] toReturn = new BukkitOfflinePlayer[ops.length]; - for (int i = 0; i < ops.length; i++) { - toReturn[i] = new BukkitOfflinePlayer(ops[i]); - } - return toReturn; + return Arrays.stream(ops).map(BukkitOfflinePlayer::new) + .toArray(BukkitOfflinePlayer[]::new); } @Override public OfflinePlotPlayer getOfflinePlayer(String name) { diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/SQLUUIDHandler.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/SQLUUIDHandler.java index 1c9a30bba..04f0b146c 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/SQLUUIDHandler.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/uuid/SQLUUIDHandler.java @@ -71,96 +71,90 @@ public class SQLUUIDHandler extends UUIDHandlerImplementation { if (!super.startCaching(whenDone)) { return false; } - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - try { - HashBiMap toAdd = - HashBiMap.create(new HashMap()); - try (PreparedStatement statement = getConnection() - .prepareStatement("SELECT `uuid`, `username` FROM `usercache`"); - ResultSet resultSet = statement.executeQuery()) { - while (resultSet.next()) { - StringWrapper username = - new StringWrapper(resultSet.getString("username")); - UUID uuid = UUID.fromString(resultSet.getString("uuid")); - toAdd.put(new StringWrapper(username.value), uuid); - } + TaskManager.runTaskAsync(() -> { + try { + HashBiMap toAdd = + HashBiMap.create(new HashMap<>()); + try (PreparedStatement statement = getConnection() + .prepareStatement("SELECT `uuid`, `username` FROM `usercache`"); + ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + StringWrapper username = + new StringWrapper(resultSet.getString("username")); + UUID uuid = UUID.fromString(resultSet.getString("uuid")); + toAdd.put(new StringWrapper(username.value), uuid); } - add(toAdd); - // This should be called as long as there are some unknown plots - final ArrayDeque toFetch = new ArrayDeque<>(); - for (UUID u : UUIDHandler.getAllUUIDS()) { - if (!uuidExists(u)) { - toFetch.add(u); - } + } + add(toAdd); + // This should be called as long as there are some unknown plots + final ArrayDeque toFetch = new ArrayDeque<>(); + for (UUID u : UUIDHandler.getAllUUIDS()) { + if (!uuidExists(u)) { + toFetch.add(u); } - if (toFetch.isEmpty()) { + } + if (toFetch.isEmpty()) { + if (whenDone != null) { + whenDone.run(); + } + return; + } + FileUUIDHandler fileHandler = + new FileUUIDHandler(SQLUUIDHandler.this.uuidWrapper); + fileHandler.startCaching(() -> { + // If the file based UUID handler didn't cache it, then we can't cache offline mode + // Also, trying to cache based on files again, is useless as that's what the file based uuid cacher does + if (Settings.UUID.OFFLINE) { if (whenDone != null) { whenDone.run(); } return; } - FileUUIDHandler fileHandler = - new FileUUIDHandler(SQLUUIDHandler.this.uuidWrapper); - fileHandler.startCaching(new Runnable() { - @Override public void run() { - // If the file based UUID handler didn't cache it, then we can't cache offline mode - // Also, trying to cache based on files again, is useless as that's what the file based uuid cacher does - if (Settings.UUID.OFFLINE) { - if (whenDone != null) { - whenDone.run(); - } - return; - } - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - while (!toFetch.isEmpty()) { - try { - for (int i = 0; - i < Math.min(500, toFetch.size()); i++) { - UUID uuid = toFetch.pop(); - HttpURLConnection connection = - (HttpURLConnection) new URL( - SQLUUIDHandler.this.PROFILE_URL + uuid - .toString().replace("-", "")) - .openConnection(); - try (InputStream con = connection - .getInputStream()) { - InputStreamReader reader = - new InputStreamReader(con); - JSONObject response = - (JSONObject) SQLUUIDHandler.this.jsonParser - .parse(reader); - String name = (String) response.get("name"); - if (name != null) { - add(new StringWrapper(name), uuid); - } - } - connection.disconnect(); - } - } catch (IOException | ParseException e) { - PlotSquared.debug( - "Invalid response from Mojang: Some UUIDs will be cached later. (`unknown` until then or player joins)"); - } - try { - Thread.sleep(INTERVAL * 50); - } catch (InterruptedException e) { - e.printStackTrace(); - break; + TaskManager.runTaskAsync(() -> { + while (!toFetch.isEmpty()) { + try { + for (int i = 0; + i < Math.min(500, toFetch.size()); i++) { + UUID uuid = toFetch.pop(); + HttpURLConnection connection = + (HttpURLConnection) new URL( + SQLUUIDHandler.this.PROFILE_URL + uuid + .toString().replace("-", "")) + .openConnection(); + try (InputStream con = connection + .getInputStream()) { + InputStreamReader reader = + new InputStreamReader(con); + JSONObject response = + (JSONObject) SQLUUIDHandler.this.jsonParser + .parse(reader); + String name = (String) response.get("name"); + if (name != null) { + add(new StringWrapper(name), uuid); } } - if (whenDone != null) { - whenDone.run(); - } - return; + connection.disconnect(); } - }); + } catch (IOException | ParseException e) { + PlotSquared.debug( + "Invalid response from Mojang: Some UUIDs will be cached later. (`unknown` until then or player joins)"); + } + try { + Thread.sleep(INTERVAL * 50); + } catch (InterruptedException e) { + e.printStackTrace(); + break; + } } + if (whenDone != null) { + whenDone.run(); + } + return; }); - } catch (SQLException e) { - throw new SQLUUIDHandlerException("Couldn't select :s", e); - } + }); + } catch (SQLException e) { + throw new SQLUUIDHandlerException("Couldn't select :s", e); } }); return true; @@ -172,34 +166,32 @@ public class SQLUUIDHandler extends UUIDHandlerImplementation { if (ifFetch == null) { return; } - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - try { - URL url = new URL(SQLUUIDHandler.this.PROFILE_URL); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setUseCaches(false); - connection.setDoInput(true); - connection.setDoOutput(true); - String body = JSONArray.toJSONString(Collections.singletonList(name)); - OutputStream stream = connection.getOutputStream(); - stream.write(body.getBytes()); - stream.flush(); - stream.close(); - JSONArray array = (JSONArray) SQLUUIDHandler.this.jsonParser - .parse(new InputStreamReader(connection.getInputStream())); - JSONObject jsonProfile = (JSONObject) array.get(0); - String id = (String) jsonProfile.get("id"); - String name = (String) jsonProfile.get("name"); - ifFetch.value = UUID.fromString( - id.substring(0, 8) + '-' + id.substring(8, 12) + '-' + id.substring(12, 16) - + '-' + id.substring(16, 20) + '-' + id.substring(20, 32)); - } catch (IOException | ParseException e) { - e.printStackTrace(); - } - TaskManager.runTask(ifFetch); + TaskManager.runTaskAsync(() -> { + try { + URL url = new URL(SQLUUIDHandler.this.PROFILE_URL); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setUseCaches(false); + connection.setDoInput(true); + connection.setDoOutput(true); + String body = JSONArray.toJSONString(Collections.singletonList(name)); + OutputStream stream = connection.getOutputStream(); + stream.write(body.getBytes()); + stream.flush(); + stream.close(); + JSONArray array = (JSONArray) SQLUUIDHandler.this.jsonParser + .parse(new InputStreamReader(connection.getInputStream())); + JSONObject jsonProfile = (JSONObject) array.get(0); + String id = (String) jsonProfile.get("id"); + String name1 = (String) jsonProfile.get("name"); + ifFetch.value = UUID.fromString( + id.substring(0, 8) + '-' + id.substring(8, 12) + '-' + id.substring(12, 16) + + '-' + id.substring(16, 20) + '-' + id.substring(20, 32)); + } catch (IOException | ParseException e) { + e.printStackTrace(); } + TaskManager.runTask(ifFetch); }); } @@ -215,18 +207,16 @@ public class SQLUUIDHandler extends UUIDHandlerImplementation { @Override public boolean add(final StringWrapper name, final UUID uuid) { // Ignoring duplicates if (super.add(name, uuid)) { - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - try (PreparedStatement statement = getConnection().prepareStatement( - "REPLACE INTO usercache (`uuid`, `username`) VALUES(?, ?)")) { - statement.setString(1, uuid.toString()); - statement.setString(2, name.toString()); - statement.execute(); - PlotSquared - .debug(C.PREFIX + "&cAdded '&6" + uuid + "&c' - '&6" + name + "&c'"); - } catch (SQLException e) { - e.printStackTrace(); - } + TaskManager.runTaskAsync(() -> { + try (PreparedStatement statement = getConnection().prepareStatement( + "REPLACE INTO usercache (`uuid`, `username`) VALUES(?, ?)")) { + statement.setString(1, uuid.toString()); + statement.setString(2, name.toString()); + statement.execute(); + PlotSquared + .debug(C.PREFIX + "&cAdded '&6" + uuid + "&c' - '&6" + name + "&c'"); + } catch (SQLException e) { + e.printStackTrace(); } }); return true; @@ -239,18 +229,16 @@ public class SQLUUIDHandler extends UUIDHandlerImplementation { */ @Override public void rename(final UUID uuid, final StringWrapper name) { super.rename(uuid, name); - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - try (PreparedStatement statement = getConnection() - .prepareStatement("UPDATE usercache SET `username`=? WHERE `uuid`=?")) { - statement.setString(1, name.value); - statement.setString(2, uuid.toString()); - statement.execute(); - PlotSquared.debug( - C.PREFIX + "Name change for '" + uuid + "' to '" + name.value + '\''); - } catch (SQLException e) { - e.printStackTrace(); - } + TaskManager.runTaskAsync(() -> { + try (PreparedStatement statement = getConnection() + .prepareStatement("UPDATE usercache SET `username`=? WHERE `uuid`=?")) { + statement.setString(1, name.value); + statement.setString(2, uuid.toString()); + statement.execute(); + PlotSquared.debug( + C.PREFIX + "Name change for '" + uuid + "' to '" + name.value + '\''); + } catch (SQLException e) { + e.printStackTrace(); } }); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/Configuration.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/Configuration.java index c2b4b4d95..8f3446487 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/Configuration.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/Configuration.java @@ -1,6 +1,7 @@ package com.github.intellectualsites.plotsquared.configuration; import java.util.Map; +import javax.annotation.Nonnull; /** * Represents a source of configurable options and settings. @@ -20,7 +21,7 @@ public interface Configuration extends ConfigurationSection { * @param value Value to set the default to. * @throws IllegalArgumentException Thrown if path is null. */ - @Override void addDefault(String path, Object value); + @Override void addDefault(@Nonnull String path, Object value); /** * Sets the default values of the given paths as provided. diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationOptions.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationOptions.java index 5d13920e4..f86016031 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationOptions.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationOptions.java @@ -31,7 +31,7 @@ class ConfigurationOptions { * * @return Path separator */ - public char pathSeparator() { + char pathSeparator() { return pathSeparator; } @@ -64,7 +64,7 @@ class ConfigurationOptions { * * @return Whether or not defaults are directly copied */ - public boolean copyDefaults() { + boolean copyDefaults() { return copyDefaults; } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationSection.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationSection.java index 0752dfb57..ac9d2d536 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationSection.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationSection.java @@ -3,6 +3,7 @@ package com.github.intellectualsites.plotsquared.configuration; import java.util.List; import java.util.Map; import java.util.Set; +import javax.annotation.Nonnull; /** * Represents a section of a {@link Configuration}. @@ -52,7 +53,7 @@ public interface ConfigurationSection { * default or being set. * @throws IllegalArgumentException Thrown when path is {@code null}. */ - boolean contains(String path); + boolean contains(@Nonnull String path); /** * Checks if this {@link ConfigurationSection} has a value set for the @@ -66,7 +67,7 @@ public interface ConfigurationSection { * having a default. * @throws IllegalArgumentException Thrown when path is {@code null}. */ - boolean isSet(String path); + boolean isSet(@Nonnull String path); /** * Gets the path of this {@link ConfigurationSection} from its root {@link @@ -151,7 +152,7 @@ public interface ConfigurationSection { * @param defaultValue The default value to return if the path is not found. * @return Requested Object. */ - Object get(String path, Object defaultValue); + Object getOrDefault(@Nonnull String path, Object defaultValue); /** * Sets the specified path to the given value. @@ -644,5 +645,5 @@ public interface ConfigurationSection { * @param value Value to set the default to * @throws IllegalArgumentException Thrown if path is {@code null} */ - void addDefault(String path, Object value); + void addDefault(@Nonnull String path, Object value); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemoryConfiguration.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemoryConfiguration.java index 20131cbe1..d44c0f3b2 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemoryConfiguration.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemoryConfiguration.java @@ -1,6 +1,7 @@ package com.github.intellectualsites.plotsquared.configuration; import java.util.Map; +import javax.annotation.Nonnull; /** * This is a {@link Configuration} implementation that does not save or load @@ -28,7 +29,7 @@ public class MemoryConfiguration extends MemorySection implements Configuration this.defaults = defaults; } - @Override public void addDefault(String path, Object value) { + @Override public void addDefault(@Nonnull String path, Object value) { if (this.defaults == null) { this.defaults = new MemoryConfiguration(); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemorySection.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemorySection.java index 0f87931f4..73f50476d 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemorySection.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemorySection.java @@ -1,777 +1,817 @@ package com.github.intellectualsites.plotsquared.configuration; import java.util.*; +import javax.annotation.Nonnull; /** * A type of {@link ConfigurationSection} that is stored in memory. */ public class MemorySection implements ConfigurationSection { - protected final Map map = new LinkedHashMap<>(); - private final Configuration root; - private final ConfigurationSection parent; - private final String path; - private final String fullPath; + protected final Map map = new LinkedHashMap<>(); + private final Configuration root; + private final ConfigurationSection parent; + private final String path; + private final String fullPath; - /** - * Creates an empty MemorySection for use as a root {@link Configuration} - * section. - * - *

Note that calling this without being yourself a {@link Configuration} - * will throw an exception! - * - * @throws IllegalStateException Thrown if this is not a {@link - * Configuration} root. - */ - protected MemorySection() { - if (!(this instanceof Configuration)) { - throw new IllegalStateException( - "Cannot construct a root MemorySection when not a Configuration"); - } - - this.path = ""; - this.fullPath = ""; - this.parent = null; - this.root = (Configuration) this; + /** + * Creates an empty MemorySection for use as a root {@link Configuration} section. + * + *

Note that calling this without being yourself a {@link Configuration} + * will throw an exception! + * + * @throws IllegalStateException Thrown if this is not a {@link Configuration} root. + */ + protected MemorySection() { + if (!(this instanceof Configuration)) { + throw new IllegalStateException( + "Cannot construct a root MemorySection when not a Configuration"); } - /** - * Creates an empty MemorySection with the specified parent and path. - * - * @param parent Parent section that contains this own section. - * @param path Path that you may access this section from via the root - * {@link Configuration}. - * @throws IllegalArgumentException Thrown is parent or path is null, or - * if parent contains no root Configuration. - */ - protected MemorySection(ConfigurationSection parent, String path) { - this.path = path; - this.parent = parent; - this.root = parent.getRoot(); + this.path = ""; + this.fullPath = ""; + this.parent = null; + this.root = (Configuration) this; + } - if (this.root == null) { - throw new NullPointerException("Path may not be orphaned"); - } + /** + * Creates an empty MemorySection with the specified parent and path. + * + * @param parent Parent section that contains this own section. + * @param path Path that you may access this section from via the root {@link Configuration}. + * @throws IllegalArgumentException Thrown is parent or path is null, or if parent contains no + * root Configuration. + */ + protected MemorySection(ConfigurationSection parent, String path) { + this.path = path; + this.parent = parent; + this.root = parent.getRoot(); - this.fullPath = createPath(parent, path); + if (this.root == null) { + throw new NullPointerException("Path may not be orphaned"); } - public static double toDouble(Object obj, double def) { - if (obj instanceof Number) { - return ((Number) obj).doubleValue(); - } - if (obj instanceof String) { - try { - return Double.parseDouble((String) obj); - } catch (NumberFormatException ignored) { - } - } else if (obj instanceof List) { - List val = (List) obj; - if (!val.isEmpty()) { - return toDouble(val.get(0), def); - } - } - return def; + this.fullPath = createPath(parent, path); + } + + public static double toDouble(Object obj, double def) { + if (obj instanceof Number) { + return ((Number) obj).doubleValue(); + } + if (obj instanceof String) { + try { + return Double.parseDouble((String) obj); + } catch (NumberFormatException ignored) { + } + } else if (obj instanceof List) { + List val = (List) obj; + if (!val.isEmpty()) { + return toDouble(val.get(0), def); + } + } + return def; + } + + public static int toInt(Object obj, int def) { + if (obj instanceof Number) { + return ((Number) obj).intValue(); + } + if (obj instanceof String) { + try { + return Integer.parseInt((String) obj); + } catch (NumberFormatException ignored) { + } + } else if (obj instanceof List) { + List val = (List) obj; + if (!val.isEmpty()) { + return toInt(val.get(0), def); + } + } + return def; + } + + public static long toLong(Object obj, long def) { + if (obj instanceof Number) { + return ((Number) obj).longValue(); + } + if (obj instanceof String) { + try { + return Long.parseLong((String) obj); + } catch (NumberFormatException ignored) { + } + } else if (obj instanceof List) { + List val = (List) obj; + if (!val.isEmpty()) { + return toLong(val.get(0), def); + } + } + return def; + } + + /** + * Creates a full path to the given {@link ConfigurationSection} from its root {@link + * Configuration}. + * + *

You may use this method for any given {@link ConfigurationSection}, not + * only {@link MemorySection}. + * + * @param section Section to create a path for. + * @param key Name of the specified section. + * @return Full path of the section from its root. + */ + public static String createPath(ConfigurationSection section, String key) { + return createPath(section, key, section.getRoot()); + } + + /** + * Creates a relative path to the given {@link ConfigurationSection} from the given relative + * section. + * + *

You may use this method for any given {@link ConfigurationSection}, not + * only {@link MemorySection}. + * + * @param section Section to create a path for. + * @param key Name of the specified section. + * @param relativeTo Section to create the path relative to. + * @return Full path of the section from its root. + */ + public static String createPath(ConfigurationSection section, String key, + ConfigurationSection relativeTo) { + Configuration root = section.getRoot(); + if (root == null) { + throw new IllegalStateException("Cannot create path without a root"); + } + char separator = root.options().pathSeparator(); + + StringBuilder builder = new StringBuilder(); + for (ConfigurationSection parent = section; + (parent != null) && (parent != relativeTo); parent = parent.getParent()) { + if (builder.length() > 0) { + builder.insert(0, separator); + } + + builder.insert(0, parent.getName()); } - public static int toInt(Object obj, int def) { - if (obj instanceof Number) { - return ((Number) obj).intValue(); - } - if (obj instanceof String) { - try { - return Integer.parseInt((String) obj); - } catch (NumberFormatException ignored) { - } - } else if (obj instanceof List) { - List val = (List) obj; - if (!val.isEmpty()) { - return toInt(val.get(0), def); - } - } - return def; + if ((key != null) && !key.isEmpty()) { + if (builder.length() > 0) { + builder.append(separator); + } + + builder.append(key); } - public static long toLong(Object obj, long def) { - if (obj instanceof Number) { - return ((Number) obj).longValue(); - } - if (obj instanceof String) { - try { - return Long.parseLong((String) obj); - } catch (NumberFormatException ignored) { - } - } else if (obj instanceof List) { - List val = (List) obj; - if (!val.isEmpty()) { - return toLong(val.get(0), def); - } - } - return def; + return builder.toString(); + } + + @Override + public Set getKeys(boolean deep) { + Set result = new LinkedHashSet<>(); + + Configuration root = getRoot(); + if ((root != null) && root.options().copyDefaults()) { + ConfigurationSection defaults = getDefaultSection(); + + if (defaults != null) { + result.addAll(defaults.getKeys(deep)); + } } - /** - * Creates a full path to the given {@link ConfigurationSection} from its - * root {@link Configuration}. - * - *

You may use this method for any given {@link ConfigurationSection}, not - * only {@link MemorySection}. - * - * @param section Section to create a path for. - * @param key Name of the specified section. - * @return Full path of the section from its root. - */ - public static String createPath(ConfigurationSection section, String key) { - return createPath(section, key, section.getRoot()); + mapChildrenKeys(result, this, deep); + + return result; + } + + @Override + public Map getValues(boolean deep) { + Map result = new LinkedHashMap<>(); + + Configuration root = getRoot(); + if ((root != null) && root.options().copyDefaults()) { + ConfigurationSection defaults = getDefaultSection(); + + if (defaults != null) { + result.putAll(defaults.getValues(deep)); + } } - /** - * Creates a relative path to the given {@link ConfigurationSection} from - * the given relative section. - * - *

You may use this method for any given {@link ConfigurationSection}, not - * only {@link MemorySection}. - * - * @param section Section to create a path for. - * @param key Name of the specified section. - * @param relativeTo Section to create the path relative to. - * @return Full path of the section from its root. - */ - public static String createPath(ConfigurationSection section, String key, - ConfigurationSection relativeTo) { - Configuration root = section.getRoot(); - if (root == null) { - throw new IllegalStateException("Cannot create path without a root"); - } - char separator = root.options().pathSeparator(); + mapChildrenValues(result, this, deep); - StringBuilder builder = new StringBuilder(); - for (ConfigurationSection parent = section; - (parent != null) && (parent != relativeTo); parent = parent.getParent()) { - if (builder.length() > 0) { - builder.insert(0, separator); - } + return result; + } - builder.insert(0, parent.getName()); - } + @Override + public boolean contains(@Nonnull String path) { + return get(path) != null; + } - if ((key != null) && !key.isEmpty()) { - if (builder.length() > 0) { - builder.append(separator); - } + @Override + public boolean isSet(@Nonnull String path) { + Configuration root = getRoot(); + if (root == null) { + return false; + } + if (root.options().copyDefaults()) { + return contains(path); + } + return getOrDefault(path, null) != null; + } - builder.append(key); - } + @Override + public String getCurrentPath() { + return this.fullPath; + } - return builder.toString(); + @Override + public String getName() { + return this.path; + } + + @Override + public Configuration getRoot() { + return this.root; + } + + @Override + public ConfigurationSection getParent() { + return this.parent; + } + + @Override + public void addDefault(@Nonnull String path, Object value) { + Configuration root = getRoot(); + if (root == null) { + throw new IllegalStateException("Cannot add default without root"); + } + if (root == this) { + throw new UnsupportedOperationException( + "Unsupported addDefault(String, Object) implementation"); + } + root.addDefault(createPath(this, path), value); + } + + @Override + public ConfigurationSection getDefaultSection() { + Configuration root = getRoot(); + Configuration defaults = root == null ? null : root.getDefaults(); + + if (defaults != null) { + if (defaults.isConfigurationSection(getCurrentPath())) { + return defaults.getConfigurationSection(getCurrentPath()); + } } - @Override public Set getKeys(boolean deep) { - Set result = new LinkedHashSet<>(); + return null; + } - Configuration root = getRoot(); - if ((root != null) && root.options().copyDefaults()) { - ConfigurationSection defaults = getDefaultSection(); + @Override + public void set(String path, Object value) { + Configuration root = getRoot(); + if (root == null) { + throw new IllegalStateException("Cannot use section without a root"); + } - if (defaults != null) { - result.addAll(defaults.getKeys(deep)); - } - } + char separator = root.options().pathSeparator(); + // i1 is the leading (higher) index + // i2 is the trailing (lower) index + int i1 = -1; + int i2; + ConfigurationSection section = this; + while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) { + String node = path.substring(i2, i1); + ConfigurationSection subSection = section.getConfigurationSection(node); + if (subSection == null) { + section = section.createSection(node); + } else { + section = subSection; + } + } - mapChildrenKeys(result, this, deep); + String key = path.substring(i2); + if (section == this) { + if (value == null) { + this.map.remove(key); + } else { + this.map.put(key, value); + } + } else { + section.set(key, value); + } + } + @Override + public Object get(String path) { + return getOrDefault(path, getDefault(path)); + } + + @Override + public Object getOrDefault(@Nonnull String path, Object defaultValue) { + if (path.isEmpty()) { + return this; + } + + Configuration root = getRoot(); + if (root == null) { + throw new IllegalStateException("Cannot access section without a root"); + } + + char separator = root.options().pathSeparator(); + // i1 is the leading (higher) index + // i2 is the trailing (lower) index + int i1 = -1; + int i2; + ConfigurationSection section = this; + while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) { + section = section.getConfigurationSection(path.substring(i2, i1)); + if (section == null) { + return defaultValue; + } + } + + String key = path.substring(i2); + if (section == this) { + Object result = this.map.get(key); + if (result == null) { + return defaultValue; + } else { return result; + } + } + return section.getOrDefault(key, defaultValue); + } + + @Override + public ConfigurationSection createSection(String path) { + Configuration root = getRoot(); + if (root == null) { + throw new IllegalStateException("Cannot create section without a root"); } - @Override public Map getValues(boolean deep) { - Map result = new LinkedHashMap<>(); + char separator = root.options().pathSeparator(); + // i1 is the leading (higher) index + // i2 is the trailing (lower) index + int i1 = -1; + int i2; + ConfigurationSection section = this; + while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) { + String node = path.substring(i2, i1); + ConfigurationSection subSection = section.getConfigurationSection(node); + if (subSection == null) { + section = section.createSection(node); + } else { + section = subSection; + } + } - Configuration root = getRoot(); - if ((root != null) && root.options().copyDefaults()) { - ConfigurationSection defaults = getDefaultSection(); + String key = path.substring(i2); + if (section == this) { + ConfigurationSection result = new MemorySection(this, key); + this.map.put(key, result); + return result; + } + return section.createSection(key); + } - if (defaults != null) { - result.putAll(defaults.getValues(deep)); - } + @Override + public ConfigurationSection createSection(String path, Map map) { + ConfigurationSection section = createSection(path); + + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() instanceof Map) { + section.createSection(entry.getKey().toString(), (Map) entry.getValue()); + } else { + section.set(entry.getKey().toString(), entry.getValue()); + } + } + + return section; + } + + // Primitives + @Override + public String getString(String path) { + Object def = getDefault(path); + return getString(path, def != null ? def.toString() : null); + } + + @Override + public String getString(String path, String def) { + Object val = getOrDefault(path, def); + if (val != null) { + return val.toString(); + } else { + return def; + } + } + + @Override + public boolean isString(String path) { + Object val = get(path); + return val instanceof String; + } + + @Override + public int getInt(String path) { + Object def = getDefault(path); + return getInt(path, toInt(def, 0)); + } + + @Override + public int getInt(String path, int def) { + Object val = getOrDefault(path, def); + return toInt(val, def); + } + + @Override + public boolean isInt(String path) { + Object val = get(path); + return val instanceof Integer; + } + + @Override + public boolean getBoolean(String path) { + Object def = getDefault(path); + if (def instanceof Boolean) { + return getBoolean(path, (Boolean) def); + } else { + return getBoolean(path, false); + } + } + + @Override + public boolean getBoolean(String path, boolean defaultValue) { + Object val = getOrDefault(path, defaultValue); + if (val instanceof Boolean) { + return (Boolean) val; + } else { + return defaultValue; + } + } + + @Override + public boolean isBoolean(String path) { + Object val = get(path); + return val instanceof Boolean; + } + + @Override + public double getDouble(String path) { + Object def = getDefault(path); + return getDouble(path, toDouble(def, 0)); + } + + @Override + public double getDouble(String path, double defaultValue) { + Object val = getOrDefault(path, defaultValue); + return toDouble(val, defaultValue); + } + + @Override + public boolean isDouble(String path) { + Object val = get(path); + return val instanceof Double; + } + + @Override + public long getLong(String path) { + Object def = getDefault(path); + return getLong(path, toLong(def, 0)); + } + + @Override + public long getLong(String path, long def) { + Object val = getOrDefault(path, def); + return toLong(val, def); + } + + @Override + public boolean isLong(String path) { + Object val = get(path); + return val instanceof Long; + } + + // Java + @Override + public List getList(String path) { + Object def = getDefault(path); + return getList(path, def instanceof List ? (List) def : null); + } + + @Override + public List getList(String path, List def) { + Object val = getOrDefault(path, def); + return (List) ((val instanceof List) ? val : def); + } + + @Override + public boolean isList(String path) { + Object val = get(path); + return val instanceof List; + } + + @Override + public List getStringList(String path) { + List list = getList(path); + + if (list == null) { + return new ArrayList<>(0); + } + + List result = new ArrayList<>(); + + for (Object object : list) { + if ((object instanceof String) || isPrimitiveWrapper(object)) { + result.add(String.valueOf(object)); + } + } + + return result; + } + + @Override + public List getIntegerList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Integer) { + result.add((Integer) object); + } else if (object instanceof String) { + try { + result.add(Integer.valueOf((String) object)); + } catch (NumberFormatException ignored) { } - - mapChildrenValues(result, this, deep); - - return result; + } else if (object instanceof Character) { + result.add((int) (Character) object); + } else if (object instanceof Number) { + result.add(((Number) object).intValue()); + } } - @Override public boolean contains(String path) { - return get(path) != null; - } + return result; + } - @Override public boolean isSet(String path) { - Configuration root = getRoot(); - if (root == null) { - return false; + @Override + public List getBooleanList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Boolean) { + result.add((Boolean) object); + } else if (object instanceof String) { + if (Boolean.TRUE.toString().equals(object)) { + result.add(true); + } else if (Boolean.FALSE.toString().equals(object)) { + result.add(false); } - if (root.options().copyDefaults()) { - return contains(path); + } + } + + return result; + } + + @Override + public List getDoubleList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Double) { + result.add((Double) object); + } else if (object instanceof String) { + try { + result.add(Double.valueOf((String) object)); + } catch (NumberFormatException ignored) { } - return get(path, null) != null; + } else if (object instanceof Character) { + result.add((double) (Character) object); + } else if (object instanceof Number) { + result.add(((Number) object).doubleValue()); + } } - @Override public String getCurrentPath() { - return this.fullPath; - } + return result; + } - @Override public String getName() { - return this.path; - } + @Override + public List getFloatList(String path) { + List list = getList(path); - @Override public Configuration getRoot() { - return this.root; - } + List result = new ArrayList<>(); - @Override public ConfigurationSection getParent() { - return this.parent; - } - - @Override public void addDefault(String path, Object value) { - Configuration root = getRoot(); - if (root == null) { - throw new IllegalStateException("Cannot add default without root"); + for (Object object : list) { + if (object instanceof Float) { + result.add((Float) object); + } else if (object instanceof String) { + try { + result.add(Float.valueOf((String) object)); + } catch (NumberFormatException ignored) { } - if (root == this) { - throw new UnsupportedOperationException( - "Unsupported addDefault(String, Object) implementation"); + } else if (object instanceof Character) { + result.add((float) (Character) object); + } else if (object instanceof Number) { + result.add(((Number) object).floatValue()); + } + } + + return result; + } + + @Override + public List getLongList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Long) { + result.add((Long) object); + } else if (object instanceof String) { + try { + result.add(Long.valueOf((String) object)); + } catch (NumberFormatException ignored) { } - root.addDefault(createPath(this, path), value); + } else if (object instanceof Character) { + result.add((long) (Character) object); + } else if (object instanceof Number) { + result.add(((Number) object).longValue()); + } } - @Override public ConfigurationSection getDefaultSection() { - Configuration root = getRoot(); - Configuration defaults = root == null ? null : root.getDefaults(); + return result; + } - if (defaults != null) { - if (defaults.isConfigurationSection(getCurrentPath())) { - return defaults.getConfigurationSection(getCurrentPath()); - } + @Override + public List getByteList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Byte) { + result.add((Byte) object); + } else if (object instanceof String) { + try { + result.add(Byte.valueOf((String) object)); + } catch (NumberFormatException ignored) { } - - return null; + } else if (object instanceof Character) { + result.add((byte) ((Character) object).charValue()); + } else if (object instanceof Number) { + result.add(((Number) object).byteValue()); + } } - @Override public void set(String path, Object value) { - Configuration root = getRoot(); - if (root == null) { - throw new IllegalStateException("Cannot use section without a root"); + return result; + } + + @Override + public List getCharacterList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Character) { + result.add((Character) object); + } else if (object instanceof String) { + String str = (String) object; + + if (str.length() == 1) { + result.add(str.charAt(0)); } + } else if (object instanceof Number) { + result.add((char) ((Number) object).intValue()); + } + } - char separator = root.options().pathSeparator(); - // i1 is the leading (higher) index - // i2 is the trailing (lower) index - int i1 = -1; - int i2; - ConfigurationSection section = this; - while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) { - String node = path.substring(i2, i1); - ConfigurationSection subSection = section.getConfigurationSection(node); - if (subSection == null) { - section = section.createSection(node); - } else { - section = subSection; - } + return result; + } + + @Override + public List getShortList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Short) { + result.add((Short) object); + } else if (object instanceof String) { + try { + result.add(Short.valueOf((String) object)); + } catch (NumberFormatException ignored) { } + } else if (object instanceof Character) { + result.add((short) ((Character) object).charValue()); + } else if (object instanceof Number) { + result.add(((Number) object).shortValue()); + } + } - String key = path.substring(i2); - if (section == this) { - if (value == null) { - this.map.remove(key); - } else { - this.map.put(key, value); - } - } else { - section.set(key, value); + return result; + } + + @Override + public List> getMapList(String path) { + List list = getList(path); + List> result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Map) { + result.add((Map) object); + } + } + + return result; + } + + @Override + public ConfigurationSection getConfigurationSection(String path) { + Object val = getOrDefault(path, null); + if (val != null) { + return (val instanceof ConfigurationSection) ? (ConfigurationSection) val : null; + } + + val = getOrDefault(path, getDefault(path)); + return (val instanceof ConfigurationSection) ? createSection(path) : null; + } + + @Override + public boolean isConfigurationSection(String path) { + Object val = get(path); + return val instanceof ConfigurationSection; + } + + protected boolean isPrimitiveWrapper(Object input) { + return (input instanceof Integer) || (input instanceof Boolean) + || (input instanceof Character) || (input instanceof Byte) || (input instanceof Short) + || (input instanceof Double) || (input instanceof Long) || (input instanceof Float); + } + + protected Object getDefault(String path) { + Configuration root = getRoot(); + Configuration defaults = root == null ? null : root.getDefaults(); + return (defaults == null) ? null : defaults.get(createPath(this, path)); + } + + protected void mapChildrenKeys(Set output, ConfigurationSection section, boolean deep) { + if (section instanceof MemorySection) { + MemorySection sec = (MemorySection) section; + + for (Map.Entry entry : sec.map.entrySet()) { + output.add(createPath(section, entry.getKey(), this)); + + if (deep && (entry.getValue() instanceof ConfigurationSection)) { + ConfigurationSection subsection = (ConfigurationSection) entry.getValue(); + mapChildrenKeys(output, subsection, deep); } - } + } + } else { + Set keys = section.getKeys(deep); - @Override public Object get(String path) { - return get(path, getDefault(path)); + for (String key : keys) { + output.add(createPath(section, key, this)); + } } + } - @Override public Object get(String path, Object defaultValue) { - if (path == null) { - throw new NullPointerException("Path cannot be null"); + protected void mapChildrenValues(Map output, ConfigurationSection section, + boolean deep) { + if (section instanceof MemorySection) { + MemorySection sec = (MemorySection) section; + + for (Map.Entry entry : sec.map.entrySet()) { + output.put(createPath(section, entry.getKey(), this), entry.getValue()); + + if (entry.getValue() instanceof ConfigurationSection) { + if (deep) { + mapChildrenValues(output, (ConfigurationSection) entry.getValue(), deep); + } } + } + } else { + Map values = section.getValues(deep); - if (path.isEmpty()) { - return this; - } - - Configuration root = getRoot(); - if (root == null) { - throw new IllegalStateException("Cannot access section without a root"); - } - - char separator = root.options().pathSeparator(); - // i1 is the leading (higher) index - // i2 is the trailing (lower) index - int i1 = -1; - int i2; - ConfigurationSection section = this; - while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) { - section = section.getConfigurationSection(path.substring(i2, i1)); - if (section == null) { - return defaultValue; - } - } - - String key = path.substring(i2); - if (section == this) { - Object result = this.map.get(key); - if (result == null) { - return defaultValue; - } else { - return result; - } - } - return section.get(key, defaultValue); + for (Map.Entry entry : values.entrySet()) { + output.put(createPath(section, entry.getKey(), this), entry.getValue()); + } } + } - @Override public ConfigurationSection createSection(String path) { - Configuration root = getRoot(); - if (root == null) { - throw new IllegalStateException("Cannot create section without a root"); - } - - char separator = root.options().pathSeparator(); - // i1 is the leading (higher) index - // i2 is the trailing (lower) index - int i1 = -1; - int i2; - ConfigurationSection section = this; - while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) { - String node = path.substring(i2, i1); - ConfigurationSection subSection = section.getConfigurationSection(node); - if (subSection == null) { - section = section.createSection(node); - } else { - section = subSection; - } - } - - String key = path.substring(i2); - if (section == this) { - ConfigurationSection result = new MemorySection(this, key); - this.map.put(key, result); - return result; - } - return section.createSection(key); - } - - @Override public ConfigurationSection createSection(String path, Map map) { - ConfigurationSection section = createSection(path); - - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() instanceof Map) { - section.createSection(entry.getKey().toString(), (Map) entry.getValue()); - } else { - section.set(entry.getKey().toString(), entry.getValue()); - } - } - - return section; - } - - // Primitives - @Override public String getString(String path) { - Object def = getDefault(path); - return getString(path, def != null ? def.toString() : null); - } - - @Override public String getString(String path, String def) { - Object val = get(path, def); - if (val != null) { - return val.toString(); - } else { - return def; - } - } - - @Override public boolean isString(String path) { - Object val = get(path); - return val instanceof String; - } - - @Override public int getInt(String path) { - Object def = getDefault(path); - return getInt(path, toInt(def, 0)); - } - - @Override public int getInt(String path, int def) { - Object val = get(path, def); - return toInt(val, def); - } - - @Override public boolean isInt(String path) { - Object val = get(path); - return val instanceof Integer; - } - - @Override public boolean getBoolean(String path) { - Object def = getDefault(path); - if (def instanceof Boolean) { - return getBoolean(path, (Boolean) def); - } else { - return getBoolean(path, false); - } - } - - @Override public boolean getBoolean(String path, boolean defaultValue) { - Object val = get(path, defaultValue); - if (val instanceof Boolean) { - return (Boolean) val; - } else { - return defaultValue; - } - } - - @Override public boolean isBoolean(String path) { - Object val = get(path); - return val instanceof Boolean; - } - - @Override public double getDouble(String path) { - Object def = getDefault(path); - return getDouble(path, toDouble(def, 0)); - } - - @Override public double getDouble(String path, double defaultValue) { - Object val = get(path, defaultValue); - return toDouble(val, defaultValue); - } - - @Override public boolean isDouble(String path) { - Object val = get(path); - return val instanceof Double; - } - - @Override public long getLong(String path) { - Object def = getDefault(path); - return getLong(path, toLong(def, 0)); - } - - @Override public long getLong(String path, long def) { - Object val = get(path, def); - return toLong(val, def); - } - - @Override public boolean isLong(String path) { - Object val = get(path); - return val instanceof Long; - } - - // Java - @Override public List getList(String path) { - Object def = getDefault(path); - return getList(path, def instanceof List ? (List) def : null); - } - - @Override public List getList(String path, List def) { - Object val = get(path, def); - return (List) ((val instanceof List) ? val : def); - } - - @Override public boolean isList(String path) { - Object val = get(path); - return val instanceof List; - } - - @Override public List getStringList(String path) { - List list = getList(path); - - if (list == null) { - return new ArrayList<>(0); - } - - List result = new ArrayList<>(); - - for (Object object : list) { - if ((object instanceof String) || isPrimitiveWrapper(object)) { - result.add(String.valueOf(object)); - } - } - - return result; - } - - @Override public List getIntegerList(String path) { - List list = getList(path); - - List result = new ArrayList<>(); - - for (Object object : list) { - if (object instanceof Integer) { - result.add((Integer) object); - } else if (object instanceof String) { - try { - result.add(Integer.valueOf((String) object)); - } catch (NumberFormatException ignored) { - } - } else if (object instanceof Character) { - result.add((int) (Character) object); - } else if (object instanceof Number) { - result.add(((Number) object).intValue()); - } - } - - return result; - } - - @Override public List getBooleanList(String path) { - List list = getList(path); - - List result = new ArrayList<>(); - - for (Object object : list) { - if (object instanceof Boolean) { - result.add((Boolean) object); - } else if (object instanceof String) { - if (Boolean.TRUE.toString().equals(object)) { - result.add(true); - } else if (Boolean.FALSE.toString().equals(object)) { - result.add(false); - } - } - } - - return result; - } - - @Override public List getDoubleList(String path) { - List list = getList(path); - - List result = new ArrayList<>(); - - for (Object object : list) { - if (object instanceof Double) { - result.add((Double) object); - } else if (object instanceof String) { - try { - result.add(Double.valueOf((String) object)); - } catch (NumberFormatException ignored) { - } - } else if (object instanceof Character) { - result.add((double) (Character) object); - } else if (object instanceof Number) { - result.add(((Number) object).doubleValue()); - } - } - - return result; - } - - @Override public List getFloatList(String path) { - List list = getList(path); - - List result = new ArrayList<>(); - - for (Object object : list) { - if (object instanceof Float) { - result.add((Float) object); - } else if (object instanceof String) { - try { - result.add(Float.valueOf((String) object)); - } catch (NumberFormatException ignored) { - } - } else if (object instanceof Character) { - result.add((float) (Character) object); - } else if (object instanceof Number) { - result.add(((Number) object).floatValue()); - } - } - - return result; - } - - @Override public List getLongList(String path) { - List list = getList(path); - - List result = new ArrayList<>(); - - for (Object object : list) { - if (object instanceof Long) { - result.add((Long) object); - } else if (object instanceof String) { - try { - result.add(Long.valueOf((String) object)); - } catch (NumberFormatException ignored) { - } - } else if (object instanceof Character) { - result.add((long) (Character) object); - } else if (object instanceof Number) { - result.add(((Number) object).longValue()); - } - } - - return result; - } - - @Override public List getByteList(String path) { - List list = getList(path); - - List result = new ArrayList<>(); - - for (Object object : list) { - if (object instanceof Byte) { - result.add((Byte) object); - } else if (object instanceof String) { - try { - result.add(Byte.valueOf((String) object)); - } catch (NumberFormatException ignored) { - } - } else if (object instanceof Character) { - result.add((byte) ((Character) object).charValue()); - } else if (object instanceof Number) { - result.add(((Number) object).byteValue()); - } - } - - return result; - } - - @Override public List getCharacterList(String path) { - List list = getList(path); - - List result = new ArrayList<>(); - - for (Object object : list) { - if (object instanceof Character) { - result.add((Character) object); - } else if (object instanceof String) { - String str = (String) object; - - if (str.length() == 1) { - result.add(str.charAt(0)); - } - } else if (object instanceof Number) { - result.add((char) ((Number) object).intValue()); - } - } - - return result; - } - - @Override public List getShortList(String path) { - List list = getList(path); - - List result = new ArrayList<>(); - - for (Object object : list) { - if (object instanceof Short) { - result.add((Short) object); - } else if (object instanceof String) { - try { - result.add(Short.valueOf((String) object)); - } catch (NumberFormatException ignored) { - } - } else if (object instanceof Character) { - result.add((short) ((Character) object).charValue()); - } else if (object instanceof Number) { - result.add(((Number) object).shortValue()); - } - } - - return result; - } - - @Override public List> getMapList(String path) { - List list = getList(path); - List> result = new ArrayList<>(); - - for (Object object : list) { - if (object instanceof Map) { - result.add((Map) object); - } - } - - return result; - } - - @Override public ConfigurationSection getConfigurationSection(String path) { - Object val = get(path, null); - if (val != null) { - return (val instanceof ConfigurationSection) ? (ConfigurationSection) val : null; - } - - val = get(path, getDefault(path)); - return (val instanceof ConfigurationSection) ? createSection(path) : null; - } - - @Override public boolean isConfigurationSection(String path) { - Object val = get(path); - return val instanceof ConfigurationSection; - } - - protected boolean isPrimitiveWrapper(Object input) { - return (input instanceof Integer) || (input instanceof Boolean) - || (input instanceof Character) || (input instanceof Byte) || (input instanceof Short) - || (input instanceof Double) || (input instanceof Long) || (input instanceof Float); - } - - protected Object getDefault(String path) { - Configuration root = getRoot(); - Configuration defaults = root == null ? null : root.getDefaults(); - return (defaults == null) ? null : defaults.get(createPath(this, path)); - } - - protected void mapChildrenKeys(Set output, ConfigurationSection section, boolean deep) { - if (section instanceof MemorySection) { - MemorySection sec = (MemorySection) section; - - for (Map.Entry entry : sec.map.entrySet()) { - output.add(createPath(section, entry.getKey(), this)); - - if (deep && (entry.getValue() instanceof ConfigurationSection)) { - ConfigurationSection subsection = (ConfigurationSection) entry.getValue(); - mapChildrenKeys(output, subsection, deep); - } - } - } else { - Set keys = section.getKeys(deep); - - for (String key : keys) { - output.add(createPath(section, key, this)); - } - } - } - - protected void mapChildrenValues(Map output, ConfigurationSection section, - boolean deep) { - if (section instanceof MemorySection) { - MemorySection sec = (MemorySection) section; - - for (Map.Entry entry : sec.map.entrySet()) { - output.put(createPath(section, entry.getKey(), this), entry.getValue()); - - if (entry.getValue() instanceof ConfigurationSection) { - if (deep) { - mapChildrenValues(output, (ConfigurationSection) entry.getValue(), deep); - } - } - } - } else { - Map values = section.getValues(deep); - - for (Map.Entry entry : values.entrySet()) { - output.put(createPath(section, entry.getKey(), this), entry.getValue()); - } - } - } - - @Override public String toString() { - Configuration root = getRoot(); - if (root == null) { - return getClass().getSimpleName() + "[path='" + getCurrentPath() + "', root='" + null - + "']"; - } else { - return getClass().getSimpleName() + "[path='" + getCurrentPath() + "', root='" + root - .getClass().getSimpleName() + "']"; - } + @Override + public String toString() { + Configuration root = getRoot(); + if (root == null) { + return getClass().getSimpleName() + "[path='" + getCurrentPath() + "', root='" + null + + "']"; + } else { + return getClass().getSimpleName() + "[path='" + getCurrentPath() + "', root='" + root + .getClass().getSimpleName() + "']"; } + } } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/FileConfiguration.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/FileConfiguration.java index 668509bf3..97643f7ee 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/FileConfiguration.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/FileConfiguration.java @@ -6,6 +6,7 @@ import com.github.intellectualsites.plotsquared.configuration.MemoryConfiguratio import java.io.*; import java.nio.charset.StandardCharsets; +import javax.annotation.Nonnull; /** * This is a base class for all File based implementations of {@link @@ -82,7 +83,7 @@ public abstract class FileConfiguration extends MemoryConfiguration { * a valid Configuration. * @throws IllegalArgumentException Thrown when file is null. */ - public void load(File file) throws IOException, InvalidConfigurationException { + public void load(@Nonnull File file) throws IOException, InvalidConfigurationException { FileInputStream stream = new FileInputStream(file); diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfiguration.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfiguration.java index d8c41c3da..1e694f05a 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfiguration.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfiguration.java @@ -83,7 +83,7 @@ public class YamlConfiguration extends FileConfiguration { Map input; try { - input = (Map) yaml.load(contents); + input = yaml.load(contents); } catch (YAMLException e) { throw new InvalidConfigurationException(e); } catch (ClassCastException ignored) { diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfigurationOptions.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfigurationOptions.java index a17bc3538..730527652 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfigurationOptions.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfigurationOptions.java @@ -42,7 +42,7 @@ public class YamlConfigurationOptions extends FileConfigurationOptions { * * @return How much to indent by */ - public int indent() { + int indent() { return indent; } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConstructor.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConstructor.java index 1f52f7abb..cdc5eb821 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConstructor.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConstructor.java @@ -9,7 +9,7 @@ import org.yaml.snakeyaml.nodes.Tag; import java.util.LinkedHashMap; import java.util.Map; -public class YamlConstructor extends SafeConstructor { +class YamlConstructor extends SafeConstructor { YamlConstructor() { yamlConstructors.put(Tag.MAP, new ConstructCustomObject()); diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/IPlotMain.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/IPlotMain.java index e50ec9e8e..7fa0ec41a 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/IPlotMain.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/IPlotMain.java @@ -76,7 +76,9 @@ public interface IPlotMain extends ILogger { * * @return */ - String getPluginName(); + default String getPluginName() { + return "PlotSquared"; + } /** * Get the version of Minecraft that is running. diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/Platform.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/Platform.java index b7eb33b83..9dfbf2ffb 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/Platform.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/Platform.java @@ -1,6 +1,6 @@ package com.github.intellectualsites.plotsquared.plot; public enum Platform { - Bukkit, Sponge, Spigot, Cauldron + Bukkit, Sponge, Spigot } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java index 2d55e9048..84991d2b4 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java @@ -47,179 +47,182 @@ import java.util.zip.ZipInputStream; /** * An implementation of the core, with a static getter for easy access. */ -@SuppressWarnings({"unused", "WeakerAccess"}) public class PlotSquared { - private static final Set EMPTY_SET = - Collections.unmodifiableSet(Collections.emptySet()); - private static PlotSquared instance; - // Implementation - public final IPlotMain IMP; - // Current thread - private final Thread thread; - // WorldEdit instance - public WorldEdit worldedit; - public File styleFile; - public File configFile; - public File worldsFile; - public File commandsFile; - public File translationFile; - public YamlConfiguration style; - public YamlConfiguration config; - public YamlConfiguration worlds; - public YamlConfiguration storage; - public YamlConfiguration commands; - // Temporary hold the plots/clusters before the worlds load - public HashMap> clusters_tmp; - public HashMap> plots_tmp; - // Implementation logger - @Setter @Getter private ILogger logger; - // Platform / Version / Update URL - private PlotVersion version; - // Files and configuration - @Getter private File jarFile = null; // This file - private File storageFile; - @Getter private PlotAreaManager plotAreaManager; +@SuppressWarnings({"unused", "WeakerAccess"}) +public class PlotSquared { - /** - * Initialize PlotSquared with the desired Implementation class. - * - * @param iPlotMain Implementation of {@link IPlotMain} used - * @param platform The platform being used - */ - public PlotSquared(final IPlotMain iPlotMain, final String platform) { - if (instance != null) { - throw new IllegalStateException("Cannot re-initialize the PlotSquared singleton"); + private static final Set EMPTY_SET = + Collections.unmodifiableSet(Collections.emptySet()); + private static PlotSquared instance; + // Implementation + public final IPlotMain IMP; + // Current thread + private final Thread thread; + // WorldEdit instance + public WorldEdit worldedit; + public File styleFile; + public File configFile; + public File worldsFile; + public File commandsFile; + public File translationFile; + public YamlConfiguration style; + public YamlConfiguration config; + public YamlConfiguration worlds; + public YamlConfiguration storage; + public YamlConfiguration commands; + // Temporary hold the plots/clusters before the worlds load + public HashMap> clusters_tmp; + public HashMap> plots_tmp; + // Implementation logger + @Setter + @Getter + private ILogger logger; + // Platform / Version / Update URL + private PlotVersion version; + // Files and configuration + @Getter + private File jarFile = null; // This file + private File storageFile; + @Getter + private PlotAreaManager plotAreaManager; + + /** + * Initialize PlotSquared with the desired Implementation class. + * + * @param iPlotMain Implementation of {@link IPlotMain} used + * @param platform The platform being used + */ + public PlotSquared(final IPlotMain iPlotMain, final String platform) { + if (instance != null) { + throw new IllegalStateException("Cannot re-initialize the PlotSquared singleton"); + } + instance = this; + + this.thread = Thread.currentThread(); + this.IMP = iPlotMain; + this.logger = iPlotMain; + Settings.PLATFORM = platform; + + // + // Register configuration serializable classes + // + ConfigurationSerialization.registerClass(PlotBlock.class, "PlotBlock"); + ConfigurationSerialization.registerClass(BlockBucket.class, "BlockBucket"); + + try { + new ReflectionUtils(this.IMP.getNMSPackage()); + try { + URL url = PlotSquared.class.getProtectionDomain().getCodeSource().getLocation(); + this.jarFile = new File( + new URL(url.toURI().toString().split("\\!")[0].replaceAll("jar:file", "file")) + .toURI().getPath()); + } catch (MalformedURLException | URISyntaxException | SecurityException e) { + e.printStackTrace(); + this.jarFile = new File(this.IMP.getDirectory().getParentFile(), "PlotSquared.jar"); + if (!this.jarFile.exists()) { + this.jarFile = new File(this.IMP.getDirectory().getParentFile(), + "PlotSquared-" + platform + ".jar"); } - instance = this; + } + TaskManager.IMP = this.IMP.getTaskManager(); - this.thread = Thread.currentThread(); - this.IMP = iPlotMain; - this.logger = iPlotMain; - Settings.PLATFORM = platform; + // World Util. Has to be done before config files are loaded + WorldUtil.IMP = this.IMP.initWorldUtil(); - // - // Register configuration serializable classes - // - ConfigurationSerialization.registerClass(PlotBlock.class, "PlotBlock"); - ConfigurationSerialization.registerClass(BlockBucket.class, "BlockBucket"); + if (!setupConfigs()) { + return; + } + this.translationFile = MainUtil.getFile(this.IMP.getDirectory(), + Settings.Paths.TRANSLATIONS + File.separator + IMP.getPluginName() + + ".use_THIS.yml"); + C.load(this.translationFile); + // Setup plotAreaManager + if (Settings.Enabled_Components.WORLDS) { + this.plotAreaManager = new SinglePlotAreaManager(); + } else { + this.plotAreaManager = new DefaultPlotAreaManager(); + } + + // Database + if (Settings.Enabled_Components.DATABASE) { + setupDatabase(); + } + // Comments + CommentManager.registerDefaultInboxes(); + // Kill entities + if (Settings.Enabled_Components.KILL_ROAD_MOBS + || Settings.Enabled_Components.KILL_ROAD_VEHICLES) { + this.IMP.runEntityTask(); + } + if (Settings.Enabled_Components.EVENTS) { + this.IMP.registerPlayerEvents(); + this.IMP.registerInventoryEvents(); + this.IMP.registerPlotPlusEvents(); + } + // Required + this.IMP.registerWorldEvents(); + if (Settings.Enabled_Components.METRICS) { + this.IMP.startMetrics(); + } else { + PlotSquared.log(C.CONSOLE_PLEASE_ENABLE_METRICS.f(IMP.getPluginName())); + } + if (Settings.Enabled_Components.CHUNK_PROCESSOR) { + this.IMP.registerChunkProcessor(); + } + // create UUIDWrapper + UUIDHandler.implementation = this.IMP.initUUIDHandler(); + if (Settings.Enabled_Components.UUID_CACHE) { + startUuidCatching(); + } else { + // Start these separately + UUIDHandler.add(new StringWrapper("*"), DBFunc.EVERYONE); + startExpiryTasks(); + } + // create event util class + EventUtil.manager = this.IMP.initEventUtil(); + // create Hybrid utility class + HybridUtils.manager = this.IMP.initHybridUtils(); + // Inventory utility class + InventoryUtil.manager = this.IMP.initInventoryUtil(); + // create setup util class + SetupUtils.manager = this.IMP.initSetupUtils(); + // Set block + GlobalBlockQueue.IMP = new GlobalBlockQueue(IMP.initBlockQueue(), 1); + GlobalBlockQueue.IMP.runTask(); + // Set chunk + ChunkManager.manager = this.IMP.initChunkManager(); + // Schematic handler + SchematicHandler.manager = this.IMP.initSchematicHandler(); + // Titles + AbstractTitle.TITLE_CLASS = this.IMP.initTitleManager(); + // Chat + ChatManager.manager = this.IMP.initChatManager(); + // Commands + if (Settings.Enabled_Components.COMMANDS) { + this.IMP.registerCommands(); + } + // WorldEdit + if (Settings.Enabled_Components.WORLDEDIT_RESTRICTIONS) { try { - new ReflectionUtils(this.IMP.getNMSPackage()); - try { - URL url = PlotSquared.class.getProtectionDomain().getCodeSource().getLocation(); - this.jarFile = new File( - new URL(url.toURI().toString().split("\\!")[0].replaceAll("jar:file", "file")) - .toURI().getPath()); - } catch (MalformedURLException | URISyntaxException | SecurityException e) { - e.printStackTrace(); - this.jarFile = new File(this.IMP.getDirectory().getParentFile(), "PlotSquared.jar"); - if (!this.jarFile.exists()) { - this.jarFile = new File(this.IMP.getDirectory().getParentFile(), - "PlotSquared-" + platform + ".jar"); - } - } - TaskManager.IMP = this.IMP.getTaskManager(); - - // World Util. Has to be done before config files are loaded - WorldUtil.IMP = this.IMP.initWorldUtil(); - - if (!setupConfigs()) { - return; - } - this.translationFile = MainUtil.getFile(this.IMP.getDirectory(), - Settings.Paths.TRANSLATIONS + File.separator + IMP.getPluginName() - + ".use_THIS.yml"); - C.load(this.translationFile); - - // Setup plotAreaManager - if (Settings.Enabled_Components.WORLDS) { - this.plotAreaManager = new SinglePlotAreaManager(); - } else { - this.plotAreaManager = new DefaultPlotAreaManager(); - } - - // Database - if (Settings.Enabled_Components.DATABASE) { - setupDatabase(); - } - // Comments - CommentManager.registerDefaultInboxes(); - // Kill entities - if (Settings.Enabled_Components.KILL_ROAD_MOBS - || Settings.Enabled_Components.KILL_ROAD_VEHICLES) { - this.IMP.runEntityTask(); - } - if (Settings.Enabled_Components.EVENTS) { - this.IMP.registerPlayerEvents(); - this.IMP.registerInventoryEvents(); - this.IMP.registerPlotPlusEvents(); - } - // Required - this.IMP.registerWorldEvents(); - if (Settings.Enabled_Components.METRICS) { - this.IMP.startMetrics(); - } else { - PlotSquared.log(C.CONSOLE_PLEASE_ENABLE_METRICS.f(IMP.getPluginName())); - } - if (Settings.Enabled_Components.CHUNK_PROCESSOR) { - this.IMP.registerChunkProcessor(); - } - // create UUIDWrapper - UUIDHandler.implementation = this.IMP.initUUIDHandler(); - if (Settings.Enabled_Components.UUID_CACHE) { - startUuidCatching(); - } else { - // Start these separately - UUIDHandler.add(new StringWrapper("*"), DBFunc.EVERYONE); - startExpiryTasks(); - } - // create event util class - EventUtil.manager = this.IMP.initEventUtil(); - // create Hybrid utility class - HybridUtils.manager = this.IMP.initHybridUtils(); - // Inventory utility class - InventoryUtil.manager = this.IMP.initInventoryUtil(); - // create setup util class - SetupUtils.manager = this.IMP.initSetupUtils(); - // Set block - GlobalBlockQueue.IMP = new GlobalBlockQueue(IMP.initBlockQueue(), 1); - GlobalBlockQueue.IMP.runTask(); - // Set chunk - ChunkManager.manager = this.IMP.initChunkManager(); - // Schematic handler - SchematicHandler.manager = this.IMP.initSchematicHandler(); - // Titles - AbstractTitle.TITLE_CLASS = this.IMP.initTitleManager(); - // Chat - ChatManager.manager = this.IMP.initChatManager(); - // Commands + if (this.IMP.initWorldEdit()) { + PlotSquared.debug(IMP.getPluginName() + " hooked into WorldEdit."); + this.worldedit = WorldEdit.getInstance(); + WorldEdit.getInstance().getEventBus().register(new WESubscriber()); if (Settings.Enabled_Components.COMMANDS) { - this.IMP.registerCommands(); + new WE_Anywhere(); } - // WorldEdit - if (Settings.Enabled_Components.WORLDEDIT_RESTRICTIONS) { - try { - if (this.IMP.initWorldEdit()) { - PlotSquared.debug(IMP.getPluginName() + " hooked into WorldEdit."); - this.worldedit = WorldEdit.getInstance(); - WorldEdit.getInstance().getEventBus().register(new WESubscriber()); - if (Settings.Enabled_Components.COMMANDS) { - new WE_Anywhere(); - } - } - } catch (Throwable e) { - PlotSquared.debug( - "Incompatible version of WorldEdit, please upgrade: http://builds.enginehub.org/job/worldedit?branch=master"); - } - } - // Economy - if (Settings.Enabled_Components.ECONOMY) { - TaskManager.runTask(new Runnable() { - @Override public void run() { - EconHandler.manager = PlotSquared.this.IMP.getEconomyHandler(); - } - }); - } + } + } catch (Throwable e) { + PlotSquared.debug( + "Incompatible version of WorldEdit, please upgrade: http://builds.enginehub.org/job/worldedit?branch=master"); + } + } + // Economy + if (Settings.Enabled_Components.ECONOMY) { + TaskManager.runTask( + () -> EconHandler.manager = PlotSquared.this.IMP.getEconomyHandler()); + } /* // Check for updates if (Settings.Enabled_Components.UPDATER) { @@ -236,1810 +239,1864 @@ import java.util.zip.ZipInputStream; }, 36000); }*/ - // World generators: - final ConfigurationSection section = this.worlds.getConfigurationSection("worlds"); - if (section != null) { - for (String world : section.getKeys(false)) { - if (world.equals("CheckingPlotSquaredGenerator")) { - continue; - } - if (WorldUtil.IMP.isWorld(world)) { - this.IMP.setGenerator(world); - } - } - TaskManager.runTaskLater(new Runnable() { - @Override public void run() { - for (String world : section.getKeys(false)) { - if (world.equals("CheckingPlotSquaredGenerator")) { - continue; - } - if (!WorldUtil.IMP.isWorld(world) && !world.equals("*")) { - debug("&c`" + world + "` was not properly loaded - " + IMP - .getPluginName() + " will now try to load it properly: "); - debug( - "&8 - &7Are you trying to delete this world? Remember to remove it from the settings.yml, bukkit.yml and multiverse worlds.yml"); - debug( - "&8 - &7Your world management plugin may be faulty (or non existent)"); - PlotSquared.this.IMP.setGenerator(world); - } - } - } - }, 1); + // World generators: + final ConfigurationSection section = this.worlds.getConfigurationSection("worlds"); + if (section != null) { + for (String world : section.getKeys(false)) { + if (world.equals("CheckingPlotSquaredGenerator")) { + continue; + } + if (WorldUtil.IMP.isWorld(world)) { + this.IMP.setGenerator(world); + } + } + TaskManager.runTaskLater(() -> { + for (String world : section.getKeys(false)) { + if (world.equals("CheckingPlotSquaredGenerator")) { + continue; } + if (!WorldUtil.IMP.isWorld(world) && !world.equals("*")) { + debug("&c`" + world + "` was not properly loaded - " + IMP + .getPluginName() + " will now try to load it properly: "); + debug( + "&8 - &7Are you trying to delete this world? Remember to remove it from the settings.yml, bukkit.yml and multiverse worlds.yml"); + debug( + "&8 - &7Your world management plugin may be faulty (or non existent)"); + PlotSquared.this.IMP.setGenerator(world); + } + } + }, 1); + } - // Copy files - copyFile("addplots.js", Settings.Paths.SCRIPTS); - copyFile("addsigns.js", Settings.Paths.SCRIPTS); - copyFile("automerge.js", Settings.Paths.SCRIPTS); - copyFile("furthest.js", Settings.Paths.SCRIPTS); - copyFile("mycommand.js", Settings.Paths.SCRIPTS); - copyFile("setbiomes.js", Settings.Paths.SCRIPTS); - copyFile("start.js", Settings.Paths.SCRIPTS); - copyFile("town.template", Settings.Paths.TEMPLATES); - copyFile("skyblock.template", Settings.Paths.TEMPLATES); - copyFile("bridge.template", Settings.Paths.TEMPLATES); - copyFile("de-DE.yml", Settings.Paths.TRANSLATIONS); - copyFile("es-ES.yml", Settings.Paths.TRANSLATIONS); - copyFile("zh-CN.yml", Settings.Paths.TRANSLATIONS); - copyFile("it-IT.yml", Settings.Paths.TRANSLATIONS); - copyFile("ko-KR.yml", Settings.Paths.TRANSLATIONS); - copyFile("fr-FR.yml", Settings.Paths.TRANSLATIONS); - showDebug(); - } catch (Throwable e) { - e.printStackTrace(); + // Copy files + copyFile("addplots.js", Settings.Paths.SCRIPTS); + copyFile("addsigns.js", Settings.Paths.SCRIPTS); + copyFile("automerge.js", Settings.Paths.SCRIPTS); + copyFile("furthest.js", Settings.Paths.SCRIPTS); + copyFile("mycommand.js", Settings.Paths.SCRIPTS); + copyFile("setbiomes.js", Settings.Paths.SCRIPTS); + copyFile("start.js", Settings.Paths.SCRIPTS); + copyFile("town.template", Settings.Paths.TEMPLATES); + copyFile("skyblock.template", Settings.Paths.TEMPLATES); + copyFile("bridge.template", Settings.Paths.TEMPLATES); + copyFile("de-DE.yml", Settings.Paths.TRANSLATIONS); + copyFile("es-ES.yml", Settings.Paths.TRANSLATIONS); + copyFile("zh-CN.yml", Settings.Paths.TRANSLATIONS); + copyFile("it-IT.yml", Settings.Paths.TRANSLATIONS); + copyFile("ko-KR.yml", Settings.Paths.TRANSLATIONS); + copyFile("fr-FR.yml", Settings.Paths.TRANSLATIONS); + showDebug(); + } catch (Throwable e) { + e.printStackTrace(); + } + + PlotSquared.log(C.ENABLED.f(IMP.getPluginName())); + } + + /** + * Get an instance of PlotSquared. + * + * @return instance of PlotSquared + */ + public static PlotSquared get() { + return PlotSquared.instance; + } + + public static IPlotMain imp() { + if (instance != null) { + return instance.IMP; + } + return null; + } + + /** + * Log a message to the IPlotMain logger. + * + * @param message Message to log + * @see IPlotMain#log(String) + */ + public static void log(Object message) { + if (message == null || message.toString().isEmpty()) { + return; + } + if (PlotSquared.get() == null || PlotSquared.get().getLogger() == null) { + System.out.printf("[P2][Info] %s\n", StringMan.getString(message)); + } else { + PlotSquared.get().getLogger().log(StringMan.getString(message)); + } + } + + /** + * Log a message to the IPlotMain logger. + * + * @param message Message to log + * @see IPlotMain#log(String) + */ + public static void debug(@Nullable Object message) { + if (Settings.DEBUG) { + if (PlotSquared.get() == null || PlotSquared.get().getLogger() == null) { + System.out.printf("[P2][Debug] %s\n", StringMan.getString(message)); + } else { + PlotSquared.get().getLogger().log(StringMan.getString(message)); + } + } + } + + private void startUuidCatching() { + TaskManager.runTaskLater(() -> { + debug("Starting UUID caching"); + UUIDHandler.startCaching(() -> { + UUIDHandler.add(new StringWrapper("*"), DBFunc.EVERYONE); + foreachPlotRaw(new RunnableVal() { + @Override + public void run(Plot plot) { + if (plot.hasOwner() && plot.temp != -1) { + if (UUIDHandler.getName(plot.owner) == null) { + UUIDHandler.implementation.unknown.add(plot.owner); + } + } + } + }); + startExpiryTasks(); + }); + }, 20); + } + + private void startExpiryTasks() { + if (Settings.Enabled_Components.PLOT_EXPIRY) { + ExpireManager.IMP = new ExpireManager(); + ExpireManager.IMP.runAutomatedTask(); + for (Settings.Auto_Clear settings : Settings.AUTO_CLEAR.getInstances()) { + ExpiryTask task = new ExpiryTask(settings); + ExpireManager.IMP.addTask(task); + } + } + } + + public boolean isMainThread(Thread thread) { + return this.thread == thread; + } + + /** + * Check if `version` is >= `version2`. + * + * @param version First version + * @param version2 Second version + * @return true if `version` is >= `version2` + */ + public boolean checkVersion(int[] version, int... version2) { + return version[0] > version2[0] || version[0] == version2[0] && version[1] > version2[1] + || version[0] == version2[0] && version[1] == version2[1] && version[2] >= version2[2]; + } + + /** + * Get the current PlotSquared version. + * + * @return current version in config or null + */ + public PlotVersion getVersion() { + return this.version; + } + + /** + * Get the server platform this plugin is running on this is running on. + *

+ *

This will be either Bukkit or Sponge

+ * + * @return the server implementation + */ + public String getPlatform() { + return Settings.PLATFORM; + } + + public PlotManager getPlotManager(Plot plot) { + return plot.getArea().manager; + } + + public PlotManager getPlotManager(Location location) { + PlotArea pa = getPlotAreaAbs(location); + return pa != null ? pa.manager : null; + } + + /** + * Add a global reference to a plot world. + * + * @param plotArea the {@code PlotArea} to add. + * @see #removePlotArea(PlotArea) To remove the reference + */ + public void addPlotArea(PlotArea plotArea) { + HashMap plots; + if (plots_tmp == null || (plots = plots_tmp.remove(plotArea.toString())) == null) { + if (plotArea.TYPE == 2) { + plots = this.plots_tmp != null ? this.plots_tmp.get(plotArea.worldname) : null; + if (plots != null) { + Iterator> iterator = plots.entrySet().iterator(); + while (iterator.hasNext()) { + Entry next = iterator.next(); + PlotId id = next.getKey(); + if (plotArea.contains(id)) { + next.getValue().setArea(plotArea); + iterator.remove(); + } + } } - - PlotSquared.log(C.ENABLED.f(IMP.getPluginName())); + } + } else { + for (Plot entry : plots.values()) { + entry.setArea(plotArea); + } } - - /** - * Get an instance of PlotSquared. - * - * @return instance of PlotSquared - */ - public static PlotSquared get() { - return PlotSquared.instance; - } - - public static IPlotMain imp() { - if (instance != null) { - return instance.IMP; + Set clusters; + if (clusters_tmp == null || (clusters = clusters_tmp.remove(plotArea.toString())) == null) { + if (plotArea.TYPE == 2) { + clusters = + this.clusters_tmp != null ? this.clusters_tmp.get(plotArea.worldname) : null; + if (clusters != null) { + Iterator iterator = clusters.iterator(); + while (iterator.hasNext()) { + PlotCluster next = iterator.next(); + if (next.intersects(plotArea.getMin(), plotArea.getMax())) { + next.setArea(plotArea); + iterator.remove(); + } + } } - return null; + } + } else { + for (PlotCluster cluster : clusters) { + cluster.setArea(plotArea); + } } + plotAreaManager.addPlotArea(plotArea); + plotArea.setupBorder(); + } - /** - * Log a message to the IPlotMain logger. - * - * @param message Message to log - * @see IPlotMain#log(String) - */ - public static void log(Object message) { - if (message == null || message.toString().isEmpty()) { + /** + * Remove a plot world reference. + * + * @param area the {@code PlotArea} to remove + */ + public void removePlotArea(PlotArea area) { + plotAreaManager.removePlotArea(area); + setPlotsTmp(area); + } + + public void removePlotAreas(String world) { + for (PlotArea area : getPlotAreas(world)) { + if (area.worldname.equals(world)) { + removePlotArea(area); + } + } + } + + private void setPlotsTmp(PlotArea area) { + if (this.plots_tmp == null) { + this.plots_tmp = new HashMap<>(); + } + HashMap map = this.plots_tmp + .computeIfAbsent(area.toString(), k -> new HashMap<>()); + for (Plot plot : area.getPlots()) { + map.put(plot.getId(), plot); + } + if (this.clusters_tmp == null) { + this.clusters_tmp = new HashMap<>(); + } + this.clusters_tmp.put(area.toString(), area.getClusters()); + } + + public Set getClusters(String world) { + Set set = new HashSet<>(); + for (PlotArea area : getPlotAreas(world)) { + set.addAll(area.getClusters()); + } + return Collections.unmodifiableSet(set); + + } + + /** + * Get all the base plots in a single set (for merged plots it just returns the bottom plot). + * + * @return Set of base Plots + */ + public Set getBasePlots() { + int size = getPlotCount(); + final Set result = new HashSet<>(size); + foreachPlotArea(new RunnableVal() { + @Override + public void run(PlotArea value) { + for (Plot plot : value.getPlots()) { + if (!plot.isBasePlot()) { + continue; + } + result.add(plot); + } + } + }); + return Collections.unmodifiableSet(result); + } + + public List sortPlotsByTemp(Collection plots) { + int max = 0; + int overflowCount = 0; + for (Plot plot : plots) { + if (plot.temp > 0) { + if (plot.temp > max) { + max = plot.temp; + } + } else { + overflowCount++; + } + } + Plot[] array = new Plot[max + 1]; + List overflow = new ArrayList<>(overflowCount); + for (Plot plot : plots) { + if (plot.temp <= 0) { + overflow.add(plot); + } else { + array[plot.temp] = plot; + } + } + ArrayList result = new ArrayList<>(plots.size()); + for (Plot plot : array) { + if (plot != null) { + result.add(plot); + } + } + overflow.sort(Comparator.comparingInt(Plot::hashCode)); + result.addAll(overflow); + return result; + } + + /** + * Sort plots by hashcode. + * + * @param plots the collection of plots to sort + * @return the sorted collection {@link #sortPlots(Collection, SortType, PlotArea)} which has + * additional checks before calling this + */ + // TODO: Re-evaluate this (previously public and deprecated), as it's being used internally + private ArrayList sortPlotsByHash(Collection plots) { + int hardmax = 256000; + int max = 0; + int overflowSize = 0; + for (Plot plot : plots) { + int hash = MathMan.getPositiveId(plot.hashCode()); + if (hash > max) { + if (hash >= hardmax) { + overflowSize++; + } else { + max = hash; + } + } + } + hardmax = Math.min(hardmax, max); + Plot[] cache = new Plot[hardmax + 1]; + List overflow = new ArrayList<>(overflowSize); + ArrayList extra = new ArrayList<>(); + for (Plot plot : plots) { + int hash = MathMan.getPositiveId(plot.hashCode()); + if (hash < hardmax) { + if (hash >= 0) { + cache[hash] = plot; + } else { + extra.add(plot); + } + } else if (Math.abs(plot.getId().x) > 15446 || Math.abs(plot.getId().y) > 15446) { + extra.add(plot); + } else { + overflow.add(plot); + } + } + Plot[] overflowArray = overflow.toArray(new Plot[overflow.size()]); + sortPlotsByHash(overflowArray); + ArrayList result = new ArrayList<>(cache.length + overflowArray.length); + for (Plot plot : cache) { + if (plot != null) { + result.add(plot); + } + } + Collections.addAll(result, overflowArray); + result.addAll(extra); + return result; + } + + private void sortPlotsByHash(Plot[] input) { + List[] bucket = new ArrayList[32]; + for (int i = 0; i < bucket.length; i++) { + bucket[i] = new ArrayList<>(); + } + boolean maxLength = false; + int placement = 1; + while (!maxLength) { + maxLength = true; + for (Plot i : input) { + int tmp = MathMan.getPositiveId(i.hashCode()) / placement; + bucket[tmp & 31].add(i); + if (maxLength && tmp > 0) { + maxLength = false; + } + } + int a = 0; + for (int b = 0; b < 32; b++) { + for (Plot i : bucket[b]) { + input[a++] = i; + } + bucket[b].clear(); + } + placement *= 32; + } + } + + private ArrayList sortPlotsByTimestamp(Collection plots) { + int hardMax = 256000; + int max = 0; + int overflowSize = 0; + for (Plot plot : plots) { + int hash = MathMan.getPositiveId(plot.hashCode()); + if (hash > max) { + if (hash >= hardMax) { + overflowSize++; + } else { + max = hash; + } + } + } + hardMax = Math.min(hardMax, max); + Plot[] cache = new Plot[hardMax + 1]; + List overflow = new ArrayList<>(overflowSize); + ArrayList extra = new ArrayList<>(); + for (Plot plot : plots) { + int hash = MathMan.getPositiveId(plot.hashCode()); + if (hash < hardMax) { + if (hash >= 0) { + cache[hash] = plot; + } else { + extra.add(plot); + } + } else if (Math.abs(plot.getId().x) > 15446 || Math.abs(plot.getId().y) > 15446) { + extra.add(plot); + } else { + overflow.add(plot); + } + } + Plot[] overflowArray = overflow.toArray(new Plot[overflow.size()]); + sortPlotsByHash(overflowArray); + ArrayList result = new ArrayList<>(cache.length + overflowArray.length); + for (Plot plot : cache) { + if (plot != null) { + result.add(plot); + } + } + Collections.addAll(result, overflowArray); + result.addAll(extra); + return result; + } + + /** + * Sort plots by creation timestamp. + */ + + private List sortPlotsByModified(Collection input) { + List list; + if (input instanceof List) { + list = (List) input; + } else { + list = new ArrayList<>(input); + } + list.sort(Comparator.comparingLong(a -> ExpireManager.IMP.getTimestamp(a.owner))); + return list; + } + + /** + * Sort a collection of plots by world (with a priority world), then by hashcode. + * + * @param plots the plots to sort + * @param type The sorting method to use for each world (timestamp, or hash) + * @param priorityArea Use null, "world", or "gibberish" if you want default world order + * @return ArrayList of plot + */ + public ArrayList sortPlots(Collection plots, SortType type, + final PlotArea priorityArea) { + // group by world + // sort each + HashMap> map = new HashMap<>(); + int totalSize = getPlotCount(); + if (plots.size() == totalSize) { + for (PlotArea area : plotAreaManager.getAllPlotAreas()) { + map.put(area, area.getPlots()); + } + } else { + for (PlotArea area : plotAreaManager.getAllPlotAreas()) { + map.put(area, new ArrayList<>(0)); + } + Collection lastList = null; + PlotArea lastWorld = null; + for (Plot plot : plots) { + if (lastWorld == plot.getArea()) { + lastList.add(plot); + } else { + lastWorld = plot.getArea(); + lastList = map.get(lastWorld); + lastList.add(plot); + } + } + } + List areas = Arrays.asList(plotAreaManager.getAllPlotAreas()); + areas.sort((a, b) -> { + if (priorityArea != null) { + if (a.equals(priorityArea)) { + return -1; + } else if (b.equals(priorityArea)) { + return 1; + } + } + return a.hashCode() - b.hashCode(); + }); + ArrayList toReturn = new ArrayList<>(plots.size()); + for (PlotArea area : areas) { + switch (type) { + case CREATION_DATE: + toReturn.addAll(sortPlotsByTemp(map.get(area))); + break; + case CREATION_DATE_TIMESTAMP: + toReturn.addAll(sortPlotsByTimestamp(map.get(area))); + break; + case DISTANCE_FROM_ORIGIN: + toReturn.addAll(sortPlotsByHash(map.get(area))); + break; + case LAST_MODIFIED: + toReturn.addAll(sortPlotsByModified(map.get(area))); + break; + default: + break; + } + } + return toReturn; + } + + /** + * A more generic way to filter plots - make your own method if you need complex filters. + * + * @param filters the filter + * @return a filtered set of plots + */ + public Set getPlots(final PlotFilter... filters) { + final HashSet set = new HashSet<>(); + foreachPlotArea(new RunnableVal() { + @Override + public void run(PlotArea value) { + for (PlotFilter filter : filters) { + if (!filter.allowsArea(value)) { return; + } } - if (PlotSquared.get() == null || PlotSquared.get().getLogger() == null) { - System.out.printf("[P2][Info] %s\n", StringMan.getString(message)); - } else { - PlotSquared.get().getLogger().log(StringMan.getString(message)); + loop: + for (Entry entry2 : value.getPlotEntries()) { + Plot plot = entry2.getValue(); + for (PlotFilter filter : filters) { + if (!filter.allowsPlot(plot)) { + continue loop; + } + } + set.add(plot); } - } + } + }); + return set; + } - /** - * Log a message to the IPlotMain logger. - * - * @param message Message to log - * @see IPlotMain#log(String) - */ - public static void debug(@Nullable Object message) { - if (Settings.DEBUG) { - if (PlotSquared.get() == null || PlotSquared.get().getLogger() == null) { - System.out.printf("[P2][Debug] %s\n", StringMan.getString(message)); - } else { - PlotSquared.get().getLogger().log(StringMan.getString(message)); - } + /** + * Get all the plots in a single set. + * + * @return Set of Plots + */ + public Set getPlots() { + int size = getPlotCount(); + final Set result = new HashSet<>(size); + foreachPlotArea(new RunnableVal() { + @Override + public void run(PlotArea value) { + result.addAll(value.getPlots()); + } + }); + return result; + } + + //TODO look at uncommenting or deleting tis. Is it useful and will it work? + //If it is readded make sure there is proper javadoc documentation for it. +/* + public void setPlots(HashMap> plots) { + if (this.plots_tmp == null) { + this.plots_tmp = new HashMap<>(); + } + for (Entry> entry : plots.entrySet()) { + String world = entry.getKey(); + PlotArea area = getPlotArea(world, null); + if (area == null) { + HashMap map = this.plots_tmp + .computeIfAbsent(world, k -> new HashMap<>()); + map.putAll(entry.getValue()); + } else { + for (Plot plot : entry.getValue().values()) { + plot.setArea(area); + area.addPlot(plot); } + } } + } +*/ - private void startUuidCatching() { - TaskManager.runTaskLater(new Runnable() { - @Override public void run() { - debug("Starting UUID caching"); - UUIDHandler.startCaching(new Runnable() { - @Override public void run() { - UUIDHandler.add(new StringWrapper("*"), DBFunc.EVERYONE); - foreachPlotRaw(new RunnableVal() { - @Override public void run(Plot plot) { - if (plot.hasOwner() && plot.temp != -1) { - if (UUIDHandler.getName(plot.owner) == null) { - UUIDHandler.implementation.unknown.add(plot.owner); - } - } - } - }); - startExpiryTasks(); - } - }); - } - }, 20); + /** + * Get all the plots owned by a player name. + * + * @param world the world + * @param player the plot owner + * @return Set of Plot + */ + public Set getPlots(String world, String player) { + final UUID uuid = UUIDHandler.getUUID(player, null); + return getPlots(world, uuid); + } + + /** + * Get all the plots owned by a player name. + * + * @param area the PlotArea + * @param player the plot owner + * @return Set of Plot + */ + public Set getPlots(PlotArea area, String player) { + UUID uuid = UUIDHandler.getUUID(player, null); + return getPlots(area, uuid); + } + + /** + * Get all plots by a PlotPlayer. + * + * @param world the world + * @param player the plot owner + * @return Set of plot + */ + public Set getPlots(String world, PlotPlayer player) { + return getPlots(world, player.getUUID()); + } + + /** + * Get all plots by a PlotPlayer. + * + * @param area the PlotArea + * @param player the plot owner + * @return Set of plot + */ + public Set getPlots(PlotArea area, PlotPlayer player) { + return getPlots(area, player.getUUID()); + } + + /** + * Get all plots by a UUID in a world. + * + * @param world the world + * @param uuid the plot owner + * @return Set of plot + */ + public Set getPlots(String world, UUID uuid) { + final Set plots = new HashSet<>(); + for (final Plot plot : getPlots(world)) { + if (plot.hasOwner() && plot.isOwnerAbs(uuid)) { + plots.add(plot); + } } + return Collections.unmodifiableSet(plots); + } - private void startExpiryTasks() { - if (Settings.Enabled_Components.PLOT_EXPIRY) { - ExpireManager.IMP = new ExpireManager(); - ExpireManager.IMP.runAutomatedTask(); - for (Settings.Auto_Clear settings : Settings.AUTO_CLEAR.getInstances()) { - ExpiryTask task = new ExpiryTask(settings); - ExpireManager.IMP.addTask(task); - } + /** + * Get all plots by a UUID in an area. + * + * @param area the {@code PlotArea} + * @param uuid the plot owner + * @return Set of plots + */ + public Set getPlots(PlotArea area, UUID uuid) { + final Set plots = new HashSet<>(); + for (Plot plot : getPlots(area)) { + if (plot.hasOwner() && plot.isOwnerAbs(uuid)) { + plots.add(plot); + } + } + return Collections.unmodifiableSet(plots); + } + + /** + * Check if a plot world. + * + * @param world the world + * @return if a plot world is registered + * @see #getPlotAreaByString(String) to get the PlotArea object + */ + public boolean hasPlotArea(String world) { + return plotAreaManager.getPlotAreas(world, null).length != 0; + } + + public Collection getPlots(String world) { + final Set set = new HashSet<>(); + foreachPlotArea(world, new RunnableVal() { + @Override + public void run(PlotArea value) { + set.addAll(value.getPlots()); + } + }); + return set; + } + + /** + * Get the plots for a PlotPlayer. + * + * @param player the player to retrieve the plots for + * @return Set of Plot + */ + public Set getPlots(PlotPlayer player) { + return getPlots(player.getUUID()); + } + + public Collection getPlots(PlotArea area) { + return area == null ? EMPTY_SET : area.getPlots(); + } + + public Plot getPlot(PlotArea area, PlotId id) { + return area == null ? null : id == null ? null : area.getPlot(id); + } + + public Set getBasePlots(PlotPlayer player) { + return getBasePlots(player.getUUID()); + } + + /** + * Get the plots for a UUID. + * + * @param uuid the plot owner + * @return Set of Plot's owned by the player + */ + public Set getPlots(final UUID uuid) { + final Set plots = new HashSet<>(); + foreachPlot(new RunnableVal() { + @Override + public void run(Plot value) { + if (value.isOwnerAbs(uuid)) { + plots.add(value); } - } + } + }); + return Collections.unmodifiableSet(plots); + } - public boolean isMainThread(Thread thread) { - return this.thread == thread; - } - - /** - * Check if `version` is >= `version2`. - * - * @param version First version - * @param version2 Second version - * @return true if `version` is >= `version2` - */ - public boolean checkVersion(int[] version, int... version2) { - return version[0] > version2[0] || version[0] == version2[0] && version[1] > version2[1] - || version[0] == version2[0] && version[1] == version2[1] && version[2] >= version2[2]; - } - - /** - * Get the current PlotSquared version. - * - * @return current version in config or null - */ - public PlotVersion getVersion() { - return this.version; - } - - /** - * Get the server platform this plugin is running on this is running on. - *

- *

This will be either Bukkit or Sponge

- * - * @return the server implementation - */ - public String getPlatform() { - return Settings.PLATFORM; - } - - public PlotManager getPlotManager(Plot plot) { - return plot.getArea().manager; - } - - public PlotManager getPlotManager(Location location) { - PlotArea pa = getPlotAreaAbs(location); - return pa != null ? pa.manager : null; - } - - /** - * Add a global reference to a plot world. - * - * @param plotArea the {@code PlotArea} to add. - * @see #removePlotArea(PlotArea) To remove the reference - */ - public void addPlotArea(PlotArea plotArea) { - HashMap plots; - if (plots_tmp == null || (plots = plots_tmp.remove(plotArea.toString())) == null) { - if (plotArea.TYPE == 2) { - plots = this.plots_tmp != null ? this.plots_tmp.get(plotArea.worldname) : null; - if (plots != null) { - Iterator> iterator = plots.entrySet().iterator(); - while (iterator.hasNext()) { - Entry next = iterator.next(); - PlotId id = next.getKey(); - if (plotArea.contains(id)) { - next.getValue().setArea(plotArea); - iterator.remove(); - } - } - } - } - } else { - for (Plot entry : plots.values()) { - entry.setArea(plotArea); - } - } - Set clusters; - if (clusters_tmp == null || (clusters = clusters_tmp.remove(plotArea.toString())) == null) { - if (plotArea.TYPE == 2) { - clusters = - this.clusters_tmp != null ? this.clusters_tmp.get(plotArea.worldname) : null; - if (clusters != null) { - Iterator iterator = clusters.iterator(); - while (iterator.hasNext()) { - PlotCluster next = iterator.next(); - if (next.intersects(plotArea.getMin(), plotArea.getMax())) { - next.setArea(plotArea); - iterator.remove(); - } - } - } - } - } else { - for (PlotCluster cluster : clusters) { - cluster.setArea(plotArea); - } - } - plotAreaManager.addPlotArea(plotArea); - plotArea.setupBorder(); - } - - /** - * Remove a plot world reference. - * - * @param area the {@code PlotArea} to remove - */ - public void removePlotArea(PlotArea area) { - plotAreaManager.removePlotArea(area); - setPlotsTmp(area); - } - - public void removePlotAreas(String world) { - for (PlotArea area : getPlotAreas(world)) { - if (area.worldname.equals(world)) { - removePlotArea(area); - } - } - } - - private void setPlotsTmp(PlotArea area) { - if (this.plots_tmp == null) { - this.plots_tmp = new HashMap<>(); - } - HashMap map = this.plots_tmp.get(area.toString()); - if (map == null) { - map = new HashMap<>(); - this.plots_tmp.put(area.toString(), map); - } - for (Plot plot : area.getPlots()) { - map.put(plot.getId(), plot); - } - if (this.clusters_tmp == null) { - this.clusters_tmp = new HashMap<>(); - } - this.clusters_tmp.put(area.toString(), area.getClusters()); - } - - public Set getClusters(String world) { - Set set = new HashSet<>(); - for (PlotArea area : getPlotAreas(world)) { - set.addAll(area.getClusters()); - } - return Collections.unmodifiableSet(set); - - } - - /** - * Get all the base plots in a single set (for merged plots it just returns - * the bottom plot). - * - * @return Set of base Plots - */ - public Set getBasePlots() { - int size = getPlotCount(); - final Set result = new HashSet<>(size); - foreachPlotArea(new RunnableVal() { - @Override public void run(PlotArea value) { - for (Plot plot : value.getPlots()) { - if (!plot.isBasePlot()) { - continue; - } - result.add(plot); - } - } - }); - return Collections.unmodifiableSet(result); - } - - public List sortPlotsByTemp(Collection plots) { - int max = 0; - int overflowCount = 0; - for (Plot plot : plots) { - if (plot.temp > 0) { - if (plot.temp > max) { - max = plot.temp; - } - } else { - overflowCount++; - } - } - Plot[] array = new Plot[max + 1]; - List overflow = new ArrayList<>(overflowCount); - for (Plot plot : plots) { - if (plot.temp <= 0) { - overflow.add(plot); - } else { - array[plot.temp] = plot; - } - } - ArrayList result = new ArrayList<>(plots.size()); - for (Plot plot : array) { - if (plot != null) { - result.add(plot); - } - } - Collections.sort(overflow, new Comparator() { - @Override public int compare(Plot a, Plot b) { - return a.hashCode() - b.hashCode(); - } - }); - result.addAll(overflow); - return result; - } - - /** - * Sort plots by hashcode. - * - * @param plots the collection of plots to sort - * @return the sorted collection - * @deprecated Unchecked, please use - * {@link #sortPlots(Collection, SortType, PlotArea)} which has - * additional checks before calling this - */ - // TODO: Re-evaluate deprecation of this, as it's being used internally - @Deprecated public ArrayList sortPlotsByHash(Collection plots) { - int hardmax = 256000; - int max = 0; - int overflowSize = 0; - for (Plot plot : plots) { - int hash = MathMan.getPositiveId(plot.hashCode()); - if (hash > max) { - if (hash >= hardmax) { - overflowSize++; - } else { - max = hash; - } - } - } - hardmax = Math.min(hardmax, max); - Plot[] cache = new Plot[hardmax + 1]; - List overflow = new ArrayList<>(overflowSize); - ArrayList extra = new ArrayList<>(); - for (Plot plot : plots) { - int hash = MathMan.getPositiveId(plot.hashCode()); - if (hash < hardmax) { - if (hash >= 0) { - cache[hash] = plot; - } else { - extra.add(plot); - } - } else if (Math.abs(plot.getId().x) > 15446 || Math.abs(plot.getId().y) > 15446) { - extra.add(plot); - } else { - overflow.add(plot); - } - } - Plot[] overflowArray = overflow.toArray(new Plot[overflow.size()]); - sortPlotsByHash(overflowArray); - ArrayList result = new ArrayList<>(cache.length + overflowArray.length); - for (Plot plot : cache) { - if (plot != null) { - result.add(plot); - } - } - Collections.addAll(result, overflowArray); - for (Plot plot : extra) { - result.add(plot); - } - return result; - } - - /** - * Unchecked, use {@link #sortPlots(Collection, SortType, PlotArea)} instead which will in turn call this. - * - * @param input an array of plots to sort - */ - // TODO: Re-evaluate deprecation of this, as it's being used internally - @Deprecated public void sortPlotsByHash(Plot[] input) { - List[] bucket = new ArrayList[32]; - for (int i = 0; i < bucket.length; i++) { - bucket[i] = new ArrayList<>(); - } - boolean maxLength = false; - int placement = 1; - while (!maxLength) { - maxLength = true; - for (Plot i : input) { - int tmp = MathMan.getPositiveId(i.hashCode()) / placement; - bucket[tmp & 31].add(i); - if (maxLength && tmp > 0) { - maxLength = false; - } - } - int a = 0; - for (int b = 0; b < 32; b++) { - for (Plot i : bucket[b]) { - input[a++] = i; - } - bucket[b].clear(); - } - placement *= 32; - } - } - - // TODO: Re-evaluate deprecation of this, as it's being used internally - @Deprecated public ArrayList sortPlotsByTimestamp(Collection plots) { - int hardMax = 256000; - int max = 0; - int overflowSize = 0; - for (Plot plot : plots) { - int hash = MathMan.getPositiveId(plot.hashCode()); - if (hash > max) { - if (hash >= hardMax) { - overflowSize++; - } else { - max = hash; - } - } - } - hardMax = Math.min(hardMax, max); - Plot[] cache = new Plot[hardMax + 1]; - List overflow = new ArrayList<>(overflowSize); - ArrayList extra = new ArrayList<>(); - for (Plot plot : plots) { - int hash = MathMan.getPositiveId(plot.hashCode()); - if (hash < hardMax) { - if (hash >= 0) { - cache[hash] = plot; - } else { - extra.add(plot); - } - } else if (Math.abs(plot.getId().x) > 15446 || Math.abs(plot.getId().y) > 15446) { - extra.add(plot); - } else { - overflow.add(plot); - } - } - Plot[] overflowArray = overflow.toArray(new Plot[overflow.size()]); - sortPlotsByHash(overflowArray); - ArrayList result = new ArrayList<>(cache.length + overflowArray.length); - for (Plot plot : cache) { - if (plot != null) { - result.add(plot); - } - } - Collections.addAll(result, overflowArray); - for (Plot plot : extra) { - result.add(plot); - } - return result; - } - - /** - * Sort plots by creation timestamp. - * - * @param input - * @return - * @deprecated Unchecked, use {@link #sortPlots(Collection, SortType, PlotArea)} instead which will call this after checks - */ - // TODO: Re-evaluate deprecation of this, as it's being used internally - @Deprecated public List sortPlotsByModified(Collection input) { - List list; - if (input instanceof List) { - list = (List) input; - } else { - list = new ArrayList<>(input); - } - Collections.sort(list, new Comparator() { - @Override public int compare(Plot a, Plot b) { - return Long.compare(ExpireManager.IMP.getTimestamp(a.owner), - ExpireManager.IMP.getTimestamp(b.owner)); - } - }); - return list; - } - - public ArrayList sortPlots(Collection plots) { - return sortPlots(plots, SortType.DISTANCE_FROM_ORIGIN, null); - } - - /** - * Sort a collection of plots by world (with a priority world), then - * by hashcode. - * - * @param plots the plots to sort - * @param type The sorting method to use for each world (timestamp, or hash) - * @param priorityArea Use null, "world", or "gibberish" if you - * want default world order - * @return ArrayList of plot - */ - public ArrayList sortPlots(Collection plots, SortType type, - final PlotArea priorityArea) { - // group by world - // sort each - HashMap> map = new HashMap<>(); - int totalSize = getPlotCount(); - if (plots.size() == totalSize) { - for (PlotArea area : plotAreaManager.getAllPlotAreas()) { - map.put(area, area.getPlots()); - } - } else { - for (PlotArea area : plotAreaManager.getAllPlotAreas()) { - map.put(area, new ArrayList(0)); - } - Collection lastList = null; - PlotArea lastWorld = null; - for (Plot plot : plots) { - if (lastWorld == plot.getArea()) { - lastList.add(plot); - } else { - lastWorld = plot.getArea(); - lastList = map.get(lastWorld); - lastList.add(plot); - } - } - } - List areas = Arrays.asList(plotAreaManager.getAllPlotAreas()); - Collections.sort(areas, new Comparator() { - @Override public int compare(PlotArea a, PlotArea b) { - if (priorityArea != null) { - if (a.equals(priorityArea)) { - return -1; - } else if (b.equals(priorityArea)) { - return 1; - } - } - return a.hashCode() - b.hashCode(); - } - }); - ArrayList toReturn = new ArrayList<>(plots.size()); - for (PlotArea area : areas) { - switch (type) { - case CREATION_DATE: - toReturn.addAll(sortPlotsByTemp(map.get(area))); - break; - case CREATION_DATE_TIMESTAMP: - toReturn.addAll(sortPlotsByTimestamp(map.get(area))); - break; - case DISTANCE_FROM_ORIGIN: - toReturn.addAll(sortPlotsByHash(map.get(area))); - break; - case LAST_MODIFIED: - toReturn.addAll(sortPlotsByModified(map.get(area))); - break; - default: - break; - } - } - return toReturn; - } - - /** - * A more generic way to filter plots - make your own method - * if you need complex filters. - * - * @param filters the filter - * @return a filtered set of plots - */ - public Set getPlots(final PlotFilter... filters) { - final HashSet set = new HashSet<>(); - foreachPlotArea(new RunnableVal() { - @Override public void run(PlotArea value) { - for (PlotFilter filter : filters) { - if (!filter.allowsArea(value)) { - return; - } - } - loop: - for (Entry entry2 : value.getPlotEntries()) { - Plot plot = entry2.getValue(); - for (PlotFilter filter : filters) { - if (!filter.allowsPlot(plot)) { - continue loop; - } - } - set.add(plot); - } - } - }); - return set; - } - - /** - * Get all the plots in a single set. - * - * @return Set of Plots - */ - public Set getPlots() { - int size = getPlotCount(); - final Set result = new HashSet<>(size); - foreachPlotArea(new RunnableVal() { - @Override public void run(PlotArea value) { - result.addAll(value.getPlots()); - } - }); - return result; - } - - public void setPlots(HashMap> plots) { - if (this.plots_tmp == null) { - this.plots_tmp = new HashMap<>(); - } - for (Entry> entry : plots.entrySet()) { - String world = entry.getKey(); - PlotArea area = getPlotArea(world, null); - if (area == null) { - HashMap map = this.plots_tmp.get(world); - if (map == null) { - map = new HashMap<>(); - this.plots_tmp.put(world, map); - } - map.putAll(entry.getValue()); - } else { - for (Plot plot : entry.getValue().values()) { - plot.setArea(area); - area.addPlot(plot); - } - } - } - } - - /** - * Get all the plots owned by a player name. - * - * @param world the world - * @param player the plot owner - * @return Set of Plot - */ - public Set getPlots(String world, String player) { - final UUID uuid = UUIDHandler.getUUID(player, null); - return getPlots(world, uuid); - } - - /** - * Get all the plots owned by a player name. - * - * @param area the PlotArea - * @param player the plot owner - * @return Set of Plot - */ - public Set getPlots(PlotArea area, String player) { - UUID uuid = UUIDHandler.getUUID(player, null); - return getPlots(area, uuid); - } - - /** - * Get all plots by a PlotPlayer. - * - * @param world the world - * @param player the plot owner - * @return Set of plot - */ - public Set getPlots(String world, PlotPlayer player) { - return getPlots(world, player.getUUID()); - } - - /** - * Get all plots by a PlotPlayer. - * - * @param area the PlotArea - * @param player the plot owner - * @return Set of plot - */ - public Set getPlots(PlotArea area, PlotPlayer player) { - return getPlots(area, player.getUUID()); - } - - /** - * Get all plots by a UUID in a world. - * - * @param world the world - * @param uuid the plot owner - * @return Set of plot - */ - public Set getPlots(String world, UUID uuid) { - final Set plots = new HashSet<>(); - for (final Plot plot : getPlots(world)) { - if (plot.hasOwner() && plot.isOwnerAbs(uuid)) { - plots.add(plot); - } - } - return Collections.unmodifiableSet(plots); - } - - /** - * Get all plots by a UUID in an area. - * - * @param area the {@code PlotArea} - * @param uuid the plot owner - * @return Set of plots - */ - public Set getPlots(PlotArea area, UUID uuid) { - final Set plots = new HashSet<>(); - for (Plot plot : getPlots(area)) { - if (plot.hasOwner() && plot.isOwnerAbs(uuid)) { - plots.add(plot); - } - } - return Collections.unmodifiableSet(plots); - } - - /** - * Check if a plot world. - * - * @param world the world - * @return if a plot world is registered - * @see #getPlotAreaByString(String) to get the PlotArea object - */ - public boolean hasPlotArea(String world) { - return plotAreaManager.getPlotAreas(world, null).length != 0; - } - - public Collection getPlots(String world) { - final Set set = new HashSet<>(); - foreachPlotArea(world, new RunnableVal() { - @Override public void run(PlotArea value) { - set.addAll(value.getPlots()); - } - }); - return set; - } - - /** - * Get the plots for a PlotPlayer. - * - * @param player the player to retrieve the plots for - * @return Set of Plot - */ - public Set getPlots(PlotPlayer player) { - return getPlots(player.getUUID()); - } - - public Collection getPlots(PlotArea area) { - return area == null ? EMPTY_SET : area.getPlots(); - } - - public Plot getPlot(PlotArea area, PlotId id) { - return area == null ? null : id == null ? null : area.getPlot(id); - } - - public Set getBasePlots(PlotPlayer player) { - return getBasePlots(player.getUUID()); - } - - /** - * Get the plots for a UUID. - * - * @param uuid the plot owner - * @return Set of Plot's owned by the player - */ - public Set getPlots(final UUID uuid) { - final Set plots = new HashSet<>(); - foreachPlot(new RunnableVal() { - @Override public void run(Plot value) { - if (value.isOwnerAbs(uuid)) { - plots.add(value); - } - } - }); - return Collections.unmodifiableSet(plots); - } - - public boolean hasPlot(final UUID uuid) { - for (final PlotArea area : plotAreaManager.getAllPlotAreas()) { - if (area.hasPlot(uuid)) - return true; - } - return false; - } - - public Set getBasePlots(final UUID uuid) { - final Set plots = new HashSet<>(); - foreachBasePlot(new RunnableVal() { - @Override public void run(Plot value) { - if (value.isOwner(uuid)) { - plots.add(value); - } - } - }); - return Collections.unmodifiableSet(plots); - } - - /** - * Get the plots for a UUID. - * - * @param uuid the UUID of the owner - * @return Set of Plot - */ - public Set getPlotsAbs(final UUID uuid) { - final Set plots = new HashSet<>(); - foreachPlot(new RunnableVal() { - @Override public void run(Plot value) { - if (value.isOwnerAbs(uuid)) { - plots.add(value); - } - } - }); - return Collections.unmodifiableSet(plots); - } - - /** - * Unregister a plot from local memory (does not call DB). - * - * @param plot the plot to remove - * @param callEvent If to call an event about the plot being removed - * @return true if plot existed | false if it didn't - */ - public boolean removePlot(Plot plot, boolean callEvent) { - if (plot == null) { - return false; - } - if (callEvent) { - EventUtil.manager.callDelete(plot); - } - if (plot.getArea().removePlot(plot.getId())) { - PlotId last = (PlotId) plot.getArea().getMeta("lastPlot"); - int last_max = Math.max(Math.abs(last.x), Math.abs(last.y)); - int this_max = Math.max(Math.abs(plot.getId().x), Math.abs(plot.getId().y)); - if (this_max < last_max) { - plot.getArea().setMeta("lastPlot", plot.getId()); - } - return true; - } - return false; - } - - /** - * This method is called by the PlotGenerator class normally. - *
    - *
  • Initializes the PlotArea and PlotManager classes - *
  • Registers the PlotArea and PlotManager classes - *
  • Loads (and/or generates) the PlotArea configuration - *
  • Sets up the world border if configured - *
- * - *

If loading an augmented plot world: - *

    - *
  • Creates the AugmentedPopulator classes - *
  • Injects the AugmentedPopulator classes if required - *
- * - * @param world the world to load - * @param baseGenerator The generator for that world, or null - */ - public void loadWorld(String world, GeneratorWrapper baseGenerator) { - if (world.equals("CheckingPlotSquaredGenerator")) { - return; - } - this.plotAreaManager.addWorld(world); - Set worlds; - if (this.worlds.contains("worlds")) { - worlds = this.worlds.getConfigurationSection("worlds").getKeys(false); - } else { - worlds = new HashSet<>(); - } - String path = "worlds." + world; - ConfigurationSection worldSection = this.worlds.getConfigurationSection(path); - int type; - if (worldSection != null) { - type = worldSection.getInt("generator.type", 0); - } else { - type = 0; - } - if (type == 0) { - if (plotAreaManager.getPlotAreas(world, null).length != 0) { - debug("World possibly already loaded: " + world); - return; - } - IndependentPlotGenerator plotGenerator; - if (baseGenerator != null && baseGenerator.isFull()) { - plotGenerator = baseGenerator.getPlotGenerator(); - } else if (worldSection != null) { - String secondaryGeneratorName = worldSection.getString("generator.plugin"); - GeneratorWrapper secondaryGenerator = - this.IMP.getGenerator(world, secondaryGeneratorName); - if (secondaryGenerator != null && secondaryGenerator.isFull()) { - plotGenerator = secondaryGenerator.getPlotGenerator(); - } else { - String primaryGeneratorName = worldSection.getString("generator.init"); - GeneratorWrapper primaryGenerator = - this.IMP.getGenerator(world, primaryGeneratorName); - if (primaryGenerator != null && primaryGenerator.isFull()) { - plotGenerator = primaryGenerator.getPlotGenerator(); - } else { - return; - } - } - } else { - return; - } - // Conventional plot generator - PlotArea plotArea = plotGenerator.getNewPlotArea(world, null, null, null); - PlotManager plotManager = plotGenerator.getNewPlotManager(); - PlotSquared.log(C.PREFIX + "&aDetected world load for '" + world + "'"); - PlotSquared.log(C.PREFIX + "&3 - generator: &7" + baseGenerator + ">" + plotGenerator); - PlotSquared.log(C.PREFIX + "&3 - plotworld: &7" + plotArea.getClass().getName()); - PlotSquared - .log(C.PREFIX + "&3 - plotAreaManager: &7" + plotManager.getClass().getName()); - if (!this.worlds.contains(path)) { - this.worlds.createSection(path); - worldSection = this.worlds.getConfigurationSection(path); - } - plotArea.saveConfiguration(worldSection); - plotArea.loadDefaultConfiguration(worldSection); - try { - this.worlds.save(this.worldsFile); - } catch (IOException e) { - e.printStackTrace(); - } - // Now add it - addPlotArea(plotArea); - plotGenerator.initialize(plotArea); - } else { - if (!worlds.contains(world)) { - return; - } - ConfigurationSection areasSection = worldSection.getConfigurationSection("areas"); - if (areasSection == null) { - if (plotAreaManager.getPlotAreas(world, null).length != 0) { - debug("World possibly already loaded: " + world); - return; - } - PlotSquared.log(C.PREFIX + "&aDetected world load for '" + world + "'"); - String gen_string = worldSection.getString("generator.plugin", IMP.getPluginName()); - if (type == 2) { - Set clusters = this.clusters_tmp != null ? - this.clusters_tmp.get(world) : - new HashSet(); - if (clusters == null) { - throw new IllegalArgumentException("No cluster exists for world: " + world); - } - ArrayDeque toLoad = new ArrayDeque<>(); - for (PlotCluster cluster : clusters) { - PlotId pos1 = cluster.getP1(); // Cluster pos1 - PlotId pos2 = cluster.getP2(); // Cluster pos2 - String name = cluster.getName(); // Cluster name - String fullId = name + "-" + pos1 + "-" + pos2; - worldSection.createSection("areas." + fullId); - DBFunc.replaceWorld(world, world + ";" + name, pos1, pos2); // NPE - - PlotSquared.log(C.PREFIX + "&3 - " + name + "-" + pos1 + "-" + pos2); - GeneratorWrapper areaGen = this.IMP.getGenerator(world, gen_string); - if (areaGen == null) { - throw new IllegalArgumentException("Invalid Generator: " + gen_string); - } - PlotArea pa = - areaGen.getPlotGenerator().getNewPlotArea(world, name, pos1, pos2); - pa.saveConfiguration(worldSection); - pa.loadDefaultConfiguration(worldSection); - try { - this.worlds.save(this.worldsFile); - } catch (IOException e) { - e.printStackTrace(); - } - PlotSquared - .log(C.PREFIX + "&c | &9generator: &7" + baseGenerator + ">" + areaGen); - PlotSquared.log(C.PREFIX + "&c | &9plotworld: &7" + pa); - PlotSquared.log(C.PREFIX + "&c | &9manager: &7" + pa); - PlotSquared.log(C.PREFIX + "&cNote: &7Area created for cluster:" + name - + " (invalid or old configuration?)"); - areaGen.getPlotGenerator().initialize(pa); - areaGen.augment(pa); - toLoad.add(pa); - } - for (PlotArea area : toLoad) { - addPlotArea(area); - } - return; - } - GeneratorWrapper areaGen = this.IMP.getGenerator(world, gen_string); - if (areaGen == null) { - throw new IllegalArgumentException("Invalid Generator: " + gen_string); - } - PlotArea pa = areaGen.getPlotGenerator().getNewPlotArea(world, null, null, null); - pa.saveConfiguration(worldSection); - pa.loadDefaultConfiguration(worldSection); - try { - this.worlds.save(this.worldsFile); - } catch (IOException e) { - e.printStackTrace(); - } - PlotSquared.log(C.PREFIX + "&3 - generator: &7" + baseGenerator + ">" + areaGen); - PlotSquared.log(C.PREFIX + "&3 - plotworld: &7" + pa); - PlotSquared.log(C.PREFIX + "&3 - plotAreaManager: &7" + pa.getPlotManager()); - areaGen.getPlotGenerator().initialize(pa); - areaGen.augment(pa); - addPlotArea(pa); - return; - } - if (type == 1) { - throw new IllegalArgumentException( - "Invalid type for multi-area world. Expected `2`, got `" + 1 + "`"); - } - for (String areaId : areasSection.getKeys(false)) { - PlotSquared.log(C.PREFIX + "&3 - " + areaId); - String[] split = areaId.split("(?<=[^;-])-"); - if (split.length != 3) { - throw new IllegalArgumentException("Invalid Area identifier: " + areaId - + ". Expected form `--`"); - } - String name = split[0]; - PlotId pos1 = PlotId.fromString(split[1]); - PlotId pos2 = PlotId.fromString(split[2]); - if (pos1 == null || pos2 == null || name.isEmpty()) { - throw new IllegalArgumentException("Invalid Area identifier: " + areaId - + ". Expected form `--`"); - } - PlotArea existing = getPlotArea(world, name); - if (existing != null && name.equals(existing.id)) { - continue; - } - ConfigurationSection section = areasSection.getConfigurationSection(areaId); - YamlConfiguration clone = new YamlConfiguration(); - for (String key : section.getKeys(true)) { - if (section.get(key) instanceof MemorySection) { - continue; - } - if (!clone.contains(key)) { - clone.set(key, section.get(key)); - } - } - for (String key : worldSection.getKeys(true)) { - if (worldSection.get(key) instanceof MemorySection) { - continue; - } - if (!key.startsWith("areas") && !clone.contains(key)) { - clone.set(key, worldSection.get(key)); - } - } - String gen_string = clone.getString("generator.plugin", IMP.getPluginName()); - GeneratorWrapper areaGen = this.IMP.getGenerator(world, gen_string); - if (areaGen == null) { - throw new IllegalArgumentException("Invalid Generator: " + gen_string); - } - PlotArea pa = areaGen.getPlotGenerator().getNewPlotArea(world, name, pos1, pos2); - pa.saveConfiguration(clone); - // netSections is the combination of - for (String key : clone.getKeys(true)) { - if (clone.get(key) instanceof MemorySection) { - continue; - } - if (!worldSection.contains(key)) { - worldSection.set(key, clone.get(key)); - } else { - Object value = worldSection.get(key); - if (!Objects.equals(value, clone.get(key))) { - section.set(key, clone.get(key)); - } - } - } - pa.loadDefaultConfiguration(clone); - try { - this.worlds.save(this.worldsFile); - } catch (IOException e) { - e.printStackTrace(); - } - PlotSquared.log(C.PREFIX + "&aDetected area load for '" + world + "'"); - PlotSquared.log(C.PREFIX + "&c | &9generator: &7" + baseGenerator + ">" + areaGen); - PlotSquared.log(C.PREFIX + "&c | &9plotworld: &7" + pa); - PlotSquared.log(C.PREFIX + "&c | &9manager: &7" + pa.getPlotManager()); - areaGen.getPlotGenerator().initialize(pa); - areaGen.augment(pa); - addPlotArea(pa); - } - } - } - - /** - * Setup the configuration for a plot world based on world arguments. - * - * - * e.g. /mv create <world> normal -g PlotSquared:<args> - * - * @param world The name of the world - * @param args The arguments - * @param generator the plot generator - * @return boolean | if valid arguments were provided - */ - public boolean setupPlotWorld(String world, String args, IndependentPlotGenerator generator) { - if (args != null && !args.isEmpty()) { - // save configuration - - final List validArguments = Arrays - .asList("s=", "size=", "g=", "gap=", "h=", "height=", "f=", "floor=", "m=", "main=", - "w=", "wall=", "b=", "border="); - - // Calculate the number of expected arguments - int expected = 0; - for (final String validArgument : validArguments) { - if (args.toLowerCase(Locale.ENGLISH).contains(validArgument)) { - expected += 1; - } - } - - String[] split = args.toLowerCase(Locale.ENGLISH).split(","); - - if (split.length > expected) { - // This means we have multi-block block buckets - String[] combinedArgs = new String[expected]; - int index = 0; - - StringBuilder argBuilder = new StringBuilder(); - outer: - for (final String string : split) { - for (final String validArgument : validArguments) { - if (string.contains(validArgument)) { - if (!argBuilder.toString().isEmpty()) { - combinedArgs[index++] = argBuilder.toString(); - argBuilder = new StringBuilder(); - } - argBuilder.append(string); - continue outer; - } - } - if (argBuilder.toString().charAt(argBuilder.length() - 1) != '=') { - argBuilder.append(","); - } - argBuilder.append(string); - } - - if (!argBuilder.toString().isEmpty()) { - combinedArgs[index] = argBuilder.toString(); - } - - split = combinedArgs; - } - - HybridPlotWorld plotworld = new HybridPlotWorld(world, null, generator, null, null); - for (String element : split) { - String[] pair = element.split("="); - if (pair.length != 2) { - PlotSquared.log("&cNo value provided for: &7" + element); - return false; - } - String key = pair[0].toLowerCase(); - String value = pair[1]; - String base = "worlds." + world + "."; - try { - switch (key) { - case "s": - case "size": - this.worlds.set(base + "plot.size", - Configuration.INTEGER.parseString(value).shortValue()); - break; - case "g": - case "gap": - this.worlds.set(base + "road.width", - Configuration.INTEGER.parseString(value).shortValue()); - break; - case "h": - case "height": - this.worlds.set(base + "road.height", - Configuration.INTEGER.parseString(value).shortValue()); - this.worlds.set(base + "plot.height", - Configuration.INTEGER.parseString(value).shortValue()); - this.worlds.set(base + "wall.height", - Configuration.INTEGER.parseString(value).shortValue()); - break; - case "f": - case "floor": - this.worlds.set(base + "plot.floor", - Configuration.BLOCK_BUCKET.parseString(value).toString()); - break; - case "m": - case "main": - this.worlds.set(base + "plot.filling", - Configuration.BLOCK_BUCKET.parseString(value).toString()); - break; - case "w": - case "wall": - this.worlds.set(base + "wall.filling", - Configuration.BLOCK_BUCKET.parseString(value).toString()); - break; - case "b": - case "border": - this.worlds.set(base + "wall.block", - Configuration.BLOCK_BUCKET.parseString(value).toString()); - break; - default: - PlotSquared.log("&cKey not found: &7" + element); - return false; - } - } catch (Exception e) { - e.printStackTrace(); - PlotSquared.log("&cInvalid value: &7" + value + " in arg " + element); - return false; - } - } - try { - ConfigurationSection section = - this.worlds.getConfigurationSection("worlds." + world); - plotworld.saveConfiguration(section); - plotworld.loadConfiguration(section); - this.worlds.save(this.worldsFile); - } catch (IOException e) { - e.printStackTrace(); - } - } + public boolean hasPlot(final UUID uuid) { + for (final PlotArea area : plotAreaManager.getAllPlotAreas()) { + if (area.hasPlot(uuid)) { return true; + } } + return false; + } - public boolean canUpdate(@NonNull final String current, @NonNull final String other) { - final String s1 = normalisedVersion(current); - final String s2 = normalisedVersion(other); - return s1.compareTo(s2) < 0; - } - - public String normalisedVersion(@NonNull final String version) { - final String[] split = Pattern.compile(".", Pattern.LITERAL).split(version); - final StringBuilder sb = new StringBuilder(); - for (final String s : split) { - sb.append(String.format("%" + 4 + 's', s)); + public Set getBasePlots(final UUID uuid) { + final Set plots = new HashSet<>(); + foreachBasePlot(new RunnableVal() { + @Override + public void run(Plot value) { + if (value.isOwner(uuid)) { + plots.add(value); } - return sb.toString(); - } + } + }); + return Collections.unmodifiableSet(plots); + } - public boolean update(PlotPlayer sender, URL url) { - try { - String name = this.jarFile.getName(); - File newJar = new File("plugins/update/" + name); - MainUtil.sendMessage(sender, "$1Downloading from provided URL: &7" + url); - URLConnection con = url.openConnection(); - try (InputStream stream = con.getInputStream()) { - File parent = newJar.getParentFile(); - if (!parent.exists()) { - parent.mkdirs(); - } - MainUtil.sendMessage(sender, "$2 - Output: " + newJar); - if (!newJar.delete()) { - MainUtil.sendMessage(sender, "Failed to update " + IMP.getPluginName() + ""); - MainUtil.sendMessage(sender, "Jar file failed to delete."); - MainUtil.sendMessage(sender, " - Please update manually"); - } - Files.copy(stream, newJar.toPath()); - } - MainUtil.sendMessage(sender, - "$1The update will take effect when the server is restarted next"); - return true; - } catch (IOException e) { - MainUtil.sendMessage(sender, "Failed to update " + IMP.getPluginName() + ""); - MainUtil.sendMessage(sender, " - Please update manually"); - PlotSquared.log("============ Stacktrace ============"); - e.printStackTrace(); - PlotSquared.log("===================================="); + /** + * Get the plots for a UUID. + * + * @param uuid the UUID of the owner + * @return Set of Plot + */ + public Set getPlotsAbs(final UUID uuid) { + final Set plots = new HashSet<>(); + foreachPlot(new RunnableVal() { + @Override + public void run(Plot value) { + if (value.isOwnerAbs(uuid)) { + plots.add(value); } - return false; - } + } + }); + return Collections.unmodifiableSet(plots); + } - /** - * Copy a file from inside the jar to a location - * - * @param file Name of the file inside PlotSquared.jar - * @param folder The output location relative to /plugins/PlotSquared/ - */ - public void copyFile(String file, String folder) { - try { - File output = this.IMP.getDirectory(); - if (!output.exists()) { - output.mkdirs(); - } - File newFile = MainUtil.getFile(output, folder + File.separator + file); - if (newFile.exists()) { - return; - } - try (InputStream stream = this.IMP.getClass().getResourceAsStream(file)) { - byte[] buffer = new byte[2048]; - if (stream == null) { - try (ZipInputStream zis = new ZipInputStream( - new FileInputStream(this.jarFile))) { - ZipEntry ze = zis.getNextEntry(); - while (ze != null) { - String name = ze.getName(); - if (name.equals(file)) { - new File(newFile.getParent()).mkdirs(); - try (FileOutputStream fos = new FileOutputStream(newFile)) { - int len; - while ((len = zis.read(buffer)) > 0) { - fos.write(buffer, 0, len); - } - } - ze = null; - } else { - ze = zis.getNextEntry(); - } - } - zis.closeEntry(); - } - return; - } - newFile.createNewFile(); - try (FileOutputStream fos = new FileOutputStream(newFile)) { - int len; - while ((len = stream.read(buffer)) > 0) { - fos.write(buffer, 0, len); - } - } - } - } catch (IOException e) { - e.printStackTrace(); - PlotSquared.log("&cCould not save " + file); + /** + * Unregister a plot from local memory (does not call DB). + * + * @param plot the plot to remove + * @param callEvent If to call an event about the plot being removed + * @return true if plot existed | false if it didn't + */ + public boolean removePlot(Plot plot, boolean callEvent) { + if (plot == null) { + return false; + } + if (callEvent) { + EventUtil.manager.callDelete(plot); + } + if (plot.getArea().removePlot(plot.getId())) { + PlotId last = (PlotId) plot.getArea().getMeta("lastPlot"); + int last_max = Math.max(Math.abs(last.x), Math.abs(last.y)); + int this_max = Math.max(Math.abs(plot.getId().x), Math.abs(plot.getId().y)); + if (this_max < last_max) { + plot.getArea().setMeta("lastPlot", plot.getId()); + } + return true; + } + return false; + } + + /** + * This method is called by the PlotGenerator class normally. + *
    + *
  • Initializes the PlotArea and PlotManager classes + *
  • Registers the PlotArea and PlotManager classes + *
  • Loads (and/or generates) the PlotArea configuration + *
  • Sets up the world border if configured + *
+ * + *

If loading an augmented plot world: + *

    + *
  • Creates the AugmentedPopulator classes + *
  • Injects the AugmentedPopulator classes if required + *
+ * + * @param world the world to load + * @param baseGenerator The generator for that world, or null + */ + public void loadWorld(String world, GeneratorWrapper baseGenerator) { + if (world.equals("CheckingPlotSquaredGenerator")) { + return; + } + this.plotAreaManager.addWorld(world); + Set worlds; + if (this.worlds.contains("worlds")) { + worlds = this.worlds.getConfigurationSection("worlds").getKeys(false); + } else { + worlds = new HashSet<>(); + } + String path = "worlds." + world; + ConfigurationSection worldSection = this.worlds.getConfigurationSection(path); + int type; + if (worldSection != null) { + type = worldSection.getInt("generator.type", 0); + } else { + type = 0; + } + if (type == 0) { + if (plotAreaManager.getPlotAreas(world, null).length != 0) { + debug("World possibly already loaded: " + world); + return; + } + IndependentPlotGenerator plotGenerator; + if (baseGenerator != null && baseGenerator.isFull()) { + plotGenerator = baseGenerator.getPlotGenerator(); + } else if (worldSection != null) { + String secondaryGeneratorName = worldSection.getString("generator.plugin"); + GeneratorWrapper secondaryGenerator = + this.IMP.getGenerator(world, secondaryGeneratorName); + if (secondaryGenerator != null && secondaryGenerator.isFull()) { + plotGenerator = secondaryGenerator.getPlotGenerator(); + } else { + String primaryGeneratorName = worldSection.getString("generator.init"); + GeneratorWrapper primaryGenerator = + this.IMP.getGenerator(world, primaryGeneratorName); + if (primaryGenerator != null && primaryGenerator.isFull()) { + plotGenerator = primaryGenerator.getPlotGenerator(); + } else { + return; + } } - } - - private Map> getPlotsRaw() { - HashMap> map = new HashMap<>(); - for (PlotArea area : this.plotAreaManager.getAllPlotAreas()) { - Map map2 = map.get(area.toString()); - if (map2 == null) { - map.put(area.toString(), area.getPlotsRaw()); - } else { - map2.putAll(area.getPlotsRaw()); - } + } else { + return; + } + // Conventional plot generator + PlotArea plotArea = plotGenerator.getNewPlotArea(world, null, null, null); + PlotManager plotManager = plotGenerator.getNewPlotManager(); + PlotSquared.log(C.PREFIX + "&aDetected world load for '" + world + "'"); + PlotSquared.log(C.PREFIX + "&3 - generator: &7" + baseGenerator + ">" + plotGenerator); + PlotSquared.log(C.PREFIX + "&3 - plotworld: &7" + plotArea.getClass().getName()); + PlotSquared + .log(C.PREFIX + "&3 - plotAreaManager: &7" + plotManager.getClass().getName()); + if (!this.worlds.contains(path)) { + this.worlds.createSection(path); + worldSection = this.worlds.getConfigurationSection(path); + } + plotArea.saveConfiguration(worldSection); + plotArea.loadDefaultConfiguration(worldSection); + try { + this.worlds.save(this.worldsFile); + } catch (IOException e) { + e.printStackTrace(); + } + // Now add it + addPlotArea(plotArea); + plotGenerator.initialize(plotArea); + } else { + if (!worlds.contains(world)) { + return; + } + ConfigurationSection areasSection = worldSection.getConfigurationSection("areas"); + if (areasSection == null) { + if (plotAreaManager.getPlotAreas(world, null).length != 0) { + debug("World possibly already loaded: " + world); + return; } - return map; - } + PlotSquared.log(C.PREFIX + "&aDetected world load for '" + world + "'"); + String gen_string = worldSection.getString("generator.plugin", IMP.getPluginName()); + if (type == 2) { + Set clusters = this.clusters_tmp != null ? + this.clusters_tmp.get(world) : + new HashSet<>(); + if (clusters == null) { + throw new IllegalArgumentException("No cluster exists for world: " + world); + } + ArrayDeque toLoad = new ArrayDeque<>(); + for (PlotCluster cluster : clusters) { + PlotId pos1 = cluster.getP1(); // Cluster pos1 + PlotId pos2 = cluster.getP2(); // Cluster pos2 + String name = cluster.getName(); // Cluster name + String fullId = name + "-" + pos1 + "-" + pos2; + worldSection.createSection("areas." + fullId); + DBFunc.replaceWorld(world, world + ";" + name, pos1, pos2); // NPE - /** - * Close the database connection. - */ - public void disable() { - try { - // Validate that all data in the db is correct - final HashSet plots = new HashSet<>(); + PlotSquared.log(C.PREFIX + "&3 - " + name + "-" + pos1 + "-" + pos2); + GeneratorWrapper areaGen = this.IMP.getGenerator(world, gen_string); + if (areaGen == null) { + throw new IllegalArgumentException("Invalid Generator: " + gen_string); + } + PlotArea pa = + areaGen.getPlotGenerator().getNewPlotArea(world, name, pos1, pos2); + pa.saveConfiguration(worldSection); + pa.loadDefaultConfiguration(worldSection); try { - foreachPlotRaw(new RunnableVal() { - @Override public void run(Plot value) { - plots.add(value); - } - }); - } catch (final Exception ignored) { + this.worlds.save(this.worldsFile); + } catch (IOException e) { + e.printStackTrace(); } - DBFunc.validatePlots(plots); - - // Close the connection - DBFunc.close(); - UUIDHandler.handleShutdown(); - } catch (NullPointerException ignored) { - ignored.printStackTrace(); - PlotSquared.log("&cCould not close database connection!"); + PlotSquared + .log(C.PREFIX + "&c | &9generator: &7" + baseGenerator + ">" + areaGen); + PlotSquared.log(C.PREFIX + "&c | &9plotworld: &7" + pa); + PlotSquared.log(C.PREFIX + "&c | &9manager: &7" + pa); + PlotSquared.log(C.PREFIX + "&cNote: &7Area created for cluster:" + name + + " (invalid or old configuration?)"); + areaGen.getPlotGenerator().initialize(pa); + areaGen.augment(pa); + toLoad.add(pa); + } + for (PlotArea area : toLoad) { + addPlotArea(area); + } + return; } - } - - /** - * Setup the database connection. - */ - public void setupDatabase() { + GeneratorWrapper areaGen = this.IMP.getGenerator(world, gen_string); + if (areaGen == null) { + throw new IllegalArgumentException("Invalid Generator: " + gen_string); + } + PlotArea pa = areaGen.getPlotGenerator().getNewPlotArea(world, null, null, null); + pa.saveConfiguration(worldSection); + pa.loadDefaultConfiguration(worldSection); try { - if (DBFunc.dbManager != null) { - DBFunc.dbManager.close(); + this.worlds.save(this.worldsFile); + } catch (IOException e) { + e.printStackTrace(); + } + PlotSquared.log(C.PREFIX + "&3 - generator: &7" + baseGenerator + ">" + areaGen); + PlotSquared.log(C.PREFIX + "&3 - plotworld: &7" + pa); + PlotSquared.log(C.PREFIX + "&3 - plotAreaManager: &7" + pa.getPlotManager()); + areaGen.getPlotGenerator().initialize(pa); + areaGen.augment(pa); + addPlotArea(pa); + return; + } + if (type == 1) { + throw new IllegalArgumentException( + "Invalid type for multi-area world. Expected `2`, got `" + 1 + "`"); + } + for (String areaId : areasSection.getKeys(false)) { + PlotSquared.log(C.PREFIX + "&3 - " + areaId); + String[] split = areaId.split("(?<=[^;-])-"); + if (split.length != 3) { + throw new IllegalArgumentException("Invalid Area identifier: " + areaId + + ". Expected form `--`"); + } + String name = split[0]; + PlotId pos1 = PlotId.fromString(split[1]); + PlotId pos2 = PlotId.fromString(split[2]); + if (pos1 == null || pos2 == null || name.isEmpty()) { + throw new IllegalArgumentException("Invalid Area identifier: " + areaId + + ". Expected form `--`"); + } + PlotArea existing = getPlotArea(world, name); + if (existing != null && name.equals(existing.id)) { + continue; + } + ConfigurationSection section = areasSection.getConfigurationSection(areaId); + YamlConfiguration clone = new YamlConfiguration(); + for (String key : section.getKeys(true)) { + if (section.get(key) instanceof MemorySection) { + continue; + } + if (!clone.contains(key)) { + clone.set(key, section.get(key)); + } + } + for (String key : worldSection.getKeys(true)) { + if (worldSection.get(key) instanceof MemorySection) { + continue; + } + if (!key.startsWith("areas") && !clone.contains(key)) { + clone.set(key, worldSection.get(key)); + } + } + String gen_string = clone.getString("generator.plugin", IMP.getPluginName()); + GeneratorWrapper areaGen = this.IMP.getGenerator(world, gen_string); + if (areaGen == null) { + throw new IllegalArgumentException("Invalid Generator: " + gen_string); + } + PlotArea pa = areaGen.getPlotGenerator().getNewPlotArea(world, name, pos1, pos2); + pa.saveConfiguration(clone); + // netSections is the combination of + for (String key : clone.getKeys(true)) { + if (clone.get(key) instanceof MemorySection) { + continue; + } + if (!worldSection.contains(key)) { + worldSection.set(key, clone.get(key)); + } else { + Object value = worldSection.get(key); + if (!Objects.equals(value, clone.get(key))) { + section.set(key, clone.get(key)); } - Database database; - if (Storage.MySQL.USE) { - database = new MySQL(Storage.MySQL.HOST, Storage.MySQL.PORT, Storage.MySQL.DATABASE, - Storage.MySQL.USER, Storage.MySQL.PASSWORD); - } else if (Storage.SQLite.USE) { - File file = MainUtil.getFile(IMP.getDirectory(), Storage.SQLite.DB + ".db"); - database = new SQLite(file); - } else { - PlotSquared.log(C.PREFIX + "&cNo storage type is set!"); - this.IMP.disable(); - return; + } + } + pa.loadDefaultConfiguration(clone); + try { + this.worlds.save(this.worldsFile); + } catch (IOException e) { + e.printStackTrace(); + } + PlotSquared.log(C.PREFIX + "&aDetected area load for '" + world + "'"); + PlotSquared.log(C.PREFIX + "&c | &9generator: &7" + baseGenerator + ">" + areaGen); + PlotSquared.log(C.PREFIX + "&c | &9plotworld: &7" + pa); + PlotSquared.log(C.PREFIX + "&c | &9manager: &7" + pa.getPlotManager()); + areaGen.getPlotGenerator().initialize(pa); + areaGen.augment(pa); + addPlotArea(pa); + } + } + } + + /** + * Setup the configuration for a plot world based on world arguments. + * + * + * e.g. /mv create <world> normal -g PlotSquared:<args> + * + * @param world The name of the world + * @param args The arguments + * @param generator the plot generator + * @return boolean | if valid arguments were provided + */ + public boolean setupPlotWorld(String world, String args, IndependentPlotGenerator generator) { + if (args != null && !args.isEmpty()) { + // save configuration + + final List validArguments = Arrays + .asList("s=", "size=", "g=", "gap=", "h=", "height=", "f=", "floor=", "m=", "main=", + "w=", "wall=", "b=", "border="); + + // Calculate the number of expected arguments + int expected = 0; + for (final String validArgument : validArguments) { + if (args.toLowerCase(Locale.ENGLISH).contains(validArgument)) { + expected += 1; + } + } + + String[] split = args.toLowerCase(Locale.ENGLISH).split(","); + + if (split.length > expected) { + // This means we have multi-block block buckets + String[] combinedArgs = new String[expected]; + int index = 0; + + StringBuilder argBuilder = new StringBuilder(); + outer: + for (final String string : split) { + for (final String validArgument : validArguments) { + if (string.contains(validArgument)) { + if (!argBuilder.toString().isEmpty()) { + combinedArgs[index++] = argBuilder.toString(); + argBuilder = new StringBuilder(); + } + argBuilder.append(string); + continue outer; } - DBFunc.dbManager = new SQLManager(database, Storage.PREFIX, false); - this.plots_tmp = DBFunc.getPlots(); - if (plotAreaManager instanceof SinglePlotAreaManager) { - SinglePlotArea area = ((SinglePlotAreaManager) plotAreaManager).getArea(); - addPlotArea(area); - ConfigurationSection section = worlds.getConfigurationSection("worlds.*"); - if (section == null) { - section = worlds.createSection("worlds.*"); + } + if (argBuilder.toString().charAt(argBuilder.length() - 1) != '=') { + argBuilder.append(","); + } + argBuilder.append(string); + } + + if (!argBuilder.toString().isEmpty()) { + combinedArgs[index] = argBuilder.toString(); + } + + split = combinedArgs; + } + + HybridPlotWorld plotworld = new HybridPlotWorld(world, null, generator, null, null); + for (String element : split) { + String[] pair = element.split("="); + if (pair.length != 2) { + PlotSquared.log("&cNo value provided for: &7" + element); + return false; + } + String key = pair[0].toLowerCase(); + String value = pair[1]; + String base = "worlds." + world + "."; + try { + switch (key) { + case "s": + case "size": + this.worlds.set(base + "plot.size", + Configuration.INTEGER.parseString(value).shortValue()); + break; + case "g": + case "gap": + this.worlds.set(base + "road.width", + Configuration.INTEGER.parseString(value).shortValue()); + break; + case "h": + case "height": + this.worlds.set(base + "road.height", + Configuration.INTEGER.parseString(value).shortValue()); + this.worlds.set(base + "plot.height", + Configuration.INTEGER.parseString(value).shortValue()); + this.worlds.set(base + "wall.height", + Configuration.INTEGER.parseString(value).shortValue()); + break; + case "f": + case "floor": + this.worlds.set(base + "plot.floor", + Configuration.BLOCK_BUCKET.parseString(value).toString()); + break; + case "m": + case "main": + this.worlds.set(base + "plot.filling", + Configuration.BLOCK_BUCKET.parseString(value).toString()); + break; + case "w": + case "wall": + this.worlds.set(base + "wall.filling", + Configuration.BLOCK_BUCKET.parseString(value).toString()); + break; + case "b": + case "border": + this.worlds.set(base + "wall.block", + Configuration.BLOCK_BUCKET.parseString(value).toString()); + break; + default: + PlotSquared.log("&cKey not found: &7" + element); + return false; + } + } catch (Exception e) { + e.printStackTrace(); + PlotSquared.log("&cInvalid value: &7" + value + " in arg " + element); + return false; + } + } + try { + ConfigurationSection section = + this.worlds.getConfigurationSection("worlds." + world); + plotworld.saveConfiguration(section); + plotworld.loadConfiguration(section); + this.worlds.save(this.worldsFile); + } catch (IOException e) { + e.printStackTrace(); + } + } + return true; + } + + public boolean canUpdate(@NonNull final String current, @NonNull final String other) { + final String s1 = normalisedVersion(current); + final String s2 = normalisedVersion(other); + return s1.compareTo(s2) < 0; + } + + public String normalisedVersion(@NonNull final String version) { + final String[] split = Pattern.compile(".", Pattern.LITERAL).split(version); + final StringBuilder sb = new StringBuilder(); + for (final String s : split) { + sb.append(String.format("%" + 4 + 's', s)); + } + return sb.toString(); + } + + public boolean update(PlotPlayer sender, URL url) { + try { + String name = this.jarFile.getName(); + File newJar = new File("plugins/update/" + name); + MainUtil.sendMessage(sender, "$1Downloading from provided URL: &7" + url); + URLConnection con = url.openConnection(); + try (InputStream stream = con.getInputStream()) { + File parent = newJar.getParentFile(); + if (!parent.exists()) { + parent.mkdirs(); + } + MainUtil.sendMessage(sender, "$2 - Output: " + newJar); + if (!newJar.delete()) { + MainUtil.sendMessage(sender, "Failed to update " + IMP.getPluginName() + ""); + MainUtil.sendMessage(sender, "Jar file failed to delete."); + MainUtil.sendMessage(sender, " - Please update manually"); + } + Files.copy(stream, newJar.toPath()); + } + MainUtil.sendMessage(sender, + "$1The update will take effect when the server is restarted next"); + return true; + } catch (IOException e) { + MainUtil.sendMessage(sender, "Failed to update " + IMP.getPluginName() + ""); + MainUtil.sendMessage(sender, " - Please update manually"); + PlotSquared.log("============ Stacktrace ============"); + e.printStackTrace(); + PlotSquared.log("===================================="); + } + return false; + } + + /** + * Copy a file from inside the jar to a location + * + * @param file Name of the file inside PlotSquared.jar + * @param folder The output location relative to /plugins/PlotSquared/ + */ + public void copyFile(String file, String folder) { + try { + File output = this.IMP.getDirectory(); + if (!output.exists()) { + output.mkdirs(); + } + File newFile = MainUtil.getFile(output, folder + File.separator + file); + if (newFile.exists()) { + return; + } + try (InputStream stream = this.IMP.getClass().getResourceAsStream(file)) { + byte[] buffer = new byte[2048]; + if (stream == null) { + try (ZipInputStream zis = new ZipInputStream( + new FileInputStream(this.jarFile))) { + ZipEntry ze = zis.getNextEntry(); + while (ze != null) { + String name = ze.getName(); + if (name.equals(file)) { + new File(newFile.getParent()).mkdirs(); + try (FileOutputStream fos = new FileOutputStream(newFile)) { + int len; + while ((len = zis.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } } - area.saveConfiguration(section); - area.loadDefaultConfiguration(section); + ze = null; + } else { + ze = zis.getNextEntry(); + } } - this.clusters_tmp = DBFunc.getClusters(); - } catch (ClassNotFoundException | SQLException e) { - PlotSquared.log( - C.PREFIX + "&cFailed to open DATABASE connection. The plugin will disable itself."); - if (Storage.MySQL.USE) { - PlotSquared.log("$4MYSQL"); - } else if (Storage.SQLite.USE) { - PlotSquared.log("$4SQLITE"); - } - PlotSquared.log( - "&d==== Here is an ugly stacktrace, if you are interested in those things ==="); + zis.closeEntry(); + } + return; + } + newFile.createNewFile(); + try (FileOutputStream fos = new FileOutputStream(newFile)) { + int len; + while ((len = stream.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + PlotSquared.log("&cCould not save " + file); + } + } + + private Map> getPlotsRaw() { + HashMap> map = new HashMap<>(); + for (PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + Map map2 = map.get(area.toString()); + if (map2 == null) { + map.put(area.toString(), area.getPlotsRaw()); + } else { + map2.putAll(area.getPlotsRaw()); + } + } + return map; + } + + /** + * Close the database connection. + */ + public void disable() { + try { + // Validate that all data in the db is correct + final HashSet plots = new HashSet<>(); + try { + foreachPlotRaw(new RunnableVal() { + @Override + public void run(Plot value) { + plots.add(value); + } + }); + } catch (final Exception ignored) { + } + DBFunc.validatePlots(plots); + + // Close the connection + DBFunc.close(); + UUIDHandler.handleShutdown(); + } catch (NullPointerException exception) { + exception.printStackTrace(); + PlotSquared.log("&cCould not close database connection!"); + } + } + + /** + * Setup the database connection. + */ + public void setupDatabase() { + try { + if (DBFunc.dbManager != null) { + DBFunc.dbManager.close(); + } + Database database; + if (Storage.MySQL.USE) { + database = new MySQL(Storage.MySQL.HOST, Storage.MySQL.PORT, Storage.MySQL.DATABASE, + Storage.MySQL.USER, Storage.MySQL.PASSWORD); + } else if (Storage.SQLite.USE) { + File file = MainUtil.getFile(IMP.getDirectory(), Storage.SQLite.DB + ".db"); + database = new SQLite(file); + } else { + PlotSquared.log(C.PREFIX + "&cNo storage type is set!"); + this.IMP.disable(); + return; + } + DBFunc.dbManager = new SQLManager(database, Storage.PREFIX, false); + PlotSquared.log("GETTING PLOTS NOW AND STORING TO PLOTS_TMP"); + for (PlotArea allPlotArea : plotAreaManager.getAllPlotAreas()) { + PlotSquared.log(allPlotArea.toString()); + } + + this.plots_tmp = DBFunc.getPlots(); + if (plotAreaManager instanceof SinglePlotAreaManager) { + SinglePlotArea area = ((SinglePlotAreaManager) plotAreaManager).getArea(); + addPlotArea(area); + ConfigurationSection section = worlds.getConfigurationSection("worlds.*"); + if (section == null) { + section = worlds.createSection("worlds.*"); + } + area.saveConfiguration(section); + area.loadDefaultConfiguration(section); + } + this.clusters_tmp = DBFunc.getClusters(); + } catch (ClassNotFoundException | SQLException e) { + PlotSquared.log( + C.PREFIX + "&cFailed to open DATABASE connection. The plugin will disable itself."); + if (Storage.MySQL.USE) { + PlotSquared.log("$4MYSQL"); + } else if (Storage.SQLite.USE) { + PlotSquared.log("$4SQLITE"); + } + PlotSquared.log( + "&d==== Here is an ugly stacktrace, if you are interested in those things ==="); + e.printStackTrace(); + PlotSquared.log("&d==== End of stacktrace ===="); + PlotSquared.log("&6Please go to the " + IMP.getPluginName() + + " 'storage.yml' and configure the database correctly."); + this.IMP.disable(); + } + } + + /** + * Setup the default configuration. + * + * @throws IOException if the config failed to save + */ + public void setupConfig() throws IOException { + String lastVersionString = this.config.getString("version"); + if (lastVersionString != null) { + String[] split = lastVersionString.split("\\."); + int[] lastVersion = new int[]{Integer.parseInt(split[0]), Integer.parseInt(split[1]), + Integer.parseInt(split[2])}; + if (checkVersion(new int[]{3, 4, 0}, lastVersion)) { + Settings.convertLegacy(configFile); + if (config.contains("worlds")) { + ConfigurationSection worldSection = config.getConfigurationSection("worlds"); + worlds.set("worlds", worldSection); + try { + worlds.save(worldsFile); + } catch (IOException e) { + PlotSquared.debug("Failed to save " + IMP.getPluginName() + " worlds.yml"); e.printStackTrace(); - PlotSquared.log("&d==== End of stacktrace ===="); - PlotSquared.log("&6Please go to the " + IMP.getPluginName() - + " 'storage.yml' and configure the database correctly."); - this.IMP.disable(); - } - } - - /** - * Setup the default configuration. - * - * @throws IOException if the config failed to save - */ - public void setupConfig() throws IOException { - String lastVersionString = this.config.getString("version"); - if (lastVersionString != null) { - String[] split = lastVersionString.split("\\."); - int[] lastVersion = new int[] {Integer.parseInt(split[0]), Integer.parseInt(split[1]), - Integer.parseInt(split[2])}; - if (checkVersion(new int[] {3, 4, 0}, lastVersion)) { - Settings.convertLegacy(configFile); - if (config.contains("worlds")) { - ConfigurationSection worldSection = config.getConfigurationSection("worlds"); - worlds.set("worlds", worldSection); - try { - worlds.save(worldsFile); - } catch (IOException e) { - PlotSquared.debug("Failed to save " + IMP.getPluginName() + " worlds.yml"); - e.printStackTrace(); - } - } - Settings.save(configFile); - } - } - Settings.load(configFile); - try { - InputStream stream = getClass().getResourceAsStream("/plugin.properties"); - BufferedReader br = new BufferedReader(new InputStreamReader(stream)); - //java.util.Scanner scanner = new java.util.Scanner(stream).useDelimiter("\\A"); - String versionString = br.readLine(); - String commitString = br.readLine(); - String dateString = br.readLine(); - //scanner.close(); - br.close(); - this.version = PlotVersion.tryParse(versionString, commitString, dateString); - Settings.DATE = new Date(100 + version.year, version.month, version.day).toGMTString(); - Settings.BUILD = "https://ci.athion.net/job/PlotSquared/" + version.build; - Settings.COMMIT = "https://github.com/IntellectualSites/PlotSquared/commit/" + Integer - .toHexString(version.hash); - System.out.println("Version is " + this.version); - } catch (Throwable ignore) { - ignore.printStackTrace(); + } } Settings.save(configFile); - config = YamlConfiguration.loadConfiguration(configFile); + } } + Settings.load(configFile); + try { + InputStream stream = getClass().getResourceAsStream("/plugin.properties"); + BufferedReader br = new BufferedReader(new InputStreamReader(stream)); + //java.util.Scanner scanner = new java.util.Scanner(stream).useDelimiter("\\A"); + String versionString = br.readLine(); + String commitString = br.readLine(); + String dateString = br.readLine(); + //scanner.close(); + br.close(); + this.version = PlotVersion.tryParse(versionString, commitString, dateString); + Settings.DATE = new Date(100 + version.year, version.month, version.day).toGMTString(); + Settings.BUILD = "https://ci.athion.net/job/PlotSquared/" + version.build; + Settings.COMMIT = "https://github.com/IntellectualSites/PlotSquared/commit/" + Integer + .toHexString(version.hash); + System.out.println("Version is " + this.version); + } catch (IOException exception) { + exception.printStackTrace(); + } + Settings.save(configFile); + config = YamlConfiguration.loadConfiguration(configFile); + } - /** - * Setup all configuration files
- * - Config: settings.yml
- * - Storage: storage.yml
- * - Translation: PlotSquared.use_THIS.yml, style.yml
- */ - public boolean setupConfigs() { - File folder = new File(this.IMP.getDirectory(), "config"); - if (!folder.exists() && !folder.mkdirs()) { - PlotSquared.log(C.PREFIX - + "&cFailed to create the /plugins/config folder. Please create it manually."); - } - try { - this.worldsFile = new File(folder, "worlds.yml"); - if (!this.worldsFile.exists() && !this.worldsFile.createNewFile()) { - PlotSquared.log( - "Could not create the worlds file, please create \"worlds.yml\" manually."); - } - this.worlds = YamlConfiguration.loadConfiguration(this.worldsFile); + /** + * Setup all configuration files
- Config: settings.yml
- Storage: storage.yml
- + * Translation: PlotSquared.use_THIS.yml, style.yml
+ */ + public boolean setupConfigs() { + File folder = new File(this.IMP.getDirectory(), "config"); + if (!folder.exists() && !folder.mkdirs()) { + PlotSquared.log(C.PREFIX + + "&cFailed to create the /plugins/config folder. Please create it manually."); + } + try { + this.worldsFile = new File(folder, "worlds.yml"); + if (!this.worldsFile.exists() && !this.worldsFile.createNewFile()) { + PlotSquared.log( + "Could not create the worlds file, please create \"worlds.yml\" manually."); + } + this.worlds = YamlConfiguration.loadConfiguration(this.worldsFile); - if (this.worlds.contains("worlds")) { - if (!this.worlds.contains("configuration_version") || !this.worlds - .getString("configuration_version") - .equalsIgnoreCase(LegacyConverter.CONFIGURATION_VERSION)) { - // Conversion needed - log(C.LEGACY_CONFIG_FOUND.s()); - try { - com.google.common.io.Files - .copy(this.worldsFile, new File(folder, "worlds.yml.old")); - log(C.LEGACY_CONFIG_BACKUP.s()); - final ConfigurationSection worlds = - this.worlds.getConfigurationSection("worlds"); - final LegacyConverter converter = new LegacyConverter(worlds); - converter.convert(); - this.worlds - .set("configuration_version", LegacyConverter.CONFIGURATION_VERSION); - this.worlds.set("worlds", worlds); // Redundant, but hey... ¯\_(ツ)_/¯ - this.worlds.save(this.worldsFile); - log(C.LEGACY_CONFIG_DONE.s()); - } catch (final Exception e) { - log(C.LEGACY_CONFIG_CONVERSION_FAILED.s()); - e.printStackTrace(); - } - // Disable plugin - this.IMP.shutdown(); - return false; - } - } else { - this.worlds.set("configuration_version", LegacyConverter.CONFIGURATION_VERSION); - } - } catch (IOException ignored) { - PlotSquared.log("Failed to save settings.yml"); - } - try { - this.configFile = new File(folder, "settings.yml"); - if (!this.configFile.exists() && !this.configFile.createNewFile()) { - PlotSquared.log( - "Could not create the settings file, please create \"settings.yml\" manually."); - } - this.config = YamlConfiguration.loadConfiguration(this.configFile); - setupConfig(); - } catch (IOException ignored) { - PlotSquared.log("Failed to save settings.yml"); - } - try { - this.styleFile = MainUtil.getFile(IMP.getDirectory(), - Settings.Paths.TRANSLATIONS + File.separator + "style.yml"); - if (!this.styleFile.exists()) { - if (!this.styleFile.getParentFile().exists()) { - this.styleFile.getParentFile().mkdirs(); - } - if (!this.styleFile.createNewFile()) { - PlotSquared.log( - "Could not create the style file, please create \"translations/style.yml\" manually"); - } - } - this.style = YamlConfiguration.loadConfiguration(this.styleFile); - setupStyle(); - } catch (IOException err) { - err.printStackTrace(); - PlotSquared.log("failed to save style.yml"); - } - try { - this.storageFile = new File(folder, "storage.yml"); - if (!this.storageFile.exists() && !this.storageFile.createNewFile()) { - PlotSquared.log( - "Could not the storage settings file, please create \"storage.yml\" manually."); - } - this.storage = YamlConfiguration.loadConfiguration(this.storageFile); - setupStorage(); - } catch (IOException ignored) { - PlotSquared.log("Failed to save storage.yml"); - } - try { - this.commandsFile = new File(folder, "commands.yml"); - if (!this.commandsFile.exists() && !this.commandsFile.createNewFile()) { - PlotSquared.log( - "Could not the storage settings file, please create \"commands.yml\" manually."); - } - this.commands = YamlConfiguration.loadConfiguration(this.commandsFile); - } catch (IOException ignored) { - PlotSquared.log("Failed to save commands.yml"); - } - try { - this.style.save(this.styleFile); - this.commands.save(this.commandsFile); - } catch (IOException e) { - PlotSquared.log("Configuration file saving failed"); + if (this.worlds.contains("worlds")) { + if (!this.worlds.contains("configuration_version") || !this.worlds + .getString("configuration_version") + .equalsIgnoreCase(LegacyConverter.CONFIGURATION_VERSION)) { + // Conversion needed + log(C.LEGACY_CONFIG_FOUND.s()); + try { + com.google.common.io.Files + .copy(this.worldsFile, new File(folder, "worlds.yml.old")); + log(C.LEGACY_CONFIG_BACKUP.s()); + final ConfigurationSection worlds = + this.worlds.getConfigurationSection("worlds"); + final LegacyConverter converter = new LegacyConverter(worlds); + converter.convert(); + this.worlds + .set("configuration_version", LegacyConverter.CONFIGURATION_VERSION); + this.worlds.set("worlds", worlds); // Redundant, but hey... ¯\_(ツ)_/¯ + this.worlds.save(this.worldsFile); + log(C.LEGACY_CONFIG_DONE.s()); + } catch (final Exception e) { + log(C.LEGACY_CONFIG_CONVERSION_FAILED.s()); e.printStackTrace(); + } + // Disable plugin + this.IMP.shutdown(); + return false; } - return true; + } else { + this.worlds.set("configuration_version", LegacyConverter.CONFIGURATION_VERSION); + } + } catch (IOException ignored) { + PlotSquared.log("Failed to save settings.yml"); } - - /** - * Setup the storage file (load + save missing nodes). - */ - private void setupStorage() { - Storage.load(storageFile); - Storage.save(storageFile); - storage = YamlConfiguration.loadConfiguration(storageFile); + try { + this.configFile = new File(folder, "settings.yml"); + if (!this.configFile.exists() && !this.configFile.createNewFile()) { + PlotSquared.log( + "Could not create the settings file, please create \"settings.yml\" manually."); + } + this.config = YamlConfiguration.loadConfiguration(this.configFile); + setupConfig(); + } catch (IOException ignored) { + PlotSquared.log("Failed to save settings.yml"); } - - /** - * Show startup debug information. - */ - private void showDebug() { - if (Settings.DEBUG) { - Map components = Settings.getFields(Settings.Enabled_Components.class); - for (Entry component : components.entrySet()) { - PlotSquared.log(C.PREFIX + String - .format("&cKey: &6%s&c, Value: &6%s", component.getKey(), - component.getValue())); - } + try { + this.styleFile = MainUtil.getFile(IMP.getDirectory(), + Settings.Paths.TRANSLATIONS + File.separator + "style.yml"); + if (!this.styleFile.exists()) { + if (!this.styleFile.getParentFile().exists()) { + this.styleFile.getParentFile().mkdirs(); } - } - - /** - * Setup the style.yml file - */ - private void setupStyle() { - if (this.version != null) { - this.style.set("version", this.version.toString()); + if (!this.styleFile.createNewFile()) { + PlotSquared.log( + "Could not create the style file, please create \"translations/style.yml\" manually"); } - Map o = new HashMap<>(4); - o.put("color.1", "6"); - o.put("color.2", "7"); - o.put("color.3", "8"); - o.put("color.4", "3"); - if (!this.style.contains("color")) { - for (Entry node : o.entrySet()) { - this.style.set(node.getKey(), node.getValue()); - } + } + this.style = YamlConfiguration.loadConfiguration(this.styleFile); + setupStyle(); + } catch (IOException err) { + err.printStackTrace(); + PlotSquared.log("failed to save style.yml"); + } + try { + this.storageFile = new File(folder, "storage.yml"); + if (!this.storageFile.exists() && !this.storageFile.createNewFile()) { + PlotSquared.log( + "Could not the storage settings file, please create \"storage.yml\" manually."); + } + this.storage = YamlConfiguration.loadConfiguration(this.storageFile); + setupStorage(); + } catch (IOException ignored) { + PlotSquared.log("Failed to save storage.yml"); + } + try { + this.commandsFile = new File(folder, "commands.yml"); + if (!this.commandsFile.exists() && !this.commandsFile.createNewFile()) { + PlotSquared.log( + "Could not the storage settings file, please create \"commands.yml\" manually."); + } + this.commands = YamlConfiguration.loadConfiguration(this.commandsFile); + } catch (IOException ignored) { + PlotSquared.log("Failed to save commands.yml"); + } + try { + this.style.save(this.styleFile); + this.commands.save(this.commandsFile); + } catch (IOException e) { + PlotSquared.log("Configuration file saving failed"); + e.printStackTrace(); + } + return true; + } + + /** + * Setup the storage file (load + save missing nodes). + */ + private void setupStorage() { + Storage.load(storageFile); + Storage.save(storageFile); + storage = YamlConfiguration.loadConfiguration(storageFile); + } + + /** + * Show startup debug information. + */ + private void showDebug() { + if (Settings.DEBUG) { + Map components = Settings.getFields(Settings.Enabled_Components.class); + for (Entry component : components.entrySet()) { + PlotSquared.log(C.PREFIX + String + .format("&cKey: &6%s&c, Value: &6%s", component.getKey(), + component.getValue())); + } + } + } + + /** + * Setup the style.yml file + */ + private void setupStyle() { + if (this.version != null) { + this.style.set("version", this.version.toString()); + } + Map o = new HashMap<>(4); + o.put("color.1", "6"); + o.put("color.2", "7"); + o.put("color.3", "8"); + o.put("color.4", "3"); + if (!this.style.contains("color")) { + for (Entry node : o.entrySet()) { + this.style.set(node.getKey(), node.getValue()); + } + } + } + + /** + * Get the Java version. + * + * @return the java version + */ + public double getJavaVersion() { + return Double.parseDouble(System.getProperty("java.specification.version")); + } + + public void foreachPlotArea(@NonNull final RunnableVal runnable) { + for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + runnable.run(area); + } + } + + public void foreachPlotArea(@NonNull final String world, + @NonNull final RunnableVal runnable) { + final PlotArea[] array = this.plotAreaManager.getPlotAreas(world, null); + if (array == null) { + return; + } + for (final PlotArea area : array) { + runnable.run(area); + } + } + + public void foreachPlot(@NonNull final RunnableVal runnable) { + for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + area.getPlots().forEach(runnable::run); + } + } + + public void foreachPlotRaw(@NonNull final RunnableVal runnable) { + for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + area.getPlots().forEach(runnable::run); + } + if (this.plots_tmp != null) { + for (final HashMap entry : this.plots_tmp.values()) { + entry.values().forEach(runnable::run); + } + } + } + + public void foreachBasePlot(@NonNull final RunnableVal run) { + for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + area.foreachBasePlot(run); + } + } + + public PlotArea getFirstPlotArea() { + PlotArea[] areas = plotAreaManager.getAllPlotAreas(); + return areas.length > 0 ? areas[0] : null; + } + + public int getPlotAreaCount() { + return this.plotAreaManager.getAllPlotAreas().length; + } + + public int getPlotCount() { + int count = 0; + for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + count += area.getPlotCount(); + } + return count; + } + + public Set getPlotAreas() { + final Set set = new HashSet<>(); + Collections.addAll(set, plotAreaManager.getAllPlotAreas()); + return Collections.unmodifiableSet(set); + } + + public boolean isAugmented(@NonNull final String world) { + final PlotArea[] areas = plotAreaManager.getPlotAreas(world, null); + return areas != null && (areas.length > 1 || areas[0].TYPE != 0); + } + + /** + * Get a list of PlotArea objects. + * + * @param world the world + * @return Collection of PlotArea objects + */ + public Set getPlotAreas(@NonNull final String world) { + final Set set = new HashSet<>(); + Collections.addAll(set, plotAreaManager.getPlotAreas(world, null)); + return set; + } + + /** + * Get the relevant plot area for a specified location. + *
    + *
  • If there is only one plot area globally that will be returned. + *
  • If there is only one plot area in the world, it will return that. + *
  • If the plot area for a location cannot be unambiguously + * resolved, null will be returned. + *
+ * Note: An applicable plot area may not include the location i.e. clusters + * + * @param location the location + */ + public PlotArea getApplicablePlotArea(@NonNull final Location location) { + return plotAreaManager.getApplicablePlotArea(location); + } + + public PlotArea getPlotArea(@NonNull final String world, final String id) { + return plotAreaManager.getPlotArea(world, id); + } + + /** + * Get the {@code PlotArea} which contains a location. + *
    + *
  • If the plot area does not contain a location, null + * will be returned. + *
+ * + * @param location the location + * @return the {@link PlotArea} in the location, null if non existent + */ + public PlotArea getPlotAreaAbs(@NonNull final Location location) { + return plotAreaManager.getPlotArea(location); + } + + public PlotArea getPlotAreaByString(@NonNull final String search) { + String[] split = search.split("[;,]"); + PlotArea[] areas = plotAreaManager.getPlotAreas(split[0], null); + if (areas == null) { + for (PlotArea area : plotAreaManager.getAllPlotAreas()) { + if (area.worldname.equalsIgnoreCase(split[0])) { + if (area.id == null || split.length == 2 && area.id + .equalsIgnoreCase(split[1])) { + return area; + } } + } + return null; } - - /** - * Get the Java version. - * - * @return the java version - */ - public double getJavaVersion() { - return Double.parseDouble(System.getProperty("java.specification.version")); - } - - public void foreachPlotArea(@NonNull final RunnableVal runnable) { - for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { - runnable.run(area); + if (areas.length == 1) { + return areas[0]; + } else if (split.length == 1) { + return null; + } else { + for (PlotArea area : areas) { + if (StringMan.isEqual(split[1], area.id)) { + return area; } + } + return null; } + } - public void foreachPlotArea(@NonNull final String world, - @NonNull final RunnableVal runnable) { - final PlotArea[] array = this.plotAreaManager.getPlotAreas(world, null); - if (array == null) { - return; - } - for (final PlotArea area : array) { - runnable.run(area); + /** + * Get Plots based on alias + * + * @param alias to search plots + * @param worldname to filter alias to a specific world [optional] null means all worlds + * @return Set<{ + * @ + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * link + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * Plot + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * }> empty if nothing found + */ + public Set getPlotsByAlias(@Nullable final String alias, + @NonNull final String worldname) { + final Set result = new HashSet<>(); + if (alias != null) { + for (final Plot plot : getPlots()) { + if (alias.equals(plot.getAlias()) && (worldname == null || worldname + .equals(plot.getWorldName()))) { + result.add(plot); } + } } + return Collections.unmodifiableSet(result); + } - public void foreachPlot(@NonNull final RunnableVal runnable) { - for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { - area.getPlots().forEach(runnable::run); - } - } + public Set getPlotAreas(final String world, final RegionWrapper region) { + final PlotArea[] areas = plotAreaManager.getPlotAreas(world, region); + final Set set = new HashSet<>(); + Collections.addAll(set, areas); + return Collections.unmodifiableSet(set); + } - public void foreachPlotRaw(@NonNull final RunnableVal runnable) { - for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { - area.getPlots().forEach(runnable::run); - } - if (this.plots_tmp != null) { - for (final HashMap entry : this.plots_tmp.values()) { - entry.values().forEach(runnable::run); - } - } - } - - public void foreachBasePlot(@NonNull final RunnableVal run) { - for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { - area.foreachBasePlot(run); - } - } - - public PlotArea getFirstPlotArea() { - PlotArea[] areas = plotAreaManager.getAllPlotAreas(); - return areas.length > 0 ? areas[0] : null; - } - - public int getPlotAreaCount() { - return this.plotAreaManager.getAllPlotAreas().length; - } - - public int getPlotCount() { - int count = 0; - for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { - count += area.getPlotCount(); - } - return count; - } - - public Set getPlotAreas() { - final Set set = new HashSet<>(); - Collections.addAll(set, plotAreaManager.getAllPlotAreas()); - return Collections.unmodifiableSet(set); - } - - public boolean isAugmented(@NonNull final String world) { - final PlotArea[] areas = plotAreaManager.getPlotAreas(world, null); - return areas != null && (areas.length > 1 || areas[0].TYPE != 0); - } - - /** - * Get a list of PlotArea objects. - * - * @param world the world - * @return Collection of PlotArea objects - */ - public Set getPlotAreas(@NonNull final String world) { - final Set set = new HashSet<>(); - Collections.addAll(set, plotAreaManager.getPlotAreas(world, null)); - return set; - } - - /** - * Get the relevant plot area for a specified location. - *
    - *
  • If there is only one plot area globally that will be returned. - *
  • If there is only one plot area in the world, it will return that. - *
  • If the plot area for a location cannot be unambiguously - * resolved, null will be returned. - *
- * Note: An applicable plot area may not include the location i.e. clusters - * - * @param location the location - * @return - */ - public PlotArea getApplicablePlotArea(@NonNull final Location location) { - return plotAreaManager.getApplicablePlotArea(location); - } - - public PlotArea getPlotArea(@NonNull final String world, final String id) { - return plotAreaManager.getPlotArea(world, id); - } - - /** - * Get the {@code PlotArea} which contains a location. - *
    - *
  • If the plot area does not contain a location, null - * will be returned. - *
- * - * @param location the location - * @return the {@link PlotArea} in the location, null if non existent - */ - public PlotArea getPlotAreaAbs(@NonNull final Location location) { - return plotAreaManager.getPlotArea(location); - } - - public PlotArea getPlotAreaByString(@NonNull final String search) { - String[] split = search.split("[;,]"); - PlotArea[] areas = plotAreaManager.getPlotAreas(split[0], null); - if (areas == null) { - for (PlotArea area : plotAreaManager.getAllPlotAreas()) { - if (area.worldname.equalsIgnoreCase(split[0])) { - if (area.id == null || split.length == 2 && area.id - .equalsIgnoreCase(split[1])) { - return area; - } - } - } - return null; - } - if (areas.length == 1) { - return areas[0]; - } else if (split.length == 1) { - return null; - } else { - for (PlotArea area : areas) { - if (StringMan.isEqual(split[1], area.id)) { - return area; - } - } - return null; - } - } - - /** - * Get Plots based on alias - * - * @param alias to search plots - * @param worldname to filter alias to a specific world [optional] null means all worlds - * @return Set<{ @ link Plot }> empty if nothing found - */ - public Set getPlotsByAlias(@Nullable final String alias, - @NonNull final String worldname) { - final Set result = new HashSet<>(); - if (alias != null) { - for (final Plot plot : getPlots()) { - if (alias.equals(plot.getAlias()) && (worldname == null || worldname - .equals(plot.getWorldName()))) { - result.add(plot); - } - } - } - return Collections.unmodifiableSet(result); - } - - public Set getPlotAreas(final String world, final RegionWrapper region) { - final PlotArea[] areas = plotAreaManager.getPlotAreas(world, region); - final Set set = new HashSet<>(); - Collections.addAll(set, areas); - return Collections.unmodifiableSet(set); - } - - public enum SortType { - CREATION_DATE, CREATION_DATE_TIMESTAMP, LAST_MODIFIED, DISTANCE_FROM_ORIGIN - } + public enum SortType { + CREATION_DATE, CREATION_DATE_TIMESTAMP, LAST_MODIFIED, DISTANCE_FROM_ORIGIN + } } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Area.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Area.java index 9dc5ce20e..ee7c1cb23 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Area.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Area.java @@ -104,36 +104,34 @@ import java.util.Set; final String path = "worlds." + area.worldname + ".areas." + area.id + '-' + object.min + '-' + object.max; - Runnable run = new Runnable() { - @Override public void run() { - if (offsetX != 0) { - PlotSquared.get().worlds - .set(path + ".road.offset.x", offsetX); - } - if (offsetZ != 0) { - PlotSquared.get().worlds - .set(path + ".road.offset.z", offsetZ); - } - final String world = SetupUtils.manager.setupWorld(object); - if (WorldUtil.IMP.isWorld(world)) { - PlotSquared.get().loadWorld(world, null); - C.SETUP_FINISHED.send(player); - player.teleport(WorldUtil.IMP.getSpawn(world)); - if (area.TERRAIN != 3) { - ChunkManager.largeRegionTask(world, region, - new RunnableVal() { - @Override public void run(ChunkLoc value) { - AugmentedUtils - .generate(world, value.x, value.z, - null); - } - }, null); - } - } else { - MainUtil.sendMessage(player, - "An error occurred while creating the world: " - + area.worldname); + Runnable run = () -> { + if (offsetX != 0) { + PlotSquared.get().worlds + .set(path + ".road.offset.x", offsetX); + } + if (offsetZ != 0) { + PlotSquared.get().worlds + .set(path + ".road.offset.z", offsetZ); + } + final String world = SetupUtils.manager.setupWorld(object); + if (WorldUtil.IMP.isWorld(world)) { + PlotSquared.get().loadWorld(world, null); + C.SETUP_FINISHED.send(player); + player.teleport(WorldUtil.IMP.getSpawn(world)); + if (area.TERRAIN != 3) { + ChunkManager.largeRegionTask(world, region, + new RunnableVal() { + @Override public void run(ChunkLoc value) { + AugmentedUtils + .generate(world, value.x, value.z, + null); + } + }, null); } + } else { + MainUtil.sendMessage(player, + "An error occurred while creating the world: " + + area.worldname); } }; if (hasConfirmation(player)) { @@ -228,32 +226,30 @@ import java.util.Set; C.SETUP_WORLD_TAKEN.send(player, pa.worldname); return false; } - Runnable run = new Runnable() { - @Override public void run() { - String path = "worlds." + pa.worldname; - if (!PlotSquared.get().worlds.contains(path)) { - PlotSquared.get().worlds.createSection(path); - } - ConfigurationSection section = - PlotSquared.get().worlds.getConfigurationSection(path); - pa.saveConfiguration(section); - pa.loadConfiguration(section); - object.plotManager = PlotSquared.imp().getPluginName(); - object.setupGenerator = PlotSquared.imp().getPluginName(); - String world = SetupUtils.manager.setupWorld(object); - if (WorldUtil.IMP.isWorld(world)) { - C.SETUP_FINISHED.send(player); - player.teleport(WorldUtil.IMP.getSpawn(world)); - } else { - MainUtil.sendMessage(player, - "An error occurred while creating the world: " - + pa.worldname); - } - try { - PlotSquared.get().worlds.save(PlotSquared.get().worldsFile); - } catch (IOException e) { - e.printStackTrace(); - } + Runnable run = () -> { + String path = "worlds." + pa.worldname; + if (!PlotSquared.get().worlds.contains(path)) { + PlotSquared.get().worlds.createSection(path); + } + ConfigurationSection section = + PlotSquared.get().worlds.getConfigurationSection(path); + pa.saveConfiguration(section); + pa.loadConfiguration(section); + object.plotManager = PlotSquared.imp().getPluginName(); + object.setupGenerator = PlotSquared.imp().getPluginName(); + String world = SetupUtils.manager.setupWorld(object); + if (WorldUtil.IMP.isWorld(world)) { + C.SETUP_FINISHED.send(player); + player.teleport(WorldUtil.IMP.getSpawn(world)); + } else { + MainUtil.sendMessage(player, + "An error occurred while creating the world: " + + pa.worldname); + } + try { + PlotSquared.get().worlds.save(PlotSquared.get().worldsFile); + } catch (IOException e) { + e.printStackTrace(); } }; if (hasConfirmation(player)) { @@ -422,11 +418,7 @@ import java.util.Set; @Override public void run(ChunkLoc value) { AugmentedUtils.generate(area.worldname, value.x, value.z, null); } - }, new Runnable() { - @Override public void run() { - player.sendMessage("Regen complete"); - } - }); + }, () -> player.sendMessage("Regen complete")); return true; } case "goto": diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Claim.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Claim.java index 88f102967..e49155b8d 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Claim.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Claim.java @@ -82,22 +82,14 @@ public class Claim extends SubCommand { if (plot.canClaim(player)) { plot.owner = player.getUUID(); final String finalSchematic = schematic; - DBFunc.createPlotSafe(plot, new Runnable() { - @Override public void run() { - TaskManager.IMP.sync(new RunnableVal() { - @Override public void run(Object value) { - plot.claim(player, true, finalSchematic, false); - if (area.AUTO_MERGE) { - plot.autoMerge(-1, Integer.MAX_VALUE, player.getUUID(), true); - } - } - }); + DBFunc.createPlotSafe(plot, () -> TaskManager.IMP.sync(new RunnableVal() { + @Override public void run(Object value) { + plot.claim(player, true, finalSchematic, false); + if (area.AUTO_MERGE) { + plot.autoMerge(-1, Integer.MAX_VALUE, player.getUUID(), true); + } } - }, new Runnable() { - @Override public void run() { - sendMessage(player, C.PLOT_NOT_CLAIMED); - } - }); + }), () -> sendMessage(player, C.PLOT_NOT_CLAIMED)); return true; } else { sendMessage(player, C.PLOT_NOT_CLAIMED); diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Cluster.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Cluster.java index c8360f696..2ead96b4f 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Cluster.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Cluster.java @@ -302,6 +302,7 @@ import java.util.UUID; PlotArea area = player.getApplicablePlotArea(); if (area == null) { C.NOT_IN_PLOT_WORLD.send(player); + return false; } PlotCluster cluster = area.getCluster(player.getLocation()); if (cluster == null) { @@ -347,6 +348,7 @@ import java.util.UUID; PlotArea area = player.getApplicablePlotArea(); if (area == null) { C.NOT_IN_PLOT_WORLD.send(player); + return false; } PlotCluster cluster = area.getCluster(player.getLocation()); if (cluster == null) { @@ -405,6 +407,7 @@ import java.util.UUID; PlotArea area = player.getApplicablePlotArea(); if (area == null) { C.NOT_IN_PLOT_WORLD.send(player); + return false; } PlotCluster cluster; if (args.length == 2) { @@ -440,7 +443,6 @@ import java.util.UUID; PlotSquared.get().getPlots(player.getLocation().getWorld(), uuid))) { PlotCluster current = plot.getCluster(); if (current != null && current.equals(cluster)) { - player.getLocation().getWorld(); plot.unclaim(); } } @@ -462,6 +464,7 @@ import java.util.UUID; PlotArea area = player.getApplicablePlotArea(); if (area == null) { C.NOT_IN_PLOT_WORLD.send(player); + return false; } PlotCluster cluster = area.getCluster(player.getLocation()); if (cluster == null) { @@ -534,6 +537,7 @@ import java.util.UUID; PlotArea area = player.getApplicablePlotArea(); if (area == null) { C.NOT_IN_PLOT_WORLD.send(player); + return false; } PlotCluster cluster; if (args.length == 2) { @@ -581,6 +585,7 @@ import java.util.UUID; PlotArea area = player.getApplicablePlotArea(); if (area == null) { C.NOT_IN_PLOT_WORLD.send(player); + return false; } PlotCluster cluster = area.getCluster(player.getLocation()); if (cluster == null) { diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Condense.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Condense.java index 040fd97b8..44d0e5593 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Condense.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Condense.java @@ -65,6 +65,7 @@ import java.util.concurrent.atomic.AtomicBoolean; sizes.add(size - 1); } // Sort plots by size (buckets?)] + //noinspection unchecked ArrayList[] buckets = new ArrayList[maxSize]; for (int i = 0; i < plots.size(); i++) { Plot plot = plots.get(i); @@ -126,13 +127,11 @@ import java.util.concurrent.atomic.AtomicBoolean; } i++; final AtomicBoolean result = new AtomicBoolean(false); - result.set(origin.move(possible, new Runnable() { - @Override public void run() { - if (result.get()) { - MainUtil.sendMessage(player, - "Moving: " + origin + " -> " + possible); - TaskManager.runTaskLater(task, 1); - } + result.set(origin.move(possible, () -> { + if (result.get()) { + MainUtil.sendMessage(player, + "Moving: " + origin + " -> " + possible); + TaskManager.runTaskLater(task, 1); } }, false)); if (result.get()) { diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Database.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Database.java index b760bc282..d945f122a 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Database.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Database.java @@ -25,174 +25,163 @@ import java.util.Map.Entry; @CommandDeclaration(command = "database", aliases = {"convert"}, category = CommandCategory.ADMINISTRATION, permission = "plots.database", description = "Convert/Backup Storage", requiredType = RequiredType.CONSOLE, - usage = "/plot database [area] ") public class Database + usage = "/plot database [area] ") +public class Database extends SubCommand { - public static void insertPlots(final SQLManager manager, final List plots, - final PlotPlayer player) { - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - try { - ArrayList ps = new ArrayList<>(); - for (Plot p : plots) { - ps.add(p); - } - MainUtil.sendMessage(player, "&6Starting..."); - manager.createPlotsAndData(ps, new Runnable() { - @Override public void run() { - MainUtil.sendMessage(player, "&6Database conversion finished!"); - manager.close(); - } - }); - } catch (Exception e) { - MainUtil.sendMessage(player, - "Failed to insert plot objects, see stacktrace for info"); - e.printStackTrace(); - } - } + public static void insertPlots(final SQLManager manager, final List plots, + final PlotPlayer player) { + TaskManager.runTaskAsync(() -> { + try { + ArrayList ps = new ArrayList<>(plots); + MainUtil.sendMessage(player, "&6Starting..."); + manager.createPlotsAndData(ps, () -> { + MainUtil.sendMessage(player, "&6Database conversion finished!"); + manager.close(); }); - } + } catch (Exception e) { + MainUtil.sendMessage(player, + "Failed to insert plot objects, see stacktrace for info"); + e.printStackTrace(); + } + }); + } - @Override public boolean onCommand(final PlotPlayer player, String[] args) { - if (args.length < 1) { - MainUtil.sendMessage(player, "/plot database [area] "); - return false; - } - List plots; - PlotArea area = PlotSquared.get().getPlotAreaByString(args[0]); - if (area != null) { - plots = PlotSquared.get().sortPlotsByTemp(area.getPlots()); - args = Arrays.copyOfRange(args, 1, args.length); - } else { - plots = PlotSquared.get().sortPlotsByTemp(PlotSquared.get().getPlots()); - } - if (args.length < 1) { - MainUtil.sendMessage(player, "/plot database [world] "); - MainUtil.sendMessage(player, "[arg] indicates an optional argument"); - return false; - } - try { - com.github.intellectualsites.plotsquared.plot.database.Database implementation; - String prefix = ""; - switch (args[0].toLowerCase()) { - case "import": - if (args.length < 2) { - MainUtil - .sendMessage(player, "/plot database import [prefix]"); - return false; - } - File file = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), - args[1].endsWith(".db") ? args[1] : args[1] + ".db"); - if (!file.exists()) { - MainUtil.sendMessage(player, "&6Database does not exist: " + file); - return false; - } - MainUtil.sendMessage(player, "&6Starting..."); - implementation = new SQLite(file); - SQLManager manager = - new SQLManager(implementation, args.length == 3 ? args[2] : "", true); - HashMap> map = manager.getPlots(); - plots = new ArrayList<>(); - for (Entry> entry : map.entrySet()) { - String areaname = entry.getKey(); - PlotArea pa = PlotSquared.get().getPlotAreaByString(areaname); - if (pa != null) { - for (Entry entry2 : entry.getValue().entrySet()) { - Plot plot = entry2.getValue(); - if (pa.getOwnedPlotAbs(plot.getId()) != null) { - if (pa instanceof SinglePlotArea) { - Plot newPlot = pa.getNextFreePlot(null, plot.getId()); - if (newPlot != null) { - PlotId newId = newPlot.getId(); - PlotId id = plot.getId(); - File worldFile = - new File(PlotSquared.imp().getWorldContainer(), - id.toCommaSeparatedString()); - if (worldFile.exists()) { - File newFile = - new File(PlotSquared.imp().getWorldContainer(), - newId.toCommaSeparatedString()); - worldFile.renameTo(newFile); - } - id.x = newId.x; - id.y = newId.y; - id.recalculateHash(); - plot.setArea(pa); - plots.add(plot); - continue; - } - } - MainUtil.sendMessage(player, - "Skipping duplicate plot: " + plot + " | id=" + plot.temp); - continue; - } - plot.setArea(pa); - plots.add(plot); - } - } else { - HashMap plotmap = - PlotSquared.get().plots_tmp.get(areaname); - if (plotmap == null) { - plotmap = new HashMap<>(); - PlotSquared.get().plots_tmp.put(areaname, plotmap); - } - plotmap.putAll(entry.getValue()); - } - } - DBFunc.createPlotsAndData(plots, new Runnable() { - @Override public void run() { - MainUtil.sendMessage(player, "&6Database conversion finished!"); - } - }); - return true; - case "mysql": - if (args.length < 6) { - return MainUtil.sendMessage(player, - "/plot database mysql [host] [port] [username] [password] [database] {prefix}"); - } - String host = args[1]; - String port = args[2]; - String username = args[3]; - String password = args[4]; - String database = args[5]; - if (args.length > 6) { - prefix = args[6]; - } - implementation = new MySQL(host, port, database, username, password); - break; - case "sqlite": - if (args.length < 2) { - return MainUtil.sendMessage(player, "/plot database sqlite [file]"); - } - File sqliteFile = - MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), args[1] + ".db"); - implementation = new SQLite(sqliteFile); - break; - default: - return MainUtil.sendMessage(player, "/plot database [sqlite/mysql]"); - } - try { - SQLManager manager = new SQLManager(implementation, prefix, true); - Database.insertPlots(manager, plots, player); - return true; - } catch (ClassNotFoundException | SQLException e) { - MainUtil.sendMessage(player, "$1Failed to save plots, read stacktrace for info"); - MainUtil.sendMessage(player, - "&d==== Here is an ugly stacktrace, if you are interested in those things ==="); - e.printStackTrace(); - MainUtil.sendMessage(player, "&d==== End of stacktrace ===="); - MainUtil - .sendMessage(player, "$1Please make sure you are using the correct arguments!"); - return false; - } - } catch (ClassNotFoundException | SQLException e) { - MainUtil.sendMessage(player, "$1Failed to open connection, read stacktrace for info"); - MainUtil.sendMessage(player, - "&d==== Here is an ugly stacktrace, if you are interested in those things ==="); - e.printStackTrace(); - MainUtil.sendMessage(player, "&d==== End of stacktrace ===="); - MainUtil.sendMessage(player, "$1Please make sure you are using the correct arguments!"); - return false; - } + @Override + public boolean onCommand(final PlotPlayer player, String[] args) { + if (args.length < 1) { + MainUtil.sendMessage(player, "/plot database [area] "); + return false; } + List plots; + PlotArea area = PlotSquared.get().getPlotAreaByString(args[0]); + if (area != null) { + plots = PlotSquared.get().sortPlotsByTemp(area.getPlots()); + args = Arrays.copyOfRange(args, 1, args.length); + } else { + plots = PlotSquared.get().sortPlotsByTemp(PlotSquared.get().getPlots()); + } + if (args.length < 1) { + MainUtil.sendMessage(player, "/plot database [world] "); + MainUtil.sendMessage(player, "[arg] indicates an optional argument"); + return false; + } + try { + com.github.intellectualsites.plotsquared.plot.database.Database implementation; + String prefix = ""; + switch (args[0].toLowerCase()) { + case "import": + if (args.length < 2) { + MainUtil + .sendMessage(player, "/plot database import [prefix]"); + return false; + } + File file = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), + args[1].endsWith(".db") ? args[1] : args[1] + ".db"); + if (!file.exists()) { + MainUtil.sendMessage(player, "&6Database does not exist: " + file); + return false; + } + MainUtil.sendMessage(player, "&6Starting..."); + implementation = new SQLite(file); + SQLManager manager = + new SQLManager(implementation, args.length == 3 ? args[2] : "", true); + HashMap> map = manager.getPlots(); + plots = new ArrayList<>(); + for (Entry> entry : map.entrySet()) { + String areaname = entry.getKey(); + PlotArea pa = PlotSquared.get().getPlotAreaByString(areaname); + if (pa != null) { + for (Entry entry2 : entry.getValue().entrySet()) { + Plot plot = entry2.getValue(); + if (pa.getOwnedPlotAbs(plot.getId()) != null) { + if (pa instanceof SinglePlotArea) { + Plot newPlot = pa.getNextFreePlot(null, plot.getId()); + if (newPlot != null) { + PlotId newId = newPlot.getId(); + PlotId id = plot.getId(); + File worldFile = + new File(PlotSquared.imp().getWorldContainer(), + id.toCommaSeparatedString()); + if (worldFile.exists()) { + File newFile = + new File(PlotSquared.imp().getWorldContainer(), + newId.toCommaSeparatedString()); + worldFile.renameTo(newFile); + } + id.x = newId.x; + id.y = newId.y; + id.recalculateHash(); + plot.setArea(pa); + plots.add(plot); + continue; + } + } + MainUtil.sendMessage(player, + "Skipping duplicate plot: " + plot + " | id=" + plot.temp); + continue; + } + plot.setArea(pa); + plots.add(plot); + } + } else { + HashMap plotmap = + PlotSquared.get().plots_tmp + .computeIfAbsent(areaname, k -> new HashMap<>()); + plotmap.putAll(entry.getValue()); + } + } + DBFunc.createPlotsAndData(plots, + () -> MainUtil.sendMessage(player, "&6Database conversion finished!")); + return true; + case "mysql": + if (args.length < 6) { + return MainUtil.sendMessage(player, + "/plot database mysql [host] [port] [username] [password] [database] {prefix}"); + } + String host = args[1]; + String port = args[2]; + String username = args[3]; + String password = args[4]; + String database = args[5]; + if (args.length > 6) { + prefix = args[6]; + } + implementation = new MySQL(host, port, database, username, password); + break; + case "sqlite": + if (args.length < 2) { + return MainUtil.sendMessage(player, "/plot database sqlite [file]"); + } + File sqliteFile = + MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), args[1] + ".db"); + implementation = new SQLite(sqliteFile); + break; + default: + return MainUtil.sendMessage(player, "/plot database [sqlite/mysql]"); + } + try { + SQLManager manager = new SQLManager(implementation, prefix, true); + Database.insertPlots(manager, plots, player); + return true; + } catch (ClassNotFoundException | SQLException e) { + MainUtil.sendMessage(player, "$1Failed to save plots, read stacktrace for info"); + MainUtil.sendMessage(player, + "&d==== Here is an ugly stacktrace, if you are interested in those things ==="); + e.printStackTrace(); + MainUtil.sendMessage(player, "&d==== End of stacktrace ===="); + MainUtil + .sendMessage(player, "$1Please make sure you are using the correct arguments!"); + return false; + } + } catch (ClassNotFoundException | SQLException e) { + MainUtil.sendMessage(player, "$1Failed to open connection, read stacktrace for info"); + MainUtil.sendMessage(player, + "&d==== Here is an ugly stacktrace, if you are interested in those things ==="); + e.printStackTrace(); + MainUtil.sendMessage(player, "&d==== End of stacktrace ===="); + MainUtil.sendMessage(player, "$1Please make sure you are using the correct arguments!"); + return false; + } + } } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Help.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Help.java index f0ff64af1..ff697953c 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Help.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Help.java @@ -57,9 +57,7 @@ public class Help extends Command { public void displayHelp(PlotPlayer player, String cat, int page) { CommandCategory catEnum = null; if (cat != null) { - if (StringMan.isEqualIgnoreCase(cat, "all")) { - catEnum = null; - } else { + if (!StringMan.isEqualIgnoreCase(cat, "all")) { for (CommandCategory c : CommandCategory.values()) { if (StringMan.isEqualIgnoreCaseToAny(cat, c.name(), c.toString())) { catEnum = c; diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Inbox.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Inbox.java index 5c7cfc0ac..908e35afc 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Inbox.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Inbox.java @@ -165,9 +165,8 @@ import java.util.Optional; inbox.clearInbox(plot); Optional> comments = plot.getSettings().getComments(inbox.toString()); - if (comments.isPresent()) { - plot.getSettings().removeComments(comments.get()); - } + comments + .ifPresent(plotComments -> plot.getSettings().removeComments(plotComments)); MainUtil.sendMessage(player, C.COMMENT_REMOVED, "*"); return true; default: diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Merge.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Merge.java index 42075f2d2..39d368865 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Merge.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Merge.java @@ -60,9 +60,9 @@ public class Merge extends SubCommand { } final PlotArea plotArea = plot.getArea(); Expression priceExr = - plotArea.PRICES.containsKey("merge") ? plotArea.PRICES.get("merge") : null; + plotArea.PRICES.getOrDefault("merge", Expression.constant(0d)); final int size = plot.getConnectedPlots().size(); - final double price = priceExr == null ? 0d : priceExr.evaluate((double) size); + final double price = priceExr.evaluate((double) size); if (EconHandler.manager != null && plotArea.USE_ECONOMY && price > 0d && EconHandler.manager.getMoney(player) < price) { sendMessage(player, C.CANNOT_AFFORD_MERGE, String.valueOf(price)); diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Purge.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Purge.java index b8b38e298..8cd4d9e56 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Purge.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Purge.java @@ -108,9 +108,7 @@ import java.util.UUID; if (unknown && UUIDHandler.getName(plot.owner) != null) { continue; } - for (Plot current : plot.getConnectedPlots()) { - toDelete.add(current); - } + toDelete.addAll(plot.getConnectedPlots()); } if (PlotSquared.get().plots_tmp != null) { for (Entry> entry : PlotSquared.get().plots_tmp @@ -143,23 +141,21 @@ import java.util.UUID; } String cmd = "/plot purge " + StringMan.join(args, " ") + " (" + toDelete.size() + " plots)"; - Runnable run = new Runnable() { - @Override public void run() { - PlotSquared.debug("Calculating plots to purge, please wait..."); - HashSet ids = new HashSet<>(); - for (Plot plot : toDelete) { - if (plot.temp != Integer.MAX_VALUE) { - ids.add(plot.temp); - plot.getArea().removePlot(plot.getId()); - for (PlotPlayer pp : plot.getPlayersInPlot()) { - PlotListener.plotEntry(pp, plot); - } - plot.removeSign(); + Runnable run = () -> { + PlotSquared.debug("Calculating plots to purge, please wait..."); + HashSet ids = new HashSet<>(); + for (Plot plot : toDelete) { + if (plot.temp != Integer.MAX_VALUE) { + ids.add(plot.temp); + plot.getArea().removePlot(plot.getId()); + for (PlotPlayer pp : plot.getPlayersInPlot()) { + PlotListener.plotEntry(pp, plot); } + plot.removeSign(); } - DBFunc.purgeIds(ids); - C.PURGE_SUCCESS.send(player, ids.size() + "/" + toDelete.size()); } + DBFunc.purgeIds(ids); + C.PURGE_SUCCESS.send(player, ids.size() + "/" + toDelete.size()); }; if (hasConfirmation(player)) { CmdConfirm.addPending(player, cmd, run); diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Rate.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Rate.java index 7141df96e..33570b9b6 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Rate.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Rate.java @@ -22,25 +22,23 @@ import java.util.Map.Entry; switch (args[0].toLowerCase()) { case "next": { ArrayList plots = new ArrayList<>(PlotSquared.get().getBasePlots()); - Collections.sort(plots, new Comparator() { - @Override public int compare(Plot p1, Plot p2) { - double v1 = 0; - if (!p1.getRatings().isEmpty()) { - for (Entry entry : p1.getRatings().entrySet()) { - v1 -= 11 - entry.getValue().getAverageRating(); - } + plots.sort((p1, p2) -> { + double v1 = 0; + if (!p1.getRatings().isEmpty()) { + for (Entry entry : p1.getRatings().entrySet()) { + v1 -= 11 - entry.getValue().getAverageRating(); } - double v2 = 0; - if (!p2.getRatings().isEmpty()) { - for (Entry entry : p2.getRatings().entrySet()) { - v2 -= 11 - entry.getValue().getAverageRating(); - } - } - if (v1 == v2) { - return -0; - } - return v2 > v1 ? 1 : -1; } + double v2 = 0; + if (!p2.getRatings().isEmpty()) { + for (Entry entry : p2.getRatings().entrySet()) { + v2 -= 11 - entry.getValue().getAverageRating(); + } + } + if (v1 == v2) { + return -0; + } + return v2 > v1 ? 1 : -1; }); UUID uuid = player.getUUID(); for (Plot p : plots) { @@ -123,7 +121,7 @@ import java.util.Map.Entry; return true; } }; - inventory.setItem(0, new PlotItemStack(35, (short) 12, 0, "0/8")); + inventory.setItem(0, new PlotItemStack("minecraft:brown_wool", 0, "0/8")); inventory.setItem(1, new PlotItemStack(35, (short) 14, 1, "1/8")); inventory.setItem(2, new PlotItemStack(35, (short) 1, 2, "2/8")); inventory.setItem(3, new PlotItemStack(35, (short) 4, 3, "3/8")); @@ -137,11 +135,9 @@ import java.util.Map.Entry; }; if (plot.getSettings().ratings == null) { if (!Settings.Enabled_Components.RATING_CACHE) { - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - plot.getSettings().ratings = DBFunc.getRatings(plot); - run.run(); - } + TaskManager.runTaskAsync(() -> { + plot.getSettings().ratings = DBFunc.getRatings(plot); + run.run(); }); return true; } @@ -167,26 +163,22 @@ import java.util.Map.Entry; return false; } final UUID uuid = player.getUUID(); - final Runnable run = new Runnable() { - @Override public void run() { - if (plot.getRatings().containsKey(uuid)) { - sendMessage(player, C.RATING_ALREADY_EXISTS, plot.getId().toString()); - return; - } - Rating result = EventUtil.manager.callRating(player, plot, new Rating(rating)); - if (result != null) { - plot.addRating(uuid, result); - sendMessage(player, C.RATING_APPLIED, plot.getId().toString()); - } + final Runnable run = () -> { + if (plot.getRatings().containsKey(uuid)) { + sendMessage(player, C.RATING_ALREADY_EXISTS, plot.getId().toString()); + return; + } + Rating result = EventUtil.manager.callRating(player, plot, new Rating(rating)); + if (result != null) { + plot.addRating(uuid, result); + sendMessage(player, C.RATING_APPLIED, plot.getId().toString()); } }; if (plot.getSettings().ratings == null) { if (!Settings.Enabled_Components.RATING_CACHE) { - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - plot.getSettings().ratings = DBFunc.getRatings(plot); - run.run(); - } + TaskManager.runTaskAsync(() -> { + plot.getSettings().ratings = DBFunc.getRatings(plot); + run.run(); }); return true; } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/AbstractDB.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/AbstractDB.java index a26d4d02e..e5341103d 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/AbstractDB.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/AbstractDB.java @@ -143,14 +143,6 @@ public interface AbstractDB { */ void setFlags(Plot plot, HashMap, Object> flags); - /** - * Set cluster flags. - * - * @param cluster PlotCluster Object - * @param flags flags to set (flag[]) - */ - void setFlags(PlotCluster cluster, HashMap, Object> flags); - /** * Rename a cluster to the given name. * diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/DBFunc.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/DBFunc.java index 5050c699f..6571a328c 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/DBFunc.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/DBFunc.java @@ -13,6 +13,7 @@ import java.util.*; * Database Functions * - These functions do not update the local plot objects and only make changes to the DB */ +@SuppressWarnings("deprecation") public class DBFunc { /** * The "global" uuid. @@ -298,17 +299,6 @@ public class DBFunc { DBFunc.dbManager.setFlags(plot, flags); } - public static void setFlags(PlotCluster cluster, HashMap, Object> flags) { - if (dbManager == null) { - return; - } - DBFunc.dbManager.setFlags(cluster, flags); - } - - /** - * @param plot - * @param alias - */ public static void setAlias(Plot plot, String alias) { if (plot.temp == -1 || dbManager == null) { return; @@ -330,10 +320,6 @@ public class DBFunc { DBFunc.dbManager.purge(area, plotIds); } - /** - * @param plot - * @param position - */ public static void setPosition(Plot plot, String position) { if (plot.temp == -1 || dbManager == null) { return; @@ -341,10 +327,6 @@ public class DBFunc { DBFunc.dbManager.setPosition(plot, position); } - /** - * @param plot - * @param comment - */ public static void removeComment(Plot plot, PlotComment comment) { if (plot.temp == -1 || dbManager == null) { return; @@ -359,10 +341,6 @@ public class DBFunc { DBFunc.dbManager.clearInbox(plot, inbox); } - /** - * @param plot - * @param comment - */ public static void setComment(Plot plot, PlotComment comment) { if (plot != null && plot.temp == -1 || dbManager == null) { return; @@ -370,9 +348,6 @@ public class DBFunc { DBFunc.dbManager.setComment(plot, comment); } - /** - * @param plot - */ public static void getComments(Plot plot, String inbox, RunnableVal> whenDone) { if (plot != null && plot.temp == -1 || dbManager == null) { @@ -381,10 +356,6 @@ public class DBFunc { DBFunc.dbManager.getComments(plot, inbox, whenDone); } - /** - * @param plot - * @param uuid - */ public static void removeTrusted(Plot plot, UUID uuid) { if (plot.temp == -1 || dbManager == null) { return; @@ -392,10 +363,6 @@ public class DBFunc { DBFunc.dbManager.removeTrusted(plot, uuid); } - /** - * @param cluster - * @param uuid - */ public static void removeHelper(PlotCluster cluster, UUID uuid) { if (dbManager == null) { return; @@ -403,9 +370,6 @@ public class DBFunc { DBFunc.dbManager.removeHelper(cluster, uuid); } - /** - * @param cluster - */ public static void createCluster(PlotCluster cluster) { if (dbManager == null) { return; @@ -413,11 +377,6 @@ public class DBFunc { DBFunc.dbManager.createCluster(cluster); } - /** - * @param current - * @param min - * @param max - */ public static void resizeCluster(PlotCluster current, PlotId min, PlotId max) { if (dbManager == null) { return; @@ -425,10 +384,6 @@ public class DBFunc { DBFunc.dbManager.resizeCluster(current, min, max); } - /** - * @param plot - * @param uuid - */ public static void removeMember(Plot plot, UUID uuid) { if (plot.temp == -1 || dbManager == null) { return; @@ -436,10 +391,6 @@ public class DBFunc { DBFunc.dbManager.removeMember(plot, uuid); } - /** - * @param cluster - * @param uuid - */ public static void removeInvited(PlotCluster cluster, UUID uuid) { if (dbManager == null) { return; @@ -447,10 +398,6 @@ public class DBFunc { DBFunc.dbManager.removeInvited(cluster, uuid); } - /** - * @param plot - * @param uuid - */ public static void setTrusted(Plot plot, UUID uuid) { if (plot.temp == -1 || dbManager == null) { return; @@ -465,10 +412,6 @@ public class DBFunc { DBFunc.dbManager.setHelper(cluster, uuid); } - /** - * @param plot - * @param uuid - */ public static void setMember(Plot plot, UUID uuid) { if (plot.temp == -1 || dbManager == null) { return; @@ -483,10 +426,6 @@ public class DBFunc { DBFunc.dbManager.setInvited(cluster, uuid); } - /** - * @param plot - * @param uuid - */ public static void removeDenied(Plot plot, UUID uuid) { if (plot.temp == -1 || dbManager == null) { return; @@ -494,10 +433,6 @@ public class DBFunc { DBFunc.dbManager.removeDenied(plot, uuid); } - /** - * @param plot - * @param uuid - */ public static void setDenied(Plot plot, UUID uuid) { if (plot.temp == -1 || dbManager == null) { return; diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/Database.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/Database.java index 4acecc01f..8626a1a24 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/Database.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/Database.java @@ -11,9 +11,9 @@ import java.sql.Statement; * @author -_Husky_- * @author tips48 */ -public abstract class Database { +public interface Database { - public abstract Connection forceConnection() throws SQLException, ClassNotFoundException; + Connection forceConnection() throws SQLException, ClassNotFoundException; /** * Opens a connection with the database. @@ -22,7 +22,7 @@ public abstract class Database { * @throws SQLException if the connection can not be opened * @throws ClassNotFoundException if the driver cannot be found */ - public abstract Connection openConnection() throws SQLException, ClassNotFoundException; + Connection openConnection() throws SQLException, ClassNotFoundException; /** * Checks if a connection is open with the database. @@ -30,14 +30,14 @@ public abstract class Database { * @return true if the connection is open * @throws SQLException if the connection cannot be checked */ - public abstract boolean checkConnection() throws SQLException; + boolean checkConnection() throws SQLException; /** * Gets the connection with the database. * * @return Connection with the database, null if none */ - public abstract Connection getConnection(); + Connection getConnection(); /** * Closes the connection with the database. @@ -45,7 +45,7 @@ public abstract class Database { * @return true if successful * @throws SQLException if the connection cannot be closed */ - public abstract boolean closeConnection() throws SQLException; + boolean closeConnection() throws SQLException; /** * Executes a SQL Query. @@ -56,7 +56,7 @@ public abstract class Database { * @throws SQLException If the query cannot be executed * @throws ClassNotFoundException If the driver cannot be found; see {@link #openConnection()} */ - public abstract ResultSet querySQL(String query) throws SQLException, ClassNotFoundException; + ResultSet querySQL(String query) throws SQLException, ClassNotFoundException; /** * Executes an Update SQL Query. @@ -68,5 +68,5 @@ public abstract class Database { * @throws SQLException If the query cannot be executed * @throws ClassNotFoundException If the driver cannot be found; see {@link #openConnection()} */ - public abstract int updateSQL(String query) throws SQLException, ClassNotFoundException; + int updateSQL(String query) throws SQLException, ClassNotFoundException; } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/MySQL.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/MySQL.java index 7e7df9124..4a0e655c5 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/MySQL.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/MySQL.java @@ -11,7 +11,7 @@ import java.sql.*; * @author -_Husky_- * @author tips48 */ -public class MySQL extends Database { +public class MySQL implements Database { private final String user; private final String database; diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/SQLManager.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/SQLManager.java index 66a21174d..ed460450d 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/SQLManager.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/SQLManager.java @@ -7,3204 +7,3296 @@ import com.github.intellectualsites.plotsquared.plot.config.Storage; import com.github.intellectualsites.plotsquared.plot.flag.Flag; import com.github.intellectualsites.plotsquared.plot.flag.FlagManager; import com.github.intellectualsites.plotsquared.plot.flag.StringFlag; -import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.object.BlockLoc; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; +import com.github.intellectualsites.plotsquared.plot.object.PlotCluster; +import com.github.intellectualsites.plotsquared.plot.object.PlotId; +import com.github.intellectualsites.plotsquared.plot.object.PlotSettings; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal; import com.github.intellectualsites.plotsquared.plot.object.comment.PlotComment; import com.github.intellectualsites.plotsquared.plot.util.MainUtil; import com.github.intellectualsites.plotsquared.plot.util.StringMan; import com.github.intellectualsites.plotsquared.plot.util.TaskManager; import com.google.common.base.Charsets; - -import java.sql.*; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.Queue; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; +import javax.annotation.Nonnull; -@SuppressWarnings("SqlDialectInspection") public class SQLManager implements AbstractDB { +@SuppressWarnings("SqlDialectInspection") +public class SQLManager implements AbstractDB { - // Public final - public final String SET_OWNER; - public final String GET_ALL_PLOTS; - public final String CREATE_PLOTS; - public final String CREATE_SETTINGS; - public final String CREATE_TIERS; - public final String CREATE_PLOT; - public final String CREATE_PLOT_SAFE; - public final String CREATE_CLUSTER; - private final String prefix; - // Private Final - private final Database database; - private final boolean mySQL; - /** - * important tasks - */ - public volatile Queue globalTasks; - /** - * Notify tasks - */ - public volatile Queue notifyTasks; - /** - * plot - * plot_denied - * plot_helpers - * plot_trusted - * plot_comments - * plot_settings - * plot_rating - */ - public volatile ConcurrentHashMap> plotTasks; - /** - * player_meta - */ - public volatile ConcurrentHashMap> playerTasks; - /** - * cluster - * cluster_helpers - * cluster_invited - * cluster_settings - */ - public volatile ConcurrentHashMap> clusterTasks; - // Private - private Connection connection; - private boolean closed = false; + // Public final + public final String SET_OWNER; + public final String GET_ALL_PLOTS; + public final String CREATE_PLOTS; + public final String CREATE_SETTINGS; + public final String CREATE_TIERS; + public final String CREATE_PLOT; + public final String CREATE_PLOT_SAFE; + public final String CREATE_CLUSTER; + private final String prefix; + // Private Final + private final Database database; + private final boolean mySQL; + /** + * important tasks + */ + public volatile Queue globalTasks; + /** + * Notify tasks + */ + public volatile Queue notifyTasks; + /** + * plot plot_denied plot_helpers plot_trusted plot_comments plot_settings plot_rating + */ + public volatile ConcurrentHashMap> plotTasks; + /** + * player_meta + */ + public volatile ConcurrentHashMap> playerTasks; + /** + * cluster cluster_helpers cluster_invited cluster_settings + */ + public volatile ConcurrentHashMap> clusterTasks; + // Private + private Connection connection; + private boolean closed = false; - /** - * Constructor - * - * @param database - * @param p prefix - * @throws SQLException - * @throws ClassNotFoundException - */ - public SQLManager(final Database database, String p, boolean debug) - throws SQLException, ClassNotFoundException { - // Private final - this.database = database; - this.connection = database.openConnection(); - this.mySQL = database instanceof MySQL; - this.globalTasks = new ConcurrentLinkedQueue<>(); - this.notifyTasks = new ConcurrentLinkedQueue<>(); - this.plotTasks = new ConcurrentHashMap<>(); - this.playerTasks = new ConcurrentHashMap<>(); - this.clusterTasks = new ConcurrentHashMap<>(); - this.prefix = p; - this.SET_OWNER = "UPDATE `" + this.prefix - + "plot` SET `owner` = ? WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND `world` = ?"; - this.GET_ALL_PLOTS = - "SELECT `id`, `plot_id_x`, `plot_id_z`, `world` FROM `" + this.prefix + "plot`"; - this.CREATE_PLOTS = "INSERT INTO `" + this.prefix - + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) values "; - this.CREATE_SETTINGS = - "INSERT INTO `" + this.prefix + "plot_settings` (`plot_plot_id`) values "; - this.CREATE_TIERS = - "INSERT INTO `" + this.prefix + "plot_%tier%` (`plot_plot_id`, `user_uuid`) values "; - this.CREATE_PLOT = "INSERT INTO `" + this.prefix - + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) VALUES(?, ?, ?, ?, ?)"; + /** + * Constructor + * + * @param p prefix + */ + public SQLManager(final Database database, String p, boolean debug) + throws SQLException, ClassNotFoundException { + // Private final + this.database = database; + this.connection = database.openConnection(); + this.mySQL = database instanceof MySQL; + this.globalTasks = new ConcurrentLinkedQueue<>(); + this.notifyTasks = new ConcurrentLinkedQueue<>(); + this.plotTasks = new ConcurrentHashMap<>(); + this.playerTasks = new ConcurrentHashMap<>(); + this.clusterTasks = new ConcurrentHashMap<>(); + this.prefix = p; + this.SET_OWNER = "UPDATE `" + this.prefix + + "plot` SET `owner` = ? WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND `world` = ?"; + this.GET_ALL_PLOTS = + "SELECT `id`, `plot_id_x`, `plot_id_z`, `world` FROM `" + this.prefix + "plot`"; + this.CREATE_PLOTS = "INSERT INTO `" + this.prefix + + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) values "; + this.CREATE_SETTINGS = + "INSERT INTO `" + this.prefix + "plot_settings` (`plot_plot_id`) values "; + this.CREATE_TIERS = + "INSERT INTO `" + this.prefix + "plot_%tier%` (`plot_plot_id`, `user_uuid`) values "; + this.CREATE_PLOT = "INSERT INTO `" + this.prefix + + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) VALUES(?, ?, ?, ?, ?)"; - if (mySQL) { - this.CREATE_PLOT_SAFE = "INSERT IGNORE INTO `" + this.prefix - + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? FROM DUAL WHERE NOT EXISTS (SELECT null FROM `" - + this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)"; + if (mySQL) { + this.CREATE_PLOT_SAFE = "INSERT IGNORE INTO `" + this.prefix + + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? FROM DUAL WHERE NOT EXISTS (SELECT null FROM `" + + this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)"; + } else { + this.CREATE_PLOT_SAFE = "INSERT INTO `" + this.prefix + + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? WHERE NOT EXISTS (SELECT null FROM `" + + this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)"; + } + this.CREATE_CLUSTER = "INSERT INTO `" + this.prefix + + "cluster`(`pos1_x`, `pos1_z`, `pos2_x`, `pos2_z`, `owner`, `world`) VALUES(?, ?, ?, ?, ?, ?)"; + try { + createTables(); + } catch (SQLException e) { + e.printStackTrace(); + } + TaskManager.runTaskAsync(() -> { + long last = System.currentTimeMillis(); + while (true) { + if (SQLManager.this.closed) { + break; + } + boolean hasTask = + !globalTasks.isEmpty() || !playerTasks.isEmpty() || !plotTasks.isEmpty() + || !clusterTasks.isEmpty(); + if (hasTask) { + if (SQLManager.this.mySQL && System.currentTimeMillis() - last > 550000 + || !isValid()) { + last = System.currentTimeMillis(); + reconnect(); + } + if (!sendBatch()) { + try { + if (!getNotifyTasks().isEmpty()) { + for (Runnable task : getNotifyTasks()) { + TaskManager.runTask(task); + } + getNotifyTasks().clear(); + } + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } } else { - this.CREATE_PLOT_SAFE = "INSERT INTO `" + this.prefix - + "plot`(`plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp`) SELECT ?, ?, ?, ?, ? WHERE NOT EXISTS (SELECT null FROM `" - + this.prefix + "plot` WHERE `world` = ? AND `plot_id_x` = ? AND `plot_id_z` = ?)"; - } - this.CREATE_CLUSTER = "INSERT INTO `" + this.prefix - + "cluster`(`pos1_x`, `pos1_z`, `pos2_x`, `pos2_z`, `owner`, `world`) VALUES(?, ?, ?, ?, ?, ?)"; - try { - createTables(); - } catch (SQLException e) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { e.printStackTrace(); + } } - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - long last = System.currentTimeMillis(); - while (true) { - if (SQLManager.this.closed) { - break; - } - boolean hasTask = - !globalTasks.isEmpty() || !playerTasks.isEmpty() || !plotTasks.isEmpty() - || !clusterTasks.isEmpty(); - if (hasTask) { - if (SQLManager.this.mySQL && System.currentTimeMillis() - last > 550000 - || !isValid()) { - last = System.currentTimeMillis(); - reconnect(); - } - if (!sendBatch()) { - try { - if (!getNotifyTasks().isEmpty()) { - for (Runnable task : getNotifyTasks()) { - TaskManager.runTask(task); - } - getNotifyTasks().clear(); - } - Thread.sleep(50); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } else { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - }); + } + }); + } + + public boolean isValid() { + try { + if (connection.isClosed()) { + return false; + } + } catch (SQLException e) { + return false; } - - public boolean isValid() { - try { - if (connection.isClosed()) { - return false; - } - } catch (SQLException e) { - return false; - } - try (PreparedStatement stmt = this.connection.prepareStatement("SELECT 1")) { - stmt.executeQuery(); - return true; - } catch (Throwable e) { - return false; - } + try (PreparedStatement stmt = this.connection.prepareStatement("SELECT 1")) { + stmt.executeQuery(); + return true; + } catch (Throwable e) { + return false; } + } - public void reconnect() { - try { - close(); - SQLManager.this.closed = false; - SQLManager.this.connection = database.forceConnection(); - } catch (SQLException | ClassNotFoundException e) { - e.printStackTrace(); - } + public void reconnect() { + try { + close(); + SQLManager.this.closed = false; + SQLManager.this.connection = database.forceConnection(); + } catch (SQLException | ClassNotFoundException e) { + e.printStackTrace(); } + } - public synchronized Queue getGlobalTasks() { - return this.globalTasks; + public synchronized Queue getGlobalTasks() { + return this.globalTasks; + } + + public synchronized Queue getNotifyTasks() { + return this.notifyTasks; + } + + public synchronized void addPlotTask(@Nonnull Plot plot, UniqueStatement task) { + Queue tasks = this.plotTasks.computeIfAbsent(plot, plot1 -> new ConcurrentLinkedQueue<>()); + if (task == null) { + task = new UniqueStatement(String.valueOf(plot.hashCode())) { + + @Override + public PreparedStatement get() { + return null; + } + + @Override + public void set(PreparedStatement stmt) { + } + + @Override + public void addBatch(PreparedStatement statement) { + } + + @Override + public void execute(PreparedStatement statement) { + } + + }; } + tasks.add(task); + } - public synchronized Queue getNotifyTasks() { - return this.notifyTasks; + public synchronized void addPlayerTask(UUID uuid, UniqueStatement task) { + if (uuid == null) { + return; } + Queue tasks = this.playerTasks.computeIfAbsent(uuid, uuid1 -> new ConcurrentLinkedQueue<>()); + if (task == null) { + task = new UniqueStatement(String.valueOf(uuid.hashCode())) { - public synchronized void addPlotTask(Plot plot, UniqueStatement task) { - if (plot == null) { - plot = new Plot(null, new PlotId(Integer.MAX_VALUE, Integer.MAX_VALUE)); + @Override + public PreparedStatement get() { + return null; } - Queue tasks = this.plotTasks.get(plot); - if (tasks == null) { - tasks = new ConcurrentLinkedQueue<>(); - this.plotTasks.put(plot, tasks); + + @Override + public void set(PreparedStatement stmt) { } - if (task == null) { - task = new UniqueStatement(String.valueOf(plot.hashCode())) { - @Override public PreparedStatement get() { - return null; - } - - @Override public void set(PreparedStatement stmt) { - } - - @Override public void addBatch(PreparedStatement statement) { - } - - @Override public void execute(PreparedStatement statement) { - } - - }; + @Override + public void addBatch(PreparedStatement statement) { } - tasks.add(task); + + @Override + public void execute(PreparedStatement statement) { + } + + }; } + tasks.add(task); + } - public synchronized void addPlayerTask(UUID uuid, UniqueStatement task) { - if (uuid == null) { - return; + public synchronized void addClusterTask(PlotCluster cluster, UniqueStatement task) { + Queue tasks = this.clusterTasks.computeIfAbsent(cluster, plotCluster -> new ConcurrentLinkedQueue<>()); + if (task == null) { + task = new UniqueStatement(String.valueOf(cluster.hashCode())) { + + @Override + public PreparedStatement get() { + return null; } - Queue tasks = this.playerTasks.get(uuid); - if (tasks == null) { - tasks = new ConcurrentLinkedQueue<>(); - this.playerTasks.put(uuid, tasks); + + @Override + public void set(PreparedStatement stmt) { } - if (task == null) { - task = new UniqueStatement(String.valueOf(uuid.hashCode())) { - @Override public PreparedStatement get() { - return null; - } - - @Override public void set(PreparedStatement stmt) { - } - - @Override public void addBatch(PreparedStatement statement) { - } - - @Override public void execute(PreparedStatement statement) { - } - - }; + @Override + public void addBatch(PreparedStatement statement) { } - tasks.add(task); + + @Override + public void execute(PreparedStatement statement) { + } + + }; } + tasks.add(task); + } - public synchronized void addClusterTask(PlotCluster cluster, UniqueStatement task) { - Queue tasks = this.clusterTasks.get(cluster); - if (tasks == null) { - tasks = new ConcurrentLinkedQueue<>(); - this.clusterTasks.put(cluster, tasks); - } - if (task == null) { - task = new UniqueStatement(String.valueOf(cluster.hashCode())) { + public synchronized void addGlobalTask(Runnable task) { + getGlobalTasks().add(task); + } - @Override public PreparedStatement get() { - return null; - } - - @Override public void set(PreparedStatement stmt) { - } - - @Override public void addBatch(PreparedStatement statement) { - } - - @Override public void execute(PreparedStatement statement) { - } - - }; - } - tasks.add(task); + public synchronized void addNotifyTask(Runnable task) { + if (task != null) { + getNotifyTasks().add(task); } + } - public synchronized void addGlobalTask(Runnable task) { - getGlobalTasks().add(task); - } - - public synchronized void addNotifyTask(Runnable task) { + public boolean sendBatch() { + try { + if (!getGlobalTasks().isEmpty()) { + if (this.connection.getAutoCommit()) { + this.connection.setAutoCommit(false); + } + Runnable task = getGlobalTasks().remove(); if (task != null) { - getNotifyTasks().add(task); - } - } - - public boolean sendBatch() { - try { - if (!getGlobalTasks().isEmpty()) { - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - Runnable task = getGlobalTasks().remove(); - if (task != null) { - try { - task.run(); - } catch (Throwable e) { - PlotSquared.debug("============ DATABASE ERROR ============"); - PlotSquared.debug("There was an error updating the database."); - PlotSquared.debug(" - It will be corrected on shutdown"); - PlotSquared.debug("========================================"); - e.printStackTrace(); - PlotSquared.debug("========================================"); - } - } - commit(); - return true; - } - int count = -1; - if (!this.plotTasks.isEmpty()) { - count = 0; - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - String method = null; - PreparedStatement statement = null; - UniqueStatement task = null; - UniqueStatement lastTask = null; - Iterator>> iter = - this.plotTasks.entrySet().iterator(); - while (iter.hasNext()) { - try { - Entry> entry = iter.next(); - Plot plot = entry.getKey(); - Queue tasks = entry.getValue(); - if (tasks.isEmpty()) { - iter.remove(); - continue; - } - task = tasks.remove(); - count++; - if (task != null) { - if (task.method == null || !task.method.equals(method) - || statement == null) { - if (statement != null) { - lastTask.execute(statement); - statement.close(); - } - method = task.method; - statement = task.get(); - } - task.set(statement); - task.addBatch(statement); - try { - if (statement.isClosed()) { - statement = null; - } - } catch (AbstractMethodError ignore) { - } - } - lastTask = task; - } catch (Throwable e) { - PlotSquared.debug("============ DATABASE ERROR ============"); - PlotSquared.debug("There was an error updating the database."); - PlotSquared.debug(" - It will be corrected on shutdown"); - PlotSquared.debug("========================================"); - e.printStackTrace(); - PlotSquared.debug("========================================"); - } - } - if (statement != null && task != null) { - task.execute(statement); - statement.close(); - } - } - if (!this.playerTasks.isEmpty()) { - count = 0; - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - String method = null; - PreparedStatement statement = null; - UniqueStatement task = null; - UniqueStatement lastTask = null; - for (Entry> entry : this.playerTasks.entrySet()) { - try { - UUID uuid = entry.getKey(); - if (this.playerTasks.get(uuid).isEmpty()) { - this.playerTasks.remove(uuid); - continue; - } - task = this.playerTasks.get(uuid).remove(); - count++; - if (task != null) { - if (task.method == null || !task.method.equals(method)) { - if (statement != null) { - lastTask.execute(statement); - statement.close(); - } - method = task.method; - statement = task.get(); - } - task.set(statement); - task.addBatch(statement); - } - lastTask = task; - } catch (Throwable e) { - PlotSquared.debug("============ DATABASE ERROR ============"); - PlotSquared.debug("There was an error updating the database."); - PlotSquared.debug(" - It will be corrected on shutdown"); - PlotSquared.debug("========================================"); - e.printStackTrace(); - PlotSquared.debug("========================================"); - } - } - if (statement != null && task != null) { - task.execute(statement); - statement.close(); - } - } - if (!this.clusterTasks.isEmpty()) { - count = 0; - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); - } - String method = null; - PreparedStatement statement = null; - UniqueStatement task = null; - UniqueStatement lastTask = null; - for (Entry> entry : this.clusterTasks - .entrySet()) { - try { - PlotCluster cluster = entry.getKey(); - if (this.clusterTasks.get(cluster).isEmpty()) { - this.clusterTasks.remove(cluster); - continue; - } - task = this.clusterTasks.get(cluster).remove(); - count++; - if (task != null) { - if (task.method == null || !task.method.equals(method)) { - if (statement != null) { - lastTask.execute(statement); - statement.close(); - } - method = task.method; - statement = task.get(); - } - task.set(statement); - task.addBatch(statement); - } - lastTask = task; - } catch (Throwable e) { - PlotSquared.debug("============ DATABASE ERROR ============"); - PlotSquared.debug("There was an error updating the database."); - PlotSquared.debug(" - It will be corrected on shutdown"); - PlotSquared.debug("========================================"); - e.printStackTrace(); - PlotSquared.debug("========================================"); - } - } - if (statement != null && task != null) { - task.execute(statement); - statement.close(); - } - } - if (count > 0) { - commit(); - return true; - } - if (count != -1) { - if (!this.connection.getAutoCommit()) { - this.connection.setAutoCommit(true); - } - } - if (!this.clusterTasks.isEmpty()) { - this.clusterTasks.clear(); - } - if (!this.plotTasks.isEmpty()) { - this.plotTasks.clear(); - } - } catch (Throwable e) { + try { + task.run(); + } catch (Throwable e) { PlotSquared.debug("============ DATABASE ERROR ============"); PlotSquared.debug("There was an error updating the database."); PlotSquared.debug(" - It will be corrected on shutdown"); PlotSquared.debug("========================================"); e.printStackTrace(); PlotSquared.debug("========================================"); + } } - return false; - } - - public Connection getConnection() { - return this.connection; - } - - /** - * Set Plot owner - * - * @param plot Plot Object - * @param uuid Owner UUID - */ - @Override public void setOwner(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("setOwner") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, uuid.toString()); - statement.setInt(2, plot.getId().x); - statement.setInt(3, plot.getId().y); - statement.setString(4, plot.getArea().toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement(SQLManager.this.SET_OWNER); - } - }); - } - - @Override public void createPlotsAndData(final List myList, final Runnable whenDone) { - addGlobalTask(new Runnable() { - @Override public void run() { - try { - // Create the plots - createPlots(myList, new Runnable() { - @Override public void run() { - try { - // Creating datastructures - HashMap plotMap = new HashMap<>(); - for (Plot plot : myList) { - plotMap.put(plot.getId(), plot); - } - ArrayList settings = new ArrayList<>(); - final ArrayList helpers = new ArrayList<>(); - final ArrayList trusted = new ArrayList<>(); - final ArrayList denied = new ArrayList<>(); - - // Populating structures - try (PreparedStatement stmt = SQLManager.this.connection - .prepareStatement(SQLManager.this.GET_ALL_PLOTS); - ResultSet result = stmt.executeQuery()) { - while (result.next()) { - int id = result.getInt("id"); - int x = result.getInt("plot_id_x"); - int y = result.getInt("plot_id_z"); - PlotId plotId = new PlotId(x, y); - Plot plot = plotMap.get(plotId); - if (plot != null) { - settings.add(new SettingsPair(id, plot.getSettings())); - for (UUID uuid : plot.getDenied()) { - denied.add(new UUIDPair(id, uuid)); - } - for (UUID uuid : plot.getMembers()) { - trusted.add(new UUIDPair(id, uuid)); - } - for (UUID uuid : plot.getTrusted()) { - helpers.add(new UUIDPair(id, uuid)); - } - } - } - } - createSettings(settings, new Runnable() { - @Override public void run() { - createTiers(helpers, "helpers", new Runnable() { - @Override public void run() { - createTiers(trusted, "trusted", new Runnable() { - @Override public void run() { - createTiers(denied, "denied", - new Runnable() { - @Override public void run() { - try { - SQLManager.this.connection - .commit(); - } catch (SQLException e) { - e.printStackTrace(); - } - if (whenDone != null) { - whenDone.run(); - } - } - }); - } - }); - } - }); - } - }); - } catch (SQLException e) { - e.printStackTrace(); - PlotSquared.debug("&7[WARN] Failed to set all helpers for plots"); - try { - SQLManager.this.connection.commit(); - } catch (SQLException e1) { - e1.printStackTrace(); - } - } - } - }); - } catch (Exception e) { - e.printStackTrace(); - PlotSquared.debug("&7[WARN] Failed to set all helpers for plots"); - try { - SQLManager.this.connection.commit(); - } catch (SQLException e1) { - e1.printStackTrace(); - } - } - } - }); - } - - /** - * Create a plot - * - * @param myList list of plots to be created - */ - public void createTiers(ArrayList myList, final String tier, Runnable whenDone) { - StmtMod mod = new StmtMod() { - @Override public String getCreateMySQL(int size) { - return getCreateMySQL(size, SQLManager.this.CREATE_TIERS.replaceAll("%tier%", tier), - 2); - } - - @Override public String getCreateSQLite(int size) { - return getCreateSQLite(size, - "INSERT INTO `" + SQLManager.this.prefix + "plot_" + tier - + "` SELECT ? AS `plot_plot_id`, ? AS `user_uuid`", 2); - } - - @Override public String getCreateSQL() { - return "INSERT INTO `" + SQLManager.this.prefix + "plot_" + tier - + "` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"; - } - - @Override public void setMySQL(PreparedStatement stmt, int i, UUIDPair pair) - throws SQLException { - stmt.setInt(i * 2 + 1, pair.id); - stmt.setString(i * 2 + 2, pair.uuid.toString()); - } - - @Override public void setSQLite(PreparedStatement stmt, int i, UUIDPair pair) - throws SQLException { - stmt.setInt(i * 2 + 1, pair.id); - stmt.setString(i * 2 + 2, pair.uuid.toString()); - } - - @Override public void setSQL(PreparedStatement stmt, UUIDPair pair) - throws SQLException { - stmt.setInt(1, pair.id); - stmt.setString(2, pair.uuid.toString()); - } - }; - setBulk(myList, mod, whenDone); - } - - /** - * Create a plot - * - * @param myList list of plots to be created - */ - public void createPlots(List myList, Runnable whenDone) { - StmtMod mod = new StmtMod() { - @Override public String getCreateMySQL(int size) { - return getCreateMySQL(size, SQLManager.this.CREATE_PLOTS, 5); - } - - @Override public String getCreateSQLite(int size) { - return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix - + "plot` SELECT ? AS `id`, ? AS `plot_id_x`, ? AS `plot_id_z`, ? AS `owner`, ? AS `world`, ? AS `timestamp` ", - 6); - } - - @Override public String getCreateSQL() { - return SQLManager.this.CREATE_PLOT; - } - - @Override public void setMySQL(PreparedStatement stmt, int i, Plot plot) - throws SQLException { - stmt.setInt(i * 5 + 1, plot.getId().x); - stmt.setInt(i * 5 + 2, plot.getId().y); - try { - stmt.setString(i * 5 + 3, plot.owner.toString()); - } catch (SQLException ignored) { - stmt.setString(i * 5 + 3, everyone.toString()); - } - stmt.setString(i * 5 + 4, plot.getArea().toString()); - stmt.setTimestamp(i * 5 + 5, new Timestamp(plot.getTimestamp())); - } - - @Override public void setSQLite(PreparedStatement stmt, int i, Plot plot) - throws SQLException { - stmt.setNull(i * 6 + 1, 4); - stmt.setInt(i * 6 + 2, plot.getId().x); - stmt.setInt(i * 6 + 3, plot.getId().y); - try { - stmt.setString(i * 6 + 4, plot.owner.toString()); - } catch (SQLException ignored) { - stmt.setString(i * 6 + 4, everyone.toString()); - } - stmt.setString(i * 6 + 5, plot.getArea().toString()); - stmt.setTimestamp(i * 6 + 6, new Timestamp(plot.getTimestamp())); - } - - @Override public void setSQL(PreparedStatement stmt, Plot plot) throws SQLException { - stmt.setInt(1, plot.getId().x); - stmt.setInt(2, plot.getId().y); - stmt.setString(3, plot.owner.toString()); - stmt.setString(4, plot.getArea().toString()); - stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); - - } - }; - setBulk(myList, mod, whenDone); - } - - public void setBulk(List objList, StmtMod mod, Runnable whenDone) { - int size = objList.size(); - if (size == 0) { - if (whenDone != null) { - whenDone.run(); - } - return; - } - int packet; - if (this.mySQL) { - packet = Math.min(size, 5000); - } else { - packet = Math.min(size, 50); - } - int amount = size / packet; - try { - int count = 0; - PreparedStatement preparedStmt = null; - int last = -1; - for (int j = 0; j <= amount; j++) { - List subList = objList.subList(j * packet, Math.min(size, (j + 1) * packet)); - if (subList.isEmpty()) { - break; - } - String statement; - if (last == -1) { - last = subList.size(); - statement = mod.getCreateMySQL(subList.size()); - preparedStmt = this.connection.prepareStatement(statement); - } - if (subList.size() != last || count % 5000 == 0 && count > 0) { - preparedStmt.executeBatch(); - preparedStmt.close(); - statement = mod.getCreateMySQL(subList.size()); - preparedStmt = this.connection.prepareStatement(statement); - } - for (int i = 0; i < subList.size(); i++) { - count++; - T obj = subList.get(i); - mod.setMySQL(preparedStmt, i, obj); - } - last = subList.size(); - preparedStmt.addBatch(); - } - PlotSquared.debug( - "&aBatch 1: " + count + " | " + objList.get(0).getClass().getCanonicalName()); - preparedStmt.executeBatch(); - preparedStmt.clearParameters(); - preparedStmt.close(); - if (whenDone != null) { - whenDone.run(); - } - return; - } catch (SQLException e) { - if (this.mySQL) { - e.printStackTrace(); - PlotSquared.debug("&cERROR 1: | " + objList.get(0).getClass().getCanonicalName()); - } - } - try { - int count = 0; - PreparedStatement preparedStmt = null; - int last = -1; - for (int j = 0; j <= amount; j++) { - List subList = objList.subList(j * packet, Math.min(size, (j + 1) * packet)); - if (subList.isEmpty()) { - break; - } - String statement; - if (last == -1) { - last = subList.size(); - statement = mod.getCreateSQLite(subList.size()); - preparedStmt = this.connection.prepareStatement(statement); - } - if (subList.size() != last || count % 5000 == 0 && count > 0) { - preparedStmt.executeBatch(); - preparedStmt.clearParameters(); - statement = mod.getCreateSQLite(subList.size()); - preparedStmt = this.connection.prepareStatement(statement); - } - for (int i = 0; i < subList.size(); i++) { - count++; - T obj = subList.get(i); - mod.setSQLite(preparedStmt, i, obj); - } - last = subList.size(); - preparedStmt.addBatch(); - } - PlotSquared.debug( - "&aBatch 2: " + count + " | " + objList.get(0).getClass().getCanonicalName()); - preparedStmt.executeBatch(); - preparedStmt.clearParameters(); - preparedStmt.close(); - } catch (SQLException e) { - e.printStackTrace(); - PlotSquared.debug("&cERROR 2: | " + objList.get(0).getClass().getCanonicalName()); - PlotSquared.debug("&6[WARN] Could not bulk save!"); - try (PreparedStatement preparedStmt = this.connection - .prepareStatement(mod.getCreateSQL())) { - for (T obj : objList) { - mod.setSQL(preparedStmt, obj); - preparedStmt.addBatch(); - } - PlotSquared.debug("&aBatch 3"); - preparedStmt.executeBatch(); - } catch (SQLException e3) { - e3.printStackTrace(); - PlotSquared.debug("&c[ERROR] Failed to save all!"); - } - } - if (whenDone != null) { - whenDone.run(); - } - } - - public void createSettings(final ArrayList myList, final Runnable whenDone) { - final StmtMod mod = new StmtMod() { - @Override public String getCreateMySQL(int size) { - return getCreateMySQL(size, "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`,`biome`,`rain`,`custom_time`,`time`,`deny_entry`,`alias`,`flags`,`merged`," - + "`position`) VALUES ", 10); - } - - @Override public String getCreateSQLite(int size) { - return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings` SELECT ? AS `plot_plot_id`, ? AS `biome`, ? AS `rain`, ? AS `custom_time`, ? AS `time`, ? AS " - + "`deny_entry`, ? AS `alias`, ? AS `flags`, ? AS `merged`, ? AS `position`", - 10); - } - - @Override public String getCreateSQL() { - return "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"; - } - - @Override public void setMySQL(PreparedStatement statement, int i, SettingsPair pair) - throws SQLException { - statement.setInt(i * 10 + 1, pair.id); // id - statement.setNull(i * 10 + 2, 4); // biome - statement.setNull(i * 10 + 3, 4); // rain - statement.setNull(i * 10 + 4, 4); // custom_time - statement.setNull(i * 10 + 5, 4); // time - statement.setNull(i * 10 + 6, 4); // deny_entry - if (pair.settings.getAlias().isEmpty()) { - statement.setNull(i * 10 + 7, 4); - } else { - statement.setString(i * 10 + 7, pair.settings.getAlias()); - } - StringBuilder flag_string = new StringBuilder(); - int k = 0; - for (Entry, ?> flag : pair.settings.flags.entrySet()) { - if (k != 0) { - flag_string.append(','); - } - flag_string.append(flag.getKey().getName()).append(':').append( - flag.getKey().valueToString(flag.getValue()).replaceAll(":", "¯") - .replaceAll(",", "´")); - k++; - } - statement.setString(i * 10 + 8, flag_string.toString()); - boolean[] merged = pair.settings.getMerged(); - int hash = MainUtil.hash(merged); - statement.setInt(i * 10 + 9, hash); - BlockLoc loc = pair.settings.getPosition(); - String position; - if (loc.y == 0) { - position = "DEFAULT"; - } else { - position = loc.x + "," + loc.y + ',' + loc.z; - } - statement.setString(i * 10 + 10, position); - } - - @Override public void setSQLite(PreparedStatement stmt, int i, SettingsPair pair) - throws SQLException { - stmt.setInt(i * 10 + 1, pair.id); // id - stmt.setNull(i * 10 + 2, 4); // biome - stmt.setNull(i * 10 + 3, 4); // rain - stmt.setNull(i * 10 + 4, 4); // custom_time - stmt.setNull(i * 10 + 5, 4); // time - stmt.setNull(i * 10 + 6, 4); // deny_entry - if (pair.settings.getAlias().isEmpty()) { - stmt.setNull(i * 10 + 7, 4); - } else { - stmt.setString(i * 10 + 7, pair.settings.getAlias()); - } - StringBuilder flag_string = new StringBuilder(); - int k = 0; - for (Entry, ?> flag : pair.settings.flags.entrySet()) { - if (k != 0) { - flag_string.append(','); - } - flag_string.append(flag.getKey().getName()).append(':').append( - flag.getKey().valueToString(flag.getValue()).replaceAll(":", "¯") - .replaceAll(",", "´")); - k++; - } - stmt.setString(i * 10 + 8, flag_string.toString()); - boolean[] merged = pair.settings.getMerged(); - int n = 0; - for (int j = 0; j < 4; ++j) { - n = (n << 1) + (merged[j] ? 1 : 0); - } - stmt.setInt(i * 10 + 9, n); - BlockLoc loc = pair.settings.getPosition(); - String position; - if (loc.y == 0) { - position = "DEFAULT"; - } else { - position = loc.x + "," + loc.y + ',' + loc.z; - } - stmt.setString(i * 10 + 10, position); - } - - @Override public void setSQL(PreparedStatement stmt, SettingsPair pair) - throws SQLException { - stmt.setInt(1, pair.id); - } - }; - addGlobalTask(new Runnable() { - @Override public void run() { - setBulk(myList, mod, whenDone); - } - }); - } - - public void createEmptySettings(final ArrayList myList, final Runnable whenDone) { - final StmtMod mod = new StmtMod() { - @Override public String getCreateMySQL(int size) { - return getCreateMySQL(size, SQLManager.this.CREATE_SETTINGS, 1); - } - - @Override public String getCreateSQLite(int size) { - return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings` SELECT ? AS `plot_plot_id`, ? AS `biome`, ? AS `rain`, ? AS `custom_time`, ? AS `time`, ? AS " - + "`deny_entry`, ? AS `alias`, ? AS `flags`, ? AS `merged`, ? AS `position` ", - 10); - } - - @Override public String getCreateSQL() { - return "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"; - } - - @Override public void setMySQL(PreparedStatement stmt, int i, Integer id) - throws SQLException { - stmt.setInt(i + 1, id); - } - - @Override public void setSQLite(PreparedStatement stmt, int i, Integer id) - throws SQLException { - stmt.setInt(i * 10 + 1, id); - stmt.setNull(i * 10 + 2, 4); - stmt.setNull(i * 10 + 3, 4); - stmt.setNull(i * 10 + 4, 4); - stmt.setNull(i * 10 + 5, 4); - stmt.setNull(i * 10 + 6, 4); - stmt.setNull(i * 10 + 7, 4); - stmt.setNull(i * 10 + 8, 4); - stmt.setNull(i * 10 + 9, 4); - stmt.setString(i * 10 + 10, "DEFAULT"); - } - - @Override public void setSQL(PreparedStatement stmt, Integer id) throws SQLException { - stmt.setInt(1, id); - } - }; - addGlobalTask(new Runnable() { - @Override public void run() { - setBulk(myList, mod, whenDone); - } - }); - } - - public void createPlotSafe(final Plot plot, final Runnable success, final Runnable failure) { - final long timestamp = plot.getTimestamp(); - addPlotTask(plot, new UniqueStatement("createPlotSafe_" + plot.hashCode()) { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, plot.getId().x); - stmt.setInt(2, plot.getId().y); - stmt.setString(3, plot.owner.toString()); - stmt.setString(4, plot.getArea().toString()); - stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); - stmt.setString(6, plot.getArea().toString()); - stmt.setInt(7, plot.getId().x); - stmt.setInt(8, plot.getId().y); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement(SQLManager.this.CREATE_PLOT_SAFE, - Statement.RETURN_GENERATED_KEYS); - } - - @Override public void execute(PreparedStatement statement) { - - } - - @Override public void addBatch(PreparedStatement statement) throws SQLException { - int inserted = statement.executeUpdate(); - if (inserted > 0) { - try (ResultSet keys = statement.getGeneratedKeys()) { - if (keys.next()) { - plot.temp = keys.getInt(1); - addPlotTask(plot, new UniqueStatement( - "createPlotAndSettings_settings_" + plot.hashCode()) { - @Override public void set(PreparedStatement stmt) - throws SQLException { - stmt.setInt(1, getId(plot)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"); - } - }); - if (success != null) - addNotifyTask(success); - return; - } - } - } - if (failure != null) - failure.run(); - } - }); - } - - public void commit() { - if (this.closed) { - return; - } - try { - if (!this.connection.getAutoCommit()) { - this.connection.commit(); - this.connection.setAutoCommit(true); - } - } catch (SQLException e) { - e.printStackTrace(); - } - } - - @Override public void createPlotAndSettings(final Plot plot, Runnable whenDone) { - addPlotTask(plot, new UniqueStatement("createPlotAndSettings_" + plot.hashCode()) { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, plot.getId().x); - stmt.setInt(2, plot.getId().y); - stmt.setString(3, plot.owner.toString()); - stmt.setString(4, plot.getArea().toString()); - stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection - .prepareStatement(SQLManager.this.CREATE_PLOT, Statement.RETURN_GENERATED_KEYS); - } - - @Override public void execute(PreparedStatement statement) { - } - - @Override public void addBatch(PreparedStatement statement) throws SQLException { - statement.executeUpdate(); - try (ResultSet keys = statement.getGeneratedKeys()) { - if (keys.next()) { - plot.temp = keys.getInt(1); - } - } - } - }); - addPlotTask(plot, new UniqueStatement("createPlotAndSettings_settings_" + plot.hashCode()) { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, getId(plot)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"); - } - }); - addNotifyTask(whenDone); - } - - /** - * Create tables. - * - * @throws SQLException - */ - @Override public void createTables() throws SQLException { - String[] tables = - new String[] {"plot", "plot_denied", "plot_helpers", "plot_comments", "plot_trusted", - "plot_rating", "plot_settings", "cluster", "player_meta"}; - DatabaseMetaData meta = this.connection.getMetaData(); - int create = 0; - for (String s : tables) { - ResultSet set = meta.getTables(null, null, this.prefix + s, new String[] {"TABLE"}); - // ResultSet set = meta.getTables(null, null, prefix + s, null); - if (!set.next()) { - create++; - } - set.close(); - } - if (create == 0) { - return; - } - boolean addConstraint = create == tables.length; - PlotSquared.debug("Creating tables"); - try (Statement stmt = this.connection.createStatement()) { - if (this.mySQL) { - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot` (" - + "`id` INT(11) NOT NULL AUTO_INCREMENT," + "`plot_id_x` INT(11) NOT NULL," - + "`plot_id_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," - + "`world` VARCHAR(45) NOT NULL," - + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP," - + "PRIMARY KEY (`id`)" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_denied` (`plot_plot_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_helpers` (" - + "`plot_plot_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" - + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," - + "`comment` VARCHAR(40) NOT NULL," + "`inbox` VARCHAR(40) NOT NULL," - + "`timestamp` INT(11) NOT NULL," + "`sender` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_trusted` (" - + "`plot_plot_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_settings` (" - + " `plot_plot_id` INT(11) NOT NULL," - + " `biome` VARCHAR(45) DEFAULT 'FOREST'," + " `rain` INT(1) DEFAULT 0," - + " `custom_time` TINYINT(1) DEFAULT '0'," + " `time` INT(11) DEFAULT '8000'," - + " `deny_entry` TINYINT(1) DEFAULT '0'," - + " `alias` VARCHAR(50) DEFAULT NULL," + " `flags` VARCHAR(512) DEFAULT NULL," - + " `merged` INT(11) DEFAULT NULL," - + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," - + " PRIMARY KEY (`plot_plot_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_rating` ( `plot_plot_id` INT(11) NOT NULL, `rating` INT(2) NOT NULL, `player` VARCHAR(40) NOT NULL) ENGINE=InnoDB " - + "DEFAULT CHARSET=utf8"); - if (addConstraint) { - stmt.addBatch("ALTER TABLE `" + this.prefix + "plot_settings` ADD CONSTRAINT `" - + this.prefix - + "plot_settings_ibfk_1` FOREIGN KEY (`plot_plot_id`) REFERENCES `" - + this.prefix + "plot` (`id`) ON DELETE CASCADE"); - } - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster` (" - + "`id` INT(11) NOT NULL AUTO_INCREMENT," + "`pos1_x` INT(11) NOT NULL," - + "`pos1_z` INT(11) NOT NULL," + "`pos2_x` INT(11) NOT NULL," - + "`pos2_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," - + "`world` VARCHAR(45) NOT NULL," - + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP," - + "PRIMARY KEY (`id`)" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_helpers` (" - + "`cluster_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_invited` (" - + "`cluster_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_settings` (" - + " `cluster_id` INT(11) NOT NULL," + " `biome` VARCHAR(45) DEFAULT 'FOREST'," - + " `rain` INT(1) DEFAULT 0," + " `custom_time` TINYINT(1) DEFAULT '0'," - + " `time` INT(11) DEFAULT '8000'," + " `deny_entry` TINYINT(1) DEFAULT '0'," - + " `alias` VARCHAR(50) DEFAULT NULL," + " `flags` VARCHAR(512) DEFAULT NULL," - + " `merged` INT(11) DEFAULT NULL," - + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," - + " PRIMARY KEY (`cluster_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "player_meta` (" - + " `meta_id` INT(11) NOT NULL AUTO_INCREMENT," - + " `uuid` VARCHAR(40) NOT NULL," + " `key` VARCHAR(32) NOT NULL," - + " `value` blob NOT NULL," + " PRIMARY KEY (`meta_id`)" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - } else { - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot` (" - + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`plot_id_x` INT(11) NOT NULL," - + "`plot_id_z` INT(11) NOT NULL," + "`owner` VARCHAR(45) NOT NULL," - + "`world` VARCHAR(45) NOT NULL," - + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_denied` (`plot_plot_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_helpers` (`plot_plot_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_trusted` (`plot_plot_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" - + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," - + "`comment` VARCHAR(40) NOT NULL," - + "`inbox` VARCHAR(40) NOT NULL, `timestamp` INT(11) NOT NULL," - + "`sender` VARCHAR(40) NOT NULL" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_settings` (" - + " `plot_plot_id` INT(11) NOT NULL," - + " `biome` VARCHAR(45) DEFAULT 'FOREST'," + " `rain` INT(1) DEFAULT 0," - + " `custom_time` TINYINT(1) DEFAULT '0'," + " `time` INT(11) DEFAULT '8000'," - + " `deny_entry` TINYINT(1) DEFAULT '0'," - + " `alias` VARCHAR(50) DEFAULT NULL," + " `flags` VARCHAR(512) DEFAULT NULL," - + " `merged` INT(11) DEFAULT NULL," - + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," - + " PRIMARY KEY (`plot_plot_id`)" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "plot_rating` (`plot_plot_id` INT(11) NOT NULL, `rating` INT(2) NOT NULL, `player` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster` (" - + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`pos1_x` INT(11) NOT NULL," - + "`pos1_z` INT(11) NOT NULL," + "`pos2_x` INT(11) NOT NULL," - + "`pos2_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," - + "`world` VARCHAR(45) NOT NULL," - + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "cluster_helpers` (`cluster_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix - + "cluster_invited` (`cluster_id` INT(11) NOT NULL," - + "`user_uuid` VARCHAR(40) NOT NULL)"); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_settings` (" - + " `cluster_id` INT(11) NOT NULL," + " `biome` VARCHAR(45) DEFAULT 'FOREST'," - + " `rain` INT(1) DEFAULT 0," + " `custom_time` TINYINT(1) DEFAULT '0'," - + " `time` INT(11) DEFAULT '8000'," + " `deny_entry` TINYINT(1) DEFAULT '0'," - + " `alias` VARCHAR(50) DEFAULT NULL," + " `flags` VARCHAR(512) DEFAULT NULL," - + " `merged` INT(11) DEFAULT NULL," - + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," - + " PRIMARY KEY (`cluster_id`)" + ')'); - stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "player_meta` (" - + " `meta_id` INTEGER PRIMARY KEY AUTOINCREMENT," - + " `uuid` VARCHAR(40) NOT NULL," + " `key` VARCHAR(32) NOT NULL," - + " `value` blob NOT NULL" + ')'); - } - stmt.executeBatch(); - stmt.clearBatch(); - } - } - - @Override public void deleteSettings(final Plot plot) { - addPlotTask(plot, new UniqueStatement("delete_plot_settings") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, getId(plot)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_settings` WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override public void deleteHelpers(final Plot plot) { - if (plot.getTrusted().isEmpty()) { - return; - } - addPlotTask(plot, new UniqueStatement("delete_plot_helpers") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, getId(plot)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_helpers` WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override public void deleteTrusted(final Plot plot) { - if (plot.getMembers().isEmpty()) { - return; - } - addPlotTask(plot, new UniqueStatement("delete_plot_trusted") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, getId(plot)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_trusted` WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override public void deleteDenied(final Plot plot) { - if (plot.getDenied().isEmpty()) { - return; - } - addPlotTask(plot, new UniqueStatement("delete_plot_denied") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, getId(plot)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_denied` WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override public void deleteComments(final Plot plot) { - addPlotTask(plot, new UniqueStatement("delete_plot_comments") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setString(1, plot.getArea().toString()); - stmt.setInt(2, plot.hashCode()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `world` = ? AND `hashcode` = ?"); - } - }); - } - - @Override public void deleteRatings(final Plot plot) { - if (Settings.Enabled_Components.RATING_CACHE && plot.getSettings().getRatings().isEmpty()) { - return; - } - addPlotTask(plot, new UniqueStatement("delete_plot_ratings") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, getId(plot)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_rating` WHERE `plot_plot_id` = ?"); - } - }); - } - - /** - * Delete a plot. - * - * @param plot - */ - @Override public void delete(final Plot plot) { - PlotSquared.debug( - "Deleting plot... Id: " + plot.getId() + " World: " + plot.getWorldName() + " Owner: " - + plot.owner + " Index: " + plot.temp); - deleteSettings(plot); - deleteDenied(plot); - deleteHelpers(plot); - deleteTrusted(plot); - deleteComments(plot); - deleteRatings(plot); - addPlotTask(plot, new UniqueStatement("delete_plot") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, getId(plot)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = ?"); - } - }); - } - - /** - * Create plot settings - * - * @param id - * @param plot - */ - @Override public void createPlotSettings(final int id, Plot plot) { - PlotSquared.debug( - "Creating plot... Id: " + plot.getId() + " World: " + plot.getWorldName() + " Owner: " - + plot.owner + " Index: " + id); - addPlotTask(plot, new UniqueStatement("createPlotSettings") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, id); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_settings`(`plot_plot_id`) VALUES(?)"); - } - }); - } - - @Override public int getClusterId(PlotCluster cluster) { - if (cluster.temp > 0) { - return cluster.temp; - } - try { - commit(); - if (cluster.temp > 0) { - return cluster.temp; - } - int c_id; - try (PreparedStatement stmt = this.connection.prepareStatement( - "SELECT `id` FROM `" + this.prefix - + "cluster` WHERE `pos1_x` = ? AND `pos1_z` = ? AND `pos2_x` = ? AND `pos2_z` = ? AND `world` = ? ORDER BY `timestamp` ASC")) { - stmt.setInt(1, cluster.getP1().x); - stmt.setInt(2, cluster.getP1().y); - stmt.setInt(3, cluster.getP2().x); - stmt.setInt(4, cluster.getP2().y); - stmt.setString(5, cluster.area.toString()); - try (ResultSet resultSet = stmt.executeQuery()) { - c_id = Integer.MAX_VALUE; - while (resultSet.next()) { - c_id = resultSet.getInt("id"); - } - } - } - if (c_id == Integer.MAX_VALUE || c_id == 0) { - if (cluster.temp > 0) { - return cluster.temp; - } - throw new SQLException("Cluster does not exist in database"); - } - cluster.temp = c_id; - return c_id; - } catch (SQLException e) { - e.printStackTrace(); - } - return Integer.MAX_VALUE; - } - - @Override public int getId(Plot plot) { - if (plot.temp > 0) { - return plot.temp; - } - try { - commit(); - if (plot.temp > 0) { - return plot.temp; - } - int id; - try (PreparedStatement statement = this.connection.prepareStatement( - "SELECT `id` FROM `" + this.prefix - + "plot` WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND world = ? ORDER BY `timestamp` ASC")) { - statement.setInt(1, plot.getId().x); - statement.setInt(2, plot.getId().y); - statement.setString(3, plot.getArea().toString()); - try (ResultSet resultSet = statement.executeQuery()) { - id = Integer.MAX_VALUE; - while (resultSet.next()) { - id = resultSet.getInt("id"); - } - } - } - if (id == Integer.MAX_VALUE || id == 0) { - if (plot.temp > 0) { - return plot.temp; - } - throw new SQLException("Plot does not exist in database"); - } - plot.temp = id; - return id; - } catch (SQLException e) { - e.printStackTrace(); - } - return Integer.MAX_VALUE; - } - - @Override public void updateTables(int[] oldVersion) { - try { - if (this.mySQL && !PlotSquared.get().checkVersion(oldVersion, 3, 3, 2)) { - try (Statement stmt = this.connection.createStatement()) { - stmt.executeUpdate( - "ALTER TABLE `" + this.prefix + "plots` DROP INDEX `unique_alias`"); - } catch (SQLException ignored) { - } - } - DatabaseMetaData data = this.connection.getMetaData(); - ResultSet rs = - data.getColumns(null, null, this.prefix + "plot_comments", "plot_plot_id"); - if (rs.next()) { - rs.close(); - rs = data.getColumns(null, null, this.prefix + "plot_comments", "hashcode"); - if (!rs.next()) { - rs.close(); - try (Statement statement = this.connection.createStatement()) { - statement.addBatch("DROP TABLE `" + this.prefix + "plot_comments`"); - if (Storage.MySQL.USE) { - statement.addBatch( - "CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" - + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," - + "`comment` VARCHAR(40) NOT NULL," - + "`inbox` VARCHAR(40) NOT NULL," - + "`timestamp` INT(11) NOT NULL," - + "`sender` VARCHAR(40) NOT NULL" - + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); - } else { - statement.addBatch( - "CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" - + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," - + "`comment` VARCHAR(40) NOT NULL," - + "`inbox` VARCHAR(40) NOT NULL, `timestamp` INT(11) NOT NULL," - + "`sender` VARCHAR(40) NOT NULL" + ')'); - } - statement.executeBatch(); - } catch (SQLException ignored) { - try (Statement statement = this.connection.createStatement()) { - statement.addBatch("ALTER IGNORE TABLE `" + this.prefix - + "plot_comments` ADD `inbox` VARCHAR(11) DEFAULT `public`"); - statement.addBatch("ALTER IGNORE TABLE `" + this.prefix - + "plot_comments` ADD `timestamp` INT(11) DEFAULT 0"); - statement.addBatch("ALTER TABLE `" + this.prefix + "plot` DROP `tier`"); - statement.executeBatch(); - } - } - } - } - rs.close(); - rs = data.getColumns(null, null, this.prefix + "plot_denied", "plot_plot_id"); - if (rs.next()) { - try (Statement statement = this.connection.createStatement()) { - statement.executeUpdate("DELETE FROM `" + this.prefix - + "plot_denied` WHERE `plot_plot_id` NOT IN (SELECT `id` FROM `" - + this.prefix + "plot`)"); - } catch (SQLException e) { - e.printStackTrace(); - } - - rs.close(); - try (Statement statement = this.connection.createStatement()) { - for (String table : new String[] {"plot_denied", "plot_helpers", - "plot_trusted"}) { - ResultSet result = statement.executeQuery( - "SELECT plot_plot_id, user_uuid, COUNT(*) FROM " + this.prefix + table - + " GROUP BY plot_plot_id, user_uuid HAVING COUNT(*) > 1"); - if (result.next()) { - PlotSquared.debug("BACKING UP: " + this.prefix + table); - result.close(); - statement.executeUpdate( - "CREATE TABLE " + this.prefix + table + "_tmp AS SELECT * FROM " - + this.prefix + table + " GROUP BY plot_plot_id, user_uuid"); - statement.executeUpdate("DROP TABLE " + this.prefix + table); - statement.executeUpdate( - "CREATE TABLE " + this.prefix + table + " AS SELECT * FROM " - + this.prefix + table + "_tmp"); - statement.executeUpdate("DROP TABLE " + this.prefix + table + "_tmp"); - PlotSquared.debug("RESTORING: " + this.prefix + table); - } - } - } catch (SQLException e2) { - e2.printStackTrace(); - } - } - } catch (SQLException e) { - e.printStackTrace(); - } - - } - - public void deleteRows(ArrayList rowIds, final String table, final String column) { - setBulk(rowIds, new StmtMod() { - - @Override public String getCreateMySQL(int size) { - return getCreateMySQL(1, "DELETE FROM `" + table + "` WHERE `" + column + "` IN ", - size); - } - - @Override public String getCreateSQLite(int size) { - return getCreateMySQL(1, "DELETE FROM `" + table + "` WHERE `" + column + "` IN ", - size); - } - - @Override public String getCreateSQL() { - return "DELETE FROM `" + table + "` WHERE `" + column + "` = ?"; - } - - @Override public void setMySQL(PreparedStatement stmt, int i, Integer obj) - throws SQLException { - stmt.setInt(i + 1, obj); - } - - @Override public void setSQLite(PreparedStatement stmt, int i, Integer obj) - throws SQLException { - stmt.setInt(i + 1, obj); - } - - @Override public void setSQL(PreparedStatement stmt, Integer obj) throws SQLException { - stmt.setInt(1, obj); - } - }, null); - } - - /** - * Load all plots, helpers, denied, trusted, and every setting from DB into a {@link HashMap}. - */ - @Override public HashMap> getPlots() { - HashMap> newPlots = new HashMap<>(); - HashMap plots = new HashMap<>(); - try { - HashSet areas = new HashSet<>(); - if (PlotSquared.get().worlds.contains("worlds")) { - ConfigurationSection worldSection = - PlotSquared.get().worlds.getConfigurationSection("worlds"); - if (worldSection != null) { - for (String worldKey : worldSection.getKeys(false)) { - areas.add(worldKey); - ConfigurationSection areaSection = - worldSection.getConfigurationSection(worldKey + ".areas"); - if (areaSection != null) { - for (String areaKey : areaSection.getKeys(false)) { - String[] split = areaKey.split("(? uuids = new HashMap<>(); - HashMap noExist = new HashMap<>(); - - /* - * Getting plots - */ - try (Statement statement = this.connection.createStatement()) { - int id; - String o; - UUID user; - try (ResultSet resultSet = statement.executeQuery( - "SELECT `id`, `plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp` FROM `" - + this.prefix + "plot`")) { - ArrayList toDelete = new ArrayList<>(); - while (resultSet.next()) { - PlotId plot_id = new PlotId(resultSet.getInt("plot_id_x"), - resultSet.getInt("plot_id_z")); - id = resultSet.getInt("id"); - String areaid = resultSet.getString("world"); - if (!areas.contains(areaid)) { - if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - continue; - } else { - AtomicInteger value = noExist.get(areaid); - if (value != null) { - value.incrementAndGet(); - } else { - noExist.put(areaid, new AtomicInteger(1)); - } - } - } - o = resultSet.getString("owner"); - user = uuids.get(o); - if (user == null) { - try { - user = UUID.fromString(o); - } catch (IllegalArgumentException e) { - if (Settings.UUID.FORCE_LOWERCASE) { - user = UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + o.toLowerCase()) - .getBytes(Charsets.UTF_8)); - } else { - user = UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + o).getBytes(Charsets.UTF_8)); - } - } - uuids.put(o, user); - } - long time; - try { - Timestamp timestamp = resultSet.getTimestamp("timestamp"); - time = timestamp.getTime(); - } catch (SQLException exception) { - String parsable = resultSet.getString("timestamp"); - try { - time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(parsable) - .getTime(); - } catch (ParseException e) { - PlotSquared.debug( - "Could not parse date for plot: #" + id + "(" + areaid + ";" - + plot_id + ") (" + parsable + ")"); - time = System.currentTimeMillis() + id; - } - } - Plot p = new Plot(plot_id, user, new HashSet(), new HashSet(), - new HashSet(), "", null, null, null, - new boolean[] {false, false, false, false}, time, id); - HashMap map = newPlots.get(areaid); - if (map != null) { - Plot last = map.put(p.getId(), p); - if (last != null) { - if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(last.temp); - } else { - PlotSquared.debug( - "&cPLOT #" + id + "(" + last + ") in `" + this.prefix - + "plot` is a duplicate. Delete this plot or set `database-purger: true` in the settings.yml."); - } - } - } else { - map = new HashMap<>(); - newPlots.put(areaid, map); - map.put(p.getId(), p); - } - plots.put(id, p); - } - deleteRows(toDelete, this.prefix + "plot", "id"); - } - if (Settings.Enabled_Components.RATING_CACHE) { - try (ResultSet r = statement.executeQuery( - "SELECT `plot_plot_id`, `player`, `rating` FROM `" + this.prefix - + "plot_rating`")) { - ArrayList toDelete = new ArrayList<>(); - while (r.next()) { - id = r.getInt("plot_plot_id"); - o = r.getString("player"); - user = uuids.get(o); - if (user == null) { - user = UUID.fromString(o); - uuids.put(o, user); - } - Plot plot = plots.get(id); - if (plot != null) { - plot.getSettings().getRatings().put(user, r.getInt("rating")); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - PlotSquared.debug("&cENTRY #" + id + "(" + plot - + ") in `plot_rating` does not exist. Create this plot or set `database-purger: true` in the " - + "settings.yml."); - } - } - deleteRows(toDelete, this.prefix + "plot_rating", "plot_plot_id"); - } - } - - /* - * Getting helpers - */ - try (ResultSet r = statement.executeQuery( - "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_helpers`")) { - ArrayList toDelete = new ArrayList<>(); - while (r.next()) { - id = r.getInt("plot_plot_id"); - o = r.getString("user_uuid"); - user = uuids.get(o); - if (user == null) { - user = UUID.fromString(o); - uuids.put(o, user); - } - Plot plot = plots.get(id); - if (plot != null) { - plot.getTrusted().add(user); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - PlotSquared.debug("&cENTRY #" + id + "(" + plot - + ") in `plot_helpers` does not exist. Create this plot or set `database-purger: true` in the settings" - + ".yml."); - } - } - deleteRows(toDelete, this.prefix + "plot_helpers", "plot_plot_id"); - } - - /* - * Getting trusted - */ - try (ResultSet r = statement.executeQuery( - "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_trusted`")) { - ArrayList toDelete = new ArrayList<>(); - while (r.next()) { - id = r.getInt("plot_plot_id"); - o = r.getString("user_uuid"); - user = uuids.get(o); - if (user == null) { - user = UUID.fromString(o); - uuids.put(o, user); - } - Plot plot = plots.get(id); - if (plot != null) { - plot.getMembers().add(user); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - PlotSquared.debug("&cENTRY #" + id + "(" + plot - + ") in `plot_trusted` does not exist. Create this plot or set `database-purger: true` in the settings" - + ".yml."); - } - } - deleteRows(toDelete, this.prefix + "plot_trusted", "plot_plot_id"); - } - - /* - * Getting denied - */ - try (ResultSet r = statement.executeQuery( - "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_denied`")) { - ArrayList toDelete = new ArrayList<>(); - while (r.next()) { - id = r.getInt("plot_plot_id"); - o = r.getString("user_uuid"); - user = uuids.get(o); - if (user == null) { - user = UUID.fromString(o); - uuids.put(o, user); - } - Plot plot = plots.get(id); - if (plot != null) { - plot.getDenied().add(user); - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - PlotSquared.debug("&cENTRY " + id - + " in `plot_denied` does not exist. Create this plot or set `database-purger: true` in the settings.yml."); - } - } - deleteRows(toDelete, this.prefix + "plot_denied", "plot_plot_id"); - } - - try (ResultSet resultSet = statement - .executeQuery("SELECT * FROM `" + this.prefix + "plot_settings`")) { - ArrayList toDelete = new ArrayList<>(); - while (resultSet.next()) { - id = resultSet.getInt("plot_plot_id"); - Plot plot = plots.get(id); - if (plot != null) { - plots.remove(id); - String alias = resultSet.getString("alias"); - if (alias != null) { - plot.getSettings().setAlias(alias); - } - String pos = resultSet.getString("position"); - switch (pos.toLowerCase()) { - case "": - case "default": - case "0,0,0": - case "center": - break; - default: - try { - plot.getSettings().setPosition(BlockLoc.fromString(pos)); - } catch (Exception ignored) { - } - } - Integer m = resultSet.getInt("merged"); - boolean[] merged = new boolean[4]; - for (int i = 0; i < 4; i++) { - merged[3 - i] = (m & 1 << i) != 0; - } - plot.getSettings().setMerged(merged); - String[] flags_string; - String myflags = resultSet.getString("flags"); - if (myflags == null || myflags.isEmpty()) { - flags_string = new String[] {}; - } else { - flags_string = myflags.split(","); - } - HashMap, Object> flags = new HashMap<>(); - boolean exception = false; - for (String element : flags_string) { - if (element.contains(":")) { - String[] split = element.split(":"); - try { - String flag_str = - split[1].replaceAll("¯", ":").replaceAll("\u00B4", ","); - Flag flag = FlagManager.getOrCreateFlag(split[0]); - flags.put(flag, flag.parseValue(flag_str)); - } catch (Exception e) { - e.printStackTrace(); - exception = true; - } - } else { - element = - element.replaceAll("\u00AF", ":").replaceAll("\u00B4", ","); - if (StringMan - .isAlpha(element.replaceAll("_", "").replaceAll("-", ""))) { - Flag flag = FlagManager.getOrCreateFlag(element); - if (flag == null) { - flag = new StringFlag(element) { - @Override public String getValueDescription() { - return "Generic Filler Flag"; - } - }; - } - flags.put(flag, flag.parseValue("")); - } else { - PlotSquared.debug("INVALID FLAG: " + element); - } - } - } - if (exception) { - PlotSquared.debug("&cPlot #" + id + "(" + plot + ") | " + plot - + " had an invalid flag. A fix has been attempted."); - PlotSquared.debug("&c" + myflags); - this.setFlags(plot, flags); - } - plot.getSettings().flags = flags; - } else if (Settings.Enabled_Components.DATABASE_PURGER) { - toDelete.add(id); - } else { - PlotSquared.debug("&cENTRY #" + id + "(" + plot - + ") in `plot_settings` does not exist. Create this plot or set `database-purger: true` in the settings" - + ".yml."); - } - } - deleteRows(toDelete, this.prefix + "plot_settings", "plot_plot_id"); - } - } - if (!plots.entrySet().isEmpty()) { - createEmptySettings(new ArrayList<>(plots.keySet()), null); - for (Entry entry : plots.entrySet()) { - entry.getValue().getSettings(); - } - } - boolean invalidPlot = false; - for (Entry entry : noExist.entrySet()) { - String worldName = entry.getKey(); - invalidPlot = true; - PlotSquared.debug("&c[WARNING] Found " + entry.getValue().intValue() - + " plots in DB for non existent world; '" + worldName + "'."); - } - if (invalidPlot) { - PlotSquared.debug( - "&c[WARNING] - Please create the world/s or remove the plots using the purge command"); - } - } catch (SQLException e) { - PlotSquared.debug("&7[WARN] Failed to load plots."); - e.printStackTrace(); - } - return newPlots; - } - - @Override public void setMerged(final Plot plot, final boolean[] merged) { - plot.getSettings().setMerged(merged); - addPlotTask(plot, new UniqueStatement("setMerged") { - @Override public void set(PreparedStatement stmt) throws SQLException { - int hash = MainUtil.hash(merged); - stmt.setInt(1, hash); - stmt.setInt(2, getId(plot)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot_settings` SET `merged` = ? WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override public void swapPlots(Plot plot1, Plot plot2) { - final int id1 = getId(plot1); - final int id2 = getId(plot2); - final PlotId pos1 = plot1.getId(); - final PlotId pos2 = plot2.getId(); - addPlotTask(plot1, new UniqueStatement("swapPlots") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, pos2.x); - stmt.setInt(2, pos2.y); - stmt.setInt(3, id1); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `plot_id_x` = ?, `plot_id_z` = ? WHERE `id` = ?"); - } - }); - addPlotTask(plot2, new UniqueStatement("swapPlots") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, pos1.x); - stmt.setInt(2, pos1.y); - stmt.setInt(3, id2); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `plot_id_x` = ?, `plot_id_z` = ? WHERE `id` = ?"); - } - }); - } - - @Override public void movePlot(final Plot original, final Plot newPlot) { - addPlotTask(original, new UniqueStatement("movePlot") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, newPlot.getId().x); - stmt.setInt(2, newPlot.getId().y); - stmt.setString(3, newPlot.getArea().toString()); - stmt.setInt(4, getId(original)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `plot_id_x` = ?, `plot_id_z` = ?, `world` = ? WHERE `id` = ?"); - } - }); - addPlotTask(newPlot, null); - } - - @Override public void setFlags(final Plot plot, HashMap, Object> flags) { - final String flag_string = FlagManager.toString(flags); - addPlotTask(plot, new UniqueStatement("setFlags") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setString(1, flag_string); - stmt.setInt(2, getId(plot)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot_settings` SET `flags` = ? WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override public void setAlias(final Plot plot, final String alias) { - addPlotTask(plot, new UniqueStatement("setAlias") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setString(1, alias); - stmt.setInt(2, getId(plot)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot_settings` SET `alias` = ? WHERE `plot_plot_id` = ?"); - } - }); - } - - /** - * Purge all plots with the following database IDs - */ - @Override public void purgeIds(final Set uniqueIds) { - addGlobalTask(new Runnable() { - @Override public void run() { - if (!uniqueIds.isEmpty()) { - try { - ArrayList uniqueIdsList = new ArrayList(uniqueIds); - String stmt_prefix = ""; - int size = uniqueIdsList.size(); - int packet = 990; - int amount = size / packet; - int count = 0; - int last = -1; - for (int j = 0; j <= amount; j++) { - PlotSquared.debug("Purging " + (j * packet) + " / " + size); - List subList = - uniqueIdsList.subList(j * packet, Math.min(size, (j + 1) * packet)); - if (subList.isEmpty()) { - break; - } - StringBuilder idstr2 = new StringBuilder(""); - stmt_prefix = ""; - for (Integer id : subList) { - idstr2.append(stmt_prefix).append(id); - stmt_prefix = " OR `id` = "; - } - stmt_prefix = ""; - StringBuilder idstr = new StringBuilder(); - for (Integer id : subList) { - idstr.append(stmt_prefix).append(id); - stmt_prefix = " OR `plot_plot_id` = "; - } - PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_helpers` WHERE `plot_plot_id` = " + idstr); - stmt.executeUpdate(); - stmt.close(); - stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_denied` WHERE `plot_plot_id` = " + idstr); - stmt.executeUpdate(); - stmt.close(); - stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_settings` WHERE `plot_plot_id` = " + idstr); - stmt.executeUpdate(); - stmt.close(); - stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_trusted` WHERE `plot_plot_id` = " + idstr); - stmt.executeUpdate(); - stmt.close(); - stmt = SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = " - + idstr2); - stmt.executeUpdate(); - stmt.close(); - commit(); - } - } catch (SQLException e) { - e.printStackTrace(); - PlotSquared.debug("&c[ERROR] FAILED TO PURGE PLOTS!"); - return; - } - } - PlotSquared.debug("&6[INFO] SUCCESSFULLY PURGED " + uniqueIds.size() + " PLOTS!"); - } - }); - } - - @Override public void purge(final PlotArea area, final Set plots) { - addGlobalTask(new Runnable() { - @Override public void run() { - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "SELECT `id`, `plot_id_x`, `plot_id_z` FROM `" + SQLManager.this.prefix - + "plot` WHERE `world` = ?")) { - stmt.setString(1, area.toString()); - Set ids; - try (ResultSet r = stmt.executeQuery()) { - ids = new HashSet<>(); - while (r.next()) { - PlotId plot_id = - new PlotId(r.getInt("plot_id_x"), r.getInt("plot_id_z")); - if (plots.contains(plot_id)) { - ids.add(r.getInt("id")); - } - } - } - purgeIds(ids); - } catch (SQLException e) { - e.printStackTrace(); - PlotSquared.debug("&c[ERROR] FAILED TO PURGE AREA '" + area + "'!"); - } - for (Iterator iterator = plots.iterator(); iterator.hasNext(); ) { - PlotId plotId = iterator.next(); - iterator.remove(); - PlotId id = new PlotId(plotId.x, plotId.y); - area.removePlot(id); - } - } - }); - } - - @Override public void setPosition(final Plot plot, final String position) { - addPlotTask(plot, new UniqueStatement("setPosition") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setString(1, position == null ? "" : position); - stmt.setInt(2, getId(plot)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot_settings` SET `position` = ? WHERE `plot_plot_id` = ?"); - } - }); - } - - @Override public void removeComment(final Plot plot, final PlotComment comment) { - addPlotTask(plot, new UniqueStatement("removeComment") { - @Override public void set(PreparedStatement statement) throws SQLException { - if (plot != null) { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.getId().hashCode()); - statement.setString(3, comment.comment); - statement.setString(4, comment.inbox); - statement.setString(5, comment.senderName); - } else { - statement.setString(1, comment.comment); - statement.setString(2, comment.inbox); - statement.setString(3, comment.senderName); - } - } - - @Override public PreparedStatement get() throws SQLException { - if (plot != null) { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `comment` = ? AND `inbox` = ? AND `sender` = ?"); - } - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `comment` = ? AND `inbox` = ? AND `sender` = ?"); - } - }); - } - - @Override public void clearInbox(final Plot plot, final String inbox) { - addPlotTask(plot, new UniqueStatement("clearInbox") { - @Override public void set(PreparedStatement statement) throws SQLException { - if (plot != null) { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.getId().hashCode()); - statement.setString(3, inbox); - } else { - statement.setString(1, inbox); - } - } - - @Override public PreparedStatement get() throws SQLException { - if (plot != null) { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `inbox` = ?"); - } - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix + "plot_comments` `inbox` = ?"); - } - }); - } - - @Override public void getComments(final Plot plot, final String inbox, - final RunnableVal> whenDone) { - addPlotTask(plot, new UniqueStatement("getComments_" + plot) { - @Override public void set(PreparedStatement statement) throws SQLException { - if (plot != null) { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.getId().hashCode()); - statement.setString(3, inbox); - } else { - statement.setString(1, inbox); - } - } - - @Override public PreparedStatement get() throws SQLException { - if (plot != null) { - return SQLManager.this.connection.prepareStatement( - "SELECT * FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `inbox` = ?"); - } - return SQLManager.this.connection.prepareStatement( - "SELECT * FROM `" + SQLManager.this.prefix - + "plot_comments` WHERE `inbox` = ?"); - } - - @Override public void execute(PreparedStatement statement) { - } - - @Override public void addBatch(PreparedStatement statement) throws SQLException { - ArrayList comments = new ArrayList<>(); - try (ResultSet set = statement.executeQuery()) { - while (set.next()) { - String sender = set.getString("sender"); - String world = set.getString("world"); - int hash = set.getInt("hashcode"); - PlotId id; - if (hash != 0) { - id = PlotId.unpair(hash); - } else { - id = null; - } - String msg = set.getString("comment"); - long timestamp = set.getInt("timestamp") * 1000; - PlotComment comment = - new PlotComment(world, id, msg, sender, inbox, timestamp); - comments.add(comment); - whenDone.value = comments; - } - } - TaskManager.runTask(whenDone); - } - }); - } - - @Override public void setComment(final Plot plot, final PlotComment comment) { - addPlotTask(plot, new UniqueStatement("setComment") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setString(1, plot.getArea().toString()); - statement.setInt(2, plot.getId().hashCode()); - statement.setString(3, comment.comment); - statement.setString(4, comment.inbox); - statement.setInt(5, (int) (comment.timestamp / 1000)); - statement.setString(6, comment.senderName); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_comments` (`world`, `hashcode`, `comment`, `inbox`, `timestamp`, `sender`) VALUES(?,?,?,?,?,?)"); - } - }); - } - - @Override public void removeTrusted(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("removeTrusted") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_helpers` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override public void removeMember(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("removeMember") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_trusted` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override public void setTrusted(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("setTrusted") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_helpers` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override public void setMember(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("setMember") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_trusted` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override public void removeDenied(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("removeDenied") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "plot_denied` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override public void setDenied(final Plot plot, final UUID uuid) { - addPlotTask(plot, new UniqueStatement("setDenied") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setString(2, uuid.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_denied` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override public HashMap getRatings(Plot plot) { - HashMap map = new HashMap<>(); - try (PreparedStatement statement = this.connection.prepareStatement( - "SELECT `rating`, `player` FROM `" + this.prefix - + "plot_rating` WHERE `plot_plot_id` = ? ")) { - statement.setInt(1, getId(plot)); - try (ResultSet resultSet = statement.executeQuery()) { - while (resultSet.next()) { - UUID uuid = UUID.fromString(resultSet.getString("player")); - int rating = resultSet.getInt("rating"); - map.put(uuid, rating); - } - } - } catch (SQLException e) { - PlotSquared - .debug("&7[WARN] Failed to fetch rating for plot " + plot.getId().toString()); - e.printStackTrace(); - } - return map; - } - - @Override public void setRating(final Plot plot, final UUID rater, final int value) { - addPlotTask(plot, new UniqueStatement("setRating") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getId(plot)); - statement.setInt(2, value); - statement.setString(3, rater.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "plot_rating` (`plot_plot_id`, `rating`, `player`) VALUES(?,?,?)"); - } - }); - } - - @Override public void delete(PlotCluster cluster) { - final int id = getClusterId(cluster); - addClusterTask(cluster, new UniqueStatement("delete_cluster_settings") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, id); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_settings` WHERE `cluster_id` = ?"); - } - }); - addClusterTask(cluster, new UniqueStatement("delete_cluster_helpers") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, id); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_helpers` WHERE `cluster_id` = ?"); - } - }); - addClusterTask(cluster, new UniqueStatement("delete_cluster_invited") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, id); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_invited` WHERE `cluster_id` = ?"); - } - }); - addClusterTask(cluster, new UniqueStatement("delete_cluster") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, id); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix + "cluster` WHERE `id` = ?"); - } - }); - } - - @Override public void addPersistentMeta(final UUID uuid, final String key, final byte[] meta, - final boolean replace) { - addPlayerTask(uuid, new UniqueStatement("addPersistentMeta") { - @Override public void set(PreparedStatement stmt) throws SQLException { - if (replace) { - stmt.setBytes(1, meta); - stmt.setString(2, uuid.toString()); - stmt.setString(3, key); - } else { - stmt.setString(1, uuid.toString()); - stmt.setString(2, key); - stmt.setBytes(3, meta); - } - } - - @Override public PreparedStatement get() throws SQLException { - if (replace) { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "player_meta` SET `value` = ? WHERE `uuid` = ? AND `key` = ?"); - } else { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "player_meta`(`uuid`, `key`, `value`) VALUES(?, ? ,?)"); - } - } - }); - } - - @Override public void removePersistentMeta(final UUID uuid, final String key) { - addPlayerTask(uuid, new UniqueStatement("removePersistentMeta") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setString(1, uuid.toString()); - stmt.setString(2, key); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "player_meta` WHERE `uuid` = ? AND `key` = ?"); - } - }); - } - - @Override - public void getPersistentMeta(final UUID uuid, final RunnableVal> result) { - addPlayerTask(uuid, new UniqueStatement("getPersistentMeta") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setString(1, uuid.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "SELECT * FROM `" + SQLManager.this.prefix - + "player_meta` WHERE `uuid` = ? ORDER BY `meta_id` ASC"); - } - - @Override public void execute(PreparedStatement statement) { - } - - @Override public void addBatch(PreparedStatement statement) throws SQLException { - ResultSet resultSet = statement.executeQuery(); - - final Map metaMap = new HashMap<>(); - - while (resultSet.next()) { - String key = resultSet.getString("key"); - byte[] bytes = resultSet.getBytes("value"); - metaMap.put(key, bytes); - } - - resultSet.close(); - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - result.run(metaMap); - } - }); - } - - }); - } - - @Override public HashMap> getClusters() { - LinkedHashMap> newClusters = new LinkedHashMap<>(); - HashMap clusters = new HashMap<>(); - try { - HashSet areas = new HashSet<>(); - if (PlotSquared.get().worlds.contains("worlds")) { - ConfigurationSection worldSection = - PlotSquared.get().worlds.getConfigurationSection("worlds"); - if (worldSection != null) { - for (String worldKey : worldSection.getKeys(false)) { - areas.add(worldKey); - ConfigurationSection areaSection = - worldSection.getConfigurationSection(worldKey + ".areas"); - if (areaSection != null) { - for (String areaKey : areaSection.getKeys(false)) { - String[] split = areaKey.split("(? uuids = new HashMap<>(); - HashMap noExist = new HashMap<>(); - /* - * Getting clusters - */ - try (Statement stmt = this.connection.createStatement()) { - ResultSet resultSet = - stmt.executeQuery("SELECT * FROM `" + this.prefix + "cluster`"); - PlotCluster cluster; - String owner; - UUID user; - int id; - while (resultSet.next()) { - PlotId pos1 = - new PlotId(resultSet.getInt("pos1_x"), resultSet.getInt("pos1_z")); - PlotId pos2 = - new PlotId(resultSet.getInt("pos2_x"), resultSet.getInt("pos2_z")); - id = resultSet.getInt("id"); - String areaid = resultSet.getString("world"); - if (!areas.contains(areaid)) { - if (noExist.containsKey(areaid)) { - noExist.put(areaid, noExist.get(areaid) + 1); - } else { - noExist.put(areaid, 1); - } - } - owner = resultSet.getString("owner"); - user = uuids.get(owner); - if (user == null) { - user = UUID.fromString(owner); - uuids.put(owner, user); - } - cluster = new PlotCluster(null, pos1, pos2, user, id); - clusters.put(id, cluster); - Set set = newClusters.get(areaid); - if (set == null) { - set = new HashSet<>(); - newClusters.put(areaid, set); - } - set.add(cluster); - } - //Getting helpers - resultSet = stmt.executeQuery( - "SELECT `user_uuid`, `cluster_id` FROM `" + this.prefix + "cluster_helpers`"); - while (resultSet.next()) { - id = resultSet.getInt("cluster_id"); - owner = resultSet.getString("user_uuid"); - user = uuids.get(owner); - if (user == null) { - user = UUID.fromString(owner); - uuids.put(owner, user); - } - cluster = clusters.get(id); - if (cluster != null) { - cluster.helpers.add(user); - } else { - PlotSquared.debug("&cCluster #" + id + "(" + cluster - + ") in cluster_helpers does not exist. Please create the cluster or remove this entry."); - } - } - // Getting invited - resultSet = stmt.executeQuery( - "SELECT `user_uuid`, `cluster_id` FROM `" + this.prefix + "cluster_invited`"); - while (resultSet.next()) { - id = resultSet.getInt("cluster_id"); - owner = resultSet.getString("user_uuid"); - user = uuids.get(owner); - if (user == null) { - user = UUID.fromString(owner); - uuids.put(owner, user); - } - cluster = clusters.get(id); - if (cluster != null) { - cluster.invited.add(user); - } else { - PlotSquared.debug("&cCluster #" + id + "(" + cluster - + ") in cluster_invited does not exist. Please create the cluster or remove this entry."); - } - } - resultSet = - stmt.executeQuery("SELECT * FROM `" + this.prefix + "cluster_settings`"); - while (resultSet.next()) { - id = resultSet.getInt("cluster_id"); - cluster = clusters.get(id); - if (cluster != null) { - String alias = resultSet.getString("alias"); - if (alias != null) { - cluster.settings.setAlias(alias); - } - String pos = resultSet.getString("position"); - switch (pos.toLowerCase()) { - case "": - case "default": - case "0,0,0": - case "center": - break; - default: - try { - BlockLoc loc = BlockLoc.fromString(pos); - cluster.settings.setPosition(loc); - } catch (Exception ignored) { - } - } - Integer m = resultSet.getInt("merged"); - boolean[] merged = new boolean[4]; - for (int i = 0; i < 4; i++) { - merged[3 - i] = (m & 1 << i) != 0; - } - cluster.settings.setMerged(merged); - String[] flags_string; - String myflags = resultSet.getString("flags"); - if (myflags == null || myflags.isEmpty()) { - flags_string = new String[] {}; - } else { - flags_string = myflags.split(","); - } - HashMap, Object> flags = new HashMap<>(); - for (String element : flags_string) { - if (element.contains(":")) { - String[] split = element.split(":"); - String flag_str = - split[1].replaceAll("\u00AF", ":").replaceAll("´", ","); - Flag flag = FlagManager.getOrCreateFlag(split[0]); - if (flag == null) { - flag = new StringFlag(split[0]) { - @Override public String getValueDescription() { - return "Generic Filler Flag"; - } - }; - } - flags.put(flag, flag.parseValue(flag_str)); - } else { - Flag flag = FlagManager.getOrCreateFlag(element); - if (flag == null) { - flag = new StringFlag(element) { - @Override public String getValueDescription() { - return "Generic Filler Flag"; - } - }; - } - flags.put(flag, flag.parseValue("")); - } - } - cluster.settings.flags = flags; - } else { - PlotSquared.debug("&cCluster #" + id + "(" + cluster - + ") in cluster_settings does not exist. Please create the cluster or remove this entry."); - } - } - resultSet.close(); - } - boolean invalidPlot = false; - for (Entry entry : noExist.entrySet()) { - String a = entry.getKey(); - invalidPlot = true; - PlotSquared.debug("&c[WARNING] Found " + noExist.get(a) - + " clusters in DB for non existent area; '" + a + "'."); - } - if (invalidPlot) { - PlotSquared.debug( - "&c[WARNING] - Please create the world/s or remove the clusters using the purge command"); - } - } catch (SQLException e) { - PlotSquared.debug("&7[WARN] Failed to load clusters."); - e.printStackTrace(); - } - return newClusters; - } - - @Override public void setFlags(final PlotCluster cluster, HashMap, Object> flags) { - final StringBuilder flag_string = new StringBuilder(); - int i = 0; - for (Entry, Object> flag : flags.entrySet()) { - if (i != 0) { - flag_string.append(','); - } - flag_string.append(flag.getKey().getName()).append(':').append( - flag.getKey().valueToString(flag.getValue()).replaceAll(":", "\u00AF") - .replaceAll(",", "´")); - i++; - } - addClusterTask(cluster, new UniqueStatement("setFlags") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setString(1, flag_string.toString()); - stmt.setInt(2, getClusterId(cluster)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster_settings` SET `flags` = ? WHERE `cluster_id` = ?"); - } - }); - } - - @Override public void setClusterName(final PlotCluster cluster, final String name) { - addClusterTask(cluster, new UniqueStatement("setClusterName") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setString(1, name); - stmt.setInt(2, getClusterId(cluster)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster_settings` SET `alias` = ? WHERE `cluster_id` = ?"); - } - }); - cluster.settings.setAlias(name); - } - - @Override public void removeHelper(final PlotCluster cluster, final UUID uuid) { - addClusterTask(cluster, new UniqueStatement("removeHelper") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, uuid.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_helpers` WHERE `cluster_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override public void setHelper(final PlotCluster cluster, final UUID uuid) { - addClusterTask(cluster, new UniqueStatement("setHelper") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, uuid.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "cluster_helpers` (`cluster_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override public void createCluster(final PlotCluster cluster) { - addClusterTask(cluster, new UniqueStatement("createCluster_" + cluster.hashCode()) { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, cluster.getP1().x); - stmt.setInt(2, cluster.getP1().y); - stmt.setInt(3, cluster.getP2().x); - stmt.setInt(4, cluster.getP2().y); - stmt.setString(5, cluster.owner.toString()); - stmt.setString(6, cluster.area.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement(SQLManager.this.CREATE_CLUSTER, - Statement.RETURN_GENERATED_KEYS); - } - - @Override public void execute(PreparedStatement statement) { - } - - @Override public void addBatch(PreparedStatement statement) throws SQLException { - statement.executeUpdate(); - try (ResultSet keys = statement.getGeneratedKeys()) { - if (keys.next()) { - cluster.temp = keys.getInt(1); - } - } - } - }); - addClusterTask(cluster, - new UniqueStatement("createCluster_settings_" + cluster.hashCode()) { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, getClusterId(cluster)); - stmt.setString(2, cluster.settings.getAlias()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "cluster_settings`(`cluster_id`, `alias`) VALUES(?, ?)"); - } - }); - } - - @Override public void resizeCluster(final PlotCluster current, PlotId min, PlotId max) { - final PlotId pos1 = new PlotId(current.getP1().x, current.getP1().y); - final PlotId pos2 = new PlotId(current.getP2().x, current.getP2().y); - current.setP1(min); - current.setP2(max); - - addClusterTask(current, new UniqueStatement("resizeCluster") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setInt(1, pos1.x); - stmt.setInt(2, pos1.y); - stmt.setInt(3, pos2.x); - stmt.setInt(4, pos2.y); - stmt.setInt(5, getClusterId(current)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster` SET `pos1_x` = ?, `pos1_z` = ?, `pos2_x` = ?, `pos2_z` = ? WHERE `id` = ?"); - } - }); - } - - @Override public void setPosition(final PlotCluster cluster, final String position) { - addClusterTask(cluster, new UniqueStatement("setPosition") { - @Override public void set(PreparedStatement stmt) throws SQLException { - stmt.setString(1, position); - stmt.setInt(2, getClusterId(cluster)); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster_settings` SET `position` = ? WHERE `cluster_id` = ?"); - } - }); - } - - @Override public void removeInvited(final PlotCluster cluster, final UUID uuid) { - addClusterTask(cluster, new UniqueStatement("removeInvited") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, uuid.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "DELETE FROM `" + SQLManager.this.prefix - + "cluster_invited` WHERE `cluster_id` = ? AND `user_uuid` = ?"); - } - }); - } - - @Override public void setInvited(final PlotCluster cluster, final UUID uuid) { - addClusterTask(cluster, new UniqueStatement("setInvited") { - @Override public void set(PreparedStatement statement) throws SQLException { - statement.setInt(1, getClusterId(cluster)); - statement.setString(2, uuid.toString()); - } - - @Override public PreparedStatement get() throws SQLException { - return SQLManager.this.connection.prepareStatement( - "INSERT INTO `" + SQLManager.this.prefix - + "cluster_invited` (`cluster_id`, `user_uuid`) VALUES(?,?)"); - } - }); - } - - @Override public boolean deleteTables() { - try (Statement stmt = this.connection.createStatement(); - PreparedStatement statement = this.connection - .prepareStatement("DROP TABLE `" + this.prefix + "plot`")) { - close(); - this.closed = false; - SQLManager.this.connection = this.database.forceConnection(); - stmt.addBatch("DROP TABLE `" + this.prefix + "cluster_invited`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "cluster_helpers`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "cluster`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_rating`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_settings`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_comments`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_trusted`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_helpers`"); - stmt.addBatch("DROP TABLE `" + this.prefix + "plot_denied`"); - stmt.executeBatch(); - stmt.clearBatch(); - statement.executeUpdate(); - } catch (ClassNotFoundException | SQLException e) { - e.printStackTrace(); - - } + commit(); return true; - } - - @Override public void validateAllPlots(Set toValidate) { - if (!isValid()) { - reconnect(); + } + int count = -1; + if (!this.plotTasks.isEmpty()) { + count = 0; + if (this.connection.getAutoCommit()) { + this.connection.setAutoCommit(false); } - PlotSquared.debug( - "$1All DB transactions during this session are being validated (This may take a while if corrections need to be made)"); - commit(); - while (true) { - if (!sendBatch()) { - break; + String method = null; + PreparedStatement statement = null; + UniqueStatement task = null; + UniqueStatement lastTask = null; + Iterator>> iter = + this.plotTasks.entrySet().iterator(); + while (iter.hasNext()) { + try { + Entry> entry = iter.next(); + Plot plot = entry.getKey(); + Queue tasks = entry.getValue(); + if (tasks.isEmpty()) { + iter.remove(); + continue; } - } - try { - if (this.connection.getAutoCommit()) { - this.connection.setAutoCommit(false); + task = tasks.remove(); + count++; + if (task != null) { + if (task.method == null || !task.method.equals(method) || statement == null) { + if (statement != null) { + lastTask.execute(statement); + statement.close(); + } + method = task.method; + statement = task.get(); + } + task.set(statement); + task.addBatch(statement); + try { + if (statement.isClosed()) { + statement = null; + } + } catch (AbstractMethodError ignore) { + } } - } catch (SQLException e) { + lastTask = task; + } catch (Throwable e) { + PlotSquared.debug("============ DATABASE ERROR ============"); + PlotSquared.debug("There was an error updating the database."); + PlotSquared.debug(" - It will be corrected on shutdown"); + PlotSquared.debug("========================================"); e.printStackTrace(); + PlotSquared.debug("========================================"); + } } - HashMap> database = getPlots(); - ArrayList toCreate = new ArrayList<>(); - for (Plot plot : toValidate) { - if (plot.temp == -1) { - continue; - } - HashMap worldPlots = database.get(plot.getArea().toString()); - if (worldPlots == null) { - PlotSquared.debug("&8 - &7Creating plot (1): " + plot); - toCreate.add(plot); - continue; - } - Plot dataPlot = worldPlots.remove(plot.getId()); - if (dataPlot == null) { - PlotSquared.debug("&8 - &7Creating plot (2): " + plot); - toCreate.add(plot); - continue; - } - // owner - if (!plot.owner.equals(dataPlot.owner)) { - PlotSquared - .debug("&8 - &7Setting owner: " + plot + " -> " + MainUtil.getName(plot.owner)); - setOwner(plot, plot.owner); - } - // trusted - if (!plot.getTrusted().equals(dataPlot.getTrusted())) { - HashSet toAdd = (HashSet) plot.getTrusted().clone(); - HashSet toRemove = (HashSet) dataPlot.getTrusted().clone(); - toRemove.removeAll(plot.getTrusted()); - toAdd.removeAll(dataPlot.getTrusted()); - PlotSquared.debug( - "&8 - &7Correcting " + (toAdd.size() + toRemove.size()) + " trusted for: " - + plot); - if (!toRemove.isEmpty()) { - for (UUID uuid : toRemove) { - removeTrusted(plot, uuid); - } - } - if (!toAdd.isEmpty()) { - for (UUID uuid : toAdd) { - setTrusted(plot, uuid); - } - } - } - if (!plot.getMembers().equals(dataPlot.getMembers())) { - HashSet toAdd = (HashSet) plot.getMembers().clone(); - HashSet toRemove = (HashSet) dataPlot.getMembers().clone(); - toRemove.removeAll(plot.getMembers()); - toAdd.removeAll(dataPlot.getMembers()); - PlotSquared.debug( - "&8 - &7Correcting " + (toAdd.size() + toRemove.size()) + " members for: " - + plot); - if (!toRemove.isEmpty()) { - for (UUID uuid : toRemove) { - removeMember(plot, uuid); - } - } - if (!toAdd.isEmpty()) { - for (UUID uuid : toAdd) { - setMember(plot, uuid); - } - } - } - if (!plot.getDenied().equals(dataPlot.getDenied())) { - HashSet toAdd = (HashSet) plot.getDenied().clone(); - HashSet toRemove = (HashSet) dataPlot.getDenied().clone(); - toRemove.removeAll(plot.getDenied()); - toAdd.removeAll(dataPlot.getDenied()); - PlotSquared.debug( - "&8 - &7Correcting " + (toAdd.size() + toRemove.size()) + " denied for: " - + plot); - if (!toRemove.isEmpty()) { - for (UUID uuid : toRemove) { - removeDenied(plot, uuid); - } - } - if (!toAdd.isEmpty()) { - for (UUID uuid : toAdd) { - setDenied(plot, uuid); - } - } - } - boolean[] pm = plot.getMerged(); - boolean[] dm = dataPlot.getMerged(); - if (pm[0] != dm[0] || pm[1] != dm[1]) { - PlotSquared.debug("&8 - &7Correcting merge for: " + plot); - setMerged(dataPlot, plot.getMerged()); - } - HashMap, Object> pf = plot.getFlags(); - HashMap, Object> df = dataPlot.getFlags(); - if (!pf.isEmpty() && !df.isEmpty()) { - if (pf.size() != df.size() || !StringMan - .isEqual(StringMan.joinOrdered(pf.values(), ","), - StringMan.joinOrdered(df.values(), ","))) { - PlotSquared.debug("&8 - &7Correcting flags for: " + plot); - setFlags(plot, pf); - } - } + if (statement != null && task != null) { + task.execute(statement); + statement.close(); } - - for (Entry> entry : database.entrySet()) { - HashMap map = entry.getValue(); - if (!map.isEmpty()) { - for (Entry entry2 : map.entrySet()) { - PlotSquared.debug("$1Plot was deleted: " + entry2.getValue().toString() - + "// TODO implement this when sure safe"); - } - } + } + if (!this.playerTasks.isEmpty()) { + count = 0; + if (this.connection.getAutoCommit()) { + this.connection.setAutoCommit(false); } - commit(); - } - - @Override - public void replaceWorld(final String oldWorld, final String newWorld, final PlotId min, - final PlotId max) { - addGlobalTask(new Runnable() { - @Override public void run() { - if (min == null) { - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `world` = ? WHERE `world` = ?")) { - stmt.setString(1, newWorld); - stmt.setString(2, oldWorld); - stmt.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster` SET `world` = ? WHERE `world` = ?")) { - stmt.setString(1, newWorld); - stmt.setString(2, oldWorld); - stmt.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - } else { - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "plot` SET `world` = ? WHERE `world` = ? AND `plot_id_x` BETWEEN ? AND ? AND `plot_id_z` BETWEEN ? AND ?")) { - stmt.setString(1, newWorld); - stmt.setString(2, oldWorld); - stmt.setInt(3, min.x); - stmt.setInt(4, max.x); - stmt.setInt(5, min.y); - stmt.setInt(6, max.y); - stmt.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( - "UPDATE `" + SQLManager.this.prefix - + "cluster` SET `world` = ? WHERE `world` = ? AND `pos1_x` <= ? AND `pos1_z` <= ? AND `pos2_x` >= ? AND `pos2_z` >= ?")) { - stmt.setString(1, newWorld); - stmt.setString(2, oldWorld); - stmt.setInt(3, max.x); - stmt.setInt(4, max.y); - stmt.setInt(5, min.x); - stmt.setInt(6, min.y); - stmt.executeUpdate(); - } catch (SQLException e) { - e.printStackTrace(); - } - } + String method = null; + PreparedStatement statement = null; + UniqueStatement task = null; + UniqueStatement lastTask = null; + for (Entry> entry : this.playerTasks.entrySet()) { + try { + UUID uuid = entry.getKey(); + if (this.playerTasks.get(uuid).isEmpty()) { + this.playerTasks.remove(uuid); + continue; } - }); - } - - @Override public void replaceUUID(final UUID old, final UUID now) { - addGlobalTask(new Runnable() { - @Override public void run() { - try (Statement stmt = SQLManager.this.connection.createStatement()) { - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "cluster` SET `owner` = '" + now - .toString() + "' WHERE `owner` = '" + old.toString() + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "cluster_helpers` SET `user_uuid` = '" - + now.toString() + "' WHERE `user_uuid` = '" + old.toString() + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "cluster_invited` SET `user_uuid` = '" - + now.toString() + "' WHERE `user_uuid` = '" + old.toString() + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "plot` SET `owner` = '" + now - .toString() + "' WHERE `owner` = '" + old.toString() + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "plot_denied` SET `user_uuid` = '" - + now.toString() + "' WHERE `user_uuid` = '" + old.toString() + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "plot_helpers` SET `user_uuid` = '" - + now.toString() + "' WHERE `user_uuid` = '" + old.toString() + '\''); - stmt.executeUpdate( - "UPDATE `" + SQLManager.this.prefix + "plot_trusted` SET `user_uuid` = '" - + now.toString() + "' WHERE `user_uuid` = '" + old.toString() + '\''); - } catch (SQLException e) { - e.printStackTrace(); + task = this.playerTasks.get(uuid).remove(); + count++; + if (task != null) { + if (task.method == null || !task.method.equals(method)) { + if (statement != null) { + lastTask.execute(statement); + statement.close(); } + method = task.method; + statement = task.get(); + } + task.set(statement); + task.addBatch(statement); } - }); - } - - @Override public void close() { - try { - this.closed = true; - this.connection.close(); - } catch (SQLException e) { + lastTask = task; + } catch (Throwable e) { + PlotSquared.debug("============ DATABASE ERROR ============"); + PlotSquared.debug("There was an error updating the database."); + PlotSquared.debug(" - It will be corrected on shutdown"); + PlotSquared.debug("========================================"); e.printStackTrace(); + PlotSquared.debug("========================================"); + } } + if (statement != null && task != null) { + task.execute(statement); + statement.close(); + } + } + if (!this.clusterTasks.isEmpty()) { + count = 0; + if (this.connection.getAutoCommit()) { + this.connection.setAutoCommit(false); + } + String method = null; + PreparedStatement statement = null; + UniqueStatement task = null; + UniqueStatement lastTask = null; + for (Entry> entry : this.clusterTasks + .entrySet()) { + try { + PlotCluster cluster = entry.getKey(); + if (this.clusterTasks.get(cluster).isEmpty()) { + this.clusterTasks.remove(cluster); + continue; + } + task = this.clusterTasks.get(cluster).remove(); + count++; + if (task != null) { + if (task.method == null || !task.method.equals(method)) { + if (statement != null) { + lastTask.execute(statement); + statement.close(); + } + method = task.method; + statement = task.get(); + } + task.set(statement); + task.addBatch(statement); + } + lastTask = task; + } catch (Throwable e) { + PlotSquared.debug("============ DATABASE ERROR ============"); + PlotSquared.debug("There was an error updating the database."); + PlotSquared.debug(" - It will be corrected on shutdown"); + PlotSquared.debug("========================================"); + e.printStackTrace(); + PlotSquared.debug("========================================"); + } + } + if (statement != null && task != null) { + task.execute(statement); + statement.close(); + } + } + if (count > 0) { + commit(); + return true; + } + if (count != -1) { + if (!this.connection.getAutoCommit()) { + this.connection.setAutoCommit(true); + } + } + if (!this.clusterTasks.isEmpty()) { + this.clusterTasks.clear(); + } + if (!this.plotTasks.isEmpty()) { + this.plotTasks.clear(); + } + } catch (Throwable e) { + PlotSquared.debug("============ DATABASE ERROR ============"); + PlotSquared.debug("There was an error updating the database."); + PlotSquared.debug(" - It will be corrected on shutdown"); + PlotSquared.debug("========================================"); + e.printStackTrace(); + PlotSquared.debug("========================================"); } + return false; + } - public abstract class UniqueStatement { + public Connection getConnection() { + return this.connection; + } - public final String method; + /** + * Set Plot owner + * + * @param plot Plot Object + * @param uuid Owner UUID + */ + @Override + public void setOwner(final Plot plot, final UUID uuid) { + addPlotTask(plot, new UniqueStatement("setOwner") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setString(1, uuid.toString()); + statement.setInt(2, plot.getId().x); + statement.setInt(3, plot.getId().y); + statement.setString(4, plot.getArea().toString()); + } - public UniqueStatement(String method) { - this.method = method; + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement(SQLManager.this.SET_OWNER); + } + }); + } + + @Override + public void createPlotsAndData(final List myList, final Runnable whenDone) { + addGlobalTask(() -> { + try { + // Create the plots + createPlots(myList, () -> { + try { + // Creating datastructures + HashMap plotMap = new HashMap<>(); + for (Plot plot : myList) { + plotMap.put(plot.getId(), plot); + } + ArrayList settings = new ArrayList<>(); + final ArrayList helpers = new ArrayList<>(); + final ArrayList trusted = new ArrayList<>(); + final ArrayList denied = new ArrayList<>(); + + // Populating structures + try (PreparedStatement stmt = SQLManager.this.connection + .prepareStatement(SQLManager.this.GET_ALL_PLOTS); + ResultSet result = stmt.executeQuery()) { + while (result.next()) { + int id = result.getInt("id"); + int x = result.getInt("plot_id_x"); + int y = result.getInt("plot_id_z"); + PlotId plotId = new PlotId(x, y); + Plot plot = plotMap.get(plotId); + if (plot != null) { + settings.add(new SettingsPair(id, plot.getSettings())); + for (UUID uuid : plot.getDenied()) { + denied.add(new UUIDPair(id, uuid)); + } + for (UUID uuid : plot.getMembers()) { + trusted.add(new UUIDPair(id, uuid)); + } + for (UUID uuid : plot.getTrusted()) { + helpers.add(new UUIDPair(id, uuid)); + } + } + } + } + createSettings(settings, () -> createTiers(helpers, "helpers", + () -> createTiers(trusted, "trusted", + () -> createTiers(denied, "denied", + () -> { + try { + SQLManager.this.connection.commit(); + } catch (SQLException e) { + e.printStackTrace(); + } + if (whenDone != null) { + whenDone.run(); + } + })))); + } catch (SQLException e) { + e.printStackTrace(); + PlotSquared.debug("&7[WARN] Failed to set all helpers for plots"); + try { + SQLManager.this.connection.commit(); + } catch (SQLException e1) { + e1.printStackTrace(); + } + } + }); + } catch (Exception e) { + e.printStackTrace(); + PlotSquared.debug("&7[WARN] Failed to set all helpers for plots"); + try { + SQLManager.this.connection.commit(); + } catch (SQLException e1) { + e1.printStackTrace(); } + } + }); + } - public void addBatch(PreparedStatement statement) throws SQLException { - statement.addBatch(); + /** + * Create a plot + * + * @param myList list of plots to be created + */ + public void createTiers(ArrayList myList, final String tier, Runnable whenDone) { + StmtMod mod = new StmtMod() { + @Override + public String getCreateMySQL(int size) { + return getCreateMySQL(size, SQLManager.this.CREATE_TIERS.replaceAll("%tier%", tier), + 2); + } + + @Override + public String getCreateSQLite(int size) { + return getCreateSQLite(size, + "INSERT INTO `" + SQLManager.this.prefix + "plot_" + tier + + "` SELECT ? AS `plot_plot_id`, ? AS `user_uuid`", 2); + } + + @Override + public String getCreateSQL() { + return "INSERT INTO `" + SQLManager.this.prefix + "plot_" + tier + + "` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"; + } + + @Override + public void setMySQL(PreparedStatement stmt, int i, UUIDPair pair) + throws SQLException { + stmt.setInt(i * 2 + 1, pair.id); + stmt.setString(i * 2 + 2, pair.uuid.toString()); + } + + @Override + public void setSQLite(PreparedStatement stmt, int i, UUIDPair pair) + throws SQLException { + stmt.setInt(i * 2 + 1, pair.id); + stmt.setString(i * 2 + 2, pair.uuid.toString()); + } + + @Override + public void setSQL(PreparedStatement stmt, UUIDPair pair) + throws SQLException { + stmt.setInt(1, pair.id); + stmt.setString(2, pair.uuid.toString()); + } + }; + setBulk(myList, mod, whenDone); + } + + /** + * Create a plot + * + * @param myList list of plots to be created + */ + public void createPlots(List myList, Runnable whenDone) { + StmtMod mod = new StmtMod() { + @Override + public String getCreateMySQL(int size) { + return getCreateMySQL(size, SQLManager.this.CREATE_PLOTS, 5); + } + + @Override + public String getCreateSQLite(int size) { + return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix + + "plot` SELECT ? AS `id`, ? AS `plot_id_x`, ? AS `plot_id_z`, ? AS `owner`, ? AS `world`, ? AS `timestamp` ", + 6); + } + + @Override + public String getCreateSQL() { + return SQLManager.this.CREATE_PLOT; + } + + @Override + public void setMySQL(PreparedStatement stmt, int i, Plot plot) + throws SQLException { + stmt.setInt(i * 5 + 1, plot.getId().x); + stmt.setInt(i * 5 + 2, plot.getId().y); + try { + stmt.setString(i * 5 + 3, plot.owner.toString()); + } catch (SQLException ignored) { + stmt.setString(i * 5 + 3, everyone.toString()); } + stmt.setString(i * 5 + 4, plot.getArea().toString()); + stmt.setTimestamp(i * 5 + 5, new Timestamp(plot.getTimestamp())); + } - public void execute(PreparedStatement statement) throws SQLException { + @Override + public void setSQLite(PreparedStatement stmt, int i, Plot plot) + throws SQLException { + stmt.setNull(i * 6 + 1, 4); + stmt.setInt(i * 6 + 2, plot.getId().x); + stmt.setInt(i * 6 + 3, plot.getId().y); + try { + stmt.setString(i * 6 + 4, plot.owner.toString()); + } catch (SQLException ignored) { + stmt.setString(i * 6 + 4, everyone.toString()); + } + stmt.setString(i * 6 + 5, plot.getArea().toString()); + stmt.setTimestamp(i * 6 + 6, new Timestamp(plot.getTimestamp())); + } + + @Override + public void setSQL(PreparedStatement stmt, Plot plot) throws SQLException { + stmt.setInt(1, plot.getId().x); + stmt.setInt(2, plot.getId().y); + stmt.setString(3, plot.owner.toString()); + stmt.setString(4, plot.getArea().toString()); + stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); + + } + }; + setBulk(myList, mod, whenDone); + } + + public void setBulk(List objList, StmtMod mod, Runnable whenDone) { + int size = objList.size(); + if (size == 0) { + if (whenDone != null) { + whenDone.run(); + } + return; + } + int packet; + if (this.mySQL) { + packet = Math.min(size, 5000); + } else { + packet = Math.min(size, 50); + } + int amount = size / packet; + try { + int count = 0; + PreparedStatement preparedStmt = null; + int last = -1; + for (int j = 0; j <= amount; j++) { + List subList = objList.subList(j * packet, Math.min(size, (j + 1) * packet)); + if (subList.isEmpty()) { + break; + } + String statement; + if (last == -1) { + last = subList.size(); + statement = mod.getCreateMySQL(subList.size()); + preparedStmt = this.connection.prepareStatement(statement); + } + if (subList.size() != last || count % 5000 == 0 && count > 0) { + preparedStmt.executeBatch(); + preparedStmt.close(); + statement = mod.getCreateMySQL(subList.size()); + preparedStmt = this.connection.prepareStatement(statement); + } + for (int i = 0; i < subList.size(); i++) { + count++; + T obj = subList.get(i); + mod.setMySQL(preparedStmt, i, obj); + } + last = subList.size(); + preparedStmt.addBatch(); + } + PlotSquared.debug( + "&aBatch 1: " + count + " | " + objList.get(0).getClass().getCanonicalName()); + preparedStmt.executeBatch(); + preparedStmt.clearParameters(); + preparedStmt.close(); + if (whenDone != null) { + whenDone.run(); + } + return; + } catch (SQLException e) { + if (this.mySQL) { + e.printStackTrace(); + PlotSquared.debug("&cERROR 1: | " + objList.get(0).getClass().getCanonicalName()); + } + } + try { + int count = 0; + PreparedStatement preparedStmt = null; + int last = -1; + for (int j = 0; j <= amount; j++) { + List subList = objList.subList(j * packet, Math.min(size, (j + 1) * packet)); + if (subList.isEmpty()) { + break; + } + String statement; + if (last == -1) { + last = subList.size(); + statement = mod.getCreateSQLite(subList.size()); + preparedStmt = this.connection.prepareStatement(statement); + } + if (subList.size() != last || count % 5000 == 0 && count > 0) { + preparedStmt.executeBatch(); + preparedStmt.clearParameters(); + statement = mod.getCreateSQLite(subList.size()); + preparedStmt = this.connection.prepareStatement(statement); + } + for (int i = 0; i < subList.size(); i++) { + count++; + T obj = subList.get(i); + mod.setSQLite(preparedStmt, i, obj); + } + last = subList.size(); + preparedStmt.addBatch(); + } + PlotSquared.debug( + "&aBatch 2: " + count + " | " + objList.get(0).getClass().getCanonicalName()); + preparedStmt.executeBatch(); + preparedStmt.clearParameters(); + preparedStmt.close(); + } catch (SQLException e) { + e.printStackTrace(); + PlotSquared.debug("&cERROR 2: | " + objList.get(0).getClass().getCanonicalName()); + PlotSquared.debug("&6[WARN] Could not bulk save!"); + try (PreparedStatement preparedStmt = this.connection + .prepareStatement(mod.getCreateSQL())) { + for (T obj : objList) { + mod.setSQL(preparedStmt, obj); + preparedStmt.addBatch(); + } + PlotSquared.debug("&aBatch 3"); + preparedStmt.executeBatch(); + } catch (SQLException e3) { + e3.printStackTrace(); + PlotSquared.debug("&c[ERROR] Failed to save all!"); + } + } + if (whenDone != null) { + whenDone.run(); + } + } + + public void createSettings(final ArrayList myList, final Runnable whenDone) { + final StmtMod mod = new StmtMod() { + @Override + public String getCreateMySQL(int size) { + return getCreateMySQL(size, "INSERT INTO `" + SQLManager.this.prefix + + "plot_settings`(`plot_plot_id`,`biome`,`rain`,`custom_time`,`time`,`deny_entry`,`alias`,`flags`,`merged`," + + "`position`) VALUES ", 10); + } + + @Override + public String getCreateSQLite(int size) { + return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix + + "plot_settings` SELECT ? AS `plot_plot_id`, ? AS `biome`, ? AS `rain`, ? AS `custom_time`, ? AS `time`, ? AS " + + "`deny_entry`, ? AS `alias`, ? AS `flags`, ? AS `merged`, ? AS `position`", + 10); + } + + @Override + public String getCreateSQL() { + return "INSERT INTO `" + SQLManager.this.prefix + + "plot_settings`(`plot_plot_id`) VALUES(?)"; + } + + @Override + public void setMySQL(PreparedStatement statement, int i, SettingsPair pair) + throws SQLException { + statement.setInt(i * 10 + 1, pair.id); // id + statement.setNull(i * 10 + 2, 4); // biome + statement.setNull(i * 10 + 3, 4); // rain + statement.setNull(i * 10 + 4, 4); // custom_time + statement.setNull(i * 10 + 5, 4); // time + statement.setNull(i * 10 + 6, 4); // deny_entry + if (pair.settings.getAlias().isEmpty()) { + statement.setNull(i * 10 + 7, 4); + } else { + statement.setString(i * 10 + 7, pair.settings.getAlias()); + } + StringBuilder flag_string = new StringBuilder(); + int k = 0; + for (Entry, ?> flag : pair.settings.flags.entrySet()) { + if (k != 0) { + flag_string.append(','); + } + flag_string.append(flag.getKey().getName()).append(':').append( + flag.getKey().valueToString(flag.getValue()).replaceAll(":", "¯") + .replaceAll(",", "´")); + k++; + } + statement.setString(i * 10 + 8, flag_string.toString()); + boolean[] merged = pair.settings.getMerged(); + int hash = MainUtil.hash(merged); + statement.setInt(i * 10 + 9, hash); + BlockLoc loc = pair.settings.getPosition(); + String position; + if (loc.y == 0) { + position = "DEFAULT"; + } else { + position = loc.x + "," + loc.y + ',' + loc.z; + } + statement.setString(i * 10 + 10, position); + } + + @Override + public void setSQLite(PreparedStatement stmt, int i, SettingsPair pair) + throws SQLException { + stmt.setInt(i * 10 + 1, pair.id); // id + stmt.setNull(i * 10 + 2, 4); // biome + stmt.setNull(i * 10 + 3, 4); // rain + stmt.setNull(i * 10 + 4, 4); // custom_time + stmt.setNull(i * 10 + 5, 4); // time + stmt.setNull(i * 10 + 6, 4); // deny_entry + if (pair.settings.getAlias().isEmpty()) { + stmt.setNull(i * 10 + 7, 4); + } else { + stmt.setString(i * 10 + 7, pair.settings.getAlias()); + } + StringBuilder flag_string = new StringBuilder(); + int k = 0; + for (Entry, ?> flag : pair.settings.flags.entrySet()) { + if (k != 0) { + flag_string.append(','); + } + flag_string.append(flag.getKey().getName()).append(':').append( + flag.getKey().valueToString(flag.getValue()).replaceAll(":", "¯") + .replaceAll(",", "´")); + k++; + } + stmt.setString(i * 10 + 8, flag_string.toString()); + boolean[] merged = pair.settings.getMerged(); + int n = 0; + for (int j = 0; j < 4; ++j) { + n = (n << 1) + (merged[j] ? 1 : 0); + } + stmt.setInt(i * 10 + 9, n); + BlockLoc loc = pair.settings.getPosition(); + String position; + if (loc.y == 0) { + position = "DEFAULT"; + } else { + position = loc.x + "," + loc.y + ',' + loc.z; + } + stmt.setString(i * 10 + 10, position); + } + + @Override + public void setSQL(PreparedStatement stmt, SettingsPair pair) + throws SQLException { + stmt.setInt(1, pair.id); + } + }; + addGlobalTask(() -> setBulk(myList, mod, whenDone)); + } + + public void createEmptySettings(final ArrayList myList, final Runnable whenDone) { + final StmtMod mod = new StmtMod() { + @Override + public String getCreateMySQL(int size) { + return getCreateMySQL(size, SQLManager.this.CREATE_SETTINGS, 1); + } + + @Override + public String getCreateSQLite(int size) { + return getCreateSQLite(size, "INSERT INTO `" + SQLManager.this.prefix + + "plot_settings` SELECT ? AS `plot_plot_id`, ? AS `biome`, ? AS `rain`, ? AS `custom_time`, ? AS `time`, ? AS " + + "`deny_entry`, ? AS `alias`, ? AS `flags`, ? AS `merged`, ? AS `position` ", + 10); + } + + @Override + public String getCreateSQL() { + return "INSERT INTO `" + SQLManager.this.prefix + + "plot_settings`(`plot_plot_id`) VALUES(?)"; + } + + @Override + public void setMySQL(PreparedStatement stmt, int i, Integer id) + throws SQLException { + stmt.setInt(i + 1, id); + } + + @Override + public void setSQLite(PreparedStatement stmt, int i, Integer id) + throws SQLException { + stmt.setInt(i * 10 + 1, id); + stmt.setNull(i * 10 + 2, 4); + stmt.setNull(i * 10 + 3, 4); + stmt.setNull(i * 10 + 4, 4); + stmt.setNull(i * 10 + 5, 4); + stmt.setNull(i * 10 + 6, 4); + stmt.setNull(i * 10 + 7, 4); + stmt.setNull(i * 10 + 8, 4); + stmt.setNull(i * 10 + 9, 4); + stmt.setString(i * 10 + 10, "DEFAULT"); + } + + @Override + public void setSQL(PreparedStatement stmt, Integer id) throws SQLException { + stmt.setInt(1, id); + } + }; + addGlobalTask(() -> setBulk(myList, mod, whenDone)); + } + + public void createPlotSafe(final Plot plot, final Runnable success, final Runnable failure) { + final long timestamp = plot.getTimestamp(); + addPlotTask(plot, new UniqueStatement("createPlotSafe_" + plot.hashCode()) { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, plot.getId().x); + stmt.setInt(2, plot.getId().y); + stmt.setString(3, plot.owner.toString()); + stmt.setString(4, plot.getArea().toString()); + stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); + stmt.setString(6, plot.getArea().toString()); + stmt.setInt(7, plot.getId().x); + stmt.setInt(8, plot.getId().y); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement(SQLManager.this.CREATE_PLOT_SAFE, + Statement.RETURN_GENERATED_KEYS); + } + + @Override + public void execute(PreparedStatement statement) { + + } + + @Override + public void addBatch(PreparedStatement statement) throws SQLException { + int inserted = statement.executeUpdate(); + if (inserted > 0) { + try (ResultSet keys = statement.getGeneratedKeys()) { + if (keys.next()) { + plot.temp = keys.getInt(1); + addPlotTask(plot, new UniqueStatement( + "createPlotAndSettings_settings_" + plot.hashCode()) { + @Override + public void set(PreparedStatement stmt) + throws SQLException { + stmt.setInt(1, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "INSERT INTO `" + SQLManager.this.prefix + + "plot_settings`(`plot_plot_id`) VALUES(?)"); + } + }); + if (success != null) { + addNotifyTask(success); + } + return; + } + } + } + if (failure != null) { + failure.run(); + } + } + }); + } + + public void commit() { + if (this.closed) { + return; + } + try { + if (!this.connection.getAutoCommit()) { + this.connection.commit(); + this.connection.setAutoCommit(true); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public void createPlotAndSettings(final Plot plot, Runnable whenDone) { + addPlotTask(plot, new UniqueStatement("createPlotAndSettings_" + plot.hashCode()) { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, plot.getId().x); + stmt.setInt(2, plot.getId().y); + stmt.setString(3, plot.owner.toString()); + stmt.setString(4, plot.getArea().toString()); + stmt.setTimestamp(5, new Timestamp(plot.getTimestamp())); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection + .prepareStatement(SQLManager.this.CREATE_PLOT, Statement.RETURN_GENERATED_KEYS); + } + + @Override + public void execute(PreparedStatement statement) { + } + + @Override + public void addBatch(PreparedStatement statement) throws SQLException { + statement.executeUpdate(); + try (ResultSet keys = statement.getGeneratedKeys()) { + if (keys.next()) { + plot.temp = keys.getInt(1); + } + } + } + }); + addPlotTask(plot, new UniqueStatement("createPlotAndSettings_settings_" + plot.hashCode()) { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "INSERT INTO `" + SQLManager.this.prefix + + "plot_settings`(`plot_plot_id`) VALUES(?)"); + } + }); + addNotifyTask(whenDone); + } + + /** + * Create tables. + */ + @Override + public void createTables() throws SQLException { + String[] tables = + new String[]{"plot", "plot_denied", "plot_helpers", "plot_comments", "plot_trusted", + "plot_rating", "plot_settings", "cluster", "player_meta"}; + DatabaseMetaData meta = this.connection.getMetaData(); + int create = 0; + for (String s : tables) { + ResultSet set = meta.getTables(null, null, this.prefix + s, new String[]{"TABLE"}); + // ResultSet set = meta.getTables(null, null, prefix + s, null); + if (!set.next()) { + create++; + } + set.close(); + } + if (create == 0) { + return; + } + boolean addConstraint = create == tables.length; + PlotSquared.debug("Creating tables"); + try (Statement stmt = this.connection.createStatement()) { + if (this.mySQL) { + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot` (" + + "`id` INT(11) NOT NULL AUTO_INCREMENT," + "`plot_id_x` INT(11) NOT NULL," + + "`plot_id_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," + + "`world` VARCHAR(45) NOT NULL," + + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP," + + "PRIMARY KEY (`id`)" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + + "plot_denied` (`plot_plot_id` INT(11) NOT NULL," + + "`user_uuid` VARCHAR(40) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_helpers` (" + + "`plot_plot_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" + + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," + + "`comment` VARCHAR(40) NOT NULL," + "`inbox` VARCHAR(40) NOT NULL," + + "`timestamp` INT(11) NOT NULL," + "`sender` VARCHAR(40) NOT NULL" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_trusted` (" + + "`plot_plot_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_settings` (" + + " `plot_plot_id` INT(11) NOT NULL," + + " `biome` VARCHAR(45) DEFAULT 'FOREST'," + " `rain` INT(1) DEFAULT 0," + + " `custom_time` TINYINT(1) DEFAULT '0'," + " `time` INT(11) DEFAULT '8000'," + + " `deny_entry` TINYINT(1) DEFAULT '0'," + + " `alias` VARCHAR(50) DEFAULT NULL," + " `flags` VARCHAR(512) DEFAULT NULL," + + " `merged` INT(11) DEFAULT NULL," + + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," + + " PRIMARY KEY (`plot_plot_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + + "plot_rating` ( `plot_plot_id` INT(11) NOT NULL, `rating` INT(2) NOT NULL, `player` VARCHAR(40) NOT NULL) ENGINE=InnoDB " + + "DEFAULT CHARSET=utf8"); + if (addConstraint) { + stmt.addBatch("ALTER TABLE `" + this.prefix + "plot_settings` ADD CONSTRAINT `" + + this.prefix + + "plot_settings_ibfk_1` FOREIGN KEY (`plot_plot_id`) REFERENCES `" + + this.prefix + "plot` (`id`) ON DELETE CASCADE"); + } + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster` (" + + "`id` INT(11) NOT NULL AUTO_INCREMENT," + "`pos1_x` INT(11) NOT NULL," + + "`pos1_z` INT(11) NOT NULL," + "`pos2_x` INT(11) NOT NULL," + + "`pos2_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," + + "`world` VARCHAR(45) NOT NULL," + + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP," + + "PRIMARY KEY (`id`)" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=0"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_helpers` (" + + "`cluster_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_invited` (" + + "`cluster_id` INT(11) NOT NULL," + "`user_uuid` VARCHAR(40) NOT NULL" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_settings` (" + + " `cluster_id` INT(11) NOT NULL," + " `biome` VARCHAR(45) DEFAULT 'FOREST'," + + " `rain` INT(1) DEFAULT 0," + " `custom_time` TINYINT(1) DEFAULT '0'," + + " `time` INT(11) DEFAULT '8000'," + " `deny_entry` TINYINT(1) DEFAULT '0'," + + " `alias` VARCHAR(50) DEFAULT NULL," + " `flags` VARCHAR(512) DEFAULT NULL," + + " `merged` INT(11) DEFAULT NULL," + + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," + + " PRIMARY KEY (`cluster_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "player_meta` (" + + " `meta_id` INT(11) NOT NULL AUTO_INCREMENT," + + " `uuid` VARCHAR(40) NOT NULL," + " `key` VARCHAR(32) NOT NULL," + + " `value` blob NOT NULL," + " PRIMARY KEY (`meta_id`)" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); + } else { + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot` (" + + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`plot_id_x` INT(11) NOT NULL," + + "`plot_id_z` INT(11) NOT NULL," + "`owner` VARCHAR(45) NOT NULL," + + "`world` VARCHAR(45) NOT NULL," + + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP)"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + + "plot_denied` (`plot_plot_id` INT(11) NOT NULL," + + "`user_uuid` VARCHAR(40) NOT NULL)"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + + "plot_helpers` (`plot_plot_id` INT(11) NOT NULL," + + "`user_uuid` VARCHAR(40) NOT NULL)"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + + "plot_trusted` (`plot_plot_id` INT(11) NOT NULL," + + "`user_uuid` VARCHAR(40) NOT NULL)"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" + + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," + + "`comment` VARCHAR(40) NOT NULL," + + "`inbox` VARCHAR(40) NOT NULL, `timestamp` INT(11) NOT NULL," + + "`sender` VARCHAR(40) NOT NULL" + ')'); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_settings` (" + + " `plot_plot_id` INT(11) NOT NULL," + + " `biome` VARCHAR(45) DEFAULT 'FOREST'," + " `rain` INT(1) DEFAULT 0," + + " `custom_time` TINYINT(1) DEFAULT '0'," + " `time` INT(11) DEFAULT '8000'," + + " `deny_entry` TINYINT(1) DEFAULT '0'," + + " `alias` VARCHAR(50) DEFAULT NULL," + " `flags` VARCHAR(512) DEFAULT NULL," + + " `merged` INT(11) DEFAULT NULL," + + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," + + " PRIMARY KEY (`plot_plot_id`)" + ')'); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + + "plot_rating` (`plot_plot_id` INT(11) NOT NULL, `rating` INT(2) NOT NULL, `player` VARCHAR(40) NOT NULL)"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster` (" + + "`id` INTEGER PRIMARY KEY AUTOINCREMENT," + "`pos1_x` INT(11) NOT NULL," + + "`pos1_z` INT(11) NOT NULL," + "`pos2_x` INT(11) NOT NULL," + + "`pos2_z` INT(11) NOT NULL," + "`owner` VARCHAR(40) NOT NULL," + + "`world` VARCHAR(45) NOT NULL," + + "`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP" + ')'); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + + "cluster_helpers` (`cluster_id` INT(11) NOT NULL," + + "`user_uuid` VARCHAR(40) NOT NULL)"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + + "cluster_invited` (`cluster_id` INT(11) NOT NULL," + + "`user_uuid` VARCHAR(40) NOT NULL)"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "cluster_settings` (" + + " `cluster_id` INT(11) NOT NULL," + " `biome` VARCHAR(45) DEFAULT 'FOREST'," + + " `rain` INT(1) DEFAULT 0," + " `custom_time` TINYINT(1) DEFAULT '0'," + + " `time` INT(11) DEFAULT '8000'," + " `deny_entry` TINYINT(1) DEFAULT '0'," + + " `alias` VARCHAR(50) DEFAULT NULL," + " `flags` VARCHAR(512) DEFAULT NULL," + + " `merged` INT(11) DEFAULT NULL," + + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," + + " PRIMARY KEY (`cluster_id`)" + ')'); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + this.prefix + "player_meta` (" + + " `meta_id` INTEGER PRIMARY KEY AUTOINCREMENT," + + " `uuid` VARCHAR(40) NOT NULL," + " `key` VARCHAR(32) NOT NULL," + + " `value` blob NOT NULL" + ')'); + } + stmt.executeBatch(); + stmt.clearBatch(); + } + } + + @Override + public void deleteSettings(final Plot plot) { + addPlotTask(plot, new UniqueStatement("delete_plot_settings") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_settings` WHERE `plot_plot_id` = ?"); + } + }); + } + + @Override + public void deleteHelpers(final Plot plot) { + if (plot.getTrusted().isEmpty()) { + return; + } + addPlotTask(plot, new UniqueStatement("delete_plot_helpers") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_helpers` WHERE `plot_plot_id` = ?"); + } + }); + } + + @Override + public void deleteTrusted(final Plot plot) { + if (plot.getMembers().isEmpty()) { + return; + } + addPlotTask(plot, new UniqueStatement("delete_plot_trusted") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_trusted` WHERE `plot_plot_id` = ?"); + } + }); + } + + @Override + public void deleteDenied(final Plot plot) { + if (plot.getDenied().isEmpty()) { + return; + } + addPlotTask(plot, new UniqueStatement("delete_plot_denied") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_denied` WHERE `plot_plot_id` = ?"); + } + }); + } + + @Override + public void deleteComments(final Plot plot) { + addPlotTask(plot, new UniqueStatement("delete_plot_comments") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setString(1, plot.getArea().toString()); + stmt.setInt(2, plot.hashCode()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_comments` WHERE `world` = ? AND `hashcode` = ?"); + } + }); + } + + @Override + public void deleteRatings(final Plot plot) { + if (Settings.Enabled_Components.RATING_CACHE && plot.getSettings().getRatings().isEmpty()) { + return; + } + addPlotTask(plot, new UniqueStatement("delete_plot_ratings") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_rating` WHERE `plot_plot_id` = ?"); + } + }); + } + + /** + * Delete a plot. + */ + @Override + public void delete(final Plot plot) { + PlotSquared.debug( + "Deleting plot... Id: " + plot.getId() + " World: " + plot.getWorldName() + " Owner: " + + plot.owner + " Index: " + plot.temp); + deleteSettings(plot); + deleteDenied(plot); + deleteHelpers(plot); + deleteTrusted(plot); + deleteComments(plot); + deleteRatings(plot); + addPlotTask(plot, new UniqueStatement("delete_plot") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = ?"); + } + }); + } + + /** + * Create plot settings + */ + @Override + public void createPlotSettings(final int id, Plot plot) { + PlotSquared.debug( + "Creating plot... Id: " + plot.getId() + " World: " + plot.getWorldName() + " Owner: " + + plot.owner + " Index: " + id); + addPlotTask(plot, new UniqueStatement("createPlotSettings") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, id); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "INSERT INTO `" + SQLManager.this.prefix + + "plot_settings`(`plot_plot_id`) VALUES(?)"); + } + }); + } + + @Override + public int getClusterId(PlotCluster cluster) { + if (cluster.temp > 0) { + return cluster.temp; + } + try { + commit(); + if (cluster.temp > 0) { + return cluster.temp; + } + int c_id; + try (PreparedStatement stmt = this.connection.prepareStatement( + "SELECT `id` FROM `" + this.prefix + + "cluster` WHERE `pos1_x` = ? AND `pos1_z` = ? AND `pos2_x` = ? AND `pos2_z` = ? AND `world` = ? ORDER BY `timestamp` ASC")) { + stmt.setInt(1, cluster.getP1().x); + stmt.setInt(2, cluster.getP1().y); + stmt.setInt(3, cluster.getP2().x); + stmt.setInt(4, cluster.getP2().y); + stmt.setString(5, cluster.area.toString()); + try (ResultSet resultSet = stmt.executeQuery()) { + c_id = Integer.MAX_VALUE; + while (resultSet.next()) { + c_id = resultSet.getInt("id"); + } + } + } + if (c_id == Integer.MAX_VALUE || c_id == 0) { + if (cluster.temp > 0) { + return cluster.temp; + } + throw new SQLException("Cluster does not exist in database"); + } + cluster.temp = c_id; + return c_id; + } catch (SQLException e) { + e.printStackTrace(); + } + return Integer.MAX_VALUE; + } + + @Override + public int getId(Plot plot) { + if (plot.temp > 0) { + return plot.temp; + } + try { + commit(); + if (plot.temp > 0) { + return plot.temp; + } + int id; + try (PreparedStatement statement = this.connection.prepareStatement( + "SELECT `id` FROM `" + this.prefix + + "plot` WHERE `plot_id_x` = ? AND `plot_id_z` = ? AND world = ? ORDER BY `timestamp` ASC")) { + statement.setInt(1, plot.getId().x); + statement.setInt(2, plot.getId().y); + statement.setString(3, plot.getArea().toString()); + try (ResultSet resultSet = statement.executeQuery()) { + id = Integer.MAX_VALUE; + while (resultSet.next()) { + id = resultSet.getInt("id"); + } + } + } + if (id == Integer.MAX_VALUE || id == 0) { + if (plot.temp > 0) { + return plot.temp; + } + throw new SQLException("Plot does not exist in database"); + } + plot.temp = id; + return id; + } catch (SQLException e) { + e.printStackTrace(); + } + return Integer.MAX_VALUE; + } + + @Override + public void updateTables(int[] oldVersion) { + try { + if (this.mySQL && !PlotSquared.get().checkVersion(oldVersion, 3, 3, 2)) { + try (Statement stmt = this.connection.createStatement()) { + stmt.executeUpdate( + "ALTER TABLE `" + this.prefix + "plots` DROP INDEX `unique_alias`"); + } catch (SQLException ignored) { + } + } + DatabaseMetaData data = this.connection.getMetaData(); + ResultSet rs = + data.getColumns(null, null, this.prefix + "plot_comments", "plot_plot_id"); + if (rs.next()) { + rs.close(); + rs = data.getColumns(null, null, this.prefix + "plot_comments", "hashcode"); + if (!rs.next()) { + rs.close(); + try (Statement statement = this.connection.createStatement()) { + statement.addBatch("DROP TABLE `" + this.prefix + "plot_comments`"); + if (Storage.MySQL.USE) { + statement.addBatch( + "CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" + + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," + + "`comment` VARCHAR(40) NOT NULL," + + "`inbox` VARCHAR(40) NOT NULL," + + "`timestamp` INT(11) NOT NULL," + + "`sender` VARCHAR(40) NOT NULL" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); + } else { + statement.addBatch( + "CREATE TABLE IF NOT EXISTS `" + this.prefix + "plot_comments` (" + + "`world` VARCHAR(40) NOT NULL, `hashcode` INT(11) NOT NULL," + + "`comment` VARCHAR(40) NOT NULL," + + "`inbox` VARCHAR(40) NOT NULL, `timestamp` INT(11) NOT NULL," + + "`sender` VARCHAR(40) NOT NULL" + ')'); + } statement.executeBatch(); + } catch (SQLException ignored) { + try (Statement statement = this.connection.createStatement()) { + statement.addBatch("ALTER IGNORE TABLE `" + this.prefix + + "plot_comments` ADD `inbox` VARCHAR(11) DEFAULT `public`"); + statement.addBatch("ALTER IGNORE TABLE `" + this.prefix + + "plot_comments` ADD `timestamp` INT(11) DEFAULT 0"); + statement.addBatch("ALTER TABLE `" + this.prefix + "plot` DROP `tier`"); + statement.executeBatch(); + } + } + } + } + rs.close(); + rs = data.getColumns(null, null, this.prefix + "plot_denied", "plot_plot_id"); + if (rs.next()) { + try (Statement statement = this.connection.createStatement()) { + statement.executeUpdate("DELETE FROM `" + this.prefix + + "plot_denied` WHERE `plot_plot_id` NOT IN (SELECT `id` FROM `" + + this.prefix + "plot`)"); + } catch (SQLException e) { + e.printStackTrace(); } - public abstract PreparedStatement get() throws SQLException; - - public abstract void set(PreparedStatement stmt) throws SQLException; - } - - - private class UUIDPair { - - public final int id; - public final UUID uuid; - - public UUIDPair(int id, UUID uuid) { - this.id = id; - this.uuid = uuid; + rs.close(); + try (Statement statement = this.connection.createStatement()) { + for (String table : new String[]{"plot_denied", "plot_helpers", + "plot_trusted"}) { + ResultSet result = statement.executeQuery( + "SELECT plot_plot_id, user_uuid, COUNT(*) FROM " + this.prefix + table + + " GROUP BY plot_plot_id, user_uuid HAVING COUNT(*) > 1"); + if (result.next()) { + PlotSquared.debug("BACKING UP: " + this.prefix + table); + result.close(); + statement.executeUpdate( + "CREATE TABLE " + this.prefix + table + "_tmp AS SELECT * FROM " + + this.prefix + table + " GROUP BY plot_plot_id, user_uuid"); + statement.executeUpdate("DROP TABLE " + this.prefix + table); + statement.executeUpdate( + "CREATE TABLE " + this.prefix + table + " AS SELECT * FROM " + + this.prefix + table + "_tmp"); + statement.executeUpdate("DROP TABLE " + this.prefix + table + "_tmp"); + PlotSquared.debug("RESTORING: " + this.prefix + table); + } + } + } catch (SQLException e2) { + e2.printStackTrace(); } + } + } catch (SQLException e) { + e.printStackTrace(); } + } - private class SettingsPair { + public void deleteRows(ArrayList rowIds, final String table, final String column) { + setBulk(rowIds, new StmtMod() { - public final int id; - public final PlotSettings settings; + @Override + public String getCreateMySQL(int size) { + return getCreateMySQL(1, "DELETE FROM `" + table + "` WHERE `" + column + "` IN ", + size); + } - public SettingsPair(int id, PlotSettings settings) { - this.id = id; - this.settings = settings; + @Override + public String getCreateSQLite(int size) { + return getCreateMySQL(1, "DELETE FROM `" + table + "` WHERE `" + column + "` IN ", + size); + } + + @Override + public String getCreateSQL() { + return "DELETE FROM `" + table + "` WHERE `" + column + "` = ?"; + } + + @Override + public void setMySQL(PreparedStatement stmt, int i, Integer obj) + throws SQLException { + stmt.setInt(i + 1, obj); + } + + @Override + public void setSQLite(PreparedStatement stmt, int i, Integer obj) + throws SQLException { + stmt.setInt(i + 1, obj); + } + + @Override + public void setSQL(PreparedStatement stmt, Integer obj) throws SQLException { + stmt.setInt(1, obj); + } + }, null); + } + + /** + * Load all plots, helpers, denied, trusted, and every setting from DB into a {@link HashMap}. + */ + @Override + public HashMap> getPlots() { + HashMap> newPlots = new HashMap<>(); + HashMap plots = new HashMap<>(); + try { + HashSet areas = new HashSet<>(); + if (PlotSquared.get().worlds.contains("worlds")) { + ConfigurationSection worldSection = + PlotSquared.get().worlds.getConfigurationSection("worlds"); + if (worldSection != null) { + for (String worldKey : worldSection.getKeys(false)) { + areas.add(worldKey); + ConfigurationSection areaSection = + worldSection.getConfigurationSection(worldKey + ".areas"); + if (areaSection != null) { + areaSection.getKeys(false).forEach(s -> { + String[] split = s.split("(? uuids = new HashMap<>(); + HashMap noExist = new HashMap<>(); + + /* + * Getting plots + */ + try (Statement statement = this.connection.createStatement()) { + int id; + String owner; + UUID user; + try (ResultSet resultSet = statement.executeQuery( + "SELECT `id`, `plot_id_x`, `plot_id_z`, `owner`, `world`, `timestamp` FROM `" + + this.prefix + "plot`")) { + ArrayList toDelete = new ArrayList<>(); + while (resultSet.next()) { + PlotId plot_id = new PlotId(resultSet.getInt("plot_id_x"), + resultSet.getInt("plot_id_z")); + id = resultSet.getInt("id"); + String areaid = resultSet.getString("world"); + if (!areas.contains(areaid)) { + if (Settings.Enabled_Components.DATABASE_PURGER) { + toDelete.add(id); + continue; + } else { + AtomicInteger value = noExist.get(areaid); + if (value != null) { + value.incrementAndGet(); + } else { + noExist.put(areaid, new AtomicInteger(1)); + } + } + } + owner = resultSet.getString("owner"); + user = uuids.computeIfAbsent(owner, s -> { + try { + return UUID.fromString(s); + } catch (IllegalArgumentException ignored) { + if (Settings.UUID.FORCE_LOWERCASE) { + return UUID.nameUUIDFromBytes( + ("OfflinePlayer:" + s.toLowerCase()) + .getBytes(Charsets.UTF_8)); + } else { + return UUID.nameUUIDFromBytes( + ("OfflinePlayer:" + s).getBytes(Charsets.UTF_8)); + } + } + }); + long time; + try { + Timestamp timestamp = resultSet.getTimestamp("timestamp"); + time = timestamp.getTime(); + } catch (SQLException exception) { + String parsable = resultSet.getString("timestamp"); + try { + time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(parsable) + .getTime(); + } catch (ParseException e) { + PlotSquared.debug( + "Could not parse date for plot: #" + id + "(" + areaid + ";" + + plot_id + ") (" + parsable + ")"); + time = System.currentTimeMillis() + id; + } + } + Plot plot = new Plot(plot_id, user, new HashSet<>(), new HashSet<>(), + new HashSet<>(), "", null, null, null, + new boolean[]{false, false, false, false}, time, id); + HashMap map = newPlots.get(areaid); + if (map != null) { + Plot last = map.put(plot.getId(), plot); + if (last != null) { + if (Settings.Enabled_Components.DATABASE_PURGER) { + toDelete.add(last.temp); + } else { + PlotSquared.debug( + "&cPLOT #" + id + "(" + last + ") in `" + this.prefix + + "plot` is a duplicate. Delete this plot or set `database-purger: true` in the settings.yml."); + } + } + } else { + map = new HashMap<>(); + newPlots.put(areaid, map); + map.put(plot.getId(), plot); + } + plots.put(id, plot); + } + deleteRows(toDelete, this.prefix + "plot", "id"); + } + if (Settings.Enabled_Components.RATING_CACHE) { + try (ResultSet r = statement.executeQuery( + "SELECT `plot_plot_id`, `player`, `rating` FROM `" + this.prefix + + "plot_rating`")) { + ArrayList toDelete = new ArrayList<>(); + while (r.next()) { + id = r.getInt("plot_plot_id"); + owner = r.getString("player"); + user = uuids.computeIfAbsent(owner, UUID::fromString); + Plot plot = plots.get(id); + if (plot != null) { + plot.getSettings().getRatings().put(user, r.getInt("rating")); + } else if (Settings.Enabled_Components.DATABASE_PURGER) { + toDelete.add(id); + } else { + PlotSquared.debug("&cENTRY #" + id + "(" + plot + + ") in `plot_rating` does not exist. Create this plot or set `database-purger: true` in the " + + "settings.yml."); + } + } + deleteRows(toDelete, this.prefix + "plot_rating", "plot_plot_id"); + } + } + + /* + * Getting helpers + */ + try (ResultSet r = statement.executeQuery( + "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_helpers`")) { + ArrayList toDelete = new ArrayList<>(); + while (r.next()) { + id = r.getInt("plot_plot_id"); + owner = r.getString("user_uuid"); + user = uuids.computeIfAbsent(owner, UUID::fromString); + Plot plot = plots.get(id); + if (plot != null) { + plot.getTrusted().add(user); + } else if (Settings.Enabled_Components.DATABASE_PURGER) { + toDelete.add(id); + } else { + PlotSquared.debug("&cENTRY #" + id + "(" + plot + + ") in `plot_helpers` does not exist. Create this plot or set `database-purger: true` in the settings" + + ".yml."); + } + } + deleteRows(toDelete, this.prefix + "plot_helpers", "plot_plot_id"); + } + + /* + * Getting trusted + */ + try (ResultSet r = statement.executeQuery( + "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_trusted`")) { + ArrayList toDelete = new ArrayList<>(); + while (r.next()) { + id = r.getInt("plot_plot_id"); + owner = r.getString("user_uuid"); + user = uuids.computeIfAbsent(owner,UUID::fromString); + Plot plot = plots.get(id); + if (plot != null) { + plot.getMembers().add(user); + } else if (Settings.Enabled_Components.DATABASE_PURGER) { + toDelete.add(id); + } else { + PlotSquared.debug("&cENTRY #" + id + "(" + plot + + ") in `plot_trusted` does not exist. Create this plot or set `database-purger: true` in the settings" + + ".yml."); + } + } + deleteRows(toDelete, this.prefix + "plot_trusted", "plot_plot_id"); + } + + /* + * Getting denied + */ + try (ResultSet r = statement.executeQuery( + "SELECT `user_uuid`, `plot_plot_id` FROM `" + this.prefix + "plot_denied`")) { + ArrayList toDelete = new ArrayList<>(); + while (r.next()) { + id = r.getInt("plot_plot_id"); + owner = r.getString("user_uuid"); + user = uuids.computeIfAbsent(owner, UUID::fromString); + Plot plot = plots.get(id); + if (plot != null) { + plot.getDenied().add(user); + } else if (Settings.Enabled_Components.DATABASE_PURGER) { + toDelete.add(id); + } else { + PlotSquared.debug("&cENTRY " + id + + " in `plot_denied` does not exist. Create this plot or set `database-purger: true` in the settings.yml."); + } + } + deleteRows(toDelete, this.prefix + "plot_denied", "plot_plot_id"); + } + + try (ResultSet resultSet = statement + .executeQuery("SELECT * FROM `" + this.prefix + "plot_settings`")) { + ArrayList toDelete = new ArrayList<>(); + while (resultSet.next()) { + id = resultSet.getInt("plot_plot_id"); + Plot plot = plots.get(id); + if (plot != null) { + plots.remove(id); + String alias = resultSet.getString("alias"); + if (alias != null) { + plot.getSettings().setAlias(alias); + } + String pos = resultSet.getString("position"); + switch (pos.toLowerCase()) { + case "": + case "default": + case "0,0,0": + case "center": + break; + default: + try { + plot.getSettings().setPosition(BlockLoc.fromString(pos)); + } catch (Exception ignored) { + } + } + int m = resultSet.getInt("merged"); + boolean[] merged = new boolean[4]; + for (int i = 0; i < 4; i++) { + merged[3 - i] = (m & 1 << i) != 0; + } + plot.getSettings().setMerged(merged); + String[] flags_string; + String myflags = resultSet.getString("flags"); + if (myflags == null || myflags.isEmpty()) { + flags_string = new String[]{}; + } else { + flags_string = myflags.split(","); + } + HashMap, Object> flags = new HashMap<>(); + boolean exception = false; + for (String element : flags_string) { + if (element.contains(":")) { + String[] split = element.split(":"); + try { + String flag_str = + split[1].replaceAll("¯", ":").replaceAll("\u00B4", ","); + Flag flag = FlagManager.getOrCreateFlag(split[0]); + flags.put(flag, flag.parseValue(flag_str)); + } catch (Exception e) { + e.printStackTrace(); + exception = true; + } + } else { + element = + element.replaceAll("\u00AF", ":").replaceAll("\u00B4", ","); + if (StringMan + .isAlpha(element.replaceAll("_", "").replaceAll("-", ""))) { + Flag flag = FlagManager.getOrCreateFlag(element); + if (flag == null) { + flag = new StringFlag(element) { + @Override + public String getValueDescription() { + return "Generic Filler Flag"; + } + }; + } + flags.put(flag, flag.parseValue("")); + } else { + PlotSquared.debug("INVALID FLAG: " + element); + } + } + } + if (exception) { + PlotSquared.debug("&cPlot #" + id + "(" + plot + ") | " + plot + + " had an invalid flag. A fix has been attempted."); + PlotSquared.debug("&c" + myflags); + this.setFlags(plot, flags); + } + plot.getSettings().flags = flags; + } else if (Settings.Enabled_Components.DATABASE_PURGER) { + toDelete.add(id); + } else { + PlotSquared.debug("&cENTRY #" + id + "(" + plot + + ") in `plot_settings` does not exist. Create this plot or set `database-purger: true` in the settings" + + ".yml."); + } + } + deleteRows(toDelete, this.prefix + "plot_settings", "plot_plot_id"); + } + } + if (!plots.entrySet().isEmpty()) { + createEmptySettings(new ArrayList<>(plots.keySet()), null); + for (Entry entry : plots.entrySet()) { + entry.getValue().getSettings(); + } + } + boolean invalidPlot = false; + for (Entry entry : noExist.entrySet()) { + String worldName = entry.getKey(); + invalidPlot = true; + PlotSquared.debug("&c[WARNING] Found " + entry.getValue().intValue() + + " plots in DB for non existent world; '" + worldName + "'."); + } + if (invalidPlot) { + PlotSquared.debug( + "&c[WARNING] - Please create the world/s or remove the plots using the purge command"); + } + } catch (SQLException e) { + PlotSquared.debug("&7[WARN] Failed to load plots."); + e.printStackTrace(); } + return newPlots; + } + + @Override + public void setMerged(final Plot plot, final boolean[] merged) { + plot.getSettings().setMerged(merged); + addPlotTask(plot, new UniqueStatement("setMerged") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + int hash = MainUtil.hash(merged); + stmt.setInt(1, hash); + stmt.setInt(2, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "plot_settings` SET `merged` = ? WHERE `plot_plot_id` = ?"); + } + }); + } + + @Override + public void swapPlots(Plot plot1, Plot plot2) { + final int id1 = getId(plot1); + final int id2 = getId(plot2); + final PlotId pos1 = plot1.getId(); + final PlotId pos2 = plot2.getId(); + addPlotTask(plot1, new UniqueStatement("swapPlots") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, pos2.x); + stmt.setInt(2, pos2.y); + stmt.setInt(3, id1); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "plot` SET `plot_id_x` = ?, `plot_id_z` = ? WHERE `id` = ?"); + } + }); + addPlotTask(plot2, new UniqueStatement("swapPlots") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, pos1.x); + stmt.setInt(2, pos1.y); + stmt.setInt(3, id2); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "plot` SET `plot_id_x` = ?, `plot_id_z` = ? WHERE `id` = ?"); + } + }); + } + + @Override + public void movePlot(final Plot original, final Plot newPlot) { + addPlotTask(original, new UniqueStatement("movePlot") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, newPlot.getId().x); + stmt.setInt(2, newPlot.getId().y); + stmt.setString(3, newPlot.getArea().toString()); + stmt.setInt(4, getId(original)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "plot` SET `plot_id_x` = ?, `plot_id_z` = ?, `world` = ? WHERE `id` = ?"); + } + }); + addPlotTask(newPlot, null); + } + + @Override + public void setFlags(final Plot plot, HashMap, Object> flags) { + final String flag_string = FlagManager.toString(flags); + addPlotTask(plot, new UniqueStatement("setFlags") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setString(1, flag_string); + stmt.setInt(2, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "plot_settings` SET `flags` = ? WHERE `plot_plot_id` = ?"); + } + }); + } + + @Override + public void setAlias(final Plot plot, final String alias) { + addPlotTask(plot, new UniqueStatement("setAlias") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setString(1, alias); + stmt.setInt(2, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "plot_settings` SET `alias` = ? WHERE `plot_plot_id` = ?"); + } + }); + } + + /** + * Purge all plots with the following database IDs + */ + @Override + public void purgeIds(final Set uniqueIds) { + addGlobalTask(() -> { + if (!uniqueIds.isEmpty()) { + try { + ArrayList uniqueIdsList = new ArrayList<>(uniqueIds); + String stmt_prefix = ""; + int size = uniqueIdsList.size(); + int packet = 990; + int amount = size / packet; + int count = 0; + int last = -1; + for (int j = 0; j <= amount; j++) { + PlotSquared.debug("Purging " + (j * packet) + " / " + size); + List subList = + uniqueIdsList.subList(j * packet, Math.min(size, (j + 1) * packet)); + if (subList.isEmpty()) { + break; + } + StringBuilder idstr2 = new StringBuilder(); + stmt_prefix = ""; + for (Integer id : subList) { + idstr2.append(stmt_prefix).append(id); + stmt_prefix = " OR `id` = "; + } + stmt_prefix = ""; + StringBuilder idstr = new StringBuilder(); + for (Integer id : subList) { + idstr.append(stmt_prefix).append(id); + stmt_prefix = " OR `plot_plot_id` = "; + } + PreparedStatement stmt = SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_helpers` WHERE `plot_plot_id` = " + idstr); + stmt.executeUpdate(); + stmt.close(); + stmt = SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_denied` WHERE `plot_plot_id` = " + idstr); + stmt.executeUpdate(); + stmt.close(); + stmt = SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_settings` WHERE `plot_plot_id` = " + idstr); + stmt.executeUpdate(); + stmt.close(); + stmt = SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_trusted` WHERE `plot_plot_id` = " + idstr); + stmt.executeUpdate(); + stmt.close(); + stmt = SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + "plot` WHERE `id` = " + + idstr2); + stmt.executeUpdate(); + stmt.close(); + commit(); + } + } catch (SQLException e) { + e.printStackTrace(); + PlotSquared.debug("&c[ERROR] FAILED TO PURGE PLOTS!"); + return; + } + } + PlotSquared.debug("&6[INFO] SUCCESSFULLY PURGED " + uniqueIds.size() + " PLOTS!"); + }); + } + + @Override + public void purge(final PlotArea area, final Set plots) { + addGlobalTask(() -> { + try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( + "SELECT `id`, `plot_id_x`, `plot_id_z` FROM `" + SQLManager.this.prefix + + "plot` WHERE `world` = ?")) { + stmt.setString(1, area.toString()); + Set ids; + try (ResultSet r = stmt.executeQuery()) { + ids = new HashSet<>(); + while (r.next()) { + PlotId plot_id = + new PlotId(r.getInt("plot_id_x"), r.getInt("plot_id_z")); + if (plots.contains(plot_id)) { + ids.add(r.getInt("id")); + } + } + } + purgeIds(ids); + } catch (SQLException e) { + e.printStackTrace(); + PlotSquared.debug("&c[ERROR] FAILED TO PURGE AREA '" + area + "'!"); + } + for (Iterator iterator = plots.iterator(); iterator.hasNext(); ) { + PlotId plotId = iterator.next(); + iterator.remove(); + PlotId id = new PlotId(plotId.x, plotId.y); + area.removePlot(id); + } + }); + } + + @Override + public void setPosition(final Plot plot, final String position) { + addPlotTask(plot, new UniqueStatement("setPosition") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setString(1, position == null ? "" : position); + stmt.setInt(2, getId(plot)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "plot_settings` SET `position` = ? WHERE `plot_plot_id` = ?"); + } + }); + } + + @Override + public void removeComment(final Plot plot, final PlotComment comment) { + addPlotTask(plot, new UniqueStatement("removeComment") { + @Override + public void set(PreparedStatement statement) throws SQLException { + if (plot != null) { + statement.setString(1, plot.getArea().toString()); + statement.setInt(2, plot.getId().hashCode()); + statement.setString(3, comment.comment); + statement.setString(4, comment.inbox); + statement.setString(5, comment.senderName); + } else { + statement.setString(1, comment.comment); + statement.setString(2, comment.inbox); + statement.setString(3, comment.senderName); + } + } + + @Override + public PreparedStatement get() throws SQLException { + if (plot != null) { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `comment` = ? AND `inbox` = ? AND `sender` = ?"); + } + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_comments` WHERE `comment` = ? AND `inbox` = ? AND `sender` = ?"); + } + }); + } + + @Override + public void clearInbox(final Plot plot, final String inbox) { + addPlotTask(plot, new UniqueStatement("clearInbox") { + @Override + public void set(PreparedStatement statement) throws SQLException { + if (plot != null) { + statement.setString(1, plot.getArea().toString()); + statement.setInt(2, plot.getId().hashCode()); + statement.setString(3, inbox); + } else { + statement.setString(1, inbox); + } + } + + @Override + public PreparedStatement get() throws SQLException { + if (plot != null) { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `inbox` = ?"); + } + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + "plot_comments` `inbox` = ?"); + } + }); + } + + @Override + public void getComments(final Plot plot, final String inbox, + final RunnableVal> whenDone) { + addPlotTask(plot, new UniqueStatement("getComments_" + plot) { + @Override + public void set(PreparedStatement statement) throws SQLException { + if (plot != null) { + statement.setString(1, plot.getArea().toString()); + statement.setInt(2, plot.getId().hashCode()); + statement.setString(3, inbox); + } else { + statement.setString(1, inbox); + } + } + + @Override + public PreparedStatement get() throws SQLException { + if (plot != null) { + return SQLManager.this.connection.prepareStatement( + "SELECT * FROM `" + SQLManager.this.prefix + + "plot_comments` WHERE `world` = ? AND `hashcode` = ? AND `inbox` = ?"); + } + return SQLManager.this.connection.prepareStatement( + "SELECT * FROM `" + SQLManager.this.prefix + + "plot_comments` WHERE `inbox` = ?"); + } + + @Override + public void execute(PreparedStatement statement) { + } + + @Override + public void addBatch(PreparedStatement statement) throws SQLException { + ArrayList comments = new ArrayList<>(); + try (ResultSet set = statement.executeQuery()) { + while (set.next()) { + String sender = set.getString("sender"); + String world = set.getString("world"); + int hash = set.getInt("hashcode"); + PlotId id; + if (hash != 0) { + id = PlotId.unpair(hash); + } else { + id = null; + } + String msg = set.getString("comment"); + long timestamp = set.getInt("timestamp") * 1000; + PlotComment comment = + new PlotComment(world, id, msg, sender, inbox, timestamp); + comments.add(comment); + whenDone.value = comments; + } + } + TaskManager.runTask(whenDone); + } + }); + } + + @Override + public void setComment(final Plot plot, final PlotComment comment) { + addPlotTask(plot, new UniqueStatement("setComment") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setString(1, plot.getArea().toString()); + statement.setInt(2, plot.getId().hashCode()); + statement.setString(3, comment.comment); + statement.setString(4, comment.inbox); + statement.setInt(5, (int) (comment.timestamp / 1000)); + statement.setString(6, comment.senderName); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "INSERT INTO `" + SQLManager.this.prefix + + "plot_comments` (`world`, `hashcode`, `comment`, `inbox`, `timestamp`, `sender`) VALUES(?,?,?,?,?,?)"); + } + }); + } + + @Override + public void removeTrusted(final Plot plot, final UUID uuid) { + addPlotTask(plot, new UniqueStatement("removeTrusted") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setInt(1, getId(plot)); + statement.setString(2, uuid.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_helpers` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); + } + }); + } + + @Override + public void removeMember(final Plot plot, final UUID uuid) { + addPlotTask(plot, new UniqueStatement("removeMember") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setInt(1, getId(plot)); + statement.setString(2, uuid.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_trusted` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); + } + }); + } + + @Override + public void setTrusted(final Plot plot, final UUID uuid) { + addPlotTask(plot, new UniqueStatement("setTrusted") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setInt(1, getId(plot)); + statement.setString(2, uuid.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "INSERT INTO `" + SQLManager.this.prefix + + "plot_helpers` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); + } + }); + } + + @Override + public void setMember(final Plot plot, final UUID uuid) { + addPlotTask(plot, new UniqueStatement("setMember") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setInt(1, getId(plot)); + statement.setString(2, uuid.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "INSERT INTO `" + SQLManager.this.prefix + + "plot_trusted` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); + } + }); + } + + @Override + public void removeDenied(final Plot plot, final UUID uuid) { + addPlotTask(plot, new UniqueStatement("removeDenied") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setInt(1, getId(plot)); + statement.setString(2, uuid.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "plot_denied` WHERE `plot_plot_id` = ? AND `user_uuid` = ?"); + } + }); + } + + @Override + public void setDenied(final Plot plot, final UUID uuid) { + addPlotTask(plot, new UniqueStatement("setDenied") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setInt(1, getId(plot)); + statement.setString(2, uuid.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "INSERT INTO `" + SQLManager.this.prefix + + "plot_denied` (`plot_plot_id`, `user_uuid`) VALUES(?,?)"); + } + }); + } + + @Override + public HashMap getRatings(Plot plot) { + HashMap map = new HashMap<>(); + try (PreparedStatement statement = this.connection.prepareStatement( + "SELECT `rating`, `player` FROM `" + this.prefix + + "plot_rating` WHERE `plot_plot_id` = ? ")) { + statement.setInt(1, getId(plot)); + try (ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + UUID uuid = UUID.fromString(resultSet.getString("player")); + int rating = resultSet.getInt("rating"); + map.put(uuid, rating); + } + } + } catch (SQLException e) { + PlotSquared + .debug("&7[WARN] Failed to fetch rating for plot " + plot.getId().toString()); + e.printStackTrace(); + } + return map; + } + + @Override + public void setRating(final Plot plot, final UUID rater, final int value) { + addPlotTask(plot, new UniqueStatement("setRating") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setInt(1, getId(plot)); + statement.setInt(2, value); + statement.setString(3, rater.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "INSERT INTO `" + SQLManager.this.prefix + + "plot_rating` (`plot_plot_id`, `rating`, `player`) VALUES(?,?,?)"); + } + }); + } + + @Override + public void delete(PlotCluster cluster) { + final int id = getClusterId(cluster); + addClusterTask(cluster, new UniqueStatement("delete_cluster_settings") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, id); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "cluster_settings` WHERE `cluster_id` = ?"); + } + }); + addClusterTask(cluster, new UniqueStatement("delete_cluster_helpers") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, id); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "cluster_helpers` WHERE `cluster_id` = ?"); + } + }); + addClusterTask(cluster, new UniqueStatement("delete_cluster_invited") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, id); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "cluster_invited` WHERE `cluster_id` = ?"); + } + }); + addClusterTask(cluster, new UniqueStatement("delete_cluster") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, id); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + "cluster` WHERE `id` = ?"); + } + }); + } + + @Override + public void addPersistentMeta(final UUID uuid, final String key, final byte[] meta, + final boolean replace) { + addPlayerTask(uuid, new UniqueStatement("addPersistentMeta") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + if (replace) { + stmt.setBytes(1, meta); + stmt.setString(2, uuid.toString()); + stmt.setString(3, key); + } else { + stmt.setString(1, uuid.toString()); + stmt.setString(2, key); + stmt.setBytes(3, meta); + } + } + + @Override + public PreparedStatement get() throws SQLException { + if (replace) { + return SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "player_meta` SET `value` = ? WHERE `uuid` = ? AND `key` = ?"); + } else { + return SQLManager.this.connection.prepareStatement( + "INSERT INTO `" + SQLManager.this.prefix + + "player_meta`(`uuid`, `key`, `value`) VALUES(?, ? ,?)"); + } + } + }); + } + + @Override + public void removePersistentMeta(final UUID uuid, final String key) { + addPlayerTask(uuid, new UniqueStatement("removePersistentMeta") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setString(1, uuid.toString()); + stmt.setString(2, key); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "player_meta` WHERE `uuid` = ? AND `key` = ?"); + } + }); + } + + @Override + public void getPersistentMeta(final UUID uuid, final RunnableVal> result) { + addPlayerTask(uuid, new UniqueStatement("getPersistentMeta") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setString(1, uuid.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "SELECT * FROM `" + SQLManager.this.prefix + + "player_meta` WHERE `uuid` = ? ORDER BY `meta_id` ASC"); + } + + @Override + public void execute(PreparedStatement statement) { + } + + @Override + public void addBatch(PreparedStatement statement) throws SQLException { + ResultSet resultSet = statement.executeQuery(); + + final Map metaMap = new HashMap<>(); + + while (resultSet.next()) { + String key = resultSet.getString("key"); + byte[] bytes = resultSet.getBytes("value"); + metaMap.put(key, bytes); + } + + resultSet.close(); + TaskManager.runTaskAsync(() -> result.run(metaMap)); + } + + }); + } + + @Override + public HashMap> getClusters() { + LinkedHashMap> newClusters = new LinkedHashMap<>(); + HashMap clusters = new HashMap<>(); + try { + HashSet areas = new HashSet<>(); + if (PlotSquared.get().worlds.contains("worlds")) { + ConfigurationSection worldSection = + PlotSquared.get().worlds.getConfigurationSection("worlds"); + if (worldSection != null) { + for (String worldKey : worldSection.getKeys(false)) { + areas.add(worldKey); + ConfigurationSection areaSection = + worldSection.getConfigurationSection(worldKey + ".areas"); + if (areaSection != null) { + for (String areaKey : areaSection.getKeys(false)) { + String[] split = areaKey.split("(? uuids = new HashMap<>(); + HashMap noExist = new HashMap<>(); + /* + * Getting clusters + */ + try (Statement stmt = this.connection.createStatement()) { + ResultSet resultSet = + stmt.executeQuery("SELECT * FROM `" + this.prefix + "cluster`"); + PlotCluster cluster; + String owner; + UUID user; + int id; + while (resultSet.next()) { + PlotId pos1 = + new PlotId(resultSet.getInt("pos1_x"), resultSet.getInt("pos1_z")); + PlotId pos2 = + new PlotId(resultSet.getInt("pos2_x"), resultSet.getInt("pos2_z")); + id = resultSet.getInt("id"); + String areaid = resultSet.getString("world"); + if (!areas.contains(areaid)) { + if (noExist.containsKey(areaid)) { + noExist.put(areaid, noExist.get(areaid) + 1); + } else { + noExist.put(areaid, 1); + } + } + owner = resultSet.getString("owner"); + user = uuids.computeIfAbsent(owner, UUID::fromString); + cluster = new PlotCluster(null, pos1, pos2, user, id); + clusters.put(id, cluster); + Set set = newClusters + .computeIfAbsent(areaid, k -> new HashSet<>()); + set.add(cluster); + } + //Getting helpers + resultSet = stmt.executeQuery( + "SELECT `user_uuid`, `cluster_id` FROM `" + this.prefix + "cluster_helpers`"); + while (resultSet.next()) { + id = resultSet.getInt("cluster_id"); + owner = resultSet.getString("user_uuid"); + user = uuids.computeIfAbsent(owner,UUID::fromString); + cluster = clusters.get(id); + if (cluster != null) { + cluster.helpers.add(user); + } else { + PlotSquared.debug("&cCluster #" + id + "(" + cluster + + ") in cluster_helpers does not exist. Please create the cluster or remove this entry."); + } + } + // Getting invited + resultSet = stmt.executeQuery( + "SELECT `user_uuid`, `cluster_id` FROM `" + this.prefix + "cluster_invited`"); + while (resultSet.next()) { + id = resultSet.getInt("cluster_id"); + owner = resultSet.getString("user_uuid"); + user = uuids.computeIfAbsent(owner,UUID::fromString); + cluster = clusters.get(id); + if (cluster != null) { + cluster.invited.add(user); + } else { + PlotSquared.debug("&cCluster #" + id + "(" + cluster + + ") in cluster_invited does not exist. Please create the cluster or remove this entry."); + } + } + resultSet = + stmt.executeQuery("SELECT * FROM `" + this.prefix + "cluster_settings`"); + while (resultSet.next()) { + id = resultSet.getInt("cluster_id"); + cluster = clusters.get(id); + if (cluster != null) { + String alias = resultSet.getString("alias"); + if (alias != null) { + cluster.settings.setAlias(alias); + } + String pos = resultSet.getString("position"); + switch (pos.toLowerCase()) { + case "": + case "default": + case "0,0,0": + case "center": + break; + default: + try { + BlockLoc loc = BlockLoc.fromString(pos); + cluster.settings.setPosition(loc); + } catch (Exception ignored) { + } + } + int m = resultSet.getInt("merged"); + boolean[] merged = new boolean[4]; + for (int i = 0; i < 4; i++) { + merged[3 - i] = (m & 1 << i) != 0; + } + cluster.settings.setMerged(merged); + String[] flags_string; + String myflags = resultSet.getString("flags"); + if (myflags == null || myflags.isEmpty()) { + flags_string = new String[]{}; + } else { + flags_string = myflags.split(","); + } + HashMap, Object> flags = new HashMap<>(); + for (String element : flags_string) { + if (element.contains(":")) { + String[] split = element.split(":"); + String flag_str = + split[1].replaceAll("\u00AF", ":").replaceAll("´", ","); + Flag flag = FlagManager.getOrCreateFlag(split[0]); + if (flag == null) { + flag = new StringFlag(split[0]) { + @Override + public String getValueDescription() { + return "Generic Filler Flag"; + } + }; + } + flags.put(flag, flag.parseValue(flag_str)); + } else { + Flag flag = FlagManager.getOrCreateFlag(element); + if (flag == null) { + flag = new StringFlag(element) { + @Override + public String getValueDescription() { + return "Generic Filler Flag"; + } + }; + } + flags.put(flag, flag.parseValue("")); + } + } + cluster.settings.flags = flags; + } else { + PlotSquared.debug("&cCluster #" + id + "(" + cluster + + ") in cluster_settings does not exist. Please create the cluster or remove this entry."); + } + } + resultSet.close(); + } + boolean invalidPlot = false; + for (Entry entry : noExist.entrySet()) { + String a = entry.getKey(); + invalidPlot = true; + PlotSquared.debug("&c[WARNING] Found " + noExist.get(a) + + " clusters in DB for non existent area; '" + a + "'."); + } + if (invalidPlot) { + PlotSquared.debug( + "&c[WARNING] - Please create the world/s or remove the clusters using the purge command"); + } + } catch (SQLException e) { + PlotSquared.debug("&7[WARN] Failed to load clusters."); + e.printStackTrace(); + } + return newClusters; + } + + @Override + public void setClusterName(final PlotCluster cluster, final String name) { + addClusterTask(cluster, new UniqueStatement("setClusterName") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setString(1, name); + stmt.setInt(2, getClusterId(cluster)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "cluster_settings` SET `alias` = ? WHERE `cluster_id` = ?"); + } + }); + cluster.settings.setAlias(name); + } + + @Override + public void removeHelper(final PlotCluster cluster, final UUID uuid) { + addClusterTask(cluster, new UniqueStatement("removeHelper") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setInt(1, getClusterId(cluster)); + statement.setString(2, uuid.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "cluster_helpers` WHERE `cluster_id` = ? AND `user_uuid` = ?"); + } + }); + } + + @Override + public void setHelper(final PlotCluster cluster, final UUID uuid) { + addClusterTask(cluster, new UniqueStatement("setHelper") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setInt(1, getClusterId(cluster)); + statement.setString(2, uuid.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "INSERT INTO `" + SQLManager.this.prefix + + "cluster_helpers` (`cluster_id`, `user_uuid`) VALUES(?,?)"); + } + }); + } + + @Override + public void createCluster(final PlotCluster cluster) { + addClusterTask(cluster, new UniqueStatement("createCluster_" + cluster.hashCode()) { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, cluster.getP1().x); + stmt.setInt(2, cluster.getP1().y); + stmt.setInt(3, cluster.getP2().x); + stmt.setInt(4, cluster.getP2().y); + stmt.setString(5, cluster.owner.toString()); + stmt.setString(6, cluster.area.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement(SQLManager.this.CREATE_CLUSTER, + Statement.RETURN_GENERATED_KEYS); + } + + @Override + public void execute(PreparedStatement statement) { + } + + @Override + public void addBatch(PreparedStatement statement) throws SQLException { + statement.executeUpdate(); + try (ResultSet keys = statement.getGeneratedKeys()) { + if (keys.next()) { + cluster.temp = keys.getInt(1); + } + } + } + }); + addClusterTask(cluster, + new UniqueStatement("createCluster_settings_" + cluster.hashCode()) { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, getClusterId(cluster)); + stmt.setString(2, cluster.getAlias()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "INSERT INTO `" + SQLManager.this.prefix + + "cluster_settings`(`cluster_id`, `alias`) VALUES(?, ?)"); + } + }); + } + + @Override + public void resizeCluster(final PlotCluster current, PlotId min, PlotId max) { + final PlotId pos1 = new PlotId(current.getP1().x, current.getP1().y); + final PlotId pos2 = new PlotId(current.getP2().x, current.getP2().y); + current.setP1(min); + current.setP2(max); + + addClusterTask(current, new UniqueStatement("resizeCluster") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setInt(1, pos1.x); + stmt.setInt(2, pos1.y); + stmt.setInt(3, pos2.x); + stmt.setInt(4, pos2.y); + stmt.setInt(5, getClusterId(current)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "cluster` SET `pos1_x` = ?, `pos1_z` = ?, `pos2_x` = ?, `pos2_z` = ? WHERE `id` = ?"); + } + }); + } + + @Override + public void setPosition(final PlotCluster cluster, final String position) { + addClusterTask(cluster, new UniqueStatement("setPosition") { + @Override + public void set(PreparedStatement stmt) throws SQLException { + stmt.setString(1, position); + stmt.setInt(2, getClusterId(cluster)); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "cluster_settings` SET `position` = ? WHERE `cluster_id` = ?"); + } + }); + } + + @Override + public void removeInvited(final PlotCluster cluster, final UUID uuid) { + addClusterTask(cluster, new UniqueStatement("removeInvited") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setInt(1, getClusterId(cluster)); + statement.setString(2, uuid.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "DELETE FROM `" + SQLManager.this.prefix + + "cluster_invited` WHERE `cluster_id` = ? AND `user_uuid` = ?"); + } + }); + } + + @Override + public void setInvited(final PlotCluster cluster, final UUID uuid) { + addClusterTask(cluster, new UniqueStatement("setInvited") { + @Override + public void set(PreparedStatement statement) throws SQLException { + statement.setInt(1, getClusterId(cluster)); + statement.setString(2, uuid.toString()); + } + + @Override + public PreparedStatement get() throws SQLException { + return SQLManager.this.connection.prepareStatement( + "INSERT INTO `" + SQLManager.this.prefix + + "cluster_invited` (`cluster_id`, `user_uuid`) VALUES(?,?)"); + } + }); + } + + @Override + public boolean deleteTables() { + try (Statement stmt = this.connection.createStatement(); + PreparedStatement statement = this.connection + .prepareStatement("DROP TABLE `" + this.prefix + "plot`")) { + close(); + this.closed = false; + SQLManager.this.connection = this.database.forceConnection(); + stmt.addBatch("DROP TABLE `" + this.prefix + "cluster_invited`"); + stmt.addBatch("DROP TABLE `" + this.prefix + "cluster_helpers`"); + stmt.addBatch("DROP TABLE `" + this.prefix + "cluster`"); + stmt.addBatch("DROP TABLE `" + this.prefix + "plot_rating`"); + stmt.addBatch("DROP TABLE `" + this.prefix + "plot_settings`"); + stmt.addBatch("DROP TABLE `" + this.prefix + "plot_comments`"); + stmt.addBatch("DROP TABLE `" + this.prefix + "plot_trusted`"); + stmt.addBatch("DROP TABLE `" + this.prefix + "plot_helpers`"); + stmt.addBatch("DROP TABLE `" + this.prefix + "plot_denied`"); + stmt.executeBatch(); + stmt.clearBatch(); + statement.executeUpdate(); + } catch (ClassNotFoundException | SQLException e) { + e.printStackTrace(); + + } + return true; + } + + @Override + public void validateAllPlots(Set toValidate) { + if (!isValid()) { + reconnect(); + } + PlotSquared.debug( + "$1All DB transactions during this session are being validated (This may take a while if corrections need to be made)"); + commit(); + while (true) { + if (!sendBatch()) { + break; + } + } + try { + if (this.connection.getAutoCommit()) { + this.connection.setAutoCommit(false); + } + } catch (SQLException e) { + e.printStackTrace(); + } + HashMap> database = getPlots(); + ArrayList toCreate = new ArrayList<>(); + for (Plot plot : toValidate) { + if (plot.temp == -1) { + continue; + } + HashMap worldPlots = database.get(plot.getArea().toString()); + if (worldPlots == null) { + PlotSquared.debug("&8 - &7Creating plot (1): " + plot); + toCreate.add(plot); + continue; + } + Plot dataPlot = worldPlots.remove(plot.getId()); + if (dataPlot == null) { + PlotSquared.debug("&8 - &7Creating plot (2): " + plot); + toCreate.add(plot); + continue; + } + // owner + if (!plot.owner.equals(dataPlot.owner)) { + PlotSquared + .debug("&8 - &7Setting owner: " + plot + " -> " + MainUtil.getName(plot.owner)); + setOwner(plot, plot.owner); + } + // trusted + if (!plot.getTrusted().equals(dataPlot.getTrusted())) { + HashSet toAdd = (HashSet) plot.getTrusted().clone(); + HashSet toRemove = (HashSet) dataPlot.getTrusted().clone(); + toRemove.removeAll(plot.getTrusted()); + toAdd.removeAll(dataPlot.getTrusted()); + PlotSquared.debug( + "&8 - &7Correcting " + (toAdd.size() + toRemove.size()) + " trusted for: " + + plot); + if (!toRemove.isEmpty()) { + for (UUID uuid : toRemove) { + removeTrusted(plot, uuid); + } + } + if (!toAdd.isEmpty()) { + for (UUID uuid : toAdd) { + setTrusted(plot, uuid); + } + } + } + if (!plot.getMembers().equals(dataPlot.getMembers())) { + HashSet toAdd = (HashSet) plot.getMembers().clone(); + HashSet toRemove = (HashSet) dataPlot.getMembers().clone(); + toRemove.removeAll(plot.getMembers()); + toAdd.removeAll(dataPlot.getMembers()); + PlotSquared.debug( + "&8 - &7Correcting " + (toAdd.size() + toRemove.size()) + " members for: " + + plot); + if (!toRemove.isEmpty()) { + for (UUID uuid : toRemove) { + removeMember(plot, uuid); + } + } + if (!toAdd.isEmpty()) { + for (UUID uuid : toAdd) { + setMember(plot, uuid); + } + } + } + if (!plot.getDenied().equals(dataPlot.getDenied())) { + HashSet toAdd = (HashSet) plot.getDenied().clone(); + HashSet toRemove = (HashSet) dataPlot.getDenied().clone(); + toRemove.removeAll(plot.getDenied()); + toAdd.removeAll(dataPlot.getDenied()); + PlotSquared.debug( + "&8 - &7Correcting " + (toAdd.size() + toRemove.size()) + " denied for: " + + plot); + if (!toRemove.isEmpty()) { + for (UUID uuid : toRemove) { + removeDenied(plot, uuid); + } + } + if (!toAdd.isEmpty()) { + for (UUID uuid : toAdd) { + setDenied(plot, uuid); + } + } + } + boolean[] pm = plot.getMerged(); + boolean[] dm = dataPlot.getMerged(); + if (pm[0] != dm[0] || pm[1] != dm[1]) { + PlotSquared.debug("&8 - &7Correcting merge for: " + plot); + setMerged(dataPlot, plot.getMerged()); + } + HashMap, Object> pf = plot.getFlags(); + HashMap, Object> df = dataPlot.getFlags(); + if (!pf.isEmpty() && !df.isEmpty()) { + if (pf.size() != df.size() || !StringMan + .isEqual(StringMan.joinOrdered(pf.values(), ","), + StringMan.joinOrdered(df.values(), ","))) { + PlotSquared.debug("&8 - &7Correcting flags for: " + plot); + setFlags(plot, pf); + } + } + } + + for (Entry> entry : database.entrySet()) { + HashMap map = entry.getValue(); + if (!map.isEmpty()) { + for (Entry entry2 : map.entrySet()) { + PlotSquared.debug("$1Plot was deleted: " + entry2.getValue().toString() + + "// TODO implement this when sure safe"); + } + } + } + commit(); + } + + @Override + public void replaceWorld(final String oldWorld, final String newWorld, final PlotId min, + final PlotId max) { + addGlobalTask(() -> { + if (min == null) { + try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "plot` SET `world` = ? WHERE `world` = ?")) { + stmt.setString(1, newWorld); + stmt.setString(2, oldWorld); + stmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "cluster` SET `world` = ? WHERE `world` = ?")) { + stmt.setString(1, newWorld); + stmt.setString(2, oldWorld); + stmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + } else { + try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "plot` SET `world` = ? WHERE `world` = ? AND `plot_id_x` BETWEEN ? AND ? AND `plot_id_z` BETWEEN ? AND ?")) { + stmt.setString(1, newWorld); + stmt.setString(2, oldWorld); + stmt.setInt(3, min.x); + stmt.setInt(4, max.x); + stmt.setInt(5, min.y); + stmt.setInt(6, max.y); + stmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + try (PreparedStatement stmt = SQLManager.this.connection.prepareStatement( + "UPDATE `" + SQLManager.this.prefix + + "cluster` SET `world` = ? WHERE `world` = ? AND `pos1_x` <= ? AND `pos1_z` <= ? AND `pos2_x` >= ? AND `pos2_z` >= ?")) { + stmt.setString(1, newWorld); + stmt.setString(2, oldWorld); + stmt.setInt(3, max.x); + stmt.setInt(4, max.y); + stmt.setInt(5, min.x); + stmt.setInt(6, min.y); + stmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + }); + } + + @Override + public void replaceUUID(final UUID old, final UUID now) { + addGlobalTask(() -> { + try (Statement stmt = SQLManager.this.connection.createStatement()) { + stmt.executeUpdate( + "UPDATE `" + SQLManager.this.prefix + "cluster` SET `owner` = '" + now + .toString() + "' WHERE `owner` = '" + old.toString() + '\''); + stmt.executeUpdate( + "UPDATE `" + SQLManager.this.prefix + "cluster_helpers` SET `user_uuid` = '" + + now.toString() + "' WHERE `user_uuid` = '" + old.toString() + '\''); + stmt.executeUpdate( + "UPDATE `" + SQLManager.this.prefix + "cluster_invited` SET `user_uuid` = '" + + now.toString() + "' WHERE `user_uuid` = '" + old.toString() + '\''); + stmt.executeUpdate( + "UPDATE `" + SQLManager.this.prefix + "plot` SET `owner` = '" + now + .toString() + "' WHERE `owner` = '" + old.toString() + '\''); + stmt.executeUpdate( + "UPDATE `" + SQLManager.this.prefix + "plot_denied` SET `user_uuid` = '" + + now.toString() + "' WHERE `user_uuid` = '" + old.toString() + '\''); + stmt.executeUpdate( + "UPDATE `" + SQLManager.this.prefix + "plot_helpers` SET `user_uuid` = '" + + now.toString() + "' WHERE `user_uuid` = '" + old.toString() + '\''); + stmt.executeUpdate( + "UPDATE `" + SQLManager.this.prefix + "plot_trusted` SET `user_uuid` = '" + + now.toString() + "' WHERE `user_uuid` = '" + old.toString() + '\''); + } catch (SQLException e) { + e.printStackTrace(); + } + }); + } + + @Override + public void close() { + try { + this.closed = true; + this.connection.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public abstract class UniqueStatement { + + public final String method; + + public UniqueStatement(String method) { + this.method = method; + } + + public void addBatch(PreparedStatement statement) throws SQLException { + statement.addBatch(); + } + + public void execute(PreparedStatement statement) throws SQLException { + statement.executeBatch(); + } + + public abstract PreparedStatement get() throws SQLException; + + public abstract void set(PreparedStatement stmt) throws SQLException; + } + + + private class UUIDPair { + + public final int id; + public final UUID uuid; + + public UUIDPair(int id, UUID uuid) { + this.id = id; + this.uuid = uuid; + } + } + + + private class SettingsPair { + + public final int id; + public final PlotSettings settings; + + public SettingsPair(int id, PlotSettings settings) { + this.id = id; + this.settings = settings; + } + } } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/SQLite.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/SQLite.java index 3675ad0cd..d42b1d67b 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/SQLite.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/database/SQLite.java @@ -9,7 +9,7 @@ import java.sql.*; /** * Connects to and uses a SQLite database. */ -public class SQLite extends Database { +public class SQLite implements Database { private final String dbLocation; private Connection connection; diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/FlagManager.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/FlagManager.java index 06be89e15..2c0746d13 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/FlagManager.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/FlagManager.java @@ -114,6 +114,7 @@ public class FlagManager { * @param flag * @return */ + @SuppressWarnings("deprecation") public static V getPlotFlagRaw(Plot plot, Flag flag) { if (plot.owner == null) { return null; @@ -141,13 +142,6 @@ public class FlagManager { return true; } - public static boolean addClusterFlag(PlotCluster cluster, Flag flag, V value) { - getSettingFlag(cluster.area, cluster.settings, flag); - cluster.settings.flags.put(flag, value); - DBFunc.setFlags(cluster, cluster.settings.flags); - return true; - } - /** * Returns a map of the {@link Flag}s and their values for the specified plot. * @@ -217,20 +211,6 @@ public class FlagManager { return true; } - public static boolean removeClusterFlag(PlotCluster cluster, Flag id) { - Object object = cluster.settings.flags.remove(id); - if (object == null) { - return false; - } - boolean result = EventUtil.manager.callFlagRemove(id, object, cluster); - if (!result) { - cluster.settings.flags.put(id, object); - return false; - } - DBFunc.setFlags(cluster, cluster.settings.flags); - return true; - } - public static void setPlotFlags(Plot origin, HashMap, Object> flags) { for (Plot plot : origin.getConnectedPlots()) { if (flags != null && !flags.isEmpty()) { @@ -248,20 +228,6 @@ public class FlagManager { } } - public static void setClusterFlags(PlotCluster cluster, Set flags) { - if (flags != null && !flags.isEmpty()) { - cluster.settings.flags.clear(); - for (Flag flag : flags) { - cluster.settings.flags.put(flag, flag); - } - } else if (cluster.settings.flags.isEmpty()) { - return; - } else { - cluster.settings.flags.clear(); - } - DBFunc.setFlags(cluster, cluster.settings.flags); - } - /** * Get a list of registered {@link Flag} objects based on player permissions. * diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotWorld.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotWorld.java index 0a722b4d6..5466df8bc 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotWorld.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotWorld.java @@ -277,11 +277,7 @@ public class HybridPlotWorld extends ClassicPlotWorld { id = rotate(id); } int pair = MathMan.pair(x, z); - BaseBlock[] existing = this.G_SCH.get(pair); - if (existing == null) { - existing = new BaseBlock[height]; - this.G_SCH.put(pair, existing); - } + BaseBlock[] existing = this.G_SCH.computeIfAbsent(pair, k -> new BaseBlock[height]); existing[y] = id; } } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/logger/ILogger.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/logger/ILogger.java index 16fb343bf..3a4645cac 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/logger/ILogger.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/logger/ILogger.java @@ -1,5 +1,6 @@ package com.github.intellectualsites.plotsquared.plot.logger; +@FunctionalInterface public interface ILogger { void log(String message); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Expression.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Expression.java index bb466c082..1214a2769 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Expression.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Expression.java @@ -4,9 +4,12 @@ import com.github.intellectualsites.plotsquared.plot.PlotSquared; import com.github.intellectualsites.plotsquared.plot.commands.DebugExec; import com.github.intellectualsites.plotsquared.plot.commands.MainCommand; +import javax.annotation.Nonnull; import javax.script.ScriptException; public abstract class Expression { + + @Nonnull public static Expression constant(final U value) { return new Expression() { @Override public U evaluate(U arg) { diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Plot.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Plot.java index 83af645cf..5a6f1c2ba 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Plot.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Plot.java @@ -20,6 +20,7 @@ import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableSet; import com.sk89q.jnbt.CompoundTag; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.awt.geom.Area; import java.awt.geom.PathIterator; @@ -32,2971 +33,2880 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; /** - * The plot class
- * [IMPORTANT] - * - Unclaimed plots will not have persistent information. - * - Any information set/modified in an unclaimed object may not be reflected in other instances - * - Using the `new` operator will create an unclaimed plot instance - * - Use the methods from the PlotArea/PS/Location etc to get existing plots + * The plot class
[IMPORTANT] - Unclaimed plots will not have persistent information. - Any + * information set/modified in an unclaimed object may not be reflected in other instances - Using + * the `new` operator will create an unclaimed plot instance - Use the methods from the + * PlotArea/PS/Location etc to get existing plots */ public class Plot { - /** - * @deprecated raw access is deprecated - */ - @Deprecated private static HashSet connected_cache; - private static HashSet regions_cache; - /** - * The {@link PlotId}. - */ - private final PlotId id; - /** - * plot owner - * (Merged plots can have multiple owners) - * Direct access is Deprecated: use getOwners() - */ - @Deprecated public UUID owner; - /** - * Has the plot changed since the last save cycle? - */ - public boolean countsTowardsMax = true; - /** - * Represents whatever the database manager needs it to:
- * - A value of -1 usually indicates the plot will not be stored in the DB
- * - A value of 0 usually indicates that the DB manager hasn't set a value
- * - * @deprecated magical - */ - @Deprecated public int temp; - /** - * Plot creation timestamp (not accurate if the plot was created before this was implemented)
- * - Milliseconds since the epoch
- */ - private long timestamp; - /** - * List of trusted (with plot permissions). - */ - private HashSet trusted; - /** - * List of members users (with plot permissions). - */ - private HashSet members; - /** - * List of denied players. - */ - private HashSet denied; - /** - * External settings class. - * - Please favor the methods over direct access to this class
- * - The methods are more likely to be left unchanged from version changes
- */ - private PlotSettings settings; - /** - * The {@link PlotArea}. - */ - private PlotArea area; - /** - * Session only plot metadata (session is until the server stops)
- *
- * For persistent metadata use the flag system - * - * @see FlagManager - */ - private ConcurrentHashMap meta; - /** - * The cached origin plot. - * - The origin plot is used for plot grouping and relational data - */ - private Plot origin; + /** + * @deprecated raw access is deprecated + */ + @Deprecated + private static HashSet connected_cache; + private static HashSet regions_cache; + /** + * The {@link PlotId}. + */ + private final PlotId id; + /** + * plot owner (Merged plots can have multiple owners) Direct access is Deprecated: use + * getOwners() + */ + @Deprecated + public UUID owner; + /** + * Has the plot changed since the last save cycle? + */ + public boolean countsTowardsMax = true; + /** + * Represents whatever the database manager needs it to:
- A value of -1 usually indicates + * the plot will not be stored in the DB
- A value of 0 usually indicates that the DB manager + * hasn't set a value
+ * + * @deprecated magical + */ + @Deprecated + public int temp; + /** + * Plot creation timestamp (not accurate if the plot was created before this was implemented)
+ * - Milliseconds since the epoch
+ */ + private long timestamp; + /** + * List of trusted (with plot permissions). + */ + private HashSet trusted; + /** + * List of members users (with plot permissions). + */ + private HashSet members; + /** + * List of denied players. + */ + private HashSet denied; + /** + * External settings class. - Please favor the methods over direct access to this class
- The + * methods are more likely to be left unchanged from version changes
+ */ + private PlotSettings settings; + /** + * The {@link PlotArea}. + */ + @Nonnull + private PlotArea area; + /** + * Session only plot metadata (session is until the server stops)
+ *
+ * For persistent metadata use the flag system + * + * @see FlagManager + */ + private ConcurrentHashMap meta; + /** + * The cached origin plot. - The origin plot is used for plot grouping and relational data + */ + private Plot origin; - /** - * Constructor for a new plot. - * (Only changes after plot.create() will be properly set in the database) - * - * @param area the PlotArea where the plot is located - * @param id the plot id - * @param owner the plot owner - * @see Plot#getPlot(Location) for existing plots - */ - public Plot(PlotArea area, PlotId id, UUID owner) { - this.area = area; - this.id = id; - this.owner = owner; + /** + * Constructor for a new plot. (Only changes after plot.create() will be properly set in the + * database) + * + * @param area the PlotArea where the plot is located + * @param id the plot id + * @param owner the plot owner + * @see Plot#getPlot(Location) for existing plots + */ + public Plot(@Nonnull PlotArea area, PlotId id, UUID owner) { + this.area = area; + this.id = id; + this.owner = owner; + } + + /** + * Constructor for an unowned plot. (Only changes after plot.create() will be properly set in the + * database) + * + * @param area the PlotArea where the plot is located + * @param id the plot id + * @see Plot#getPlot(Location) for existing plots + */ + public Plot(@Nonnull PlotArea area, PlotId id) { + this.area = area; + this.id = id; + } + + /** + * Constructor for a temporary plot (use -1 for temp)
The database will ignore any queries + * regarding temporary plots. Please note that some bulk plot management functions may still + * affect temporary plots (TODO: fix this) + * + * @param area the PlotArea where the plot is located + * @param id the plot id + * @param owner the owner of the plot + * @param temp Represents whatever the database manager needs it to + * @see Plot#getPlot(Location) for existing plots + */ + public Plot(@Nonnull PlotArea area, PlotId id, UUID owner, int temp) { + this.area = area; + this.id = id; + this.owner = owner; + this.temp = temp; + } + + /** + * Constructor for a saved plots (Used by the database manager when plots are fetched) + * + * @param id the plot id + * @param owner the plot owner + * @param trusted the plot trusted players + * @param denied the plot denied players + * @param merged array giving merged plots + * @see Plot#getPlot(Location) for existing plots + */ + public Plot(PlotId id, UUID owner, HashSet trusted, HashSet members, + HashSet denied, String alias, BlockLoc position, Collection flags, + @Nonnull PlotArea area, boolean[] merged, long timestamp, int temp) { + this.id = id; + this.area = area; + this.owner = owner; + this.settings = new PlotSettings(); + this.members = members; + this.trusted = trusted; + this.denied = denied; + this.settings.setAlias(alias); + this.settings.setPosition(position); + this.settings.setMerged(merged); + if (flags != null) { + for (Flag flag : flags) { + this.settings.flags.put(flag, flag); + } } + this.timestamp = timestamp; + this.temp = temp; + } - /** - * Constructor for an unowned plot. - * (Only changes after plot.create() will be properly set in the database) - * - * @param area the PlotArea where the plot is located - * @param id the plot id - * @see Plot#getPlot(Location) for existing plots - */ - public Plot(PlotArea area, PlotId id) { - this.area = area; - this.id = id; + /** + * Get a plot from a string e.g. [area];[id] + * + * @param defaultArea If no area is specified + * @param string plot id/area + id + * @return New or existing plot object + */ + public static Plot fromString(PlotArea defaultArea, String string) { + String[] split = string.split(";|,"); + if (split.length == 2) { + if (defaultArea != null) { + PlotId id = PlotId.fromString(split[0] + ';' + split[1]); + return id != null ? defaultArea.getPlotAbs(id) : null; + } + } else if (split.length == 3) { + PlotArea pa = PlotSquared.get().getPlotArea(split[0], null); + if (pa != null) { + PlotId id = PlotId.fromString(split[1] + ';' + split[2]); + return pa.getPlotAbs(id); + } + } else if (split.length == 4) { + PlotArea pa = PlotSquared.get().getPlotArea(split[0], split[1]); + if (pa != null) { + PlotId id = PlotId.fromString(split[1] + ';' + split[2]); + return pa.getPlotAbs(id); + } } + return null; + } - /** - * Constructor for a temporary plot (use -1 for temp)
- * The database will ignore any queries regarding temporary plots. - * Please note that some bulk plot management functions may still affect temporary plots (TODO: fix this) - * - * @param area the PlotArea where the plot is located - * @param id the plot id - * @param owner the owner of the plot - * @param temp Represents whatever the database manager needs it to - * @see Plot#getPlot(Location) for existing plots - */ - public Plot(PlotArea area, PlotId id, UUID owner, int temp) { - this.area = area; - this.id = id; - this.owner = owner; - this.temp = temp; + /** + * Return a new/cached plot object at a given location. + * + * @param location the location of the plot + * @return plot at location or null + * @see PlotPlayer#getCurrentPlot() if a player is expected here. + */ + public static Plot getPlot(Location location) { + PlotArea pa = PlotSquared.get().getPlotAreaAbs(location); + if (pa != null) { + return pa.getPlot(location); } + return null; + } - /** - * Constructor for a saved plots (Used by the database manager when plots are fetched) - * - * @param id the plot id - * @param owner the plot owner - * @param trusted the plot trusted players - * @param denied the plot denied players - * @param merged array giving merged plots - * @see Plot#getPlot(Location) for existing plots - */ - public Plot(PlotId id, UUID owner, HashSet trusted, HashSet members, - HashSet denied, String alias, BlockLoc position, Collection flags, - PlotArea area, boolean[] merged, long timestamp, int temp) { - this.id = id; - this.area = area; - this.owner = owner; - this.settings = new PlotSettings(); - this.members = members; - this.trusted = trusted; - this.denied = denied; - this.settings.setAlias(alias); - this.settings.setPosition(position); - this.settings.setMerged(merged); - if (flags != null) { - for (Flag flag : flags) { - this.settings.flags.put(flag, flag); - } + public String getWorldName() { + return area.worldname; + } + + /** + * Session only plot metadata (session is until the server stops)
+ *
+ * For persistent metadata use the flag system + * + * @param key metadata key + * @param value metadata value + * @see FlagManager + */ + public void setMeta(String key, Object value) { + if (this.meta == null) { + this.meta = new ConcurrentHashMap<>(); + } + this.meta.put(key, value); + } + + /** + * Get the metadata for a key
+ *
+ * For persistent metadata use the flag system + * + * @param key metadata key to get value for + * @return Object value + */ + public Object getMeta(String key) { + if (this.meta != null) { + return this.meta.get(key); + } + return null; + } + + /** + * Delete the metadata for a key
- metadata is session only - deleting other plugin's metadata + * may cause issues + * + * @param key key to delete + */ + public void deleteMeta(String key) { + if (this.meta != null) { + this.meta.remove(key); + } + } + + /** + * Get the cluster this plot is associated with + * + * @return the PlotCluster object, or null + */ + public PlotCluster getCluster() { + return this.getArea().getCluster(this.id); + } + + /** + * Efficiently get the players currently inside this plot
- Will return an empty list if no + * players are in the plot
- Remember, you can cast a PlotPlayer to it's respective + * implementation (BukkitPlayer, SpongePlayer) to obtain the player object + * + * @return list of PlotPlayer(s) or an empty list + */ + public List getPlayersInPlot() { + ArrayList players = new ArrayList<>(); + for (Entry entry : UUIDHandler.getPlayers().entrySet()) { + PlotPlayer pp = entry.getValue(); + if (this.equals(pp.getCurrentPlot())) { + players.add(pp); + } + } + return players; + } + + /** + * Check if the plot has an owner. + * + * @return false if there is no owner + */ + public boolean hasOwner() { + return this.owner != null; + } + + /** + * Check if a UUID is a plot owner (merged plots may have multiple owners) + * + * @param uuid the player uuid + * @return if the provided uuid is the owner of the plot + */ + public boolean isOwner(UUID uuid) { + if (uuid.equals(this.owner)) { + return true; + } + if (!isMerged()) { + return false; + } + Set connected = getConnectedPlots(); + for (Plot current : connected) { + if (uuid.equals(current.owner)) { + return true; + } + } + return false; + } + + public boolean isOwnerAbs(UUID uuid) { + return uuid.equals(this.owner); + } + + /** + * Get a immutable set of owner UUIDs for a plot (supports multi-owner mega-plots). + * + * @return the plot owners + */ + public Set getOwners() { + if (this.owner == null) { + return ImmutableSet.of(); + } + if (isMerged()) { + Set plots = getConnectedPlots(); + Plot[] array = plots.toArray(new Plot[0]); + ImmutableSet.Builder owners = ImmutableSet.builder(); + UUID last = this.owner; + owners.add(this.owner); + for (Plot current : array) { + if (last == null || current.owner.getMostSignificantBits() != last + .getMostSignificantBits()) { + owners.add(current.owner); + last = current.owner; } - this.timestamp = timestamp; - this.temp = temp; + } + return owners.build(); } + return ImmutableSet.of(this.owner); + } - /** - * Get a plot from a string e.g. [area];[id] - * - * @param defaultArea If no area is specified - * @param string plot id/area + id - * @return New or existing plot object - */ - public static Plot fromString(PlotArea defaultArea, String string) { - String[] split = string.split(";|,"); - if (split.length == 2) { - if (defaultArea != null) { - PlotId id = PlotId.fromString(split[0] + ';' + split[1]); - return id != null ? defaultArea.getPlotAbs(id) : null; - } - } else if (split.length == 3) { - PlotArea pa = PlotSquared.get().getPlotArea(split[0], null); - if (pa != null) { - PlotId id = PlotId.fromString(split[1] + ';' + split[2]); - return pa.getPlotAbs(id); - } - } else if (split.length == 4) { - PlotArea pa = PlotSquared.get().getPlotArea(split[0], split[1]); - if (pa != null) { - PlotId id = PlotId.fromString(split[1] + ';' + split[2]); - return pa.getPlotAbs(id); - } - } - return null; + /** + * Check if the player is either the owner or on the trusted/added list. + * + * @param uuid uuid to check + * @return true if the player is added/trusted or is the owner + */ + public boolean isAdded(UUID uuid) { + if (this.owner == null || getDenied().contains(uuid)) { + return false; } - - /** - * Return a new/cached plot object at a given location. - * - * @param location the location of the plot - * @return plot at location or null - * @see PlotPlayer#getCurrentPlot() if a player is expected here. - */ - public static Plot getPlot(Location location) { - PlotArea pa = PlotSquared.get().getPlotAreaAbs(location); - if (pa != null) { - return pa.getPlot(location); - } - return null; + if (isOwner(uuid)) { + return true; } - - public String getWorldName() { - return area.worldname; + if (getMembers().contains(uuid)) { + return isOnline(); } - - /** - * Session only plot metadata (session is until the server stops)
- *
- * For persistent metadata use the flag system - * - * @param key metadata key - * @param value metadata value - * @see FlagManager - */ - public void setMeta(String key, Object value) { - if (this.meta == null) { - this.meta = new ConcurrentHashMap<>(); - } - this.meta.put(key, value); + if (getTrusted().contains(uuid) || getTrusted().contains(DBFunc.EVERYONE)) { + return true; } - - /** - * Get the metadata for a key
- *
- * For persistent metadata use the flag system - * - * @param key metadata key to get value for - * @return Object value - */ - public Object getMeta(String key) { - if (this.meta != null) { - return this.meta.get(key); - } - return null; + if (getMembers().contains(DBFunc.EVERYONE)) { + return isOnline(); } + return false; + } - /** - * Delete the metadata for a key
- * - metadata is session only - * - deleting other plugin's metadata may cause issues - * - * @param key key to delete - */ - public void deleteMeta(String key) { - if (this.meta != null) { - this.meta.remove(key); - } + /** + * Should the player be denied from entering. + * + * @param uuid uuid to check + * @return boolean false if the player is allowed to enter + */ + public boolean isDenied(UUID uuid) { + return this.denied != null && (this.denied.contains(DBFunc.EVERYONE) && !this.isAdded(uuid) + || !this.isAdded(uuid) && this.denied.contains(uuid)); + } + + /** + * Get the {@link PlotId}. + */ + @Nonnull + public PlotId getId() { + return this.id; + } + + /** + * Get the plot world object for this plot
- The generic PlotArea object can be casted to its + * respective class for more control (e.g. HybridPlotWorld) + * + * @return PlotArea + */ + @Nonnull + public PlotArea getArea() { + return this.area; + } + + /** + * Assign this plot to a plot area.
(Mostly used during startup when worlds are being + * created)
Note: Using this when it doesn't make sense will result in strange behavior + * + * @param area area to assign to + */ + public void setArea(@Nonnull PlotArea area) { + if (this.getArea() == area) { + return; } + this.area.removePlot(this.id); + this.area = area; + area.addPlot(this); + } - /** - * Get the cluster this plot is associated with - * - * @return the PlotCluster object, or null - */ - public PlotCluster getCluster() { - return this.getArea().getCluster(this.id); + /** + * Get the plot manager object for this plot
- The generic PlotManager object can be casted to + * its respective class for more control (e.g. HybridPlotManager) + * + * @return PlotManager + */ + public PlotManager getManager() { + return this.area.getPlotManager(); + } + + /** + * Get or create plot settings. + * + * @return PlotSettings + * @deprecated use equivalent plot method; + */ + @Deprecated + @Nonnull + public PlotSettings getSettings() { + if (this.settings == null) { + this.settings = new PlotSettings(); } + return this.settings; + } - /** - * Efficiently get the players currently inside this plot
- * - Will return an empty list if no players are in the plot
- * - Remember, you can cast a PlotPlayer to it's respective implementation (BukkitPlayer, SpongePlayer) to obtain the player object - * - * @return list of PlotPlayer(s) or an empty list - */ - public List getPlayersInPlot() { - ArrayList players = new ArrayList<>(); - for (Entry entry : UUIDHandler.getPlayers().entrySet()) { - PlotPlayer pp = entry.getValue(); - if (this.equals(pp.getCurrentPlot())) { - players.add(pp); - } - } - return players; + /** + * Returns true if the plot is not merged, or it is the base plot of multiple merged plots. + * + * @return Boolean + */ + public boolean isBasePlot() { + return !this.isMerged() || this.equals(this.getBasePlot(false)); + } + + /** + * The base plot is an arbitrary but specific connected plot. It is useful for the following:
+ * - Merged plots need to be treated as a single plot for most purposes
- Some data such as + * home location needs to be associated with the group rather than each plot
- If the plot is + * not merged it will return itself.
- The result is cached locally + * + * @return base Plot + */ + public Plot getBasePlot(boolean recalculate) { + if (this.origin != null && !recalculate) { + if (this.equals(this.origin)) { + return this; + } + return this.origin.getBasePlot(false); } - - /** - * Check if the plot has an owner. - * - * @return false if there is no owner - */ - public boolean hasOwner() { - return this.owner != null; + if (!this.isMerged()) { + this.origin = this; + return this.origin; } + this.origin = this; + PlotId min = this.id; + for (Plot plot : this.getConnectedPlots()) { + if (plot.id.y < min.y || plot.id.y == min.y && plot.id.x < min.x) { + this.origin = plot; + min = plot.id; + } + } + for (Plot plot : this.getConnectedPlots()) { + plot.origin = this.origin; + } + return this.origin; + } - /** - * Check if a UUID is a plot owner (merged plots may have multiple owners) - * - * @param uuid the player uuid - * @return if the provided uuid is the owner of the plot - */ - public boolean isOwner(UUID uuid) { - if (uuid.equals(this.owner)) { - return true; - } - if (!isMerged()) { - return false; - } - Set connected = getConnectedPlots(); - for (Plot current : connected) { - if (uuid.equals(current.owner)) { + /** + * Check if the plot is merged in any direction. + * + * @return is the plot merged or not + */ + public boolean isMerged() { + return getSettings().getMerged(0) || getSettings().getMerged(2) || getSettings() + .getMerged(1) || getSettings().getMerged(3); + } + + /** + * Get the timestamp of when the plot was created (unreliable)
- not accurate if the plot was + * created before this was implemented
- Milliseconds since the epoch
+ * + * @return the creation date of the plot + */ + public long getTimestamp() { + if (this.timestamp == 0) { + this.timestamp = System.currentTimeMillis(); + } + return this.timestamp; + } + + /** + * Get if the plot is merged in a direction
------- Actual -------
0 = north
1 = + * east
2 = south
3 = west
----- Artificial -----
4 = north-east
5 = + * south-east
6 = south-west
7 = north-west
----------
Note: A plot that is merged + * north and east will not be merged northeast if the northeast plot is not part of the same + * group
+ * + * @param direction direction to check for merged plot + * @return true if merged in that direction + */ + public boolean getMerged(int direction) { + if (this.settings == null) { + return false; + } + switch (direction) { + case 0: + case 1: + case 2: + case 3: + return this.getSettings().getMerged(direction); + case 7: + int i = direction - 4; + int i2 = 0; + if (this.getSettings().getMerged(i2)) { + if (this.getSettings().getMerged(i)) { + if (this.area.getPlotAbs(this.id.getRelative(i)).getMerged(i2)) { + if (this.area.getPlotAbs(this.id.getRelative(i2)).getMerged(i)) { return true; + } } + } } return false; - } + case 4: + case 5: + case 6: + i = direction - 4; + i2 = direction - 3; + return this.getSettings().getMerged(i2) && this.getSettings().getMerged(i) + && this.area.getPlotAbs(this.id.getRelative(i)).getMerged(i2) && this.area + .getPlotAbs(this.id.getRelative(i2)).getMerged(i); - public boolean isOwnerAbs(UUID uuid) { - return uuid.equals(this.owner); } + return false; + } - /** - * Get a immutable set of owner UUIDs for a plot (supports multi-owner mega-plots). - * - * @return the plot owners - */ - public Set getOwners() { - if (this.owner == null) { - return ImmutableSet.of(); - } - if (isMerged()) { - Set plots = getConnectedPlots(); - Plot[] array = plots.toArray(new Plot[plots.size()]); - ImmutableSet.Builder owners = ImmutableSet.builder(); - UUID last = this.owner; - owners.add(this.owner); - for (Plot current : array) { - if (last == null || current.owner.getMostSignificantBits() != last - .getMostSignificantBits()) { - owners.add(current.owner); - last = current.owner; - } - } - return owners.build(); - } - return ImmutableSet.of(this.owner); + /** + * Get the denied users. + * + * @return a set of denied users + */ + public HashSet getDenied() { + if (this.denied == null) { + this.denied = new HashSet<>(); } + return this.denied; + } - /** - * Check if the player is either the owner or on the trusted/added list. - * - * @param uuid uuid to check - * @return true if the player is added/trusted or is the owner - */ - public boolean isAdded(UUID uuid) { - if (this.owner == null || getDenied().contains(uuid)) { - return false; - } - if (isOwner(uuid)) { - return true; - } - if (getMembers().contains(uuid)) { - return isOnline(); - } - if (getTrusted().contains(uuid) || getTrusted().contains(DBFunc.EVERYONE)) { - return true; - } - if (getMembers().contains(DBFunc.EVERYONE)) { - return isOnline(); - } + /** + * Set the denied users for this plot. + * + * @param uuids uuids to deny + */ + public void setDenied(Set uuids) { + boolean larger = uuids.size() > getDenied().size(); + HashSet intersection = new HashSet<>(larger ? getDenied() : uuids); + intersection.retainAll(larger ? uuids : getDenied()); + uuids.removeAll(intersection); + HashSet toRemove = new HashSet<>(getDenied()); + toRemove.removeAll(intersection); + for (UUID uuid : toRemove) { + removeDenied(uuid); + } + for (UUID uuid : uuids) { + addDenied(uuid); + } + } + + /** + * Get the trusted users. + * + * @return a set of trusted users + */ + public HashSet getTrusted() { + if (this.trusted == null) { + this.trusted = new HashSet<>(); + } + return this.trusted; + } + + /** + * Set the trusted users for this plot. + * + * @param uuids uuids to trust + */ + public void setTrusted(Set uuids) { + boolean larger = uuids.size() > getTrusted().size(); + HashSet intersection = new HashSet<>(larger ? getTrusted() : uuids); + intersection.retainAll(larger ? uuids : getTrusted()); + uuids.removeAll(intersection); + HashSet toRemove = new HashSet<>(getTrusted()); + toRemove.removeAll(intersection); + for (UUID uuid : toRemove) { + removeTrusted(uuid); + } + for (UUID uuid : uuids) { + addTrusted(uuid); + } + } + + /** + * Get the members + * + * @return a set of members + */ + public HashSet getMembers() { + if (this.members == null) { + this.members = new HashSet<>(); + } + return this.members; + } + + /** + * Set the members for this plot + * + * @param uuids uuids to set member status for + */ + public void setMembers(Set uuids) { + boolean larger = uuids.size() > getMembers().size(); + HashSet intersection = new HashSet<>(larger ? getMembers() : uuids); + intersection.retainAll(larger ? uuids : getMembers()); + uuids.removeAll(intersection); + HashSet toRemove = new HashSet<>(getMembers()); + toRemove.removeAll(intersection); + for (UUID uuid : toRemove) { + removeMember(uuid); + } + for (UUID uuid : uuids) { + addMember(uuid); + } + } + + /** + * Deny someone (updates database as well) + * + * @param uuid the uuid of the player to deny. + */ + public void addDenied(UUID uuid) { + for (Plot current : getConnectedPlots()) { + if (current.getDenied().add(uuid)) { + DBFunc.setDenied(current, uuid); + } + } + } + + /** + * Add someone as a helper (updates database as well) + * + * @param uuid the uuid of the player to trust + */ + public void addTrusted(UUID uuid) { + for (Plot current : getConnectedPlots()) { + if (current.getTrusted().add(uuid)) { + DBFunc.setTrusted(current, uuid); + } + } + } + + /** + * Add someone as a trusted user (updates database as well) + * + * @param uuid the uuid of the player to add as a member + */ + public void addMember(UUID uuid) { + for (Plot current : getConnectedPlots()) { + if (current.getMembers().add(uuid)) { + DBFunc.setMember(current, uuid); + } + } + } + + /** + * Set the plot owner (and update the database) + * + * @param owner uuid to set as owner + */ + public void setOwner(UUID owner) { + if (!hasOwner()) { + this.owner = owner; + create(); + return; + } + if (!isMerged()) { + if (!this.owner.equals(owner)) { + this.owner = owner; + DBFunc.setOwner(this, owner); + } + return; + } + for (Plot current : getConnectedPlots()) { + if (!owner.equals(current.owner)) { + current.owner = owner; + DBFunc.setOwner(current, owner); + } + } + } + + /** + * Set the plot owner (and update the database) + * + * @param owner uuid to set as owner + * @param initiator player initiating set owner + * @return boolean + */ + public boolean setOwner(UUID owner, PlotPlayer initiator) { + boolean result = EventUtil.manager + .callOwnerChange(initiator, this, owner, hasOwner() ? this.owner : null, hasOwner()); + if (!result) { + return false; + } + if (!hasOwner()) { + this.owner = owner; + create(); + return true; + } + if (!isMerged()) { + if (!this.owner.equals(owner)) { + this.owner = owner; + DBFunc.setOwner(this, owner); + } + return true; + } + for (Plot current : getConnectedPlots()) { + if (!owner.equals(current.owner)) { + current.owner = owner; + DBFunc.setOwner(current, owner); + } + } + return true; + } + + /** + * Clear a plot. + * + * @param whenDone A runnable to execute when clearing finishes, or null + * @see this#clear(boolean, boolean, Runnable) + * @see #deletePlot(Runnable) to clear and delete a plot + */ + public void clear(Runnable whenDone) { + this.clear(false, false, whenDone); + } + + public boolean clear(boolean checkRunning, final boolean isDelete, final Runnable whenDone) { + if (checkRunning && this.getRunning() != 0) { + return false; + } + if (isDelete) { + if (!EventUtil.manager.callDelete(this)) { return false; - } - - /** - * Should the player be denied from entering. - * - * @param uuid uuid to check - * @return boolean false if the player is allowed to enter - */ - public boolean isDenied(UUID uuid) { - return this.denied != null && (this.denied.contains(DBFunc.EVERYONE) && !this.isAdded(uuid) - || !this.isAdded(uuid) && this.denied.contains(uuid)); - } - - /** - * Get the {@link PlotId}. - */ - public PlotId getId() { - return this.id; - } - - /** - * Get the plot world object for this plot
- * - The generic PlotArea object can be casted to its respective class for more control (e.g. HybridPlotWorld) - * - * @return PlotArea - */ - public PlotArea getArea() { - return this.area; - } - - /** - * Assign this plot to a plot area.
- * (Mostly used during startup when worlds are being created)
- * Note: Using this when it doesn't make sense will result in strange behavior - * - * @param area area to assign to - */ - public void setArea(PlotArea area) { - if (this.getArea() == area) { - return; - } - if (this.getArea() != null) { - this.area.removePlot(this.id); - } - this.area = area; - area.addPlot(this); - } - - /** - * Get the plot manager object for this plot
- * - The generic PlotManager object can be casted to its respective class for more control (e.g. HybridPlotManager) - * - * @return PlotManager - */ - public PlotManager getManager() { - return this.area.getPlotManager(); - } - - /** - * Get or create plot settings. - * - * @return PlotSettings - * @deprecated use equivalent plot method; - */ - @Deprecated public PlotSettings getSettings() { - if (this.settings == null) { - this.settings = new PlotSettings(); - } - return this.settings; - } - - /** - * Returns true if the plot is not merged, or it is the base - * plot of multiple merged plots. - * - * @return Boolean - */ - public boolean isBasePlot() { - return !this.isMerged() || this.equals(this.getBasePlot(false)); - } - - /** - * The base plot is an arbitrary but specific connected plot. It is useful for the following:
- * - Merged plots need to be treated as a single plot for most purposes
- * - Some data such as home location needs to be associated with the group rather than each plot
- * - If the plot is not merged it will return itself.
- * - The result is cached locally - * - * @return base Plot - */ - public Plot getBasePlot(boolean recalculate) { - if (this.origin != null && !recalculate) { - if (this.equals(this.origin)) { - return this; - } - return this.origin.getBasePlot(false); - } - if (!this.isMerged()) { - this.origin = this; - return this.origin; - } - this.origin = this; - PlotId min = this.id; - for (Plot plot : this.getConnectedPlots()) { - if (plot.id.y < min.y || plot.id.y == min.y && plot.id.x < min.x) { - this.origin = plot; - min = plot.id; - } - } - for (Plot plot : this.getConnectedPlots()) { - plot.origin = this.origin; - } - return this.origin; - } - - /** - * Check if the plot is merged in any direction. - * - * @return is the plot merged or not - */ - public boolean isMerged() { - return getSettings().getMerged(0) || getSettings().getMerged(2) || getSettings() - .getMerged(1) || getSettings().getMerged(3); - } - - /** - * Get the timestamp of when the plot was created (unreliable)
- * - not accurate if the plot was created before this was implemented
- * - Milliseconds since the epoch
- * - * @return the creation date of the plot - */ - public long getTimestamp() { - if (this.timestamp == 0) { - this.timestamp = System.currentTimeMillis(); - } - return this.timestamp; - } - - /** - * Get if the plot is merged in a direction
- * ------- Actual -------
- * 0 = north
- * 1 = east
- * 2 = south
- * 3 = west
- * ----- Artificial -----
- * 4 = north-east
- * 5 = south-east
- * 6 = south-west
- * 7 = north-west
- * ----------
- * Note: A plot that is merged north and east will not be merged northeast if the northeast plot is not part of the same group
- * - * @param direction direction to check for merged plot - * @return true if merged in that direction - */ - public boolean getMerged(int direction) { - if (this.settings == null) { - return false; - } - switch (direction) { - case 0: - case 1: - case 2: - case 3: - return this.getSettings().getMerged(direction); - case 7: - int i = direction - 4; - int i2 = 0; - if (this.getSettings().getMerged(i2)) { - if (this.getSettings().getMerged(i)) { - if (this.area.getPlotAbs(this.id.getRelative(i)).getMerged(i2)) { - if (this.area.getPlotAbs(this.id.getRelative(i2)).getMerged(i)) { - return true; - } - } - } - } - return false; - case 4: - case 5: - case 6: - i = direction - 4; - i2 = direction - 3; - return this.getSettings().getMerged(i2) && this.getSettings().getMerged(i) - && this.area.getPlotAbs(this.id.getRelative(i)).getMerged(i2) && this.area - .getPlotAbs(this.id.getRelative(i2)).getMerged(i); - - } + } + } else { + if (!EventUtil.manager.callClear(this)) { return false; + } } - - /** - * Get the denied users. - * - * @return a set of denied users - */ - public HashSet getDenied() { - if (this.denied == null) { - this.denied = new HashSet<>(); - } - return this.denied; + final HashSet regions = this.getRegions(); + final Set plots = this.getConnectedPlots(); + final ArrayDeque queue = new ArrayDeque<>(plots); + if (isDelete) { + this.removeSign(); } - - /** - * Set the denied users for this plot. - * - * @param uuids uuids to deny - */ - public void setDenied(Set uuids) { - boolean larger = uuids.size() > getDenied().size(); - HashSet intersection = new HashSet<>(larger ? getDenied() : uuids); - intersection.retainAll(larger ? uuids : getDenied()); - uuids.removeAll(intersection); - HashSet toRemove = new HashSet<>(getDenied()); - toRemove.removeAll(intersection); - for (UUID uuid : toRemove) { - removeDenied(uuid); - } - for (UUID uuid : uuids) { - addDenied(uuid); - } - } - - /** - * Get the trusted users. - * - * @return a set of trusted users - */ - public HashSet getTrusted() { - if (this.trusted == null) { - this.trusted = new HashSet<>(); - } - return this.trusted; - } - - /** - * Set the trusted users for this plot. - * - * @param uuids uuids to trust - */ - public void setTrusted(Set uuids) { - boolean larger = uuids.size() > getTrusted().size(); - HashSet intersection = new HashSet<>(larger ? getTrusted() : uuids); - intersection.retainAll(larger ? uuids : getTrusted()); - uuids.removeAll(intersection); - HashSet toRemove = new HashSet<>(getTrusted()); - toRemove.removeAll(intersection); - for (UUID uuid : toRemove) { - removeTrusted(uuid); - } - for (UUID uuid : uuids) { - addTrusted(uuid); - } - } - - /** - * Get the members - * - * @return a set of members - */ - public HashSet getMembers() { - if (this.members == null) { - this.members = new HashSet<>(); - } - return this.members; - } - - /** - * Set the members for this plot - * - * @param uuids uuids to set member status for - */ - public void setMembers(Set uuids) { - boolean larger = uuids.size() > getMembers().size(); - HashSet intersection = new HashSet<>(larger ? getMembers() : uuids); - intersection.retainAll(larger ? uuids : getMembers()); - uuids.removeAll(intersection); - HashSet toRemove = new HashSet<>(getMembers()); - toRemove.removeAll(intersection); - for (UUID uuid : toRemove) { - removeMember(uuid); - } - for (UUID uuid : uuids) { - addMember(uuid); - } - } - - /** - * Deny someone (updates database as well) - * - * @param uuid the uuid of the player to deny. - */ - public void addDenied(UUID uuid) { - for (Plot current : getConnectedPlots()) { - if (current.getDenied().add(uuid)) { - DBFunc.setDenied(current, uuid); + this.unlinkPlot(true, !isDelete); + final PlotManager manager = this.area.getPlotManager(); + Runnable run = new Runnable() { + @Override + public void run() { + if (queue.isEmpty()) { + Runnable run = () -> { + for (RegionWrapper region : regions) { + Location[] corners = region.getCorners(getWorldName()); + ChunkManager.manager.clearAllEntities(corners[0], corners[1]); } + TaskManager.runTask(whenDone); + }; + for (Plot current : plots) { + if (isDelete || current.owner == null) { + manager.unclaimPlot(Plot.this.area, current, null); + } else { + manager.claimPlot(Plot.this.area, current); + } + } + GlobalBlockQueue.IMP.addTask(run); + return; } + Plot current = queue.poll(); + if (Plot.this.area.TERRAIN != 0) { + ChunkManager.manager + .regenerateRegion(current.getBottomAbs(), current.getTopAbs(), false, this); + return; + } + manager.clearPlot(Plot.this.area, current, this); + } + }; + run.run(); + return true; + } + + /** + * Set the biome for a plot asynchronously + * + * @param biome The biome e.g. "forest" + * @param whenDone The task to run when finished, or null + */ + public void setBiome(final String biome, final Runnable whenDone) { + final ArrayDeque regions = new ArrayDeque<>(this.getRegions()); + final int extendBiome; + if (area instanceof SquarePlotWorld) { + extendBiome = (((SquarePlotWorld) area).ROAD_WIDTH > 0) ? 1 : 0; + } else { + extendBiome = 0; } - - /** - * Add someone as a helper (updates database as well) - * - * @param uuid the uuid of the player to trust - */ - public void addTrusted(UUID uuid) { - for (Plot current : getConnectedPlots()) { - if (current.getTrusted().add(uuid)) { - DBFunc.setTrusted(current, uuid); - } + Runnable run = new Runnable() { + @Override + public void run() { + if (regions.isEmpty()) { + Plot.this.refreshChunks(); + TaskManager.runTask(whenDone); + return; } + RegionWrapper region = regions.poll(); + Location pos1 = new Location(getWorldName(), region.minX - extendBiome, region.minY, + region.minZ - extendBiome); + Location pos2 = new Location(getWorldName(), region.maxX + extendBiome, region.maxY, + region.maxZ + extendBiome); + ChunkManager.chunkTask(pos1, pos2, new RunnableVal() { + @Override + public void run(int[] value) { + ChunkLoc loc = new ChunkLoc(value[0], value[1]); + ChunkManager.manager.loadChunk(getWorldName(), loc, false); + MainUtil.setBiome(getWorldName(), value[2], value[3], value[4], value[5], + biome); + ChunkManager.manager.unloadChunk(getWorldName(), loc, true, true); + } + }, this, 5); + + } + }; + run.run(); + } + + /** + * Unlink the plot and all connected plots. + * + * @param createSign whether to recreate signs + * @param createRoad whether to recreate road + * @return success/!cancelled + */ + public boolean unlinkPlot(boolean createRoad, boolean createSign) { + if (!this.isMerged()) { + return false; } - - /** - * Add someone as a trusted user (updates database as well) - * - * @param uuid the uuid of the player to add as a member - */ - public void addMember(UUID uuid) { - for (Plot current : getConnectedPlots()) { - if (current.getMembers().add(uuid)) { - DBFunc.setMember(current, uuid); - } - } + final Set plots = this.getConnectedPlots(); + ArrayList ids = new ArrayList<>(plots.size()); + for (Plot current : plots) { + current.setHome(null); + ids.add(current.getId()); } - - /** - * Set the plot owner (and update the database) - * - * @param owner uuid to set as owner - */ - public void setOwner(UUID owner) { - if (!hasOwner()) { - this.owner = owner; - create(); - return; - } - if (!isMerged()) { - if (!this.owner.equals(owner)) { - this.owner = owner; - DBFunc.setOwner(this, owner); - } - return; - } - for (Plot current : getConnectedPlots()) { - if (!owner.equals(current.owner)) { - current.owner = owner; - DBFunc.setOwner(current, owner); - } - } + boolean result = EventUtil.manager.callUnlink(this.area, ids); + if (!result) { + return false; } - - /** - * Set the plot owner (and update the database) - * - * @param owner uuid to set as owner - * @param initiator player initiating set owner - * @return boolean - */ - public boolean setOwner(UUID owner, PlotPlayer initiator) { - boolean result = EventUtil.manager - .callOwnerChange(initiator, this, owner, hasOwner() ? this.owner : null, hasOwner()); - if (!result) - return false; - if (!hasOwner()) { - this.owner = owner; - create(); - return true; - } - if (!isMerged()) { - if (!this.owner.equals(owner)) { - this.owner = owner; - DBFunc.setOwner(this, owner); - } - return true; - } - for (Plot current : getConnectedPlots()) { - if (!owner.equals(current.owner)) { - current.owner = owner; - DBFunc.setOwner(current, owner); - } - } - return true; + this.clearRatings(); + if (createSign) { + this.removeSign(); } - - /** - * Clear a plot. - * - * @param whenDone A runnable to execute when clearing finishes, or null - * @see this#clear(boolean, boolean, Runnable) - * @see #deletePlot(Runnable) to clear and delete a plot - */ - public void clear(Runnable whenDone) { - this.clear(false, false, whenDone); + PlotManager manager = this.area.getPlotManager(); + if (createRoad) { + manager.startPlotUnlink(this.area, ids); } - - public boolean clear(boolean checkRunning, final boolean isDelete, final Runnable whenDone) { - if (checkRunning && this.getRunning() != 0) { - return false; - } - if (isDelete) { - if (!EventUtil.manager.callDelete(this)) { - return false; - } - } else { - if (!EventUtil.manager.callClear(this)) { - return false; + if (this.area.TERRAIN != 3 && createRoad) { + for (Plot current : plots) { + if (current.getMerged(1)) { + manager.createRoadEast(current.area, current); + if (current.getMerged(2)) { + manager.createRoadSouth(current.area, current); + if (current.getMerged(5)) { + manager.createRoadSouthEast(current.area, current); } + } + } else if (current.getMerged(2)) { + manager.createRoadSouth(current.area, current); } - final HashSet regions = this.getRegions(); - final Set plots = this.getConnectedPlots(); - final ArrayDeque queue = new ArrayDeque<>(plots); - if (isDelete) { - this.removeSign(); - } - this.unlinkPlot(true, !isDelete); - final PlotManager manager = this.area.getPlotManager(); - Runnable run = new Runnable() { - @Override public void run() { - if (queue.isEmpty()) { - Runnable run = () -> { - for (RegionWrapper region : regions) { - Location[] corners = region.getCorners(getWorldName()); - ChunkManager.manager.clearAllEntities(corners[0], corners[1]); - } - TaskManager.runTask(whenDone); - }; - for (Plot current : plots) { - if (isDelete || current.owner == null) { - manager.unclaimPlot(Plot.this.area, current, null); - } else { - manager.claimPlot(Plot.this.area, current); - } - } - GlobalBlockQueue.IMP.addTask(run); - return; - } - Plot current = queue.poll(); - if (Plot.this.area.TERRAIN != 0) { - ChunkManager.manager - .regenerateRegion(current.getBottomAbs(), current.getTopAbs(), false, this); - return; - } - manager.clearPlot(Plot.this.area, current, this); - } - }; - run.run(); - return true; + } } - - /** - * Set the biome for a plot asynchronously - * - * @param biome The biome e.g. "forest" - * @param whenDone The task to run when finished, or null - */ - public void setBiome(final String biome, final Runnable whenDone) { - final ArrayDeque regions = new ArrayDeque<>(this.getRegions()); - final int extendBiome; - if (area instanceof SquarePlotWorld) { - extendBiome = (((SquarePlotWorld) area).ROAD_WIDTH > 0) ? 1 : 0; - } else { - extendBiome = 0; - } - Runnable run = new Runnable() { - @Override public void run() { - if (regions.isEmpty()) { - Plot.this.refreshChunks(); - TaskManager.runTask(whenDone); - return; - } - RegionWrapper region = regions.poll(); - Location pos1 = new Location(getWorldName(), region.minX - extendBiome, region.minY, - region.minZ - extendBiome); - Location pos2 = new Location(getWorldName(), region.maxX + extendBiome, region.maxY, - region.maxZ + extendBiome); - ChunkManager.chunkTask(pos1, pos2, new RunnableVal() { - @Override public void run(int[] value) { - ChunkLoc loc = new ChunkLoc(value[0], value[1]); - ChunkManager.manager.loadChunk(getWorldName(), loc, false); - MainUtil.setBiome(getWorldName(), value[2], value[3], value[4], value[5], - biome); - ChunkManager.manager.unloadChunk(getWorldName(), loc, true, true); - } - }, this, 5); - - } - }; - run.run(); + for (Plot current : plots) { + boolean[] merged = new boolean[]{false, false, false, false}; + current.setMerged(merged); } - - /** - * Unlink the plot and all connected plots. - * - * @param createSign whether to recreate signs - * @param createRoad whether to recreate road - * @return success/!cancelled - */ - public boolean unlinkPlot(boolean createRoad, boolean createSign) { - if (!this.isMerged()) { - return false; - } - final Set plots = this.getConnectedPlots(); - ArrayList ids = new ArrayList<>(plots.size()); + if (createSign) { + GlobalBlockQueue.IMP.addTask(() -> { for (Plot current : plots) { - current.setHome(null); - ids.add(current.getId()); + current.setSign(MainUtil.getName(current.owner)); } - boolean result = EventUtil.manager.callUnlink(this.area, ids); - if (!result) { - return false; + }); + } + if (createRoad) { + manager.finishPlotUnlink(this.area, ids); + } + return true; + } + + /** + * Set the sign for a plot to a specific name + * + * @param name name + */ + public void setSign(final String name) { + if (!isLoaded()) { + return; + } + if (!PlotSquared.get().isMainThread(Thread.currentThread())) { + TaskManager.runTask(() -> Plot.this.setSign(name)); + return; + } + if (name == null) { + PlotSquared.log("Attempted to add null name to sign at plot: " + getId()); + return; + } + PlotManager manager = this.area.getPlotManager(); + if (this.area.ALLOW_SIGNS) { + Location loc = manager.getSignLoc(this.area, this); + String id = this.id.x + ";" + this.id.y; + String[] lines = new String[]{C.OWNER_SIGN_LINE_1.formatted().replaceAll("%id%", id), + C.OWNER_SIGN_LINE_2.formatted().replaceAll("%id%", id).replaceAll("%plr%", name), + C.OWNER_SIGN_LINE_3.formatted().replaceAll("%id%", id).replaceAll("%plr%", name), + C.OWNER_SIGN_LINE_4.formatted().replaceAll("%id%", id).replaceAll("%plr%", name)}; + WorldUtil.IMP.setSign(this.getWorldName(), loc.getX(), loc.getY(), loc.getZ(), lines); + } + } + + protected boolean isLoaded() { + return WorldUtil.IMP.isWorld(getWorldName()); + } + + /** + * This will return null if the plot hasn't been analyzed + * + * @return analysis of plot + */ + public PlotAnalysis getComplexity(Settings.Auto_Clear settings) { + return PlotAnalysis.getAnalysis(this, settings); + } + + public void analyze(RunnableVal whenDone) { + PlotAnalysis.analyzePlot(this, whenDone); + } + + /** + * Set a flag for this plot + * + * @param flag Flag to set + * @param value Flag value + */ + public boolean setFlag(Flag flag, Object value) { + if (flag == Flags.KEEP && ExpireManager.IMP != null) { + ExpireManager.IMP.updateExpired(this); + } + return FlagManager.addPlotFlag(this, flag, value); + } + + /** + * Remove a flag from this plot + * + * @param flag the flag to remove + * @return success + */ + public boolean removeFlag(Flag flag) { + return FlagManager.removePlotFlag(this, flag); + } + + /** + * Get the flag for a given key + * + * @param key Flag to get value for + */ + public Optional getFlag(Flag key) { + return FlagManager.getPlotFlag(this, key); + } + + /** + * Get the flag for a given key + * + * @param key the flag + * @param defaultValue if the key is null, the value to return + */ + public V getFlag(Flag key, V defaultValue) { + V value = FlagManager.getPlotFlagRaw(this, key); + if (value == null) { + return defaultValue; + } else { + return value; + } + } + + /** + * Delete a plot (use null for the runnable if you don't need to be notified on completion) + * + * @see PlotSquared#removePlot(Plot, boolean) + * @see #clear(Runnable) to simply clear a plot + */ + public boolean deletePlot(final Runnable whenDone) { + if (!this.hasOwner()) { + return false; + } + final Set plots = this.getConnectedPlots(); + this.clear(false, true, () -> { + for (Plot current : plots) { + current.unclaim(); + } + TaskManager.runTask(whenDone); + }); + return true; + } + + /** + * Count the entities in a plot + * + * @return array of entity counts + * @see ChunkManager#countEntities(Plot) 0 = Entity 1 = Animal 2 = Monster 3 = Mob 4 = Boat 5 = + * Misc + */ + public int[] countEntities() { + int[] count = new int[6]; + for (Plot current : this.getConnectedPlots()) { + int[] result = ChunkManager.manager.countEntities(current); + count[0] += result[0]; + count[1] += result[1]; + count[2] += result[2]; + count[3] += result[3]; + count[4] += result[4]; + count[5] += result[5]; + } + return count; + } + + /** + * Returns true if a previous task was running + * + * @return true if a previous task is running + */ + public int addRunning() { + int value = this.getRunning(); + for (Plot plot : this.getConnectedPlots()) { + plot.setMeta("running", value + 1); + } + return value; + } + + /** + * Decrement the number of tracked tasks this plot is running
- Used to track/limit the number + * of things a player can do on the plot at once + * + * @return previous number of tasks (int) + */ + public int removeRunning() { + int value = this.getRunning(); + if (value < 2) { + for (Plot plot : this.getConnectedPlots()) { + plot.deleteMeta("running"); + } + } else { + for (Plot plot : this.getConnectedPlots()) { + plot.setMeta("running", value - 1); + } + } + return value; + } + + /** + * Get the number of tracked running tasks for this plot
- Used to track/limit the number of + * things a player can do on the plot at once + * + * @return number of tasks (int) + */ + public int getRunning() { + Integer value = (Integer) this.getMeta("running"); + return value == null ? 0 : value; + } + + /** + * Unclaim the plot (does not modify terrain). Changes made to this plot will not be reflected in + * unclaimed plot objects. + * + * @return false if the Plot has no owner, otherwise true. + */ + public boolean unclaim() { + if (this.owner == null) { + return false; + } + for (Plot current : getConnectedPlots()) { + List players = current.getPlayersInPlot(); + for (PlotPlayer pp : players) { + PlotListener.plotExit(pp, current); + } + getArea().removePlot(getId()); + DBFunc.delete(current); + current.owner = null; + current.settings = null; + for (PlotPlayer pp : players) { + PlotListener.plotEntry(pp, current); + } + } + return true; + } + + /** + * Unlink a plot and remove the roads + * + * @return true if plot was linked + * @see this#unlinkPlot(boolean, boolean) + */ + public boolean unlink() { + return this.unlinkPlot(true, true); + } + + public Location getCenter() { + Location[] corners = getCorners(); + Location top = corners[0]; + Location bot = corners[1]; + Location loc = new Location(this.getWorldName(), MathMan.average(bot.getX(), top.getX()), + MathMan.average(bot.getY(), top.getY()), MathMan.average(bot.getZ(), top.getZ())); + if (!isLoaded()) { + return loc; + } + int y = + isLoaded() ? WorldUtil.IMP.getHighestBlock(getWorldName(), loc.getX(), loc.getZ()) : 62; + if (area.ALLOW_SIGNS) { + y = Math.max(y, getManager().getSignLoc(area, this).getY()); + } + loc.setY(1 + y); + return loc; + } + + public Location getSide() { + RegionWrapper largest = getLargestRegion(); + int x = (largest.maxX >> 1) - (largest.minX >> 1) + largest.minX; + int z = largest.minZ - 1; + PlotManager manager = getManager(); + int y = isLoaded() ? WorldUtil.IMP.getHighestBlock(getWorldName(), x, z) : 62; + if (area.ALLOW_SIGNS && (y <= 0 || y >= 255)) { + y = Math.max(y, manager.getSignLoc(area, this).getY() - 1); + } + return new Location(getWorldName(), x, y + 1, z); + } + + /** + * Return the home location for the plot + * + * @return Home location + */ + public Location getHome() { + BlockLoc home = this.getPosition(); + if (home == null || home.x == 0 && home.z == 0) { + return this.getDefaultHome(true); + } else { + Location bot = this.getBottomAbs(); + Location loc = new Location(bot.getWorld(), bot.getX() + home.x, bot.getY() + home.y, + bot.getZ() + home.z, home.yaw, home.pitch); + if (!isLoaded()) { + return loc; + } + if (!WorldUtil.IMP.getBlock(loc).isAir()) { + loc.setY(Math.max( + 1 + WorldUtil.IMP.getHighestBlock(this.getWorldName(), loc.getX(), loc.getZ()), + bot.getY())); + } + return loc; + } + } + + /** + * Set the home location + * + * @param location location to set as home + */ + public void setHome(BlockLoc location) { + Plot plot = this.getBasePlot(false); + if (location != null && new BlockLoc(0, 0, 0).equals(location)) { + return; + } + plot.getSettings().setPosition(location); + if (location != null) { + DBFunc.setPosition(plot, plot.getSettings().getPosition().toString()); + return; + } + DBFunc.setPosition(plot, null); + } + + /** + * Get the default home location for a plot
- Ignores any home location set for that specific + * plot + * + * @return Location + */ + public Location getDefaultHome() { + return getDefaultHome(false); + } + + public Location getDefaultHome(boolean member) { + Plot plot = this.getBasePlot(false); + PlotLoc loc = member ? area.DEFAULT_HOME : area.NONMEMBER_HOME; + if (loc != null) { + int x; + int z; + if (loc.x == Integer.MAX_VALUE && loc.z == Integer.MAX_VALUE) { + // center + RegionWrapper largest = plot.getLargestRegion(); + x = (largest.maxX >> 1) - (largest.minX >> 1) + largest.minX; + z = (largest.maxZ >> 1) - (largest.minZ >> 1) + largest.minZ; + } else { + // specific + Location bot = plot.getBottomAbs(); + x = bot.getX() + loc.x; + z = bot.getZ() + loc.z; + } + int y = loc.y < 1 ? + (isLoaded() ? WorldUtil.IMP.getHighestBlock(plot.getWorldName(), x, z) + 1 : 63) : + loc.y; + PlotSquared.log("Getting home with Y " + y); + return new Location(plot.getWorldName(), x, y, z); + } + // Side + return plot.getSide(); + } + + public double getVolume() { + double count = 0; + for (RegionWrapper region : getRegions()) { + count += + (region.maxX - (double) region.minX + 1) * (region.maxZ - (double) region.minZ + 1) + * 256; + } + return count; + } + + /** + * Get the average rating of the plot. This is the value displayed in /plot info + * + * @return average rating as double + */ + public double getAverageRating() { + double sum = 0; + Collection ratings = this.getRatings().values(); + for (Rating rating : ratings) { + sum += rating.getAverageRating(); + } + return sum / ratings.size(); + } + + /** + * Set a rating for a user
- If the user has already rated, the following will return false + * + * @param uuid uuid of rater + * @param rating rating + * @return success + */ + public boolean addRating(UUID uuid, Rating rating) { + Plot base = this.getBasePlot(false); + PlotSettings baseSettings = base.getSettings(); + if (baseSettings.getRatings().containsKey(uuid)) { + return false; + } + int aggregate = rating.getAggregate(); + baseSettings.getRatings().put(uuid, aggregate); + DBFunc.setRating(base, uuid, aggregate); + return true; + } + + /** + * Clear the ratings for this plot + */ + public void clearRatings() { + Plot base = this.getBasePlot(false); + PlotSettings baseSettings = base.getSettings(); + if (baseSettings.ratings != null && !baseSettings.getRatings().isEmpty()) { + DBFunc.deleteRatings(base); + baseSettings.ratings = null; + } + } + + /** + * Get the ratings associated with a plot
- The rating object may contain multiple categories + * + * @return Map of user who rated to the rating + */ + public HashMap getRatings() { + Plot base = this.getBasePlot(false); + HashMap map = new HashMap<>(); + if (!base.hasRatings()) { + return map; + } + for (Entry entry : base.getSettings().getRatings().entrySet()) { + map.put(entry.getKey(), new Rating(entry.getValue())); + } + return map; + } + + public boolean hasRatings() { + Plot base = this.getBasePlot(false); + return base.settings != null && base.settings.ratings != null; + } + + /** + * Resend all chunks inside the plot to nearby players
This should not need to be called + */ + public void refreshChunks() { + LocalBlockQueue queue = GlobalBlockQueue.IMP.getNewQueue(getWorldName(), false); + HashSet chunks = new HashSet<>(); + for (RegionWrapper region : Plot.this.getRegions()) { + for (int x = region.minX >> 4; x <= region.maxX >> 4; x++) { + for (int z = region.minZ >> 4; z <= region.maxZ >> 4; z++) { + if (chunks.add(new ChunkLoc(x, z))) { + queue.refreshChunk(x, z); + } } - this.clearRatings(); - if (createSign) { - this.removeSign(); - } - PlotManager manager = this.area.getPlotManager(); - if (createRoad) { - manager.startPlotUnlink(this.area, ids); - } - if (this.area.TERRAIN != 3 && createRoad) { - for (Plot current : plots) { - if (current.getMerged(1)) { - manager.createRoadEast(current.area, current); - if (current.getMerged(2)) { - manager.createRoadSouth(current.area, current); - if (current.getMerged(5)) { - manager.createRoadSouthEast(current.area, current); - } - } - } else if (current.getMerged(2)) { - manager.createRoadSouth(current.area, current); - } - } - } - for (Plot current : plots) { - boolean[] merged = new boolean[] {false, false, false, false}; - current.setMerged(merged); - } - if (createSign) { - GlobalBlockQueue.IMP.addTask(() -> { - for (Plot current : plots) { - current.setSign(MainUtil.getName(current.owner)); - } - }); - } - if (createRoad) { - manager.finishPlotUnlink(this.area, ids); + } + } + } + + /** + * Remove the plot sign if it is set. + */ + public void removeSign() { + PlotManager manager = this.area.getPlotManager(); + if (!this.area.ALLOW_SIGNS) { + return; + } + Location loc = manager.getSignLoc(this.area, this); + LocalBlockQueue queue = GlobalBlockQueue.IMP.getNewQueue(getWorldName(), false); + queue.setBlock(loc.getX(), loc.getY(), loc.getZ(), PlotBlock.get("air")); + queue.flush(); + } + + /** + * Set the plot sign if plot signs are enabled. + */ + public void setSign() { + if (this.owner == null) { + this.setSign("unknown"); + return; + } + this.setSign(UUIDHandler.getName(this.owner)); + } + + /** + * Register a plot and create it in the database
- The plot will not be created if the owner + * is null
- Any setting from before plot creation will not be saved until the server is + * stopped properly. i.e. Set any values/options after plot creation. + * + * @return true if plot was created successfully + */ + public boolean create() { + return this.create(this.owner, true); + } + + public boolean claim(final PlotPlayer player, boolean teleport, String schematic) { + if (!canClaim(player)) { + return false; + } + return claim(player, teleport, schematic, true); + } + + public boolean claim(final PlotPlayer player, boolean teleport, String schematic, + boolean updateDB) { + boolean result = EventUtil.manager.callClaim(player, this, false); + if (updateDB) { + if (!result || (!create(player.getUUID(), true))) { + return false; + } + } else { + area.addPlot(this); + } + setSign(player.getName()); + MainUtil.sendMessage(player, C.CLAIMED); + if (teleport) { + teleportPlayer(player); + } + PlotArea plotworld = getArea(); + if (plotworld.SCHEMATIC_ON_CLAIM) { + Schematic sch; + try { + if (schematic == null || schematic.isEmpty()) { + sch = SchematicHandler.manager.getSchematic(plotworld.SCHEMATIC_FILE); + } else { + sch = SchematicHandler.manager.getSchematic(schematic); + if (sch == null) { + sch = SchematicHandler.manager.getSchematic(plotworld.SCHEMATIC_FILE); + } } + } catch (SchematicHandler.UnsupportedFormatException e) { + e.printStackTrace(); return true; + } + SchematicHandler.manager + .paste(sch, this, 0, 1, 0, Settings.Schematics.PASTE_ON_TOP, new RunnableVal() { + @Override + public void run(Boolean value) { + if (value) { + MainUtil.sendMessage(player, C.SCHEMATIC_PASTE_SUCCESS); + } else { + MainUtil.sendMessage(player, C.SCHEMATIC_PASTE_FAILED); + } + } + }); } + plotworld.getPlotManager().claimPlot(plotworld, this); + return true; + } - /** - * Set the sign for a plot to a specific name - * - * @param name name - */ - public void setSign(final String name) { - if (!isLoaded()) - return; - if (!PlotSquared.get().isMainThread(Thread.currentThread())) { - TaskManager.runTask(() -> Plot.this.setSign(name)); - return; - } - if(name == null) { - PlotSquared.log("Attempted to add null name to sign at plot: " + getId()); - return; - } - PlotManager manager = this.area.getPlotManager(); - if (this.area.ALLOW_SIGNS) { - Location loc = manager.getSignLoc(this.area, this); - String id = this.id.x + ";" + this.id.y; - String[] lines = new String[] {C.OWNER_SIGN_LINE_1.formatted().replaceAll("%id%", id), - C.OWNER_SIGN_LINE_2.formatted().replaceAll("%id%", id).replaceAll("%plr%", name), - C.OWNER_SIGN_LINE_3.formatted().replaceAll("%id%", id).replaceAll("%plr%", name), - C.OWNER_SIGN_LINE_4.formatted().replaceAll("%id%", id).replaceAll("%plr%", name)}; - WorldUtil.IMP.setSign(this.getWorldName(), loc.getX(), loc.getY(), loc.getZ(), lines); + /** + * Register a plot and create it in the database
- The plot will not be created if the owner + * is null
- Any setting from before plot creation will not be saved until the server is + * stopped properly. i.e. Set any values/options after plot creation. + * + * @param uuid the uuid of the plot owner + * @param notify notify + * @return true if plot was created successfully + */ + public boolean create(final UUID uuid, final boolean notify) { + if (uuid == null) { + throw new IllegalArgumentException("UUID cannot be null"); + } + this.owner = uuid; + Plot existing = this.area.getOwnedPlotAbs(this.id); + if (existing != null) { + throw new IllegalStateException("Plot already exists!"); + } + if (notify) { + Integer meta = (Integer) this.area.getMeta("worldBorder"); + if (meta != null) { + this.updateWorldBorder(); + } + } + connected_cache = null; + regions_cache = null; + this.getTrusted().clear(); + this.getMembers().clear(); + this.getDenied().clear(); + this.settings = new PlotSettings(); + if (this.area.addPlot(this)) { + DBFunc.createPlotAndSettings(this, () -> { + PlotArea plotworld = Plot.this.area; + if (notify && plotworld.AUTO_MERGE) { + Plot.this.autoMerge(-1, Integer.MAX_VALUE, uuid, true); } + }); + return true; } + return false; + } - protected boolean isLoaded() { - return WorldUtil.IMP.isWorld(getWorldName()); + /** + * Set components such as border, wall, floor. (components are generator specific) + */ + public boolean setComponent(String component, String blocks) { + BlockBucket parsed = Configuration.BLOCK_BUCKET.parseString(blocks); + return !(parsed == null || parsed.isEmpty()) && this.setComponent(component, parsed); + } + + /** + * Retrieve the biome of the plot. + * + * @return the name of the biome + */ + public String getBiome() { + Location loc = this.getCenter(); + return WorldUtil.IMP.getBiome(loc.getWorld(), loc.getX(), loc.getZ()); + } + + /** + * Return the top location for the plot. + */ + public Location getTopAbs() { + Location top = this.area.getPlotManager().getPlotTopLocAbs(this.area, this.id); + top.setWorld(getWorldName()); + return top; + } + + /** + * Return the bottom location for the plot. + */ + public Location getBottomAbs() { + Location loc = this.area.getPlotManager().getPlotBottomLocAbs(this.area, this.id); + loc.setWorld(getWorldName()); + return loc; + } + + /** + * Swap the settings for two plots. + * + * @param plot the plot to swap data with + * @param whenDone the task to run at the end of this method. + */ + public boolean swapData(Plot plot, Runnable whenDone) { + if (this.owner == null) { + if (plot != null && plot.hasOwner()) { + plot.moveData(this, whenDone); + return true; + } + return false; } - - /** - * This will return null if the plot hasn't been analyzed - * - * @return analysis of plot - */ - public PlotAnalysis getComplexity(Settings.Auto_Clear settings) { - return PlotAnalysis.getAnalysis(this, settings); + if (plot == null || plot.owner == null) { + this.moveData(plot, whenDone); + return true; } + // Swap cached + PlotId temp = new PlotId(this.getId().x, this.getId().y); + this.getId().x = plot.getId().x; + this.getId().y = plot.getId().y; + plot.getId().x = temp.x; + plot.getId().y = temp.y; + this.area.removePlot(this.getId()); + plot.area.removePlot(plot.getId()); + this.getId().recalculateHash(); + plot.getId().recalculateHash(); + this.area.addPlotAbs(this); + plot.area.addPlotAbs(plot); + // Swap database + DBFunc.swapPlots(plot, this); + TaskManager.runTaskLater(whenDone, 1); + return true; + } - public void analyze(RunnableVal whenDone) { - PlotAnalysis.analyzePlot(this, whenDone); + /** + * Move the settings for a plot. + * + * @param plot the plot to move + */ + public boolean moveData(Plot plot, Runnable whenDone) { + if (this.owner == null) { + PlotSquared.debug(plot + " is unowned (single)"); + TaskManager.runTask(whenDone); + return false; } - - /** - * Set a flag for this plot - * - * @param flag Flag to set - * @param value Flag value - */ - public boolean setFlag(Flag flag, Object value) { - if (flag == Flags.KEEP && ExpireManager.IMP != null) { - ExpireManager.IMP.updateExpired(this); - } - return FlagManager.addPlotFlag(this, flag, value); + if (plot.hasOwner()) { + PlotSquared.debug(plot + " is unowned (multi)"); + TaskManager.runTask(whenDone); + return false; } + this.area.removePlot(this.id); + this.getId().x = plot.getId().x; + this.getId().y = plot.getId().y; + this.getId().recalculateHash(); + this.area.addPlotAbs(this); + DBFunc.movePlot(this, plot); + TaskManager.runTaskLater(whenDone, 1); + return true; + } - /** - * Remove a flag from this plot - * - * @param flag the flag to remove - * @return success - */ - public boolean removeFlag(Flag flag) { - return FlagManager.removePlotFlag(this, flag); + /** + * Gets the top loc of a plot (if mega, returns top loc of that mega plot) - If you would like + * each plot treated as a small plot use getPlotTopLocAbs(...) + * + * @return Location top of mega plot + */ + public Location getExtendedTopAbs() { + Location top = this.getTopAbs(); + if (!this.isMerged()) { + return top; } - - /** - * Get the flag for a given key - * - * @param key Flag to get value for - */ - public Optional getFlag(Flag key) { - return FlagManager.getPlotFlag(this, key); + if (this.getMerged(2)) { + top.setZ(this.getRelative(2).getBottomAbs().getZ() - 1); } + if (this.getMerged(1)) { + top.setX(this.getRelative(1).getBottomAbs().getX() - 1); + } + return top; + } - /** - * Get the flag for a given key - * - * @param key the flag - * @param defaultValue if the key is null, the value to return - */ - public V getFlag(Flag key, V defaultValue) { - V value = FlagManager.getPlotFlagRaw(this, key); + /** + * Gets the bottom location for a plot.
- Does not respect mega plots
- Merged plots, only + * the road will be considered part of the plot
+ * + * @return Location bottom of mega plot + */ + public Location getExtendedBottomAbs() { + Location bot = this.getBottomAbs(); + if (!this.isMerged()) { + return bot; + } + if (this.getMerged(0)) { + bot.setZ(this.getRelative(0).getTopAbs().getZ() + 1); + } + if (this.getMerged(3)) { + bot.setX(this.getRelative(3).getTopAbs().getX() + 1); + } + return bot; + } + + /** + * Returns the top and bottom location.
- If the plot is not connected, it will return its own + * corners
- the returned locations will not necessarily correspond to claimed plots if the + * connected plots do not form a rectangular shape + * + * @return new Location[] { bottom, top } + * @deprecated as merged plots no longer need to be rectangular + */ + @Deprecated + public Location[] getCorners() { + if (!this.isMerged()) { + return new Location[]{this.getBottomAbs(), this.getTopAbs()}; + } + return MainUtil.getCorners(this.getWorldName(), this.getRegions()); + } + + /** + * Remove the east road section of a plot
- Used when a plot is merged
+ */ + public void removeRoadEast() { + if (this.area.TYPE != 0 && this.area.TERRAIN > 1) { + if (this.area.TERRAIN == 3) { + return; + } + Plot other = this.getRelative(1); + Location bot = other.getBottomAbs(); + Location top = this.getTopAbs(); + Location pos1 = new Location(this.getWorldName(), top.getX(), 0, bot.getZ()); + Location pos2 = new Location(this.getWorldName(), bot.getX(), 256, top.getZ()); + ChunkManager.manager.regenerateRegion(pos1, pos2, true, null); + } else { + this.area.getPlotManager().removeRoadEast(this.area, this); + } + } + + /** + * @deprecated in favor of getCorners()[0];
+ */ + // Won't remove as suggestion also points to deprecated method + @Deprecated + public Location getBottom() { + return this.getCorners()[0]; + } + + /** + * @return the top corner of the plot + * @deprecated in favor of getCorners()[1]; + */ + // Won't remove as suggestion also points to deprecated method + @Deprecated + public Location getTop() { + return this.getCorners()[1]; + } + + /** + * Swap the plot contents and settings with another location
- The destination must correspond + * to a valid plot of equal dimensions + * + * @param destination The other plot to swap with + * @param whenDone A task to run when finished, or null + * @return boolean if swap was successful + * @see ChunkManager#swap(Location, Location, Location, Location, Runnable) to swap terrain + * @see this#swapData(Plot, Runnable) to swap plot settings + * @see this#swapData(Plot, Runnable) + */ + public boolean swap(Plot destination, Runnable whenDone) { + return this.move(destination, whenDone, true); + } + + /** + * Move the plot to an empty location
- The location must be empty + * + * @param destination Where to move the plot + * @param whenDone A task to run when done, or null + * @return if the move was successful + */ + public boolean move(Plot destination, Runnable whenDone) { + return this.move(destination, whenDone, false); + } + + /** + * Get plot display name. + * + * @return alias if set, else id + */ + @Override + public String toString() { + if (this.settings != null && this.settings.getAlias().length() > 1) { + return this.settings.getAlias(); + } + return this.area + ";" + this.id.x + ";" + this.id.y; + } + + + /** + * Remove a denied player (use DBFunc as well)
Using the * uuid will remove all users + */ + public boolean removeDenied(UUID uuid) { + if (uuid == DBFunc.EVERYONE && !denied.contains(uuid)) { + boolean result = false; + for (UUID other : new HashSet<>(getDenied())) { + result = rmvDenied(other) || result; + } + return result; + } + return rmvDenied(uuid); + } + + private boolean rmvDenied(UUID uuid) { + for (Plot current : this.getConnectedPlots()) { + if (current.getDenied().remove(uuid)) { + DBFunc.removeDenied(current, uuid); + } else { + return false; + } + } + return true; + } + + /** + * Remove a helper (use DBFunc as well)
Using the * uuid will remove all users + */ + public boolean removeTrusted(UUID uuid) { + if (uuid == DBFunc.EVERYONE && !trusted.contains(uuid)) { + boolean result = false; + for (UUID other : new HashSet<>(getTrusted())) { + result = rmvTrusted(other) || result; + } + return result; + } + return rmvTrusted(uuid); + } + + private boolean rmvTrusted(UUID uuid) { + for (Plot plot : this.getConnectedPlots()) { + if (plot.getTrusted().remove(uuid)) { + DBFunc.removeTrusted(plot, uuid); + } else { + return false; + } + } + return true; + } + + /** + * Remove a trusted user (use DBFunc as well)
Using the * uuid will remove all users + */ + public boolean removeMember(UUID uuid) { + if (this.members == null) { + return false; + } + if (uuid == DBFunc.EVERYONE && !members.contains(uuid)) { + boolean result = false; + for (UUID other : new HashSet<>(this.members)) { + result = rmvMember(other) || result; + } + return result; + } + return rmvMember(uuid); + } + + private boolean rmvMember(UUID uuid) { + for (Plot current : this.getConnectedPlots()) { + if (current.getMembers().remove(uuid)) { + DBFunc.removeMember(current, uuid); + } else { + return false; + } + } + return true; + } + + /** + * Export the plot as a schematic to the configured output directory. + */ + public void export(final RunnableVal whenDone) { + SchematicHandler.manager.getCompoundTag(this, new RunnableVal() { + @Override + public void run(final CompoundTag value) { if (value == null) { - return defaultValue; - } else { - return value; - } - } - - /** - * Delete a plot (use null for the runnable if you don't need to be notified on completion) - * - * @see PlotSquared#removePlot(Plot, boolean) - * @see #clear(Runnable) to simply clear a plot - */ - public boolean deletePlot(final Runnable whenDone) { - if (!this.hasOwner()) { - return false; - } - final Set plots = this.getConnectedPlots(); - this.clear(false, true, () -> { - for (Plot current : plots) { - current.unclaim(); - } + if (whenDone != null) { + whenDone.value = false; TaskManager.runTask(whenDone); - }); - return true; - } - - /** - * Count the entities in a plot - * - * @return array of entity counts - * @see ChunkManager#countEntities(Plot) - * 0 = Entity - * 1 = Animal - * 2 = Monster - * 3 = Mob - * 4 = Boat - * 5 = Misc - */ - public int[] countEntities() { - int[] count = new int[6]; - for (Plot current : this.getConnectedPlots()) { - int[] result = ChunkManager.manager.countEntities(current); - count[0] += result[0]; - count[1] += result[1]; - count[2] += result[2]; - count[3] += result[3]; - count[4] += result[4]; - count[5] += result[5]; - } - return count; - } - - /** - * Returns true if a previous task was running - * - * @return true if a previous task is running - */ - public int addRunning() { - int value = this.getRunning(); - for (Plot plot : this.getConnectedPlots()) { - plot.setMeta("running", value + 1); - } - return value; - } - - /** - * Decrement the number of tracked tasks this plot is running
- * - Used to track/limit the number of things a player can do on the plot at once - * - * @return previous number of tasks (int) - */ - public int removeRunning() { - int value = this.getRunning(); - if (value < 2) { - for (Plot plot : this.getConnectedPlots()) { - plot.deleteMeta("running"); - } + } } else { - for (Plot plot : this.getConnectedPlots()) { - plot.setMeta("running", value - 1); + TaskManager.runTaskAsync(() -> { + String name = Plot.this.id + "," + Plot.this.area + ',' + MainUtil + .getName(Plot.this.owner); + boolean result = SchematicHandler.manager.save(value, + Settings.Paths.SCHEMATICS + File.separator + name + ".schematic"); + if (whenDone != null) { + whenDone.value = result; + TaskManager.runTask(whenDone); } + }); } - return value; - } + } + }); + } - /** - * Get the number of tracked running tasks for this plot
- * - Used to track/limit the number of things a player can do on the plot at once - * - * @return number of tasks (int) - */ - public int getRunning() { - Integer value = (Integer) this.getMeta("running"); - return value == null ? 0 : value; - } + /** + * Upload the plot as a schematic to the configured web interface. + * + * @param whenDone value will be null if uploading fails + */ + public void upload(final RunnableVal whenDone) { + SchematicHandler.manager.getCompoundTag(this, new RunnableVal() { + @Override + public void run(CompoundTag value) { + SchematicHandler.manager.upload(value, null, null, whenDone); + } + }); + } - /** - * Unclaim the plot (does not modify terrain). Changes made to this plot will not be reflected in unclaimed plot objects. - * - * @return false if the Plot has no owner, otherwise true. - */ - public boolean unclaim() { - if (this.owner == null) { - return false; + /** + * Upload this plot as a world file
- The mca files are each 512x512, so depending on the plot + * size it may also download adjacent plots
- Works best when (plot width + road width) % 512 + * == 0
+ * + * @see WorldUtil + */ + public void uploadWorld(RunnableVal whenDone) { + WorldUtil.IMP.upload(this, null, null, whenDone); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (this.getClass() != obj.getClass()) { + return false; + } + Plot other = (Plot) obj; + return this.hashCode() == other.hashCode() && this.id.equals(other.id) + && this.area == other.area; + } + + /** + * Get the plot hashcode
Note: The hashcode is unique if:
- Plots are in the same + * world
- The x,z coordinates are between Short.MIN_VALUE and Short.MAX_VALUE
+ * + * @return integer. + */ + @Override + public int hashCode() { + return this.id.hashCode(); + } + + /** + * Get the flags specific to this plot
- Does not take default flags into account
+ */ + public HashMap, Object> getFlags() { + return this.getSettings().flags; + } + + /** + * Set a flag for this plot. + */ + public void setFlags(HashMap, Object> flags) { + FlagManager.setPlotFlags(this, flags); + } + + /** + * Get the plot alias. - Returns an empty string if no alias is set + * + * @return The plot alias + */ + public String getAlias() { + if (this.settings == null) { + return ""; + } + return this.settings.getAlias(); + } + + /** + * Set the plot alias. + * + * @param alias The alias + */ + public void setAlias(String alias) { + for (Plot current : this.getConnectedPlots()) { + String name = this.getSettings().getAlias(); + if (alias == null) { + alias = ""; + } + if (name.equals(alias)) { + return; + } + current.getSettings().setAlias(alias); + DBFunc.setAlias(current, alias); + } + } + + /** + * Set the raw merge data
- Updates DB
- Does not modify terrain
----------
0 = + * north
1 = east
2 = south
3 = west
----------
+ */ + private void setMerged(int direction, boolean value) { + if (this.getSettings().setMerged(direction, value)) { + if (value) { + Plot other = this.getRelative(direction).getBasePlot(false); + if (!other.equals(this.getBasePlot(false))) { + Plot base = other.id.y < this.id.y + || other.id.y == this.id.y && other.id.x < this.id.x ? other : this.origin; + this.origin.origin = base; + other.origin = base; + this.origin = base; + connected_cache = null; } - for (Plot current : getConnectedPlots()) { - List players = current.getPlayersInPlot(); - for (PlotPlayer pp : players) { - PlotListener.plotExit(pp, current); - } - getArea().removePlot(getId()); - DBFunc.delete(current); - current.owner = null; - current.settings = null; - for (PlotPlayer pp : players) { - PlotListener.plotEntry(pp, current); - } - } - return true; - } - - /** - * Unlink a plot and remove the roads - * - * @return true if plot was linked - * @see this#unlinkPlot(boolean, boolean) - */ - public boolean unlink() { - return this.unlinkPlot(true, true); - } - - public Location getCenter() { - Location[] corners = getCorners(); - Location top = corners[0]; - Location bot = corners[1]; - Location loc = new Location(this.getWorldName(), MathMan.average(bot.getX(), top.getX()), - MathMan.average(bot.getY(), top.getY()), MathMan.average(bot.getZ(), top.getZ())); - if (!isLoaded()) - return loc; - int y = - isLoaded() ? WorldUtil.IMP.getHighestBlock(getWorldName(), loc.getX(), loc.getZ()) : 62; - if (area.ALLOW_SIGNS) { - y = Math.max(y, getManager().getSignLoc(area, this).getY()); - } - loc.setY(1 + y); - return loc; - } - - public Location getSide() { - RegionWrapper largest = getLargestRegion(); - int x = (largest.maxX >> 1) - (largest.minX >> 1) + largest.minX; - int z = largest.minZ - 1; - PlotManager manager = getManager(); - int y = isLoaded() ? WorldUtil.IMP.getHighestBlock(getWorldName(), x, z) : 62; - if (area.ALLOW_SIGNS && (y <= 0 || y >= 255)) { - y = Math.max(y, manager.getSignLoc(area, this).getY() - 1); - } - return new Location(getWorldName(), x, y + 1, z); - } - - /** - * Return the home location for the plot - * - * @return Home location - */ - public Location getHome() { - BlockLoc home = this.getPosition(); - if (home == null || home.x == 0 && home.z == 0) { - return this.getDefaultHome(true); - } else { - Location bot = this.getBottomAbs(); - Location loc = new Location(bot.getWorld(), bot.getX() + home.x, bot.getY() + home.y, - bot.getZ() + home.z, home.yaw, home.pitch); - if (!isLoaded()) - return loc; - if (!WorldUtil.IMP.getBlock(loc).isAir()) { - loc.setY(Math.max( - 1 + WorldUtil.IMP.getHighestBlock(this.getWorldName(), loc.getX(), loc.getZ()), - bot.getY())); - } - return loc; - } - } - - /** - * Set the home location - * - * @param location location to set as home - */ - public void setHome(BlockLoc location) { - Plot plot = this.getBasePlot(false); - if (location != null && new BlockLoc(0, 0, 0).equals(location)) { - return; - } - plot.getSettings().setPosition(location); - if (location != null) { - DBFunc.setPosition(plot, plot.getSettings().getPosition().toString()); - return; - } - DBFunc.setPosition(plot, null); - } - - /** - * Get the default home location for a plot
- * - Ignores any home location set for that specific plot - * - * @return Location - */ - public Location getDefaultHome() { - return getDefaultHome(false); - } - - public Location getDefaultHome(boolean member) { - Plot plot = this.getBasePlot(false); - PlotLoc loc = member ? area.DEFAULT_HOME : area.NONMEMBER_HOME; - if (loc != null) { - int x; - int z; - if (loc.x == Integer.MAX_VALUE && loc.z == Integer.MAX_VALUE) { - // center - RegionWrapper largest = plot.getLargestRegion(); - x = (largest.maxX >> 1) - (largest.minX >> 1) + largest.minX; - z = (largest.maxZ >> 1) - (largest.minZ >> 1) + largest.minZ; - } else { - // specific - Location bot = plot.getBottomAbs(); - x = bot.getX() + loc.x; - z = bot.getZ() + loc.z; - } - int y = loc.y < 1 ? - (isLoaded() ? WorldUtil.IMP.getHighestBlock(plot.getWorldName(), x, z) + 1 : 63) : - loc.y; - PlotSquared.log("Getting home with Y " + y); - return new Location(plot.getWorldName(), x, y, z); - } - // Side - return plot.getSide(); - } - - public double getVolume() { - double count = 0; - for (RegionWrapper region : getRegions()) { - count += - (region.maxX - (double) region.minX + 1) * (region.maxZ - (double) region.minZ + 1) - * 256; - } - return count; - } - - /** - * Get the average rating of the plot. This is the value displayed in /plot info - * - * @return average rating as double - */ - public double getAverageRating() { - double sum = 0; - Collection ratings = this.getRatings().values(); - for (Rating rating : ratings) { - sum += rating.getAverageRating(); - } - return sum / ratings.size(); - } - - /** - * Set a rating for a user
- * - If the user has already rated, the following will return false - * - * @param uuid uuid of rater - * @param rating rating - * @return success - */ - public boolean addRating(UUID uuid, Rating rating) { - Plot base = this.getBasePlot(false); - PlotSettings baseSettings = base.getSettings(); - if (baseSettings.getRatings().containsKey(uuid)) { - return false; - } - int aggregate = rating.getAggregate(); - baseSettings.getRatings().put(uuid, aggregate); - DBFunc.setRating(base, uuid, aggregate); - return true; - } - - /** - * Clear the ratings for this plot - */ - public void clearRatings() { - Plot base = this.getBasePlot(false); - PlotSettings baseSettings = base.getSettings(); - if (baseSettings.ratings != null && !baseSettings.getRatings().isEmpty()) { - DBFunc.deleteRatings(base); - baseSettings.ratings = null; - } - } - - /** - * Get the ratings associated with a plot
- * - The rating object may contain multiple categories - * - * @return Map of user who rated to the rating - */ - public HashMap getRatings() { - Plot base = this.getBasePlot(false); - HashMap map = new HashMap<>(); - if (!base.hasRatings()) { - return map; - } - for (Entry entry : base.getSettings().getRatings().entrySet()) { - map.put(entry.getKey(), new Rating(entry.getValue())); - } - return map; - } - - public boolean hasRatings() { - Plot base = this.getBasePlot(false); - return base.settings != null && base.settings.ratings != null; - } - - /** - * Resend all chunks inside the plot to nearby players
- * This should not need to be called - */ - public void refreshChunks() { - LocalBlockQueue queue = GlobalBlockQueue.IMP.getNewQueue(getWorldName(), false); - HashSet chunks = new HashSet<>(); - for (RegionWrapper region : Plot.this.getRegions()) { - for (int x = region.minX >> 4; x <= region.maxX >> 4; x++) { - for (int z = region.minZ >> 4; z <= region.maxZ >> 4; z++) { - if (chunks.add(new ChunkLoc(x, z))) { - queue.refreshChunk(x, z); - } - } - } - } - } - - /** - * Remove the plot sign if it is set. - */ - public void removeSign() { - PlotManager manager = this.area.getPlotManager(); - if (!this.area.ALLOW_SIGNS) { - return; - } - Location loc = manager.getSignLoc(this.area, this); - LocalBlockQueue queue = GlobalBlockQueue.IMP.getNewQueue(getWorldName(), false); - queue.setBlock(loc.getX(), loc.getY(), loc.getZ(), PlotBlock.get("air")); - queue.flush(); - } - - /** - * Set the plot sign if plot signs are enabled. - */ - public void setSign() { - if (this.owner == null) { - this.setSign("unknown"); - return; - } - this.setSign(UUIDHandler.getName(this.owner)); - } - - /** - * Register a plot and create it in the database
- * - The plot will not be created if the owner is null
- * - Any setting from before plot creation will not be saved until the server is stopped properly. i.e. Set any values/options after plot - * creation. - * - * @return true if plot was created successfully - */ - public boolean create() { - return this.create(this.owner, true); - } - - public boolean claim(final PlotPlayer player, boolean teleport, String schematic) { - if (!canClaim(player)) { - return false; - } - return claim(player, teleport, schematic, true); - } - - public boolean claim(final PlotPlayer player, boolean teleport, String schematic, - boolean updateDB) { - boolean result = EventUtil.manager.callClaim(player, this, false); - if (updateDB) { - if (!result || (!create(player.getUUID(), true))) { - return false; - } - } else { - area.addPlot(this); - } - setSign(player.getName()); - MainUtil.sendMessage(player, C.CLAIMED); - if (teleport) { - teleportPlayer(player); - } - PlotArea plotworld = getArea(); - if (plotworld.SCHEMATIC_ON_CLAIM) { - Schematic sch; - try { - if (schematic == null || schematic.isEmpty()) { - sch = SchematicHandler.manager.getSchematic(plotworld.SCHEMATIC_FILE); - } else { - sch = SchematicHandler.manager.getSchematic(schematic); - if (sch == null) { - sch = SchematicHandler.manager.getSchematic(plotworld.SCHEMATIC_FILE); - } - } - } catch (SchematicHandler.UnsupportedFormatException e) { - e.printStackTrace(); - return true; - } - SchematicHandler.manager.paste(sch, this, 0, 1, 0, Settings.Schematics.PASTE_ON_TOP, new RunnableVal() { - @Override public void run(Boolean value) { - if (value) { - MainUtil.sendMessage(player, C.SCHEMATIC_PASTE_SUCCESS); - } else { - MainUtil.sendMessage(player, C.SCHEMATIC_PASTE_FAILED); - } - } - }); - } - plotworld.getPlotManager().claimPlot(plotworld, this); - return true; - } - - /** - * Register a plot and create it in the database
- * - The plot will not be created if the owner is null
- * - Any setting from before plot creation will not be saved until the server is stopped properly. i.e. Set any values/options after plot - * creation. - * - * @param uuid the uuid of the plot owner - * @param notify notify - * @return true if plot was created successfully - */ - public boolean create(final UUID uuid, final boolean notify) { - if (uuid == null) { - throw new IllegalArgumentException("UUID cannot be null"); - } - this.owner = uuid; - Plot existing = this.area.getOwnedPlotAbs(this.id); - if (existing != null) { - throw new IllegalStateException("Plot already exists!"); - } - if (notify) { - Integer meta = (Integer) this.area.getMeta("worldBorder"); - if (meta != null) { - this.updateWorldBorder(); - } - } - connected_cache = null; - regions_cache = null; - this.getTrusted().clear(); - this.getMembers().clear(); - this.getDenied().clear(); - this.settings = new PlotSettings(); - if (this.area.addPlot(this)) { - DBFunc.createPlotAndSettings(this, () -> { - PlotArea plotworld = Plot.this.area; - if (notify && plotworld.AUTO_MERGE) { - Plot.this.autoMerge(-1, Integer.MAX_VALUE, uuid, true); - } - }); - return true; - } - return false; - } - - /** - * Set components such as border, wall, floor. - * (components are generator specific) - */ - public boolean setComponent(String component, String blocks) { - BlockBucket parsed = Configuration.BLOCK_BUCKET.parseString(blocks); - return !(parsed == null || parsed.isEmpty()) && this.setComponent(component, parsed); - } - - /** - * Retrieve the biome of the plot. - * - * @return the name of the biome - */ - public String getBiome() { - Location loc = this.getCenter(); - return WorldUtil.IMP.getBiome(loc.getWorld(), loc.getX(), loc.getZ()); - } - - /** - * Return the top location for the plot. - * - * @return - */ - public Location getTopAbs() { - Location top = this.area.getPlotManager().getPlotTopLocAbs(this.area, this.id); - top.setWorld(getWorldName()); - return top; - } - - /** - * Return the bottom location for the plot. - * - * @return - */ - public Location getBottomAbs() { - Location loc = this.area.getPlotManager().getPlotBottomLocAbs(this.area, this.id); - loc.setWorld(getWorldName()); - return loc; - } - - /** - * Swap the settings for two plots. - * - * @param plot the plot to swap data with - * @param whenDone the task to run at the end of this method. - * @return - */ - public boolean swapData(Plot plot, Runnable whenDone) { - if (this.owner == null) { - if (plot != null && plot.hasOwner()) { - plot.moveData(this, whenDone); - return true; - } - return false; - } - if (plot == null || plot.owner == null) { - this.moveData(plot, whenDone); - return true; - } - // Swap cached - PlotId temp = new PlotId(this.getId().x, this.getId().y); - this.getId().x = plot.getId().x; - this.getId().y = plot.getId().y; - plot.getId().x = temp.x; - plot.getId().y = temp.y; - this.area.removePlot(this.getId()); - plot.area.removePlot(plot.getId()); - this.getId().recalculateHash(); - plot.getId().recalculateHash(); - this.area.addPlotAbs(this); - plot.area.addPlotAbs(plot); - // Swap database - DBFunc.swapPlots(plot, this); - TaskManager.runTaskLater(whenDone, 1); - return true; - } - - /** - * Move the settings for a plot. - * - * @param plot the plot to move - * @param whenDone - * @return - */ - public boolean moveData(Plot plot, Runnable whenDone) { - if (this.owner == null) { - PlotSquared.debug(plot + " is unowned (single)"); - TaskManager.runTask(whenDone); - return false; - } - if (plot.hasOwner()) { - PlotSquared.debug(plot + " is unowned (multi)"); - TaskManager.runTask(whenDone); - return false; - } - this.area.removePlot(this.id); - this.getId().x = plot.getId().x; - this.getId().y = plot.getId().y; - this.getId().recalculateHash(); - this.area.addPlotAbs(this); - DBFunc.movePlot(this, plot); - TaskManager.runTaskLater(whenDone, 1); - return true; - } - - /** - * Gets the top loc of a plot (if mega, returns top loc of that mega plot) - If you would like each plot treated as - * a small plot use getPlotTopLocAbs(...) - * - * @return Location top of mega plot - */ - public Location getExtendedTopAbs() { - Location top = this.getTopAbs(); - if (!this.isMerged()) { - return top; - } - if (this.getMerged(2)) { - top.setZ(this.getRelative(2).getBottomAbs().getZ() - 1); - } - if (this.getMerged(1)) { - top.setX(this.getRelative(1).getBottomAbs().getX() - 1); - } - return top; - } - - /** - * Gets the bottom location for a plot.
- * - Does not respect mega plots
- * - Merged plots, only the road will be considered part of the plot
- * - * @return Location bottom of mega plot - */ - public Location getExtendedBottomAbs() { - Location bot = this.getBottomAbs(); - if (!this.isMerged()) { - return bot; - } - if (this.getMerged(0)) { - bot.setZ(this.getRelative(0).getTopAbs().getZ() + 1); - } - if (this.getMerged(3)) { - bot.setX(this.getRelative(3).getTopAbs().getX() + 1); - } - return bot; - } - - /** - * Returns the top and bottom location.
- * - If the plot is not connected, it will return its own corners
- * - the returned locations will not necessarily correspond to claimed plots if the connected plots do not form a rectangular shape - * - * @return new Location[] { bottom, top } - * @deprecated as merged plots no longer need to be rectangular - */ - @Deprecated public Location[] getCorners() { - if (!this.isMerged()) { - return new Location[] {this.getBottomAbs(), this.getTopAbs()}; - } - return MainUtil.getCorners(this.getWorldName(), this.getRegions()); - } - - /** - * Remove the east road section of a plot
- * - Used when a plot is merged
- */ - public void removeRoadEast() { - if (this.area.TYPE != 0 && this.area.TERRAIN > 1) { - if (this.area.TERRAIN == 3) { - return; - } - Plot other = this.getRelative(1); - Location bot = other.getBottomAbs(); - Location top = this.getTopAbs(); - Location pos1 = new Location(this.getWorldName(), top.getX(), 0, bot.getZ()); - Location pos2 = new Location(this.getWorldName(), bot.getX(), 256, top.getZ()); - ChunkManager.manager.regenerateRegion(pos1, pos2, true, null); - } else { - this.area.getPlotManager().removeRoadEast(this.area, this); - } - } - - /** - * @return - * @deprecated in favor of getCorners()[0];
- */ - // Won't remove as suggestion also points to deprecated method - @Deprecated public Location getBottom() { - return this.getCorners()[0]; - } - - /** - * @return the top corner of the plot - * @deprecated in favor of getCorners()[1]; - */ - // Won't remove as suggestion also points to deprecated method - @Deprecated public Location getTop() { - return this.getCorners()[1]; - } - - /** - * Swap the plot contents and settings with another location
- * - The destination must correspond to a valid plot of equal dimensions - * - * @param destination The other plot to swap with - * @param whenDone A task to run when finished, or null - * @return boolean if swap was successful - * @see ChunkManager#swap(Location, Location, Location, Location, Runnable) to swap terrain - * @see this#swapData(Plot, Runnable) to swap plot settings - * @see this#swapData(Plot, Runnable) - */ - public boolean swap(Plot destination, Runnable whenDone) { - return this.move(destination, whenDone, true); - } - - /** - * Move the plot to an empty location
- * - The location must be empty - * - * @param destination Where to move the plot - * @param whenDone A task to run when done, or null - * @return if the move was successful - */ - public boolean move(Plot destination, Runnable whenDone) { - return this.move(destination, whenDone, false); - } - - /** - * Get plot display name. - * - * @return alias if set, else id - */ - @Override public String toString() { - if (this.settings != null && this.settings.getAlias().length() > 1) { - return this.settings.getAlias(); - } - return this.area + ";" + this.id.x + ";" + this.id.y; - } - - - /** - * Remove a denied player (use DBFunc as well)
- * Using the * uuid will remove all users - * - * @param uuid - */ - public boolean removeDenied(UUID uuid) { - if (uuid == DBFunc.EVERYONE && !denied.contains(uuid)) { - boolean result = false; - for (UUID other : new HashSet<>(getDenied())) { - result = rmvDenied(other) || result; - } - return result; - } - return rmvDenied(uuid); - } - - private boolean rmvDenied(UUID uuid) { - for (Plot current : this.getConnectedPlots()) { - if (current.getDenied().remove(uuid)) { - DBFunc.removeDenied(current, uuid); - } else { - return false; - } - } - return true; - } - - /** - * Remove a helper (use DBFunc as well)
- * Using the * uuid will remove all users - * - * @param uuid - */ - public boolean removeTrusted(UUID uuid) { - if (uuid == DBFunc.EVERYONE && !trusted.contains(uuid)) { - boolean result = false; - for (UUID other : new HashSet<>(getTrusted())) { - result = rmvTrusted(other) || result; - } - return result; - } - return rmvTrusted(uuid); - } - - private boolean rmvTrusted(UUID uuid) { - for (Plot plot : this.getConnectedPlots()) { - if (plot.getTrusted().remove(uuid)) { - DBFunc.removeTrusted(plot, uuid); - } else { - return false; - } - } - return true; - } - - /** - * Remove a trusted user (use DBFunc as well)
- * Using the * uuid will remove all users - * - * @param uuid - */ - public boolean removeMember(UUID uuid) { - if (this.members == null) { - return false; - } - if (uuid == DBFunc.EVERYONE && !members.contains(uuid)) { - boolean result = false; - for (UUID other : new HashSet<>(this.members)) { - result = rmvMember(other) || result; - } - return result; - } - return rmvMember(uuid); - } - - private boolean rmvMember(UUID uuid) { - for (Plot current : this.getConnectedPlots()) { - if (current.getMembers().remove(uuid)) { - DBFunc.removeMember(current, uuid); - } else { - return false; - } - } - return true; - } - - /** - * Export the plot as a schematic to the configured output directory. - * - * @return - */ - public void export(final RunnableVal whenDone) { - SchematicHandler.manager.getCompoundTag(this, new RunnableVal() { - @Override public void run(final CompoundTag value) { - if (value == null) { - if (whenDone != null) { - whenDone.value = false; - TaskManager.runTask(whenDone); - } - } else { - TaskManager.runTaskAsync(() -> { - String name = Plot.this.id + "," + Plot.this.area + ',' + MainUtil - .getName(Plot.this.owner); - boolean result = SchematicHandler.manager.save(value, - Settings.Paths.SCHEMATICS + File.separator + name + ".schematic"); - if (whenDone != null) { - whenDone.value = result; - TaskManager.runTask(whenDone); - } - }); - } - } - }); - } - - /** - * Upload the plot as a schematic to the configured web interface. - * - * @param whenDone value will be null if uploading fails - */ - public void upload(final RunnableVal whenDone) { - SchematicHandler.manager.getCompoundTag(this, new RunnableVal() { - @Override public void run(CompoundTag value) { - SchematicHandler.manager.upload(value, null, null, whenDone); - } - }); - } - - /** - * Upload this plot as a world file
- * - The mca files are each 512x512, so depending on the plot size it may also download adjacent plots
- * - Works best when (plot width + road width) % 512 == 0
- * - * @param whenDone - * @see WorldUtil - */ - public void uploadWorld(RunnableVal whenDone) { - WorldUtil.IMP.upload(this, null, null, whenDone); - } - - @Override public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (this.getClass() != obj.getClass()) { - return false; - } - Plot other = (Plot) obj; - return this.hashCode() == other.hashCode() && this.id.equals(other.id) - && this.area == other.area; - } - - /** - * Get the plot hashcode
- * Note: The hashcode is unique if:
- * - Plots are in the same world
- * - The x,z coordinates are between Short.MIN_VALUE and Short.MAX_VALUE
- * - * @return integer. - */ - @Override public int hashCode() { - return this.id.hashCode(); - } - - /** - * Get the flags specific to this plot
- * - Does not take default flags into account
- * - * @return - */ - public HashMap, Object> getFlags() { - return this.getSettings().flags; - } - - /** - * Set a flag for this plot. - * - * @param flags - */ - public void setFlags(HashMap, Object> flags) { - FlagManager.setPlotFlags(this, flags); - } - - /** - * Get the plot alias. - * - Returns an empty string if no alias is set - * - * @return The plot alias - */ - public String getAlias() { - if (this.settings == null) { - return ""; - } - return this.settings.getAlias(); - } - - /** - * Set the plot alias. - * - * @param alias The alias - */ - public void setAlias(String alias) { - for (Plot current : this.getConnectedPlots()) { - String name = this.getSettings().getAlias(); - if (alias == null) { - alias = ""; - } - if (name.equals(alias)) { - return; - } - current.getSettings().setAlias(alias); - DBFunc.setAlias(current, alias); - } - } - - /** - * Set the raw merge data
- * - Updates DB
- * - Does not modify terrain
- * ----------
- * 0 = north
- * 1 = east
- * 2 = south
- * 3 = west
- * ----------
- * - * @param direction - * @param value - */ - public void setMerged(int direction, boolean value) { - if (this.getSettings().setMerged(direction, value)) { - if (value) { - Plot other = this.getRelative(direction).getBasePlot(false); - if (!other.equals(this.getBasePlot(false))) { - Plot base = other.id.y < this.id.y - || other.id.y == this.id.y && other.id.x < this.id.x ? other : this.origin; - this.origin.origin = base; - other.origin = base; - this.origin = base; - connected_cache = null; - } - } else { - if (this.origin != null) { - this.origin.origin = null; - this.origin = null; - } - connected_cache = null; - } - DBFunc.setMerged(this, this.getSettings().getMerged()); - regions_cache = null; - } - } - - /** - * Get the merged array. - * - * @return boolean [ north, east, south, west ] - */ - public boolean[] getMerged() { - return this.getSettings().getMerged(); - } - - /** - * Set the raw merge data
- * - Updates DB
- * - Does not modify terrain
- * Get if the plot is merged in a direction
- * ----------
- * 0 = north
- * 1 = east
- * 2 = south
- * 3 = west
- * ----------
- * Note: Diagonal merging (4-7) must be done by merging the corresponding plots. - * - * @param merged - */ - public void setMerged(boolean[] merged) { - this.getSettings().setMerged(merged); - DBFunc.setMerged(this, merged); - clearCache(); - } - - public void clearCache() { - connected_cache = null; - regions_cache = null; + } else { if (this.origin != null) { - this.origin.origin = null; - this.origin = null; + this.origin.origin = null; + this.origin = null; } + connected_cache = null; + } + DBFunc.setMerged(this, this.getSettings().getMerged()); + regions_cache = null; + } + } + + /** + * Get the merged array. + * + * @return boolean [ north, east, south, west ] + */ + public boolean[] getMerged() { + return this.getSettings().getMerged(); + } + + /** + * Set the raw merge data
- Updates DB
- Does not modify terrain
Get if the plot is + * merged in a direction
----------
0 = north
1 = east
2 = south
3 = west
+ * ----------
Note: Diagonal merging (4-7) must be done by merging the corresponding plots. + */ + public void setMerged(boolean[] merged) { + this.getSettings().setMerged(merged); + DBFunc.setMerged(this, merged); + clearCache(); + } + + private void clearCache() { + connected_cache = null; + regions_cache = null; + if (this.origin != null) { + this.origin.origin = null; + this.origin = null; + } + } + + /** + * Get the set home location or 0,0,0 if no location is set
- Does not take the default home + * location into account + * + * @see #getHome() + */ + public BlockLoc getPosition() { + return this.getSettings().getPosition(); + } + + /** + * Check if a plot can be claimed by the provided player. + * + * @param player the claiming player + */ + public boolean canClaim(@Nullable PlotPlayer player) { + PlotCluster cluster = this.getCluster(); + if (cluster != null && player != null) { + if (!cluster.isAdded(player.getUUID()) && !Permissions + .hasPermission(player, "plots.admin.command.claim")) { + return false; + } + } + return this.guessOwner() == null && !isMerged(); + } + + /** + * Guess the owner of a plot either by the value in memory, or the sign data
Note: Recovering + * from sign information is useful if e.g. PlotMe conversion wasn't successful + * + * @return UUID + */ + public UUID guessOwner() { + if (this.hasOwner()) { + return this.owner; + } + if (!this.area.ALLOW_SIGNS) { + return null; + } + try { + final Location loc = this.getManager().getSignLoc(this.area, this); + String[] lines = TaskManager.IMP.sync(new RunnableVal() { + @Override + public void run(String[] value) { + ChunkManager.manager.loadChunk(loc.getWorld(), loc.getChunkLoc(), false); + this.value = WorldUtil.IMP.getSign(loc); + } + }); + if (lines == null) { + return null; + } + loop: + for (int i = 4; i > 0; i--) { + String caption = C.valueOf("OWNER_SIGN_LINE_" + i).s(); + int index = caption.indexOf("%plr%"); + if (index < 0) { + continue; + } + String line = lines[i - 1]; + if (line.length() <= index) { + return null; + } + String name = line.substring(index); + if (name.isEmpty()) { + return null; + } + UUID owner = UUIDHandler.getUUID(name, null); + if (owner != null) { + this.owner = owner; + break; + } + if (lines[i - 1].length() == 15) { + BiMap map = UUIDHandler.getUuidMap(); + for (Entry entry : map.entrySet()) { + String key = entry.getKey().value; + if (key.length() > name.length() && key.startsWith(name)) { + this.owner = entry.getValue(); + break loop; + } + } + } + this.owner = UUID.nameUUIDFromBytes( + ("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)); + break; + } + if (this.hasOwner()) { + this.create(); + } + return this.owner; + } catch (IllegalArgumentException ignored) { + return null; + } + } + + /** + * Remove the south road section of a plot
- Used when a plot is merged
+ */ + public void removeRoadSouth() { + if (this.area.TYPE != 0 && this.area.TERRAIN > 1) { + if (this.area.TERRAIN == 3) { + return; + } + Plot other = this.getRelative(2); + Location bot = other.getBottomAbs(); + Location top = this.getTopAbs(); + Location pos1 = new Location(this.getWorldName(), bot.getX(), 0, top.getZ()); + Location pos2 = new Location(this.getWorldName(), top.getX(), 256, bot.getZ()); + ChunkManager.manager.regenerateRegion(pos1, pos2, true, null); + } else { + this.getManager().removeRoadSouth(this.area, this); + } + } + + /** + * Auto merge a plot in a specific direction
+ * + * @param dir The direction to merge
-1 = All directions
0 = north
1 = east
2 = + * south
3 = west
+ * @param max The max number of merges to do + * @param uuid The UUID it is allowed to merge with + * @param removeRoads Whether to remove roads + * @return true if a merge takes place + */ + public boolean autoMerge(int dir, int max, UUID uuid, boolean removeRoads) { + if (this.owner == null) { + return false; + } + if (!EventUtil.manager.callMerge(this, dir, max)) { + return false; + } + HashSet visited = new HashSet<>(); + HashSet merged = new HashSet<>(); + Set connected = this.getConnectedPlots(); + for (Plot current : connected) { + merged.add(current.getId()); + } + ArrayDeque frontier = new ArrayDeque<>(connected); + Plot current; + boolean toReturn = false; + while ((current = frontier.poll()) != null && max >= 0) { + if (visited.contains(current)) { + continue; + } + visited.add(current); + Set plots; + if ((dir == -1 || dir == 0) && !current.getMerged(0)) { + Plot other = current.getRelative(0); + if (other != null && other.isOwner(uuid) && ( + other.getBasePlot(false).equals(current.getBasePlot(false)) + || (plots = other.getConnectedPlots()).size() <= max && frontier + .addAll(plots) && (max -= plots.size()) != -1)) { + current.mergePlot(other, removeRoads); + merged.add(current.getId()); + merged.add(other.getId()); + toReturn = true; + } + } + if (max >= 0 && (dir == -1 || dir == 1) && !current.getMerged(1)) { + Plot other = current.getRelative(1); + if (other != null && other.isOwner(uuid) && ( + other.getBasePlot(false).equals(current.getBasePlot(false)) + || (plots = other.getConnectedPlots()).size() <= max && frontier + .addAll(plots) && (max -= plots.size()) != -1)) { + current.mergePlot(other, removeRoads); + merged.add(current.getId()); + merged.add(other.getId()); + toReturn = true; + } + } + if (max >= 0 && (dir == -1 || dir == 2) && !current.getMerged(2)) { + Plot other = current.getRelative(2); + if (other != null && other.isOwner(uuid) && ( + other.getBasePlot(false).equals(current.getBasePlot(false)) + || (plots = other.getConnectedPlots()).size() <= max && frontier + .addAll(plots) && (max -= plots.size()) != -1)) { + current.mergePlot(other, removeRoads); + merged.add(current.getId()); + merged.add(other.getId()); + toReturn = true; + } + } + if (max >= 0 && (dir == -1 || dir == 3) && !current.getMerged(3)) { + Plot other = current.getRelative(3); + if (other != null && other.isOwner(uuid) && ( + other.getBasePlot(false).equals(current.getBasePlot(false)) + || (plots = other.getConnectedPlots()).size() <= max && frontier + .addAll(plots) && (max -= plots.size()) != -1)) { + current.mergePlot(other, removeRoads); + merged.add(current.getId()); + merged.add(other.getId()); + toReturn = true; + } + } + } + if (removeRoads && toReturn) { + ArrayList ids = new ArrayList<>(merged); + this.getManager().finishPlotMerge(this.area, ids); + } + return toReturn; + } + + /** + * Merge the plot settings
- Used when a plot is merged
+ */ + public void mergeData(Plot b) { + HashMap, Object> flags1 = this.getFlags(); + HashMap, Object> flags2 = b.getFlags(); + if ((!flags1.isEmpty() || !flags2.isEmpty()) && !flags1.equals(flags2)) { + boolean greater = flags1.size() > flags2.size(); + if (greater) { + flags1.putAll(flags2); + } else { + flags2.putAll(flags1); + } + HashMap, Object> net = (greater ? flags1 : flags2); + this.setFlags(net); + b.setFlags(net); + } + if (!this.getAlias().isEmpty()) { + b.setAlias(this.getAlias()); + } else if (!b.getAlias().isEmpty()) { + this.setAlias(b.getAlias()); + } + for (UUID uuid : this.getTrusted()) { + b.addTrusted(uuid); + } + for (UUID uuid : b.getTrusted()) { + this.addTrusted(uuid); + } + for (UUID uuid : this.getMembers()) { + b.addMember(uuid); + } + for (UUID uuid : b.getMembers()) { + this.addMember(uuid); } - /** - * Get the set home location or 0,0,0 if no location is set
- * - Does not take the default home location into account - * - * @return - * @see #getHome() - */ - public BlockLoc getPosition() { - return this.getSettings().getPosition(); + for (UUID uuid : this.getDenied()) { + b.addDenied(uuid); } - - /** - * Check if a plot can be claimed by the provided player. - * - * @param player the claiming player - * @return - */ - public boolean canClaim(@Nullable PlotPlayer player) { - PlotCluster cluster = this.getCluster(); - if (cluster != null && player != null) { - if (!cluster.isAdded(player.getUUID()) && !Permissions - .hasPermission(player, "plots.admin.command.claim")) { - return false; - } - } - return this.guessOwner() == null && !isMerged(); + for (UUID uuid : b.getDenied()) { + this.addDenied(uuid); } + } - /** - * Guess the owner of a plot either by the value in memory, or the sign data
- * Note: Recovering from sign information is useful if e.g. PlotMe conversion wasn't successful - * - * @return UUID - */ - public UUID guessOwner() { - if (this.hasOwner()) { - return this.owner; - } - if (!this.area.ALLOW_SIGNS) { - return null; - } - try { - final Location loc = this.getManager().getSignLoc(this.area, this); - String[] lines = TaskManager.IMP.sync(new RunnableVal() { - @Override public void run(String[] value) { - ChunkManager.manager.loadChunk(loc.getWorld(), loc.getChunkLoc(), false); - this.value = WorldUtil.IMP.getSign(loc); - } - }); - if (lines == null) { - return null; - } - loop: - for (int i = 4; i > 0; i--) { - String caption = C.valueOf("OWNER_SIGN_LINE_" + i).s(); - int index = caption.indexOf("%plr%"); - if (index < 0) { - continue; - } - String line = lines[i - 1]; - if (line.length() <= index) { - return null; - } - String name = line.substring(index); - if (name.isEmpty()) { - return null; - } - UUID owner = UUIDHandler.getUUID(name, null); - if (owner != null) { - this.owner = owner; - break; - } - if (lines[i - 1].length() == 15) { - BiMap map = UUIDHandler.getUuidMap(); - for (Entry entry : map.entrySet()) { - String key = entry.getKey().value; - if (key.length() > name.length() && key.startsWith(name)) { - this.owner = entry.getValue(); - break loop; - } - } - } - this.owner = UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)); - break; - } - if (this.hasOwner()) { - this.create(); - } - return this.owner; - } catch (IllegalArgumentException ignored) { - return null; - } + /** + * Remove the SE road (only effects terrain) + */ + public void removeRoadSouthEast() { + if (this.area.TYPE != 0 && this.area.TERRAIN > 1) { + if (this.area.TERRAIN == 3) { + return; + } + Plot other = this.getRelative(1, 1); + Location pos1 = this.getTopAbs().add(1, 0, 1); + Location pos2 = other.getBottomAbs().subtract(1, 0, 1); + pos1.setY(0); + pos2.setY(256); + ChunkManager.manager.regenerateRegion(pos1, pos2, true, null); + } else { + this.area.getPlotManager().removeRoadSouthEast(this.area, this); } + } - /** - * Remove the south road section of a plot
- * - Used when a plot is merged
- */ - public void removeRoadSouth() { - if (this.area.TYPE != 0 && this.area.TERRAIN > 1) { - if (this.area.TERRAIN == 3) { - return; - } - Plot other = this.getRelative(2); - Location bot = other.getBottomAbs(); - Location top = this.getTopAbs(); - Location pos1 = new Location(this.getWorldName(), bot.getX(), 0, top.getZ()); - Location pos2 = new Location(this.getWorldName(), top.getX(), 256, bot.getZ()); - ChunkManager.manager.regenerateRegion(pos1, pos2, true, null); + /** + * Get the plot in a relative location
Note: May be null if the partial plot area does not + * include the relative location + * + * @return Plot + */ + public Plot getRelative(int x, int y) { + return this.area.getPlotAbs(this.id.getRelative(x, y)); + } + + public Plot getRelative(PlotArea area, int x, int y) { + return area.getPlotAbs(this.id.getRelative(x, y)); + } + + /** + * Get the plot in a relative direction
0 = north
1 = east
2 = south
3 = west
+ * Note: May be null if the partial plot area does not include the relative location + */ + public Plot getRelative(int direction) { + return this.area.getPlotAbs(this.id.getRelative(direction)); + } + + /** + * Get a set of plots connected (and including) this plot
- This result is cached globally + */ + public Set getConnectedPlots() { + if (this.settings == null || !this.isMerged()) { + return Collections.singleton(this); + } + boolean[] merged = this.getMerged(); + int hash = MainUtil.hash(merged); + if (hash == 0) { + return Collections.singleton(this); + } + if (connected_cache != null && connected_cache.contains(this)) { + return connected_cache; + } + regions_cache = null; + + HashSet tmpSet = new HashSet<>(); + ArrayDeque frontier = new ArrayDeque<>(); + HashSet queuecache = new HashSet<>(); + tmpSet.add(this); + Plot tmp; + if (merged[0]) { + tmp = this.area.getPlotAbs(this.id.getRelative(0)); + if (!tmp.getMerged(2)) { + // invalid merge + PlotSquared.debug("Fixing invalid merge: " + this); + if (tmp.isOwnerAbs(this.owner)) { + tmp.getSettings().setMerged(2, true); + DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); } else { - this.getManager().removeRoadSouth(this.area, this); + this.getSettings().setMerged(0, false); + DBFunc.setMerged(this, this.getSettings().getMerged()); } + } + queuecache.add(tmp); + frontier.add(tmp); } - - /** - * Auto merge a plot in a specific direction
- * - * @param dir The direction to merge
- * -1 = All directions
- * 0 = north
- * 1 = east
- * 2 = south
- * 3 = west
- * @param max The max number of merges to do - * @param uuid The UUID it is allowed to merge with - * @param removeRoads Whether to remove roads - * @return true if a merge takes place - */ - public boolean autoMerge(int dir, int max, UUID uuid, boolean removeRoads) { - if (this.owner == null) { - return false; - } - if (!EventUtil.manager.callMerge(this, dir, max)) { - return false; - } - HashSet visited = new HashSet<>(); - HashSet merged = new HashSet<>(); - Set connected = this.getConnectedPlots(); - for (Plot current : connected) { - merged.add(current.getId()); - } - ArrayDeque frontier = new ArrayDeque<>(connected); - Plot current; - boolean toReturn = false; - while ((current = frontier.poll()) != null && max >= 0) { - if (visited.contains(current)) { - continue; - } - visited.add(current); - Set plots; - if ((dir == -1 || dir == 0) && !current.getMerged(0)) { - Plot other = current.getRelative(0); - if (other != null && other.isOwner(uuid) && ( - other.getBasePlot(false).equals(current.getBasePlot(false)) - || (plots = other.getConnectedPlots()).size() <= max && frontier - .addAll(plots) && (max -= plots.size()) != -1)) { - current.mergePlot(other, removeRoads); - merged.add(current.getId()); - merged.add(other.getId()); - toReturn = true; - } - } - if (max >= 0 && (dir == -1 || dir == 1) && !current.getMerged(1)) { - Plot other = current.getRelative(1); - if (other != null && other.isOwner(uuid) && ( - other.getBasePlot(false).equals(current.getBasePlot(false)) - || (plots = other.getConnectedPlots()).size() <= max && frontier - .addAll(plots) && (max -= plots.size()) != -1)) { - current.mergePlot(other, removeRoads); - merged.add(current.getId()); - merged.add(other.getId()); - toReturn = true; - } - } - if (max >= 0 && (dir == -1 || dir == 2) && !current.getMerged(2)) { - Plot other = current.getRelative(2); - if (other != null && other.isOwner(uuid) && ( - other.getBasePlot(false).equals(current.getBasePlot(false)) - || (plots = other.getConnectedPlots()).size() <= max && frontier - .addAll(plots) && (max -= plots.size()) != -1)) { - current.mergePlot(other, removeRoads); - merged.add(current.getId()); - merged.add(other.getId()); - toReturn = true; - } - } - if (max >= 0 && (dir == -1 || dir == 3) && !current.getMerged(3)) { - Plot other = current.getRelative(3); - if (other != null && other.isOwner(uuid) && ( - other.getBasePlot(false).equals(current.getBasePlot(false)) - || (plots = other.getConnectedPlots()).size() <= max && frontier - .addAll(plots) && (max -= plots.size()) != -1)) { - current.mergePlot(other, removeRoads); - merged.add(current.getId()); - merged.add(other.getId()); - toReturn = true; - } - } - } - if (removeRoads && toReturn) { - ArrayList ids = new ArrayList<>(merged); - this.getManager().finishPlotMerge(this.area, ids); - } - return toReturn; - } - - /** - * Merge the plot settings
- * - Used when a plot is merged
- * - * @param b - */ - public void mergeData(Plot b) { - HashMap, Object> flags1 = this.getFlags(); - HashMap, Object> flags2 = b.getFlags(); - if ((!flags1.isEmpty() || !flags2.isEmpty()) && !flags1.equals(flags2)) { - boolean greater = flags1.size() > flags2.size(); - if (greater) { - flags1.putAll(flags2); - } else { - flags2.putAll(flags1); - } - HashMap, Object> net = (greater ? flags1 : flags2); - this.setFlags(net); - b.setFlags(net); - } - if (!this.getAlias().isEmpty()) { - b.setAlias(this.getAlias()); - } else if (!b.getAlias().isEmpty()) { - this.setAlias(b.getAlias()); - } - for (UUID uuid : this.getTrusted()) { - b.addTrusted(uuid); - } - for (UUID uuid : b.getTrusted()) { - this.addTrusted(uuid); - } - for (UUID uuid : this.getMembers()) { - b.addMember(uuid); - } - for (UUID uuid : b.getMembers()) { - this.addMember(uuid); - } - - for (UUID uuid : this.getDenied()) { - b.addDenied(uuid); - } - for (UUID uuid : b.getDenied()) { - this.addDenied(uuid); - } - } - - /** - * Remove the SE road (only effects terrain) - */ - public void removeRoadSouthEast() { - if (this.area.TYPE != 0 && this.area.TERRAIN > 1) { - if (this.area.TERRAIN == 3) { - return; - } - Plot other = this.getRelative(1, 1); - Location pos1 = this.getTopAbs().add(1, 0, 1); - Location pos2 = other.getBottomAbs().subtract(1, 0, 1); - pos1.setY(0); - pos2.setY(256); - ChunkManager.manager.regenerateRegion(pos1, pos2, true, null); + if (merged[1]) { + tmp = this.area.getPlotAbs(this.id.getRelative(1)); + if (!tmp.getMerged(3)) { + // invalid merge + PlotSquared.debug("Fixing invalid merge: " + this); + if (tmp.isOwnerAbs(this.owner)) { + tmp.getSettings().setMerged(3, true); + DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); } else { - this.area.getPlotManager().removeRoadSouthEast(this.area, this); + this.getSettings().setMerged(1, false); + DBFunc.setMerged(this, this.getSettings().getMerged()); } + } + queuecache.add(tmp); + frontier.add(tmp); } - - /** - * Get the plot in a relative location
- * Note: May be null if the partial plot area does not include the relative location - * - * @param x - * @param y - * @return Plot - */ - public Plot getRelative(int x, int y) { - return this.area.getPlotAbs(this.id.getRelative(x, y)); + if (merged[2]) { + tmp = this.area.getPlotAbs(this.id.getRelative(2)); + if (!tmp.getMerged(0)) { + // invalid merge + PlotSquared.debug("Fixing invalid merge: " + this); + if (tmp.isOwnerAbs(this.owner)) { + tmp.getSettings().setMerged(0, true); + DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); + } else { + this.getSettings().setMerged(2, false); + DBFunc.setMerged(this, this.getSettings().getMerged()); + } + } + queuecache.add(tmp); + frontier.add(tmp); } - - public Plot getRelative(PlotArea area, int x, int y) { - return area.getPlotAbs(this.id.getRelative(x, y)); + if (merged[3]) { + tmp = this.area.getPlotAbs(this.id.getRelative(3)); + if (!tmp.getMerged(1)) { + // invalid merge + PlotSquared.debug("Fixing invalid merge: " + this); + if (tmp.isOwnerAbs(this.owner)) { + tmp.getSettings().setMerged(1, true); + DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); + } else { + this.getSettings().setMerged(3, false); + DBFunc.setMerged(this, this.getSettings().getMerged()); + } + } + queuecache.add(tmp); + frontier.add(tmp); } - - /** - * Get the plot in a relative direction
- * 0 = north
- * 1 = east
- * 2 = south
- * 3 = west
- * Note: May be null if the partial plot area does not include the relative location - * - * @param direction - * @return - */ - public Plot getRelative(int direction) { - return this.area.getPlotAbs(this.id.getRelative(direction)); + Plot current; + while ((current = frontier.poll()) != null) { + if (current.owner == null || current.settings == null) { + // Invalid plot + // merged onto unclaimed plot + PlotSquared + .debug("Ignoring invalid merged plot: " + current + " | " + current.owner); + continue; + } + tmpSet.add(current); + queuecache.remove(current); + merged = current.getMerged(); + if (merged[0]) { + tmp = current.area.getPlotAbs(current.id.getRelative(0)); + if (tmp != null && !queuecache.contains(tmp) && !tmpSet.contains(tmp)) { + queuecache.add(tmp); + frontier.add(tmp); + } + } + if (merged[1]) { + tmp = current.area.getPlotAbs(current.id.getRelative(1)); + if (tmp != null && !queuecache.contains(tmp) && !tmpSet.contains(tmp)) { + queuecache.add(tmp); + frontier.add(tmp); + } + } + if (merged[2]) { + tmp = current.area.getPlotAbs(current.id.getRelative(2)); + if (tmp != null && !queuecache.contains(tmp) && !tmpSet.contains(tmp)) { + queuecache.add(tmp); + frontier.add(tmp); + } + } + if (merged[3]) { + tmp = current.area.getPlotAbs(current.id.getRelative(3)); + if (tmp != null && !queuecache.contains(tmp) && !tmpSet.contains(tmp)) { + queuecache.add(tmp); + frontier.add(tmp); + } + } } + connected_cache = tmpSet; + return tmpSet; + } - /** - * Get a set of plots connected (and including) this plot
- * - This result is cached globally - * - * @return - */ - public Set getConnectedPlots() { - if (this.settings == null) { - return Collections.singleton(this); - } - boolean[] merged = this.getMerged(); - int hash = MainUtil.hash(merged); - if (hash == 0) { - return Collections.singleton(this); - } - if (connected_cache != null && connected_cache.contains(this)) { - return connected_cache; - } - regions_cache = null; - - HashSet tmpSet = new HashSet<>(); - ArrayDeque frontier = new ArrayDeque<>(); - HashSet queuecache = new HashSet<>(); - tmpSet.add(this); - Plot tmp; - if (merged[0]) { - tmp = this.area.getPlotAbs(this.id.getRelative(0)); - if (!tmp.getMerged(2)) { - // invalid merge - PlotSquared.debug("Fixing invalid merge: " + this); - if (tmp.isOwnerAbs(this.owner)) { - tmp.getSettings().setMerged(2, true); - DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); - } else { - this.getSettings().setMerged(0, false); - DBFunc.setMerged(this, this.getSettings().getMerged()); - } - } - queuecache.add(tmp); - frontier.add(tmp); - } - if (merged[1]) { - tmp = this.area.getPlotAbs(this.id.getRelative(1)); - if (!tmp.getMerged(3)) { - // invalid merge - PlotSquared.debug("Fixing invalid merge: " + this); - if (tmp.isOwnerAbs(this.owner)) { - tmp.getSettings().setMerged(3, true); - DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); - } else { - this.getSettings().setMerged(1, false); - DBFunc.setMerged(this, this.getSettings().getMerged()); - } - } - queuecache.add(tmp); - frontier.add(tmp); - } - if (merged[2]) { - tmp = this.area.getPlotAbs(this.id.getRelative(2)); - if (!tmp.getMerged(0)) { - // invalid merge - PlotSquared.debug("Fixing invalid merge: " + this); - if (tmp.isOwnerAbs(this.owner)) { - tmp.getSettings().setMerged(0, true); - DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); - } else { - this.getSettings().setMerged(2, false); - DBFunc.setMerged(this, this.getSettings().getMerged()); - } - } - queuecache.add(tmp); - frontier.add(tmp); - } - if (merged[3]) { - tmp = this.area.getPlotAbs(this.id.getRelative(3)); - if (!tmp.getMerged(1)) { - // invalid merge - PlotSquared.debug("Fixing invalid merge: " + this); - if (tmp.isOwnerAbs(this.owner)) { - tmp.getSettings().setMerged(1, true); - DBFunc.setMerged(tmp, tmp.getSettings().getMerged()); - } else { - this.getSettings().setMerged(3, false); - DBFunc.setMerged(this, this.getSettings().getMerged()); - } - } - queuecache.add(tmp); - frontier.add(tmp); - } - Plot current; - while ((current = frontier.poll()) != null) { - if (current.owner == null || current.settings == null) { - // Invalid plot - // merged onto unclaimed plot - PlotSquared - .debug("Ignoring invalid merged plot: " + current + " | " + current.owner); - continue; - } - tmpSet.add(current); - queuecache.remove(current); - merged = current.getMerged(); - if (merged[0]) { - tmp = current.area.getPlotAbs(current.id.getRelative(0)); - if (tmp != null && !queuecache.contains(tmp) && !tmpSet.contains(tmp)) { - queuecache.add(tmp); - frontier.add(tmp); - } - } - if (merged[1]) { - tmp = current.area.getPlotAbs(current.id.getRelative(1)); - if (tmp != null && !queuecache.contains(tmp) && !tmpSet.contains(tmp)) { - queuecache.add(tmp); - frontier.add(tmp); - } - } - if (merged[2]) { - tmp = current.area.getPlotAbs(current.id.getRelative(2)); - if (tmp != null && !queuecache.contains(tmp) && !tmpSet.contains(tmp)) { - queuecache.add(tmp); - frontier.add(tmp); - } - } - if (merged[3]) { - tmp = current.area.getPlotAbs(current.id.getRelative(3)); - if (tmp != null && !queuecache.contains(tmp) && !tmpSet.contains(tmp)) { - queuecache.add(tmp); - frontier.add(tmp); - } - } - } - connected_cache = tmpSet; - return tmpSet; + /** + * This will combine each plot into effective rectangular regions
- This result is cached + * globally
- Useful for handling non rectangular shapes + */ + public HashSet getRegions() { + if (regions_cache != null && connected_cache != null && connected_cache.contains(this)) { + return regions_cache; } - - /** - * This will combine each plot into effective rectangular regions
- * - This result is cached globally
- * - Useful for handling non rectangular shapes - * - * @return - */ - public HashSet getRegions() { - if (regions_cache != null && connected_cache != null && connected_cache.contains(this)) { - return regions_cache; + if (!this.isMerged()) { + Location pos1 = this.getBottomAbs(); + Location pos2 = this.getTopAbs(); + connected_cache = new HashSet<>(Collections.singletonList(this)); + regions_cache = new HashSet<>(1); + regions_cache.add( + new RegionWrapper(pos1.getX(), pos2.getX(), pos1.getY(), pos2.getY(), pos1.getZ(), + pos2.getZ())); + return regions_cache; + } + Set plots = this.getConnectedPlots(); + HashSet regions = regions_cache = new HashSet<>(); + HashSet visited = new HashSet<>(); + for (Plot current : plots) { + if (visited.contains(current.getId())) { + continue; + } + boolean merge = true; + PlotId bot = new PlotId(current.getId().x, current.getId().y); + PlotId top = new PlotId(current.getId().x, current.getId().y); + while (merge) { + merge = false; + ArrayList ids = MainUtil.getPlotSelectionIds(new PlotId(bot.x, bot.y - 1), + new PlotId(top.x, bot.y - 1)); + boolean tmp = true; + for (PlotId id : ids) { + Plot plot = this.area.getPlotAbs(id); + if (plot == null || !plot.getMerged(2) || visited.contains(plot.getId())) { + tmp = false; + } } - if (!this.isMerged()) { - Location pos1 = this.getBottomAbs(); - Location pos2 = this.getTopAbs(); - connected_cache = new HashSet<>(Collections.singletonList(this)); - regions_cache = new HashSet<>(1); - regions_cache.add( - new RegionWrapper(pos1.getX(), pos2.getX(), pos1.getY(), pos2.getY(), pos1.getZ(), - pos2.getZ())); - return regions_cache; + if (tmp) { + merge = true; + bot.y--; } - Set plots = this.getConnectedPlots(); - HashSet regions = regions_cache = new HashSet<>(); - HashSet visited = new HashSet<>(); - for (Plot current : plots) { - if (visited.contains(current.getId())) { - continue; - } - boolean merge = true; - PlotId bot = new PlotId(current.getId().x, current.getId().y); - PlotId top = new PlotId(current.getId().x, current.getId().y); - while (merge) { - merge = false; - ArrayList ids = MainUtil.getPlotSelectionIds(new PlotId(bot.x, bot.y - 1), - new PlotId(top.x, bot.y - 1)); - boolean tmp = true; - for (PlotId id : ids) { - Plot plot = this.area.getPlotAbs(id); - if (plot == null || !plot.getMerged(2) || visited.contains(plot.getId())) { - tmp = false; - } - } - if (tmp) { - merge = true; - bot.y--; - } - ids = MainUtil.getPlotSelectionIds(new PlotId(top.x + 1, bot.y), - new PlotId(top.x + 1, top.y)); - tmp = true; - for (PlotId id : ids) { - Plot plot = this.area.getPlotAbs(id); - if (plot == null || !plot.getMerged(3) || visited.contains(plot.getId())) { - tmp = false; - } - } - if (tmp) { - merge = true; - top.x++; - } - ids = MainUtil.getPlotSelectionIds(new PlotId(bot.x, top.y + 1), - new PlotId(top.x, top.y + 1)); - tmp = true; - for (PlotId id : ids) { - Plot plot = this.area.getPlotAbs(id); - if (plot == null || !plot.getMerged(0) || visited.contains(plot.getId())) { - tmp = false; - } - } - if (tmp) { - merge = true; - top.y++; - } - ids = MainUtil.getPlotSelectionIds(new PlotId(bot.x - 1, bot.y), - new PlotId(bot.x - 1, top.y)); - tmp = true; - for (PlotId id : ids) { - Plot plot = this.area.getPlotAbs(id); - if (plot == null || !plot.getMerged(1) || visited.contains(plot.getId())) { - tmp = false; - } - } - if (tmp) { - merge = true; - bot.x--; - } - } - Location gtopabs = this.area.getPlotAbs(top).getTopAbs(); - Location gbotabs = this.area.getPlotAbs(bot).getBottomAbs(); - for (PlotId id : MainUtil.getPlotSelectionIds(bot, top)) { - visited.add(id); - } - for (int x = bot.x; x <= top.x; x++) { - Plot plot = this.area.getPlotAbs(new PlotId(x, top.y)); - if (plot.getMerged(2)) { - // south wedge - Location toploc = plot.getExtendedTopAbs(); - Location botabs = plot.getBottomAbs(); - Location topabs = plot.getTopAbs(); - regions.add(new RegionWrapper(botabs.getX(), topabs.getX(), topabs.getZ() + 1, - toploc.getZ())); - if (plot.getMerged(5)) { - regions.add( - new RegionWrapper(topabs.getX() + 1, toploc.getX(), topabs.getZ() + 1, - toploc.getZ())); - // intersection - } - } - } - - for (int y = bot.y; y <= top.y; y++) { - Plot plot = this.area.getPlotAbs(new PlotId(top.x, y)); - if (plot.getMerged(1)) { - // east wedge - Location toploc = plot.getExtendedTopAbs(); - Location botabs = plot.getBottomAbs(); - Location topabs = plot.getTopAbs(); - regions.add(new RegionWrapper(topabs.getX() + 1, toploc.getX(), botabs.getZ(), - topabs.getZ())); - if (plot.getMerged(5)) { - regions.add( - new RegionWrapper(topabs.getX() + 1, toploc.getX(), topabs.getZ() + 1, - toploc.getZ())); - // intersection - } - } - } + ids = MainUtil.getPlotSelectionIds(new PlotId(top.x + 1, bot.y), + new PlotId(top.x + 1, top.y)); + tmp = true; + for (PlotId id : ids) { + Plot plot = this.area.getPlotAbs(id); + if (plot == null || !plot.getMerged(3) || visited.contains(plot.getId())) { + tmp = false; + } + } + if (tmp) { + merge = true; + top.x++; + } + ids = MainUtil.getPlotSelectionIds(new PlotId(bot.x, top.y + 1), + new PlotId(top.x, top.y + 1)); + tmp = true; + for (PlotId id : ids) { + Plot plot = this.area.getPlotAbs(id); + if (plot == null || !plot.getMerged(0) || visited.contains(plot.getId())) { + tmp = false; + } + } + if (tmp) { + merge = true; + top.y++; + } + ids = MainUtil.getPlotSelectionIds(new PlotId(bot.x - 1, bot.y), + new PlotId(bot.x - 1, top.y)); + tmp = true; + for (PlotId id : ids) { + Plot plot = this.area.getPlotAbs(id); + if (plot == null || !plot.getMerged(1) || visited.contains(plot.getId())) { + tmp = false; + } + } + if (tmp) { + merge = true; + bot.x--; + } + } + Location gtopabs = this.area.getPlotAbs(top).getTopAbs(); + Location gbotabs = this.area.getPlotAbs(bot).getBottomAbs(); + visited.addAll(MainUtil.getPlotSelectionIds(bot, top)); + for (int x = bot.x; x <= top.x; x++) { + Plot plot = this.area.getPlotAbs(new PlotId(x, top.y)); + if (plot.getMerged(2)) { + // south wedge + Location toploc = plot.getExtendedTopAbs(); + Location botabs = plot.getBottomAbs(); + Location topabs = plot.getTopAbs(); + regions.add(new RegionWrapper(botabs.getX(), topabs.getX(), topabs.getZ() + 1, + toploc.getZ())); + if (plot.getMerged(5)) { regions.add( - new RegionWrapper(gbotabs.getX(), gtopabs.getX(), gbotabs.getZ(), gtopabs.getZ())); + new RegionWrapper(topabs.getX() + 1, toploc.getX(), topabs.getZ() + 1, + toploc.getZ())); + // intersection + } } - return regions; - } + } - /** - * Attempt to find the largest rectangular region in a plot (as plots can form non rectangular shapes) - * - * @return - */ - public RegionWrapper getLargestRegion() { - HashSet regions = this.getRegions(); - RegionWrapper max = null; - double area = Double.NEGATIVE_INFINITY; - for (RegionWrapper region : regions) { - double current = - (region.maxX - (double) region.minX + 1) * (region.maxZ - (double) region.minZ + 1); - if (current > area) { - max = region; - area = current; - } + for (int y = bot.y; y <= top.y; y++) { + Plot plot = this.area.getPlotAbs(new PlotId(top.x, y)); + if (plot.getMerged(1)) { + // east wedge + Location toploc = plot.getExtendedTopAbs(); + Location botabs = plot.getBottomAbs(); + Location topabs = plot.getTopAbs(); + regions.add(new RegionWrapper(topabs.getX() + 1, toploc.getX(), botabs.getZ(), + topabs.getZ())); + if (plot.getMerged(5)) { + regions.add( + new RegionWrapper(topabs.getX() + 1, toploc.getX(), topabs.getZ() + 1, + toploc.getZ())); + // intersection + } } - return max; + } + regions.add( + new RegionWrapper(gbotabs.getX(), gtopabs.getX(), gbotabs.getZ(), gtopabs.getZ())); } + return regions; + } - /** - * Do the plot entry tasks for each player in the plot
- * - Usually called when the plot state changes (unclaimed/claimed/flag change etc) - */ - public void reEnter() { - TaskManager.runTaskLater(() -> { - for (PlotPlayer pp : Plot.this.getPlayersInPlot()) { - PlotListener.plotExit(pp, Plot.this); - PlotListener.plotEntry(pp, Plot.this); - } - }, 1); + /** + * Attempt to find the largest rectangular region in a plot (as plots can form non rectangular + * shapes) + */ + public RegionWrapper getLargestRegion() { + HashSet regions = this.getRegions(); + RegionWrapper max = null; + double area = Double.NEGATIVE_INFINITY; + for (RegionWrapper region : regions) { + double current = + (region.maxX - (double) region.minX + 1) * (region.maxZ - (double) region.minZ + 1); + if (current > area) { + max = region; + area = current; + } } + return max; + } - /** - * Get all the corners of the plot (supports non-rectangular shapes). - * - * @return A list of the plot corners - */ - public List getAllCorners() { - Area area = new Area(); - for (RegionWrapper region : this.getRegions()) { - Rectangle2D rect = new Rectangle2D.Double(region.minX - 0.6, region.minZ - 0.6, - region.maxX - region.minX + 1.2, region.maxZ - region.minZ + 1.2); - Area rectArea = new Area(rect); - area.add(rectArea); - } - List locs = new ArrayList<>(); - double[] coords = new double[6]; - for (PathIterator pi = area.getPathIterator(null); !pi.isDone(); pi.next()) { - int type = pi.currentSegment(coords); - int x = (int) MathMan.inverseRound(coords[0]); - int z = (int) MathMan.inverseRound(coords[1]); - if (type != 4) { - locs.add(new Location(this.getWorldName(), x, 0, z)); - } - } - return locs; + /** + * Do the plot entry tasks for each player in the plot
- Usually called when the plot state + * changes (unclaimed/claimed/flag change etc) + */ + public void reEnter() { + TaskManager.runTaskLater(() -> { + for (PlotPlayer pp : Plot.this.getPlayersInPlot()) { + PlotListener.plotExit(pp, Plot.this); + PlotListener.plotEntry(pp, Plot.this); + } + }, 1); + } + + /** + * Get all the corners of the plot (supports non-rectangular shapes). + * + * @return A list of the plot corners + */ + public List getAllCorners() { + Area area = new Area(); + for (RegionWrapper region : this.getRegions()) { + Rectangle2D rect = new Rectangle2D.Double(region.minX - 0.6, region.minZ - 0.6, + region.maxX - region.minX + 1.2, region.maxZ - region.minZ + 1.2); + Area rectArea = new Area(rect); + area.add(rectArea); } - - /** - * Teleport a player to a plot and send them the teleport message. - * - * @param player the player - * @return if the teleport succeeded - */ - public boolean teleportPlayer(final PlotPlayer player) { - Plot plot = this.getBasePlot(false); - boolean result = EventUtil.manager.callTeleport(player, player.getLocation(), plot); - if (result) { - final Location location; - if (this.area.HOME_ALLOW_NONMEMBER || plot.isAdded(player.getUUID())) { - location = this.getHome(); - } else { - location = this.getDefaultHome(false); - } - if (Settings.Teleport.DELAY == 0 || Permissions - .hasPermission(player, "plots.teleport.delay.bypass")) { - MainUtil.sendMessage(player, C.TELEPORTED_TO_PLOT); - player.teleport(location); - return true; - } - MainUtil.sendMessage(player, C.TELEPORT_IN_SECONDS, Settings.Teleport.DELAY + ""); - final String name = player.getName(); - TaskManager.TELEPORT_QUEUE.add(name); - TaskManager.runTaskLater(() -> { - if (!TaskManager.TELEPORT_QUEUE.contains(name)) { - MainUtil.sendMessage(player, C.TELEPORT_FAILED); - return; - } - TaskManager.TELEPORT_QUEUE.remove(name); - if (player.isOnline()) { - MainUtil.sendMessage(player, C.TELEPORTED_TO_PLOT); - player.teleport(location); - } - }, Settings.Teleport.DELAY * 20); - return true; - } - return false; + List locs = new ArrayList<>(); + double[] coords = new double[6]; + for (PathIterator pi = area.getPathIterator(null); !pi.isDone(); pi.next()) { + int type = pi.currentSegment(coords); + int x = (int) MathMan.inverseRound(coords[0]); + int z = (int) MathMan.inverseRound(coords[1]); + if (type != 4) { + locs.add(new Location(this.getWorldName(), x, 0, z)); + } } + return locs; + } - public boolean isOnline() { - if (this.owner == null) { - return false; - } - if (!isMerged()) { - return UUIDHandler.getPlayer(this.owner) != null; - } - for (Plot current : getConnectedPlots()) { - if (current.hasOwner() && UUIDHandler.getPlayer(current.owner) != null) { - return true; - } - } - return false; - } - - /** - * Set a component for a plot to the provided blocks
- * - E.g. floor, wall, border etc.
- * - The available components depend on the generator being used
- * - * @param component - * @param blocks - * @return - */ - public boolean setComponent(String component, BlockBucket blocks) { - if (StringMan - .isEqualToAny(component, getManager().getPlotComponents(this.area, this.getId()))) { - EventUtil.manager.callComponentSet(this, component); - } - return this.getManager().setComponent(this.area, this.getId(), component, blocks); - } - - public int getDistanceFromOrigin() { - Location bot = getManager().getPlotBottomLocAbs(this.area, id); - Location top = getManager().getPlotTopLocAbs(this.area, id); - return Math.max(Math.max(Math.abs(bot.getX()), Math.abs(bot.getZ())), - Math.max(Math.abs(top.getX()), Math.abs(top.getZ()))); - } - - /** - * Expand the world border to include the provided plot (if applicable). - */ - public void updateWorldBorder() { - if (this.owner == null) { - return; - } - int border = this.area.getBorder(); - if (border == Integer.MAX_VALUE) { - return; - } - int max = getDistanceFromOrigin(); - if (max > border) { - this.area.setMeta("worldBorder", max); - } - } - - /** - * Merges 2 plots Removes the road in-between
- Assumes plots are directly next to each other
- saves to DB - * - * @param lesserPlot - * @param removeRoads - */ - public void mergePlot(Plot lesserPlot, boolean removeRoads) { - Plot greaterPlot = this; - if (lesserPlot.getId().x == greaterPlot.getId().x) { - if (lesserPlot.getId().y > greaterPlot.getId().y) { - Plot tmp = lesserPlot; - lesserPlot = greaterPlot; - greaterPlot = tmp; - } - if (!lesserPlot.getMerged(2)) { - lesserPlot.clearRatings(); - greaterPlot.clearRatings(); - lesserPlot.setMerged(2, true); - greaterPlot.setMerged(0, true); - lesserPlot.mergeData(greaterPlot); - if (removeRoads) { - lesserPlot.removeRoadSouth(); - Plot diagonal = greaterPlot.getRelative(1); - if (diagonal.getMerged(7)) { - lesserPlot.removeRoadSouthEast(); - } - Plot below = greaterPlot.getRelative(3); - if (below.getMerged(4)) { - below.getRelative(0).removeRoadSouthEast(); - } - } - } - } else { - if (lesserPlot.getId().x > greaterPlot.getId().x) { - Plot tmp = lesserPlot; - lesserPlot = greaterPlot; - greaterPlot = tmp; - } - if (!lesserPlot.getMerged(1)) { - lesserPlot.clearRatings(); - greaterPlot.clearRatings(); - lesserPlot.setMerged(1, true); - greaterPlot.setMerged(3, true); - lesserPlot.mergeData(greaterPlot); - if (removeRoads) { - Plot diagonal = greaterPlot.getRelative(2); - if (diagonal.getMerged(7)) { - lesserPlot.removeRoadSouthEast(); - } - lesserPlot.removeRoadEast(); - } - Plot below = greaterPlot.getRelative(0); - if (below.getMerged(6)) { - below.getRelative(3).removeRoadSouthEast(); - } - } - } - } - - /** - * Move a plot physically, as well as the corresponding settings. - * - * @param destination Plot moved to - * @param whenDone task when done - * @param allowSwap whether to swap plots - * @return success - */ - public boolean move(final Plot destination, final Runnable whenDone, boolean allowSwap) { - final PlotId offset = new PlotId(destination.getId().x - this.getId().x, - destination.getId().y - this.getId().y); - Location db = destination.getBottomAbs(); - Location ob = this.getBottomAbs(); - final int offsetX = db.getX() - ob.getX(); - final int offsetZ = db.getZ() - ob.getZ(); - if (this.owner == null) { - TaskManager.runTaskLater(whenDone, 1); - return false; - } - boolean occupied = false; - Set plots = this.getConnectedPlots(); - for (Plot plot : plots) { - Plot other = plot.getRelative(destination.getArea(), offset.x, offset.y); - if (other.hasOwner()) { - if (!allowSwap) { - TaskManager.runTaskLater(whenDone, 1); - return false; - } - occupied = true; - } else { - plot.removeSign(); - } - } - // world border - destination.updateWorldBorder(); - final ArrayDeque regions = new ArrayDeque<>(this.getRegions()); - // move / swap data - final PlotArea originArea = getArea(); - for (Plot plot : plots) { - Plot other = plot.getRelative(destination.getArea(), offset.x, offset.y); - plot.swapData(other, null); - } - // copy terrain - Runnable move = new Runnable() { - @Override public void run() { - if (regions.isEmpty()) { - Plot plot = destination.getRelative(0, 0); - for (Plot current : plot.getConnectedPlots()) { - getManager().claimPlot(current.getArea(), current); - Plot originPlot = originArea.getPlotAbs( - new PlotId(current.id.x - offset.x, current.id.y - offset.y)); - originPlot.getManager().unclaimPlot(originArea, originPlot, null); - } - plot.setSign(); - TaskManager.runTask(whenDone); - return; - } - final Runnable task = this; - RegionWrapper region = regions.poll(); - Location[] corners = region.getCorners(getWorldName()); - final Location pos1 = corners[0]; - final Location pos2 = corners[1]; - Location newPos = pos1.clone().add(offsetX, 0, offsetZ); - newPos.setWorld(destination.getWorldName()); - ChunkManager.manager.copyRegion(pos1, pos2, newPos, - () -> ChunkManager.manager.regenerateRegion(pos1, pos2, false, task)); - } - }; - Runnable swap = new Runnable() { - @Override public void run() { - if (regions.isEmpty()) { - TaskManager.runTask(whenDone); - return; - } - RegionWrapper region = regions.poll(); - Location[] corners = region.getCorners(getWorldName()); - Location pos1 = corners[0]; - Location pos2 = corners[1]; - Location pos3 = pos1.clone().add(offsetX, 0, offsetZ); - Location pos4 = pos2.clone().add(offsetX, 0, offsetZ); - pos3.setWorld(destination.getWorldName()); - pos4.setWorld(destination.getWorldName()); - ChunkManager.manager.swap(pos1, pos2, pos3, pos4, this); - } - }; - if (occupied) { - swap.run(); - } else { - move.run(); - } + /** + * Teleport a player to a plot and send them the teleport message. + * + * @param player the player + * @return if the teleport succeeded + */ + public boolean teleportPlayer(final PlotPlayer player) { + Plot plot = this.getBasePlot(false); + boolean result = EventUtil.manager.callTeleport(player, player.getLocation(), plot); + if (result) { + final Location location; + if (this.area.HOME_ALLOW_NONMEMBER || plot.isAdded(player.getUUID())) { + location = this.getHome(); + } else { + location = this.getDefaultHome(false); + } + if (Settings.Teleport.DELAY == 0 || Permissions + .hasPermission(player, "plots.teleport.delay.bypass")) { + MainUtil.sendMessage(player, C.TELEPORTED_TO_PLOT); + player.teleport(location); return true; + } + MainUtil.sendMessage(player, C.TELEPORT_IN_SECONDS, Settings.Teleport.DELAY + ""); + final String name = player.getName(); + TaskManager.TELEPORT_QUEUE.add(name); + TaskManager.runTaskLater(() -> { + if (!TaskManager.TELEPORT_QUEUE.contains(name)) { + MainUtil.sendMessage(player, C.TELEPORT_FAILED); + return; + } + TaskManager.TELEPORT_QUEUE.remove(name); + if (player.isOnline()) { + MainUtil.sendMessage(player, C.TELEPORTED_TO_PLOT); + player.teleport(location); + } + }, Settings.Teleport.DELAY * 20); + return true; } + return false; + } - /** - * Copy a plot to a location, both physically and the settings - * - * @param destination - * @param whenDone - * @return - */ - public boolean copy(final Plot destination, final Runnable whenDone) { - PlotId offset = new PlotId(destination.getId().x - this.getId().x, - destination.getId().y - this.getId().y); - Location db = destination.getBottomAbs(); - Location ob = this.getBottomAbs(); - final int offsetX = db.getX() - ob.getX(); - final int offsetZ = db.getZ() - ob.getZ(); - if (this.owner == null) { - TaskManager.runTaskLater(whenDone, 1); - return false; - } - Set plots = this.getConnectedPlots(); - for (Plot plot : plots) { - Plot other = plot.getRelative(destination.getArea(), offset.x, offset.y); - if (other.hasOwner()) { - TaskManager.runTaskLater(whenDone, 1); - return false; - } - } - // world border - destination.updateWorldBorder(); - // copy data - for (Plot plot : plots) { - Plot other = plot.getRelative(destination.getArea(), offset.x, offset.y); - other.create(plot.owner, false); - if (!plot.getFlags().isEmpty()) { - other.getSettings().flags = plot.getFlags(); - DBFunc.setFlags(other, plot.getFlags()); - } - if (plot.isMerged()) { - other.setMerged(plot.getMerged()); - } - if (plot.members != null && !plot.members.isEmpty()) { - other.members = plot.members; - for (UUID member : plot.members) { - DBFunc.setMember(other, member); - } - } - if (plot.trusted != null && !plot.trusted.isEmpty()) { - other.trusted = plot.trusted; - for (UUID trusted : plot.trusted) { - DBFunc.setTrusted(other, trusted); - } - } - if (plot.denied != null && !plot.denied.isEmpty()) { - other.denied = plot.denied; - for (UUID denied : plot.denied) { - DBFunc.setDenied(other, denied); - } - } - } - // copy terrain - final ArrayDeque regions = new ArrayDeque<>(this.getRegions()); - Runnable run = new Runnable() { - @Override public void run() { - if (regions.isEmpty()) { - for (Plot current : getConnectedPlots()) { - destination.getManager().claimPlot(destination.getArea(), destination); - } - destination.setSign(); - TaskManager.runTask(whenDone); - return; - } - RegionWrapper region = regions.poll(); - Location[] corners = region.getCorners(getWorldName()); - Location pos1 = corners[0]; - Location pos2 = corners[1]; - Location newPos = pos1.clone().add(offsetX, 0, offsetZ); - newPos.setWorld(destination.getWorldName()); - ChunkManager.manager.copyRegion(pos1, pos2, newPos, this); - } - }; - run.run(); + public boolean isOnline() { + if (this.owner == null) { + return false; + } + if (!isMerged()) { + return UUIDHandler.getPlayer(this.owner) != null; + } + for (Plot current : getConnectedPlots()) { + if (current.hasOwner() && UUIDHandler.getPlayer(current.owner) != null) { return true; + } } + return false; + } - public boolean hasFlag(Flag flag) { - return getFlags().containsKey(flag); + /** + * Set a component for a plot to the provided blocks
- E.g. floor, wall, border etc.
- The + * available components depend on the generator being used
+ */ + public boolean setComponent(String component, BlockBucket blocks) { + if (StringMan + .isEqualToAny(component, getManager().getPlotComponents(this.area, this.getId()))) { + EventUtil.manager.callComponentSet(this, component); } + return this.getManager().setComponent(this.area, this.getId(), component, blocks); + } + + public int getDistanceFromOrigin() { + Location bot = getManager().getPlotBottomLocAbs(this.area, id); + Location top = getManager().getPlotTopLocAbs(this.area, id); + return Math.max(Math.max(Math.abs(bot.getX()), Math.abs(bot.getZ())), + Math.max(Math.abs(top.getX()), Math.abs(top.getZ()))); + } + + /** + * Expand the world border to include the provided plot (if applicable). + */ + public void updateWorldBorder() { + if (this.owner == null) { + return; + } + int border = this.area.getBorder(); + if (border == Integer.MAX_VALUE) { + return; + } + int max = getDistanceFromOrigin(); + if (max > border) { + this.area.setMeta("worldBorder", max); + } + } + + /** + * Merges 2 plots Removes the road in-between
- Assumes plots are directly next to each other + *
- saves to DB + */ + public void mergePlot(Plot lesserPlot, boolean removeRoads) { + Plot greaterPlot = this; + if (lesserPlot.getId().x == greaterPlot.getId().x) { + if (lesserPlot.getId().y > greaterPlot.getId().y) { + Plot tmp = lesserPlot; + lesserPlot = greaterPlot; + greaterPlot = tmp; + } + if (!lesserPlot.getMerged(2)) { + lesserPlot.clearRatings(); + greaterPlot.clearRatings(); + lesserPlot.setMerged(2, true); + greaterPlot.setMerged(0, true); + lesserPlot.mergeData(greaterPlot); + if (removeRoads) { + lesserPlot.removeRoadSouth(); + Plot diagonal = greaterPlot.getRelative(1); + if (diagonal.getMerged(7)) { + lesserPlot.removeRoadSouthEast(); + } + Plot below = greaterPlot.getRelative(3); + if (below.getMerged(4)) { + below.getRelative(0).removeRoadSouthEast(); + } + } + } + } else { + if (lesserPlot.getId().x > greaterPlot.getId().x) { + Plot tmp = lesserPlot; + lesserPlot = greaterPlot; + greaterPlot = tmp; + } + if (!lesserPlot.getMerged(1)) { + lesserPlot.clearRatings(); + greaterPlot.clearRatings(); + lesserPlot.setMerged(1, true); + greaterPlot.setMerged(3, true); + lesserPlot.mergeData(greaterPlot); + if (removeRoads) { + Plot diagonal = greaterPlot.getRelative(2); + if (diagonal.getMerged(7)) { + lesserPlot.removeRoadSouthEast(); + } + lesserPlot.removeRoadEast(); + } + Plot below = greaterPlot.getRelative(0); + if (below.getMerged(6)) { + below.getRelative(3).removeRoadSouthEast(); + } + } + } + } + + /** + * Move a plot physically, as well as the corresponding settings. + * + * @param destination Plot moved to + * @param whenDone task when done + * @param allowSwap whether to swap plots + * @return success + */ + public boolean move(final Plot destination, final Runnable whenDone, boolean allowSwap) { + final PlotId offset = new PlotId(destination.getId().x - this.getId().x, + destination.getId().y - this.getId().y); + Location db = destination.getBottomAbs(); + Location ob = this.getBottomAbs(); + final int offsetX = db.getX() - ob.getX(); + final int offsetZ = db.getZ() - ob.getZ(); + if (this.owner == null) { + TaskManager.runTaskLater(whenDone, 1); + return false; + } + boolean occupied = false; + Set plots = this.getConnectedPlots(); + for (Plot plot : plots) { + Plot other = plot.getRelative(destination.getArea(), offset.x, offset.y); + if (other.hasOwner()) { + if (!allowSwap) { + TaskManager.runTaskLater(whenDone, 1); + return false; + } + occupied = true; + } else { + plot.removeSign(); + } + } + // world border + destination.updateWorldBorder(); + final ArrayDeque regions = new ArrayDeque<>(this.getRegions()); + // move / swap data + final PlotArea originArea = getArea(); + for (Plot plot : plots) { + Plot other = plot.getRelative(destination.getArea(), offset.x, offset.y); + plot.swapData(other, null); + } + // copy terrain + Runnable move = new Runnable() { + @Override + public void run() { + if (regions.isEmpty()) { + Plot plot = destination.getRelative(0, 0); + for (Plot current : plot.getConnectedPlots()) { + getManager().claimPlot(current.getArea(), current); + Plot originPlot = originArea.getPlotAbs( + new PlotId(current.id.x - offset.x, current.id.y - offset.y)); + originPlot.getManager().unclaimPlot(originArea, originPlot, null); + } + plot.setSign(); + TaskManager.runTask(whenDone); + return; + } + final Runnable task = this; + RegionWrapper region = regions.poll(); + Location[] corners = region.getCorners(getWorldName()); + final Location pos1 = corners[0]; + final Location pos2 = corners[1]; + Location newPos = pos1.clone().add(offsetX, 0, offsetZ); + newPos.setWorld(destination.getWorldName()); + ChunkManager.manager.copyRegion(pos1, pos2, newPos, + () -> ChunkManager.manager.regenerateRegion(pos1, pos2, false, task)); + } + }; + Runnable swap = new Runnable() { + @Override + public void run() { + if (regions.isEmpty()) { + TaskManager.runTask(whenDone); + return; + } + RegionWrapper region = regions.poll(); + Location[] corners = region.getCorners(getWorldName()); + Location pos1 = corners[0]; + Location pos2 = corners[1]; + Location pos3 = pos1.clone().add(offsetX, 0, offsetZ); + Location pos4 = pos2.clone().add(offsetX, 0, offsetZ); + pos3.setWorld(destination.getWorldName()); + pos4.setWorld(destination.getWorldName()); + ChunkManager.manager.swap(pos1, pos2, pos3, pos4, this); + } + }; + if (occupied) { + swap.run(); + } else { + move.run(); + } + return true; + } + + /** + * Copy a plot to a location, both physically and the settings + */ + public boolean copy(final Plot destination, final Runnable whenDone) { + PlotId offset = new PlotId(destination.getId().x - this.getId().x, + destination.getId().y - this.getId().y); + Location db = destination.getBottomAbs(); + Location ob = this.getBottomAbs(); + final int offsetX = db.getX() - ob.getX(); + final int offsetZ = db.getZ() - ob.getZ(); + if (this.owner == null) { + TaskManager.runTaskLater(whenDone, 1); + return false; + } + Set plots = this.getConnectedPlots(); + for (Plot plot : plots) { + Plot other = plot.getRelative(destination.getArea(), offset.x, offset.y); + if (other.hasOwner()) { + TaskManager.runTaskLater(whenDone, 1); + return false; + } + } + // world border + destination.updateWorldBorder(); + // copy data + for (Plot plot : plots) { + Plot other = plot.getRelative(destination.getArea(), offset.x, offset.y); + other.create(plot.owner, false); + if (!plot.getFlags().isEmpty()) { + other.getSettings().flags = plot.getFlags(); + DBFunc.setFlags(other, plot.getFlags()); + } + if (plot.isMerged()) { + other.setMerged(plot.getMerged()); + } + if (plot.members != null && !plot.members.isEmpty()) { + other.members = plot.members; + for (UUID member : plot.members) { + DBFunc.setMember(other, member); + } + } + if (plot.trusted != null && !plot.trusted.isEmpty()) { + other.trusted = plot.trusted; + for (UUID trusted : plot.trusted) { + DBFunc.setTrusted(other, trusted); + } + } + if (plot.denied != null && !plot.denied.isEmpty()) { + other.denied = plot.denied; + for (UUID denied : plot.denied) { + DBFunc.setDenied(other, denied); + } + } + } + // copy terrain + final ArrayDeque regions = new ArrayDeque<>(this.getRegions()); + Runnable run = new Runnable() { + @Override + public void run() { + if (regions.isEmpty()) { + for (Plot current : getConnectedPlots()) { + destination.getManager().claimPlot(destination.getArea(), destination); + } + destination.setSign(); + TaskManager.runTask(whenDone); + return; + } + RegionWrapper region = regions.poll(); + Location[] corners = region.getCorners(getWorldName()); + Location pos1 = corners[0]; + Location pos2 = corners[1]; + Location newPos = pos1.clone().add(offsetX, 0, offsetZ); + newPos.setWorld(destination.getWorldName()); + ChunkManager.manager.copyRegion(pos1, pos2, newPos, this); + } + }; + run.run(); + return true; + } + + public boolean hasFlag(Flag flag) { + return getFlags().containsKey(flag); + } } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotArea.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotArea.java index 48ebb759a..00a30e22d 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotArea.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotArea.java @@ -721,6 +721,9 @@ public abstract class PlotArea { } else { start = start.getNextId(1); } + if (start == null) { + PlotSquared.debug("NPE possible in getNextFreePlot"); + } currentId = new PlotId(center.x + start.x, center.y + start.y); Plot plot = getPlotAbs(currentId); if (plot != null && plot.canClaim(player)) { diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotCluster.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotCluster.java index a1134cbce..4a12bfb7b 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotCluster.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotCluster.java @@ -5,19 +5,25 @@ import com.github.intellectualsites.plotsquared.plot.util.MainUtil; import java.util.HashSet; import java.util.UUID; +import javax.annotation.Nonnull; +import lombok.Getter; public class PlotCluster { public PlotArea area; + @Nonnull + @Getter public PlotSettings settings; public UUID owner; public HashSet helpers = new HashSet<>(); public HashSet invited = new HashSet<>(); public int temp; + @Nonnull private PlotId pos1; + @Nonnull private PlotId pos2; private RegionWrapper region; - public PlotCluster(PlotArea area, PlotId pos1, PlotId pos2, UUID owner) { + public PlotCluster(PlotArea area, @Nonnull PlotId pos1, @Nonnull PlotId pos2, UUID owner) { this.area = area; this.pos1 = pos1; this.pos2 = pos2; @@ -27,7 +33,7 @@ public class PlotCluster { setRegion(); } - public PlotCluster(PlotArea area, PlotId pos1, PlotId pos2, UUID owner, int temp) { + public PlotCluster(PlotArea area, @Nonnull PlotId pos1, PlotId pos2, UUID owner, int temp) { this.area = area; this.pos1 = pos1; this.pos2 = pos2; @@ -82,6 +88,11 @@ public class PlotCluster { return this.settings.getAlias(); } + public String getAlias() { + return this.settings.getAlias(); + } + + public void setName(String name) { this.settings.setAlias(name);} /** * Get the area (in plots). * diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotMessage.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotMessage.java index 47069a38e..6db234de3 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotMessage.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotMessage.java @@ -13,6 +13,7 @@ public class PlotMessage { try { reset(ChatManager.manager); } catch (Throwable e) { + assert PlotSquared.imp() != null; PlotSquared.debug( PlotSquared.imp().getPluginName() + " doesn't support fancy chat for " + PlotSquared .get().IMP.getServerVersion()); diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotPlayer.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotPlayer.java index d535c625e..850c77365 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotPlayer.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotPlayer.java @@ -24,655 +24,632 @@ import java.util.concurrent.atomic.AtomicInteger; */ public abstract class PlotPlayer implements CommandCaller, OfflinePlotPlayer { - public static final String META_LAST_PLOT = "lastplot"; - public static final String META_LOCATION = "location"; - private static final Map converters = new HashMap<>(); - private Map metaMap = new HashMap<>(); - /** - * The metadata map. - */ - private ConcurrentHashMap meta; + public static final String META_LAST_PLOT = "lastplot"; + public static final String META_LOCATION = "location"; + private static final Map converters = new HashMap<>(); + private Map metaMap = new HashMap<>(); + /** + * The metadata map. + */ + private ConcurrentHashMap meta; - public static PlotPlayer from(@NonNull final T object) { - if (!converters.containsKey(object.getClass())) { - throw new IllegalArgumentException(String - .format("There is no registered PlotPlayer converter for type %s", - object.getClass().getSimpleName())); + public static PlotPlayer from(@NonNull final T object) { + if (!converters.containsKey(object.getClass())) { + throw new IllegalArgumentException(String + .format("There is no registered PlotPlayer converter for type %s", + object.getClass().getSimpleName())); + } + return converters.get(object.getClass()).convert(object); + } + + public static void registerConverter(@NonNull final Class clazz, + final PlotPlayerConverter converter) { + converters.put(clazz, converter); + } + + /** + * Efficiently wrap a Player, or OfflinePlayer object to get a PlotPlayer (or fetch if it's + * already cached)
- Accepts sponge/bukkit Player (online) - Accepts player name (online) - + * Accepts UUID - Accepts bukkit OfflinePlayer (offline) + */ + public static PlotPlayer wrap(Object player) { + return PlotSquared.get().IMP.wrapPlayer(player); + } + + /** + * Get the cached PlotPlayer from a username
- This will return null if the player has not + * finished logging in or is not online + */ + public static PlotPlayer get(String name) { + return UUIDHandler.getPlayer(name); + } + + /** + * Set some session only metadata for this player. + */ + public void setMeta(String key, Object value) { + if (value == null) { + deleteMeta(key); + } else { + if (this.meta == null) { + this.meta = new ConcurrentHashMap<>(); + } + this.meta.put(key, value); + } + } + + /** + * Get the session metadata for a key. + * + * @param key the name of the metadata key + * @param the object type to return + * @return the value assigned to the key or null if it does not exist + */ + public T getMeta(String key) { + if (this.meta != null) { + return (T) this.meta.get(key); + } + return null; + } + + public T getMeta(String key, T defaultValue) { + T meta = getMeta(key); + if (meta == null) { + return defaultValue; + } + return meta; + } + + /** + * Delete the metadata for a key. - metadata is session only - deleting other plugin's metadata + * may cause issues + */ + public Object deleteMeta(String key) { + return this.meta == null ? null : this.meta.remove(key); + } + + /** + * This player's name. + * + * @return the name of the player + */ + @Override + public String toString() { + return getName(); + } + + /** + * Get this player's current plot. + * + * @return the plot the player is standing on or null if standing on a road or not in a {@link + * PlotArea} + */ + public Plot getCurrentPlot() { + Plot value = getMeta(PlotPlayer.META_LAST_PLOT); + if (value == null && !Settings.Enabled_Components.EVENTS) { + return getLocation().getPlot(); + } + return value; + } + + /** + * Get the total number of allowed plots Possibly relevant: (To increment the player's allowed + * plots, see the example script on the wiki) + * + * @return number of allowed plots within the scope (globally, or in the player's current world as + * defined in the settings.yml) + */ + public int getAllowedPlots() { + return Permissions.hasPermissionRange(this, "plots.plot", Settings.Limit.MAX_PLOTS); + } + + /** + * Get the total number of allowed clusters + * + * @return number of allowed clusters within the scope (globally, or in the player's current world + * as defined in the settings.yml) + */ + public int getAllowedClusters() { + return Permissions.hasPermissionRange(this, "plots.cluster", Settings.Limit.MAX_PLOTS); + } + + public int hasPermissionRange(String stub, int range) { + if (hasPermission(C.PERMISSION_ADMIN.s())) { + return Integer.MAX_VALUE; + } + String[] nodes = stub.split("\\."); + StringBuilder n = new StringBuilder(); + for (int i = 0; i < (nodes.length - 1); i++) { + n.append(nodes[i]).append("."); + if (!stub.equals(n + C.PERMISSION_STAR.s())) { + if (hasPermission(n + C.PERMISSION_STAR.s())) { + return Integer.MAX_VALUE; } - return converters.get(object.getClass()).convert(object); + } } - - public static void registerConverter(@NonNull final Class clazz, - final PlotPlayerConverter converter) { - converters.put(clazz, converter); + if (hasPermission(stub + ".*")) { + return Integer.MAX_VALUE; } - - /** - * Efficiently wrap a Player, or OfflinePlayer object to get a PlotPlayer (or fetch if it's already cached)
- * - Accepts sponge/bukkit Player (online) - * - Accepts player name (online) - * - Accepts UUID - * - Accepts bukkit OfflinePlayer (offline) - * - * @param player - * @return - */ - public static PlotPlayer wrap(Object player) { - return PlotSquared.get().IMP.wrapPlayer(player); + for (int i = range; i > 0; i--) { + if (hasPermission(stub + "." + i)) { + return i; + } } + return 0; + } - /** - * Get the cached PlotPlayer from a username
- * - This will return null if the player has not finished logging in or is not online - * - * @param name - * @return - */ - public static PlotPlayer get(String name) { - return UUIDHandler.getPlayer(name); + /** + * Get the number of plots this player owns. + * + * @return number of plots within the scope (globally, or in the player's current world as defined + * in the settings.yml) + * @see #getPlotCount(String); + * @see #getPlots() + */ + public int getPlotCount() { + if (!Settings.Limit.GLOBAL) { + return getPlotCount(getLocation().getWorld()); } - - /** - * Set some session only metadata for this player. - * - * @param key - * @param value - */ - public void setMeta(String key, Object value) { - if (value == null) { - deleteMeta(key); + final AtomicInteger count = new AtomicInteger(0); + final UUID uuid = getUUID(); + PlotSquared.get().foreachPlotArea(new RunnableVal() { + @Override + public void run(PlotArea value) { + if (!Settings.Done.COUNTS_TOWARDS_LIMIT) { + for (Plot plot : value.getPlotsAbs(uuid)) { + if (!plot.hasFlag(Flags.DONE)) { + count.incrementAndGet(); + } + } } else { - if (this.meta == null) { - this.meta = new ConcurrentHashMap<>(); - } - this.meta.put(key, value); + count.addAndGet(value.getPlotsAbs(uuid).size()); } - } + } + }); + return count.get(); + } - /** - * Get the session metadata for a key. - * - * @param key the name of the metadata key - * @param the object type to return - * @return the value assigned to the key or null if it does not exist - */ - public T getMeta(String key) { - if (this.meta != null) { - return (T) this.meta.get(key); + public int getClusterCount() { + if (!Settings.Limit.GLOBAL) { + return getClusterCount(getLocation().getWorld()); + } + final AtomicInteger count = new AtomicInteger(0); + final UUID uuid = getUUID(); + PlotSquared.get().foreachPlotArea(new RunnableVal() { + @Override + public void run(PlotArea value) { + for (PlotCluster cluster : value.getClusters()) { + if (cluster.isOwner(getUUID())) { + count.incrementAndGet(); + } } - return null; - } + } + }); + return count.get(); + } - public T getMeta(String key, T defaultValue) { - T meta = getMeta(key); - if (meta == null) { - return defaultValue; + /** + * Get the number of plots this player owns in the world. + * + * @param world the name of the plotworld to check. + */ + public int getPlotCount(String world) { + UUID uuid = getUUID(); + int count = 0; + for (PlotArea area : PlotSquared.get().getPlotAreas(world)) { + if (!Settings.Done.COUNTS_TOWARDS_LIMIT) { + for (Plot plot : area.getPlotsAbs(uuid)) { + if (!plot.getFlag(Flags.DONE).isPresent()) { + count++; + } } - return meta; + } else { + count += area.getPlotsAbs(uuid).size(); + } } + return count; + } - /** - * Delete the metadata for a key. - * - metadata is session only - * - deleting other plugin's metadata may cause issues - * - * @param key - */ - public Object deleteMeta(String key) { - return this.meta == null ? null : this.meta.remove(key); - } - - /** - * This player's name. - * - * @return the name of the player - */ - @Override public String toString() { - return getName(); - } - - /** - * Get this player's current plot. - * - * @return the plot the player is standing on or null if standing on a road or not in a {@link PlotArea} - */ - public Plot getCurrentPlot() { - Plot value = getMeta(PlotPlayer.META_LAST_PLOT); - if (value == null && !Settings.Enabled_Components.EVENTS) { - return getLocation().getPlot(); + public int getClusterCount(String world) { + UUID uuid = getUUID(); + int count = 0; + for (PlotArea area : PlotSquared.get().getPlotAreas(world)) { + for (PlotCluster cluster : area.getClusters()) { + if (cluster.isOwner(getUUID())) { + count++; } - return value; + } } + return count; + } - /** - * Get the total number of allowed plots - * Possibly relevant: (To increment the player's allowed plots, see the example script on the wiki) - * - * @return number of allowed plots within the scope (globally, or in the player's current world as defined in the settings.yml) - */ - public int getAllowedPlots() { - return Permissions.hasPermissionRange(this, "plots.plot", Settings.Limit.MAX_PLOTS); + /** + * Get a {@code Set} of plots owned by this player. + * + * @return a {@code Set} of plots owned by the player + * @see PlotSquared for more searching functions + * @see #getPlotCount() for the number of plots + */ + public Set getPlots() { + return PlotSquared.get().getPlots(this); + } + + /** + * Return the PlotArea this player is currently in, or null. + */ + public PlotArea getPlotAreaAbs() { + return PlotSquared.get().getPlotAreaAbs(getLocation()); + } + + public PlotArea getApplicablePlotArea() { + return PlotSquared.get().getApplicablePlotArea(getLocation()); + } + + @Override + public RequiredType getSuperCaller() { + return RequiredType.PLAYER; + } + + /** + * Get this player's last recorded location or null if they don't any plot relevant location. + * + * @return The location + */ + public Location getLocation() { + Location location = getMeta("location"); + if (location != null) { + return location; } + return getLocationFull(); + } - /** - * Get the total number of allowed clusters - * - * @return number of allowed clusters within the scope (globally, or in the player's current world as defined in the settings.yml) - */ - public int getAllowedClusters() { - return Permissions.hasPermissionRange(this, "plots.cluster", Settings.Limit.MAX_PLOTS); + /////////////// PLAYER META /////////////// + + ////////////// PARTIALLY IMPLEMENTED /////////// + + /** + * Get this player's full location (including yaw/pitch) + */ + public abstract Location getLocationFull(); + + //////////////////////////////////////////////// + + /** + * Get this player's UUID. === !IMPORTANT ===
The UUID is dependent on the mode chosen in the + * settings.yml and may not be the same as Bukkit has (especially if using an old version of + * Bukkit that does not support UUIDs) + * + * @return UUID + */ + @Override + public abstract UUID getUUID(); + + public boolean canTeleport(Location loc) { + Location current = getLocationFull(); + teleport(loc); + boolean result = true; + if (!getLocation().equals(loc)) { + result = false; } + teleport(current); + return result; + } - public int hasPermissionRange(String stub, int range) { - if (hasPermission(C.PERMISSION_ADMIN.s())) { - return Integer.MAX_VALUE; - } - String[] nodes = stub.split("\\."); - StringBuilder n = new StringBuilder(); - for (int i = 0; i < (nodes.length - 1); i++) { - n.append(nodes[i]).append("."); - if (!stub.equals(n + C.PERMISSION_STAR.s())) { - if (hasPermission(n + C.PERMISSION_STAR.s())) { - return Integer.MAX_VALUE; - } - } - } - if (hasPermission(stub + ".*")) { - return Integer.MAX_VALUE; - } - for (int i = range; i > 0; i--) { - if (hasPermission(stub + "." + i)) { - return i; - } - } - return 0; + /** + * Teleport this player to a location. + * + * @param location the target location + */ + public abstract void teleport(Location location); + + /** + * Kick this player to a location + * + * @param location the target location + */ + public void plotkick(Location location) { + setMeta("kick", true); + teleport(location); + deleteMeta("kick"); + } + + /** + * Set this compass target. + * + * @param location the target location + */ + public abstract void setCompassTarget(Location location); + + /** + * Set player data that will persist restarts. - Please note that this is not intended to store + * large values - For session only data use meta + */ + public void setAttribute(String key) { + setPersistentMeta("attrib_" + key, new byte[]{(byte) 1}); + } + + /** + * Retrieves the attribute of this player. + * + * @return the attribute will be either true or false + */ + public boolean getAttribute(String key) { + if (!hasPersistentMeta("attrib_" + key)) { + return false; } + return getPersistentMeta("attrib_" + key)[0] == 1; + } - /** - * Get the number of plots this player owns. - * - * @return number of plots within the scope (globally, or in the player's current world as defined in the settings.yml) - * @see #getPlotCount(String); - * @see #getPlots() - */ - public int getPlotCount() { - if (!Settings.Limit.GLOBAL) { - return getPlotCount(getLocation().getWorld()); - } - final AtomicInteger count = new AtomicInteger(0); - final UUID uuid = getUUID(); - PlotSquared.get().foreachPlotArea(new RunnableVal() { - @Override public void run(PlotArea value) { - if (!Settings.Done.COUNTS_TOWARDS_LIMIT) { - for (Plot plot : value.getPlotsAbs(uuid)) { - if (!plot.hasFlag(Flags.DONE)) { - count.incrementAndGet(); - } - } - } else { - count.addAndGet(value.getPlotsAbs(uuid).size()); - } - } - }); - return count.get(); + /** + * Remove an attribute from a player. + */ + public void removeAttribute(String key) { + removePersistentMeta("attrib_" + key); + } + + /** + * Sets the local weather for this Player. + * + * @param weather the weather visible to the player + */ + public abstract void setWeather(PlotWeather weather); + + /** + * Get this player's gamemode. + * + * @return the gamemode of the player. + */ + public abstract PlotGameMode getGameMode(); + + /** + * Set this player's gameMode. + * + * @param gameMode the gamemode to set + */ + public abstract void setGameMode(PlotGameMode gameMode); + + /** + * Set this player's local time (ticks). + * + * @param time the time visible to the player + */ + public abstract void setTime(long time); + + public abstract boolean getFlight(); + + /** + * Set this player's fly mode. + * + * @param fly if the player can fly + */ + public abstract void setFlight(boolean fly); + + /** + * Play music at a location for this player. + * + * @param location where to play the music + * @param id the record item id + */ + public abstract void playMusic(Location location, PlotBlock id); + + /** + * Check if this player is banned. + * + * @return true if the player is banned, false otherwise. + */ + public abstract boolean isBanned(); + + /** + * Kick this player from the game. + * + * @param message the reason for the kick + */ + public abstract void kick(String message); + + /** + * Called when this player quits. + */ + public void unregister() { + Plot plot = getCurrentPlot(); + if (plot != null && Settings.Enabled_Components.PERSISTENT_META && plot + .getArea() instanceof SinglePlotArea) { + PlotId id = plot.getId(); + int x = id.x; + int z = id.y; + ByteBuffer buffer = ByteBuffer.allocate(13); + buffer.putShort((short) x); + buffer.putShort((short) z); + Location loc = getLocation(); + buffer.putInt(loc.getX()); + buffer.put((byte) loc.getY()); + buffer.putInt(loc.getZ()); + setPersistentMeta("quitLoc", buffer.array()); + } else if (hasPersistentMeta("quitLoc")) { + removePersistentMeta("quitLoc"); } - - public int getClusterCount() { - if (!Settings.Limit.GLOBAL) { - return getClusterCount(getLocation().getWorld()); - } - final AtomicInteger count = new AtomicInteger(0); - final UUID uuid = getUUID(); - PlotSquared.get().foreachPlotArea(new RunnableVal() { - @Override public void run(PlotArea value) { - for (PlotCluster cluster : value.getClusters()) { - if (cluster.isOwner(getUUID())) { - count.incrementAndGet(); - } - } - } - }); - return count.get(); + if (plot != null) { + EventUtil.manager.callLeave(this, plot); } - - /** - * Get the number of plots this player owns in the world. - * - * @param world the name of the plotworld to check. - * @return - */ - public int getPlotCount(String world) { - UUID uuid = getUUID(); - int count = 0; - for (PlotArea area : PlotSquared.get().getPlotAreas(world)) { - if (!Settings.Done.COUNTS_TOWARDS_LIMIT) { - for (Plot plot : area.getPlotsAbs(uuid)) { - if (!plot.getFlag(Flags.DONE).isPresent()) { - count++; - } - } - } else { - count += area.getPlotsAbs(uuid).size(); - } - } - return count; + if (Settings.Enabled_Components.BAN_DELETER && isBanned()) { + for (Plot owned : getPlots()) { + owned.deletePlot(null); + PlotSquared.debug(String + .format("&cPlot &6%s &cwas deleted + cleared due to &6%s&c getting banned", + owned.getId(), getName())); + } } - - public int getClusterCount(String world) { - UUID uuid = getUUID(); - int count = 0; - for (PlotArea area : PlotSquared.get().getPlotAreas(world)) { - for (PlotCluster cluster : area.getClusters()) { - if (cluster.isOwner(getUUID())) { - count++; - } - } - } - return count; + String name = getName(); + if (ExpireManager.IMP != null) { + ExpireManager.IMP.storeDate(getUUID(), System.currentTimeMillis()); } + UUIDHandler.getPlayers().remove(name); + PlotSquared.get().IMP.unregister(this); + } - /** - * Get a {@code Set} of plots owned by this player. - * - * @return a {@code Set} of plots owned by the player - * @see PlotSquared for more searching functions - * @see #getPlotCount() for the number of plots - */ - public Set getPlots() { - return PlotSquared.get().getPlots(this); + /** + * Get the amount of clusters this player owns in the specific world. + */ + public int getPlayerClusterCount(String world) { + UUID uuid = getUUID(); + int count = 0; + for (PlotCluster cluster : PlotSquared.get().getClusters(world)) { + if (uuid.equals(cluster.owner)) { + count += cluster.getArea(); + } } + return count; + } - /** - * Return the PlotArea this player is currently in, or null. - * - * @return - */ - public PlotArea getPlotAreaAbs() { - return PlotSquared.get().getPlotAreaAbs(getLocation()); + /** + * Get the amount of clusters this player owns. + * + * @return the number of clusters this player owns + */ + public int getPlayerClusterCount() { + final AtomicInteger count = new AtomicInteger(); + PlotSquared.get().foreachPlotArea(new RunnableVal() { + @Override + public void run(PlotArea value) { + count.addAndGet(value.getClusters().size()); + } + }); + return count.get(); + } + + /** + * Return a {@code Set} of all plots this player owns in a certain world. + * + * @param world the world to retrieve plots from + * @return a {@code Set} of plots this player owns in the provided world + */ + public Set getPlots(String world) { + UUID uuid = getUUID(); + HashSet plots = new HashSet<>(); + for (Plot plot : PlotSquared.get().getPlots(world)) { + if (plot.isOwner(uuid)) { + plots.add(plot); + } } + return plots; + } - public PlotArea getApplicablePlotArea() { - return PlotSquared.get().getApplicablePlotArea(getLocation()); - } + public void populatePersistentMetaMap() { + if (Settings.Enabled_Components.PERSISTENT_META) { + DBFunc.getPersistentMeta(getUUID(), new RunnableVal>() { + @Override + public void run(Map value) { + try { + PlotPlayer.this.metaMap = value; + if (!value.isEmpty()) { + if (Settings.Enabled_Components.PERSISTENT_META) { + PlotAreaManager manager = PlotSquared.get().getPlotAreaManager(); + if (manager instanceof SinglePlotAreaManager) { + PlotArea area = ((SinglePlotAreaManager) manager).getArea(); + byte[] arr = PlotPlayer.this.getPersistentMeta("quitLoc"); + if (arr != null) { + removePersistentMeta("quitLoc"); - @Override public RequiredType getSuperCaller() { - return RequiredType.PLAYER; - } - - /** - * Get this player's last recorded location or null if they don't any plot relevant location. - * - * @return The location - */ - public Location getLocation() { - Location location = getMeta("location"); - if (location != null) { - return location; - } - return getLocationFull(); - } - - /////////////// PLAYER META /////////////// - - ////////////// PARTIALLY IMPLEMENTED /////////// - - /** - * Get this player's full location (including yaw/pitch) - * - * @return - */ - public abstract Location getLocationFull(); - - //////////////////////////////////////////////// - - /** - * Get this player's UUID. - * === !IMPORTANT ===
- * The UUID is dependent on the mode chosen in the settings.yml and may not be the same as Bukkit has - * (especially if using an old version of Bukkit that does not support UUIDs) - * - * @return UUID - */ - @Override public abstract UUID getUUID(); - - public boolean canTeleport(Location loc) { - Location current = getLocationFull(); - teleport(loc); - boolean result = true; - if (!getLocation().equals(loc)) { - result = false; - } - teleport(current); - return result; - } - - /** - * Teleport this player to a location. - * - * @param location the target location - */ - public abstract void teleport(Location location); - - /** - * Kick this player to a location - * - * @param location the target location - */ - public void plotkick(Location location) { - setMeta("kick", true); - teleport(location); - deleteMeta("kick"); - } - - /** - * Set this compass target. - * - * @param location the target location - */ - public abstract void setCompassTarget(Location location); - - /** - * Set player data that will persist restarts. - * - Please note that this is not intended to store large values - * - For session only data use meta - * - * @param key - */ - public void setAttribute(String key) { - setPersistentMeta("attrib_" + key, new byte[] {(byte) 1}); - } - - /** - * Retrieves the attribute of this player. - * - * @param key - * @return the attribute will be either true or false - */ - public boolean getAttribute(String key) { - if (!hasPersistentMeta("attrib_" + key)) { - return false; - } - return getPersistentMeta("attrib_" + key)[0] == 1; - } - - /** - * Remove an attribute from a player. - * - * @param key - */ - public void removeAttribute(String key) { - removePersistentMeta("attrib_" + key); - } - - /** - * Sets the local weather for this Player. - * - * @param weather the weather visible to the player - */ - public abstract void setWeather(PlotWeather weather); - - /** - * Get this player's gamemode. - * - * @return the gamemode of the player. - */ - public abstract PlotGameMode getGameMode(); - - /** - * Set this player's gameMode. - * - * @param gameMode the gamemode to set - */ - public abstract void setGameMode(PlotGameMode gameMode); - - /** - * Set this player's local time (ticks). - * - * @param time the time visible to the player - */ - public abstract void setTime(long time); - - public abstract boolean getFlight(); - - /** - * Set this player's fly mode. - * - * @param fly if the player can fly - */ - public abstract void setFlight(boolean fly); - - /** - * Play music at a location for this player. - * - * @param location where to play the music - * @param id the record item id - */ - public abstract void playMusic(Location location, PlotBlock id); - - /** - * Check if this player is banned. - * - * @return true if the player is banned, false otherwise. - */ - public abstract boolean isBanned(); - - /** - * Kick this player from the game. - * - * @param message the reason for the kick - */ - public abstract void kick(String message); - - /** - * Called when this player quits. - */ - public void unregister() { - Plot plot = getCurrentPlot(); - if (plot != null && Settings.Enabled_Components.PERSISTENT_META && plot - .getArea() instanceof SinglePlotArea) { - PlotId id = plot.getId(); - int x = id.x; - int z = id.y; - ByteBuffer buffer = ByteBuffer.allocate(13); - buffer.putShort((short) x); - buffer.putShort((short) z); - Location loc = getLocation(); - buffer.putInt(loc.getX()); - buffer.put((byte) loc.getY()); - buffer.putInt(loc.getZ()); - setPersistentMeta("quitLoc", buffer.array()); - } else if (hasPersistentMeta("quitLoc")) { - removePersistentMeta("quitLoc"); - } - if (plot != null) { - EventUtil.manager.callLeave(this, plot); - } - if (Settings.Enabled_Components.BAN_DELETER && isBanned()) { - for (Plot owned : getPlots()) { - owned.deletePlot(null); - PlotSquared.debug(String - .format("&cPlot &6%s &cwas deleted + cleared due to &6%s&c getting banned", - plot.getId(), getName())); - } - } - String name = getName(); - if (ExpireManager.IMP != null) { - ExpireManager.IMP.storeDate(getUUID(), System.currentTimeMillis()); - } - UUIDHandler.getPlayers().remove(name); - PlotSquared.get().IMP.unregister(this); - } - - /** - * Get the amount of clusters this player owns in the specific world. - * - * @param world - * @return - */ - public int getPlayerClusterCount(String world) { - UUID uuid = getUUID(); - int count = 0; - for (PlotCluster cluster : PlotSquared.get().getClusters(world)) { - if (uuid.equals(cluster.owner)) { - count += cluster.getArea(); - } - } - return count; - } - - /** - * Get the amount of clusters this player owns. - * - * @return the number of clusters this player owns - */ - public int getPlayerClusterCount() { - final AtomicInteger count = new AtomicInteger(); - PlotSquared.get().foreachPlotArea(new RunnableVal() { - @Override public void run(PlotArea value) { - count.addAndGet(value.getClusters().size()); - } - }); - return count.get(); - } - - /** - * Return a {@code Set} of all plots this player owns in a certain world. - * - * @param world the world to retrieve plots from - * @return a {@code Set} of plots this player owns in the provided world - */ - public Set getPlots(String world) { - UUID uuid = getUUID(); - HashSet plots = new HashSet<>(); - for (Plot plot : PlotSquared.get().getPlots(world)) { - if (plot.isOwner(uuid)) { - plots.add(plot); - } - } - return plots; - } - - public void populatePersistentMetaMap() { - if (Settings.Enabled_Components.PERSISTENT_META) { - DBFunc.getPersistentMeta(getUUID(), new RunnableVal>() { - @Override public void run(Map value) { - try { - PlotPlayer.this.metaMap = value; - if (!value.isEmpty()) { - if (Settings.Enabled_Components.PERSISTENT_META) { - PlotAreaManager manager = PlotSquared.get().getPlotAreaManager(); - if (manager instanceof SinglePlotAreaManager) { - PlotArea area = ((SinglePlotAreaManager) manager).getArea(); - byte[] arr = PlotPlayer.this.getPersistentMeta("quitLoc"); - if (arr != null) { - removePersistentMeta("quitLoc"); - - if (getMeta("teleportOnLogin", true)) { - ByteBuffer quitWorld = ByteBuffer.wrap(arr); - final int plotX = quitWorld.getShort(); - final int plotZ = quitWorld.getShort(); - PlotId id = new PlotId(plotX, plotZ); - int x = quitWorld.getInt(); - int y = quitWorld.get() & 0xFF; - int z = quitWorld.getInt(); - Plot plot = area.getOwnedPlot(id); - if (plot != null) { - final Location loc = - new Location(plot.getWorldName(), x, y, z); - if (plot.isLoaded()) { - TaskManager.runTask(new Runnable() { - @Override public void run() { - if (getMeta("teleportOnLogin", true)) { - teleport(loc); - sendMessage(C.TELEPORTED_TO_PLOT.f() - + " (quitLoc) (" + plotX + "," - + plotZ + ")"); - } - } - }); - } else if (!PlotSquared.get() - .isMainThread(Thread.currentThread())) { - if (getMeta("teleportOnLogin", true)) { - if (plot.teleportPlayer(PlotPlayer.this)) { - TaskManager.runTask(new Runnable() { - @Override public void run() { - if (getMeta("teleportOnLogin", - true)) { - teleport(loc); - sendMessage( - C.TELEPORTED_TO_PLOT.f() - + " (quitLoc-unloaded) (" - + plotX + "," - + plotZ + ")"); - } - } - }); - } - } - } - } - } - } - } + if (getMeta("teleportOnLogin", true)) { + ByteBuffer quitWorld = ByteBuffer.wrap(arr); + final int plotX = quitWorld.getShort(); + final int plotZ = quitWorld.getShort(); + PlotId id = new PlotId(plotX, plotZ); + int x = quitWorld.getInt(); + int y = quitWorld.get() & 0xFF; + int z = quitWorld.getInt(); + Plot plot = area.getOwnedPlot(id); + if (plot != null) { + final Location loc = + new Location(plot.getWorldName(), x, y, z); + if (plot.isLoaded()) { + TaskManager.runTask(() -> { + if (getMeta("teleportOnLogin", true)) { + teleport(loc); + sendMessage(C.TELEPORTED_TO_PLOT.f() + + " (quitLoc) (" + plotX + "," + + plotZ + ")"); } + }); + } else if (!PlotSquared.get() + .isMainThread(Thread.currentThread())) { + if (getMeta("teleportOnLogin", true)) { + if (plot.teleportPlayer(PlotPlayer.this)) { + TaskManager.runTask(() -> { + if (getMeta("teleportOnLogin", + true)) { + teleport(loc); + sendMessage( + C.TELEPORTED_TO_PLOT.f() + + " (quitLoc-unloaded) (" + + plotX + "," + + plotZ + ")"); + } + }); + } + } } - } catch (Throwable e) { - e.printStackTrace(); + } } + } } - }); + } + } + } catch (Throwable e) { + e.printStackTrace(); + } } + }); } + } - public byte[] getPersistentMeta(String key) { - return this.metaMap.get(key); + public byte[] getPersistentMeta(String key) { + return this.metaMap.get(key); + } + + public void removePersistentMeta(String key) { + if (this.metaMap.containsKey(key)) { + this.metaMap.remove(key); } - - public void removePersistentMeta(String key) { - if (this.metaMap.containsKey(key)) { - this.metaMap.remove(key); - } - if (Settings.Enabled_Components.PERSISTENT_META) { - DBFunc.removePersistentMeta(getUUID(), key); - } + if (Settings.Enabled_Components.PERSISTENT_META) { + DBFunc.removePersistentMeta(getUUID(), key); } + } - public void setPersistentMeta(String key, byte[] value) { - boolean delete = hasPersistentMeta(key); - this.metaMap.put(key, value); - if (Settings.Enabled_Components.PERSISTENT_META) { - DBFunc.addPersistentMeta(getUUID(), key, value, delete); - } + public void setPersistentMeta(String key, byte[] value) { + boolean delete = hasPersistentMeta(key); + this.metaMap.put(key, value); + if (Settings.Enabled_Components.PERSISTENT_META) { + DBFunc.addPersistentMeta(getUUID(), key, value, delete); } + } - public boolean hasPersistentMeta(String key) { - return this.metaMap.containsKey(key); + public boolean hasPersistentMeta(String key) { + return this.metaMap.containsKey(key); + } + + public abstract void stopSpectating(); + + /** + * The amount of money this Player has. + */ + public double getMoney() { + return EconHandler.manager == null ? 0 : EconHandler.manager.getMoney(this); + } + + public void withdraw(double amount) { + if (EconHandler.manager != null) { + EconHandler.manager.withdrawMoney(this, amount); } + } - public abstract void stopSpectating(); - - /** - * The amount of money this Player has. - * - * @return - */ - public double getMoney() { - return EconHandler.manager == null ? 0 : EconHandler.manager.getMoney(this); + public void deposit(double amount) { + if (EconHandler.manager != null) { + EconHandler.manager.depositMoney(this, amount); } + } - public void withdraw(double amount) { - if (EconHandler.manager != null) { - EconHandler.manager.withdrawMoney(this, amount); - } - } + public interface PlotPlayerConverter { - public void deposit(double amount) { - if (EconHandler.manager != null) { - EconHandler.manager.depositMoney(this, amount); - } - } - - public interface PlotPlayerConverter { - PlotPlayer convert(BaseObject object); - } + PlotPlayer convert(BaseObject object); + } } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotSettings.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotSettings.java index 4f3701f56..2ccaa47a8 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotSettings.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotSettings.java @@ -42,7 +42,7 @@ public class PlotSettings { /** * Flags. * - * @deprecated Raw access + * @deprecated Raw access. Not compatible with PlotClusters. */ @Deprecated public HashMap, Object> flags = new HashMap<>(); /** @@ -85,7 +85,7 @@ public class PlotSettings { return this.ratings; } - public boolean setMerged(int direction, boolean merged) { + boolean setMerged(int direction, boolean merged) { if (this.merged[direction] != merged) { this.merged[direction] = merged; return true; @@ -142,6 +142,7 @@ public class PlotSettings { } } + //todo need a plot method public Optional> getComments(String inbox) { ArrayList c = new ArrayList<>(); if (this.comments == null) { @@ -155,22 +156,26 @@ public class PlotSettings { return Optional.of(c); } + //todo need a plot method public void setComments(List comments) { this.comments = comments; } + //todo need a plot method public void removeComment(PlotComment comment) { if (this.comments.contains(comment)) { this.comments.remove(comment); } } + //todo need a plot method public void removeComments(List comments) { for (PlotComment comment : comments) { removeComment(comment); } } + //todo need a plot method public void addComment(PlotComment comment) { if (this.comments == null) { this.comments = new ArrayList<>(); diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/stream/AbstractDelegateOutputStream.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/stream/AbstractDelegateOutputStream.java index 994f6a465..19425065f 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/stream/AbstractDelegateOutputStream.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/stream/AbstractDelegateOutputStream.java @@ -4,30 +4,31 @@ import java.io.IOException; import java.io.OutputStream; public class AbstractDelegateOutputStream extends OutputStream { - private final OutputStream parent; - public AbstractDelegateOutputStream(OutputStream os) { - this.parent = os; - } + private final OutputStream parent; - @Override public void write(int b) throws IOException { - parent.write(b); - } + public AbstractDelegateOutputStream(OutputStream os) { + this.parent = os; + } - @Override public void write(byte[] b) throws IOException { - parent.write(b); - } + @Override + public void write(int b) throws IOException { + parent.write(b); + } - @Override public void write(byte[] b, int off, int len) throws IOException { - parent.write(b, off, len); - } + @Override + public void write(byte[] b) throws IOException { + parent.write(b); + } + + @Override + public void flush() throws IOException { + parent.flush(); + } - @Override public void flush() throws IOException { - parent.flush(); - } - - @Override public void close() throws IOException { - parent.close(); - } + @Override + public void close() throws IOException { + parent.close(); + } } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/DefaultPlotAreaManager.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/DefaultPlotAreaManager.java index 989948f0c..0919624d9 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/DefaultPlotAreaManager.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/DefaultPlotAreaManager.java @@ -88,9 +88,9 @@ public class DefaultPlotAreaManager implements PlotAreaManager { HashSet globalAreas = new HashSet<>(Arrays.asList(plotAreas)); localAreas.add(plotArea); globalAreas.add(plotArea); - this.plotAreas = globalAreas.toArray(new PlotArea[globalAreas.size()]); + this.plotAreas = globalAreas.toArray(new PlotArea[0]); this.plotAreaMap - .put(plotArea.worldname, localAreas.toArray(new PlotArea[localAreas.size()])); + .put(plotArea.worldname, localAreas.toArray(new PlotArea[0])); QuadMap map = this.plotAreaGrid.get(plotArea.worldname); if (map == null) { map = new QuadMap(Integer.MAX_VALUE, 0, 0) { @@ -104,15 +104,15 @@ public class DefaultPlotAreaManager implements PlotAreaManager { } @Override public void removePlotArea(PlotArea area) { - ArrayList globalAreas = new ArrayList(Arrays.asList(plotAreas)); + ArrayList globalAreas = new ArrayList<>(Arrays.asList(plotAreas)); globalAreas.remove(area); - this.plotAreas = globalAreas.toArray(new PlotArea[globalAreas.size()]); + this.plotAreas = globalAreas.toArray(new PlotArea[0]); if (globalAreas.isEmpty()) { this.plotAreaMap.remove(area.worldname); this.plotAreaGrid.remove(area.worldname); } else { this.plotAreaMap - .put(area.worldname, globalAreas.toArray(new PlotArea[globalAreas.size()])); + .put(area.worldname, globalAreas.toArray(new PlotArea[0])); this.plotAreaGrid.get(area.worldname).remove(area); } } @@ -206,7 +206,7 @@ public class DefaultPlotAreaManager implements PlotAreaManager { return noPlotAreas; } else { Set found = areas.get(region); - return found.toArray(new PlotArea[found.size()]); + return found.toArray(new PlotArea[0]); } } @@ -217,14 +217,14 @@ public class DefaultPlotAreaManager implements PlotAreaManager { Set tmp = new LinkedHashSet<>(); Collections.addAll(tmp, worlds); tmp.add(worldName); - worlds = tmp.toArray(new String[tmp.size()]); + worlds = tmp.toArray(new String[0]); } @Override public void removeWorld(String worldName) { Set tmp = new LinkedHashSet<>(); Collections.addAll(tmp, worlds); tmp.remove(worldName); - worlds = tmp.toArray(new String[tmp.size()]); + worlds = tmp.toArray(new String[0]); } @Override public String[] getAllWorlds() { diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/PlotAreaManager.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/PlotAreaManager.java index aef7f53a8..7a59dab9d 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/PlotAreaManager.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/PlotAreaManager.java @@ -5,24 +5,24 @@ import com.github.intellectualsites.plotsquared.plot.object.PlotArea; import com.github.intellectualsites.plotsquared.plot.object.RegionWrapper; public interface PlotAreaManager { - public PlotArea getApplicablePlotArea(Location location); + PlotArea getApplicablePlotArea(Location location); - public PlotArea getPlotArea(Location location); + PlotArea getPlotArea(Location location); - public PlotArea getPlotArea(String world, String id); + PlotArea getPlotArea(String world, String id); - public PlotArea[] getPlotAreas(String world, RegionWrapper region); + PlotArea[] getPlotAreas(String world, RegionWrapper region); - public PlotArea[] getAllPlotAreas(); + PlotArea[] getAllPlotAreas(); - public String[] getAllWorlds(); + String[] getAllWorlds(); - public void addPlotArea(PlotArea area); + void addPlotArea(PlotArea area); - public void removePlotArea(PlotArea area); + void removePlotArea(PlotArea area); - public void addWorld(String worldName); + void addWorld(String worldName); - public void removeWorld(String worldName); + void removeWorld(String worldName); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlot.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlot.java index 5e153c02e..7d57e7d2c 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlot.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlot.java @@ -7,6 +7,7 @@ import com.github.intellectualsites.plotsquared.plot.object.*; import java.util.Collection; import java.util.HashSet; import java.util.UUID; +import javax.annotation.Nonnull; public class SinglePlot extends Plot { private HashSet regions; @@ -40,6 +41,7 @@ public class SinglePlot extends Plot { return getId().toCommaSeparatedString(); } + @Nonnull @Override public SinglePlotArea getArea() { return (SinglePlotArea) super.getArea(); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlotAreaManager.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlotAreaManager.java index adc462f4e..a3b398136 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlotAreaManager.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlotAreaManager.java @@ -35,8 +35,7 @@ public class SinglePlotAreaManager extends DefaultPlotAreaManager { if (chars.length == 1 && chars[0] == '*') { return true; } - for (int i = 0; i < chars.length; i++) { - char c = chars[i]; + for (char c : chars) { switch (mode) { case 0: mode = 1; diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlotManager.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlotManager.java index 8e5a6da12..f8e4ab000 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlotManager.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlotManager.java @@ -30,12 +30,10 @@ public class SinglePlotManager extends PlotManager { SetupUtils.manager.unload(plot.getWorldName(), false); final File worldFolder = new File(PlotSquared.get().IMP.getWorldContainer(), plot.getWorldName()); - TaskManager.IMP.taskAsync(new Runnable() { - @Override public void run() { - MainUtil.deleteDirectory(worldFolder); - if (whenDone != null) - whenDone.run(); - } + TaskManager.IMP.taskAsync(() -> { + MainUtil.deleteDirectory(worldFolder); + if (whenDone != null) + whenDone.run(); }); return true; } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/AbstractTitle.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/AbstractTitle.java index a5f75c96a..329230eaf 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/AbstractTitle.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/AbstractTitle.java @@ -15,6 +15,6 @@ public abstract class AbstractTitle { } } - public abstract void sendTitle(PlotPlayer player, String head, String sub, int in, int delay, + protected abstract void sendTitle(PlotPlayer player, String head, String sub, int in, int delay, int out); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ChunkManager.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ChunkManager.java index e863e1302..d27dc7597 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ChunkManager.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ChunkManager.java @@ -71,41 +71,39 @@ public abstract class ChunkManager { public static void largeRegionTask(final String world, final RegionWrapper region, final RunnableVal task, final Runnable whenDone) { - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - HashSet chunks = new HashSet<>(); - Set mcrs = manager.getChunkChunks(world); - for (ChunkLoc mcr : mcrs) { - int bx = mcr.x << 9; - int bz = mcr.z << 9; - int tx = bx + 511; - int tz = bz + 511; - if (bx <= region.maxX && tx >= region.minX && bz <= region.maxZ - && tz >= region.minZ) { - for (int x = bx >> 4; x <= (tx >> 4); x++) { - int cbx = x << 4; - int ctx = cbx + 15; - if (cbx <= region.maxX && ctx >= region.minX) { - for (int z = bz >> 4; z <= (tz >> 4); z++) { - int cbz = z << 4; - int ctz = cbz + 15; - if (cbz <= region.maxZ && ctz >= region.minZ) { - chunks.add(new ChunkLoc(x, z)); - } + TaskManager.runTaskAsync(() -> { + HashSet chunks = new HashSet<>(); + Set mcrs = manager.getChunkChunks(world); + for (ChunkLoc mcr : mcrs) { + int bx = mcr.x << 9; + int bz = mcr.z << 9; + int tx = bx + 511; + int tz = bz + 511; + if (bx <= region.maxX && tx >= region.minX && bz <= region.maxZ + && tz >= region.minZ) { + for (int x = bx >> 4; x <= (tx >> 4); x++) { + int cbx = x << 4; + int ctx = cbx + 15; + if (cbx <= region.maxX && ctx >= region.minX) { + for (int z = bz >> 4; z <= (tz >> 4); z++) { + int cbz = z << 4; + int ctz = cbz + 15; + if (cbz <= region.maxZ && ctz >= region.minZ) { + chunks.add(new ChunkLoc(x, z)); } } } } } - TaskManager.objectTask(chunks, new RunnableVal() { - - @Override public void run(ChunkLoc value) { - if (manager.loadChunk(world, value, false)) { - task.run(value); - } - } - }, whenDone); } + TaskManager.objectTask(chunks, new RunnableVal() { + + @Override public void run(ChunkLoc value) { + if (manager.loadChunk(world, value, false)) { + task.run(value); + } + } + }, whenDone); }); } @@ -239,20 +237,18 @@ public abstract class ChunkManager { public void deleteRegionFiles(final String world, final Collection chunks, final Runnable whenDone) { - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - for (ChunkLoc loc : chunks) { - String directory = - world + File.separator + "region" + File.separator + "r." + loc.x + "." - + loc.z + ".mca"; - File file = new File(PlotSquared.get().IMP.getWorldContainer(), directory); - PlotSquared.log("&6 - Deleting file: " + file.getName() + " (max 1024 chunks)"); - if (file.exists()) { - file.delete(); - } + TaskManager.runTaskAsync(() -> { + for (ChunkLoc loc : chunks) { + String directory = + world + File.separator + "region" + File.separator + "r." + loc.x + "." + + loc.z + ".mca"; + File file = new File(PlotSquared.get().IMP.getWorldContainer(), directory); + PlotSquared.log("&6 - Deleting file: " + file.getName() + " (max 1024 chunks)"); + if (file.exists()) { + file.delete(); } - TaskManager.runTask(whenDone); } + TaskManager.runTask(whenDone); }); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/CmdConfirm.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/CmdConfirm.java index 11c157320..d0b4012a6 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/CmdConfirm.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/CmdConfirm.java @@ -19,11 +19,9 @@ public class CmdConfirm { removePending(player); if (commandStr != null) MainUtil.sendMessage(player, C.REQUIRES_CONFIRM, commandStr); - TaskManager.runTaskLater(new Runnable() { - @Override public void run() { - CmdInstance cmd = new CmdInstance(runnable); - player.setMeta("cmdConfirm", cmd); - } + TaskManager.runTaskLater(() -> { + CmdInstance cmd = new CmdInstance(runnable); + player.setMeta("cmdConfirm", cmd); }, 1); } } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/CommentManager.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/CommentManager.java index 3dc43fe06..cc5021c57 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/CommentManager.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/CommentManager.java @@ -20,34 +20,32 @@ public class CommentManager { if (!Settings.Enabled_Components.COMMENT_NOTIFIER || !plot.isOwner(player.getUUID())) { return; } - TaskManager.runTaskLaterAsync(new Runnable() { - @Override public void run() { - Collection boxes = CommentManager.inboxes.values(); - final AtomicInteger count = new AtomicInteger(0); - final AtomicInteger size = new AtomicInteger(boxes.size()); - for (final CommentInbox inbox : inboxes.values()) { - inbox.getComments(plot, new RunnableVal>() { - @Override public void run(List value) { - int total; - if (value != null) { - int num = 0; - for (PlotComment comment : value) { - if (comment.timestamp > getTimestamp(player, - inbox.toString())) { - num++; - } + TaskManager.runTaskLaterAsync(() -> { + Collection boxes = CommentManager.inboxes.values(); + final AtomicInteger count = new AtomicInteger(0); + final AtomicInteger size = new AtomicInteger(boxes.size()); + for (final CommentInbox inbox : inboxes.values()) { + inbox.getComments(plot, new RunnableVal>() { + @Override public void run(List value) { + int total; + if (value != null) { + int num = 0; + for (PlotComment comment : value) { + if (comment.timestamp > getTimestamp(player, + inbox.toString())) { + num++; } - total = count.addAndGet(num); - } else { - total = count.get(); - } - if ((size.decrementAndGet() == 0) && (total > 0)) { - AbstractTitle.sendTitle(player, "", - C.INBOX_NOTIFICATION.s().replaceAll("%s", "" + total)); } + total = count.addAndGet(num); + } else { + total = count.get(); } - }); - } + if ((size.decrementAndGet() == 0) && (total > 0)) { + AbstractTitle.sendTitle(player, "", + C.INBOX_NOTIFICATION.s().replaceAll("%s", "" + total)); + } + } + }); } }, 20); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/EventUtil.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/EventUtil.java index b8037944e..7d82e5236 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/EventUtil.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/EventUtil.java @@ -43,8 +43,6 @@ public abstract class EventUtil { public abstract boolean callFlagRemove(Flag flag, Plot plot, Object value); - public abstract boolean callFlagRemove(Flag flag, Object value, PlotCluster cluster); - public abstract boolean callMerge(Plot plot, int dir, int max); public abstract boolean callAutoMerge(Plot plot, List plots); @@ -78,11 +76,7 @@ public abstract class EventUtil { } final Plot plot = player.getCurrentPlot(); if (Settings.Teleport.ON_LOGIN && plot != null) { - TaskManager.runTask(new Runnable() { - @Override public void run() { - plot.teleportPlayer(player); - } - }); + TaskManager.runTask(() -> plot.teleportPlayer(player)); MainUtil.sendMessage(player, C.TELEPORTED_TO_ROAD.f() + " (on-login) " + "(" + plot.getId().x + ";" + plot .getId().y + ")"); diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/MainUtil.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/MainUtil.java index 906c70595..e65169260 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/MainUtil.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/MainUtil.java @@ -411,7 +411,7 @@ public class MainUtil { ArrayList> plotList = new ArrayList<>(size); for (int i = 0; i < size; i++) { - plotList.add(new ArrayList()); + plotList.add(new ArrayList<>()); } for (Plot plot : PlotSquared.get().getPlots()) { @@ -430,7 +430,7 @@ public class MainUtil { count++; } } - if (area != null && plot.getArea().equals(area)) { + if (plot.getArea().equals(area)) { count++; } if (alias != null && alias.equals(plot.getAlias())) { @@ -622,14 +622,12 @@ public class MainUtil { if (caption.s().isEmpty()) { return true; } - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - String m = C.format(caption, args); - if (player == null) { - PlotSquared.log(m); - } else { - player.sendMessage(m); - } + TaskManager.runTaskAsync(() -> { + String m = C.format(caption, args); + if (player == null) { + PlotSquared.log(m); + } else { + player.sendMessage(m); } }); return true; @@ -780,31 +778,29 @@ public class MainUtil { info = info.replace("%desc%", "No description set."); if (info.contains("%rating%")) { final String newInfo = info; - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - int max = 10; - if (Settings.Ratings.CATEGORIES != null && !Settings.Ratings.CATEGORIES - .isEmpty()) { - max = 8; - } - String info; - if (full && Settings.Ratings.CATEGORIES != null - && Settings.Ratings.CATEGORIES.size() > 1) { - double[] ratings = MainUtil.getAverageRatings(plot); - String rating = ""; - String prefix = ""; - for (int i = 0; i < ratings.length; i++) { - rating += prefix + Settings.Ratings.CATEGORIES.get(i) + '=' + String - .format("%.1f", ratings[i]); - prefix = ","; - } - info = newInfo.replaceAll("%rating%", rating); - } else { - info = newInfo.replaceAll("%rating%", - String.format("%.1f", plot.getAverageRating()) + '/' + max); - } - whenDone.run(info); + TaskManager.runTaskAsync(() -> { + int max = 10; + if (Settings.Ratings.CATEGORIES != null && !Settings.Ratings.CATEGORIES + .isEmpty()) { + max = 8; } + String info1; + if (full && Settings.Ratings.CATEGORIES != null + && Settings.Ratings.CATEGORIES.size() > 1) { + double[] ratings = MainUtil.getAverageRatings(plot); + String rating = ""; + String prefix = ""; + for (int i = 0; i < ratings.length; i++) { + rating += prefix + Settings.Ratings.CATEGORIES.get(i) + '=' + String + .format("%.1f", ratings[i]); + prefix = ","; + } + info1 = newInfo.replaceAll("%rating%", rating); + } else { + info1 = newInfo.replaceAll("%rating%", + String.format("%.1f", plot.getAverageRating()) + '/' + max); + } + whenDone.run(info1); }); return; } @@ -815,10 +811,9 @@ public class MainUtil { if (directory.exists()) { File[] files = directory.listFiles(); if (null != files) { - for (int i = 0; i < files.length; i++) { - File file = files[i]; + for (File file : files) { if (file.isDirectory()) { - deleteDirectory(files[i]); + deleteDirectory(file); } else { PlotSquared.debug("Deleting file: " + file + " | " + file.delete()); } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/SchematicHandler.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/SchematicHandler.java index f1ca31b4d..05eeee166 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/SchematicHandler.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/SchematicHandler.java @@ -87,7 +87,7 @@ public abstract class SchematicHandler { } else { MainUtil.sendMessage(null, "&7 - &a success: " + plot.getId()); } - TaskManager.runTask(() -> THIS.run()); + TaskManager.runTask(THIS); }); } } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/block/GlobalBlockQueue.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/block/GlobalBlockQueue.java index 3991cd78d..3d065a527 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/block/GlobalBlockQueue.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/block/GlobalBlockQueue.java @@ -13,292 +13,292 @@ import java.util.concurrent.atomic.AtomicBoolean; public class GlobalBlockQueue { - public static GlobalBlockQueue IMP; - private final int PARALLEL_THREADS; - private final ConcurrentLinkedDeque activeQueues; - private final ConcurrentLinkedDeque inactiveQueues; - private final ConcurrentLinkedDeque runnables; - private final AtomicBoolean running; - private QueueProvider provider; - /** - * Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the server - */ - private long last; - private long secondLast; - private long lastSuccess; - private final RunnableVal2 SET_TASK = - new RunnableVal2() { - @Override public void run(Long free, LocalBlockQueue queue) { - do { - boolean more = queue.next(); - if (!more) { - lastSuccess = last; - if (inactiveQueues.size() == 0 && activeQueues.size() == 0) { - tasks(); - } - return; - } - } while (((GlobalBlockQueue.this.secondLast = System.currentTimeMillis()) - - GlobalBlockQueue.this.last) < free); + public static GlobalBlockQueue IMP; + private final int PARALLEL_THREADS; + private final ConcurrentLinkedDeque activeQueues; + private final ConcurrentLinkedDeque inactiveQueues; + private final ConcurrentLinkedDeque runnables; + private final AtomicBoolean running; + private QueueProvider provider; + /** + * Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the + * server + */ + private long last; + private long secondLast; + private long lastSuccess; + private final RunnableVal2 SET_TASK = + new RunnableVal2() { + @Override + public void run(Long free, LocalBlockQueue queue) { + do { + boolean more = queue.next(); + if (!more) { + lastSuccess = last; + if (inactiveQueues.size() == 0 && activeQueues.size() == 0) { + tasks(); + } + return; } - }; - - public GlobalBlockQueue(QueueProvider provider, int threads) { - this.provider = provider; - activeQueues = new ConcurrentLinkedDeque<>(); - inactiveQueues = new ConcurrentLinkedDeque<>(); - runnables = new ConcurrentLinkedDeque<>(); - running = new AtomicBoolean(); - this.PARALLEL_THREADS = threads; - } - - public QueueProvider getProvider() { - return provider; - } - - public void setProvider(QueueProvider provider) { - this.provider = provider; - } - - public LocalBlockQueue getNewQueue(String world, boolean autoQueue) { - LocalBlockQueue queue = provider.getNewQueue(world); - if (autoQueue) { - inactiveQueues.add(queue); + } while (((GlobalBlockQueue.this.secondLast = System.currentTimeMillis()) + - GlobalBlockQueue.this.last) < free); } - return queue; - } + }; - public boolean stop() { - if (!running.get()) { - return false; - } - running.set(false); - return true; - } + public GlobalBlockQueue(QueueProvider provider, int threads) { + this.provider = provider; + activeQueues = new ConcurrentLinkedDeque<>(); + inactiveQueues = new ConcurrentLinkedDeque<>(); + runnables = new ConcurrentLinkedDeque<>(); + running = new AtomicBoolean(); + this.PARALLEL_THREADS = threads; + } - public boolean runTask() { - if (running.get()) { - return false; - } - running.set(true); - TaskManager.runTaskRepeat(new Runnable() { - @Override public void run() { - if (inactiveQueues.isEmpty() && activeQueues.isEmpty()) { - lastSuccess = System.currentTimeMillis(); - tasks(); - return; - } - SET_TASK.value1 = 50 + Math.min( - (50 + GlobalBlockQueue.this.last) - (GlobalBlockQueue.this.last = - System.currentTimeMillis()), - GlobalBlockQueue.this.secondLast - System.currentTimeMillis()); - SET_TASK.value2 = getNextQueue(); - if (SET_TASK.value2 == null) { - return; - } - if (!PlotSquared.get().isMainThread(Thread.currentThread())) { - throw new IllegalStateException( - "This shouldn't be possible for placement to occur off the main thread"); - } - // Disable the async catcher as it can't discern async vs parallel - SET_TASK.value2.startSet(true); - try { - if (PARALLEL_THREADS <= 1) { - SET_TASK.run(); - } else { - ArrayList threads = new ArrayList(); - for (int i = 0; i < PARALLEL_THREADS; i++) { - threads.add(new Thread(SET_TASK)); - } - for (Thread thread : threads) { - thread.start(); - } - for (Thread thread : threads) { - try { - thread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } catch (Throwable e) { - e.printStackTrace(); - } finally { - // Enable it again (note that we are still on the main thread) - SET_TASK.value2.endSet(true); - } - } - }, 1); - return true; - } + public QueueProvider getProvider() { + return provider; + } - public QueueStage getStage(LocalBlockQueue queue) { - if (activeQueues.contains(queue)) { - return QueueStage.ACTIVE; - } else if (inactiveQueues.contains(queue)) { - return QueueStage.INACTIVE; - } - return QueueStage.NONE; - } + public void setProvider(QueueProvider provider) { + this.provider = provider; + } - public boolean isStage(LocalBlockQueue queue, QueueStage stage) { - switch (stage) { - case ACTIVE: - return activeQueues.contains(queue); - case INACTIVE: - return inactiveQueues.contains(queue); - case NONE: - return !activeQueues.contains(queue) && !inactiveQueues.contains(queue); - } - return false; + public LocalBlockQueue getNewQueue(String world, boolean autoQueue) { + LocalBlockQueue queue = provider.getNewQueue(world); + if (autoQueue) { + inactiveQueues.add(queue); } + return queue; + } - public void enqueue(LocalBlockQueue queue) { - inactiveQueues.remove(queue); - if (queue.size() > 0 && !activeQueues.contains(queue)) { - queue.optimize(); - activeQueues.add(queue); - } + public boolean stop() { + if (!running.get()) { + return false; } + running.set(false); + return true; + } - public void dequeue(LocalBlockQueue queue) { - inactiveQueues.remove(queue); - activeQueues.remove(queue); + public boolean runTask() { + if (running.get()) { + return false; } - - public List getAllQueues() { - ArrayList list = - new ArrayList(activeQueues.size() + inactiveQueues.size()); - list.addAll(inactiveQueues); - list.addAll(activeQueues); - return list; - } - - public List getActiveQueues() { - return new ArrayList<>(activeQueues); - } - - public List getInactiveQueues() { - return new ArrayList<>(inactiveQueues); - } - - public void flush(LocalBlockQueue queue) { - SET_TASK.value1 = Long.MAX_VALUE; - SET_TASK.value2 = queue; - if (SET_TASK.value2 == null) { - return; - } - if (PlotSquared.get().isMainThread(Thread.currentThread())) { - throw new IllegalStateException("Must be flushed on the main thread!"); - } - // Disable the async catcher as it can't discern async vs parallel - SET_TASK.value2.startSet(true); - try { - if (PARALLEL_THREADS <= 1) { - SET_TASK.run(); - } else { - ArrayList threads = new ArrayList(); - for (int i = 0; i < PARALLEL_THREADS; i++) { - threads.add(new Thread(SET_TASK)); - } - for (Thread thread : threads) { - thread.start(); - } - for (Thread thread : threads) { - try { - thread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } catch (Throwable e) { - e.printStackTrace(); - } finally { - // Enable it again (note that we are still on the main thread) - SET_TASK.value2.endSet(true); - dequeue(queue); - } - } - - public LocalBlockQueue getNextQueue() { - long now = System.currentTimeMillis(); - while (activeQueues.size() > 0) { - LocalBlockQueue queue = activeQueues.peek(); - if (queue != null && queue.size() > 0) { - queue.setModified(now); - return queue; - } else { - activeQueues.poll(); - } - } - int size = inactiveQueues.size(); - if (size > 0) { - Iterator iter = inactiveQueues.iterator(); + running.set(true); + TaskManager.runTaskRepeat(() -> { + if (inactiveQueues.isEmpty() && activeQueues.isEmpty()) { + lastSuccess = System.currentTimeMillis(); + tasks(); + return; + } + SET_TASK.value1 = 50 + Math.min( + (50 + GlobalBlockQueue.this.last) - (GlobalBlockQueue.this.last = + System.currentTimeMillis()), + GlobalBlockQueue.this.secondLast - System.currentTimeMillis()); + SET_TASK.value2 = getNextQueue(); + if (SET_TASK.value2 == null) { + return; + } + if (!PlotSquared.get().isMainThread(Thread.currentThread())) { + throw new IllegalStateException( + "This shouldn't be possible for placement to occur off the main thread"); + } + // Disable the async catcher as it can't discern async vs parallel + SET_TASK.value2.startSet(true); + try { + if (PARALLEL_THREADS <= 1) { + SET_TASK.run(); + } else { + ArrayList threads = new ArrayList(); + for (int i = 0; i < PARALLEL_THREADS; i++) { + threads.add(new Thread(SET_TASK)); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { try { - int total = 0; - LocalBlockQueue firstNonEmpty = null; - while (iter.hasNext()) { - LocalBlockQueue queue = iter.next(); - long age = now - queue.getModified(); - total += queue.size(); - if (queue.size() == 0) { - if (age > 1000) { - iter.remove(); - } - continue; - } - if (firstNonEmpty == null) { - firstNonEmpty = queue; - } - if (total > 64) { - firstNonEmpty.setModified(now); - return firstNonEmpty; - } - if (age > 60000) { - queue.setModified(now); - return queue; - } - } - } catch (ConcurrentModificationException e) { - e.printStackTrace(); + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); } + } } - return null; - } + } catch (Throwable e) { + e.printStackTrace(); + } finally { + // Enable it again (note that we are still on the main thread) + SET_TASK.value2.endSet(true); + } + }, 1); + return true; + } - public boolean isDone() { - return activeQueues.size() == 0 && inactiveQueues.size() == 0; + public QueueStage getStage(LocalBlockQueue queue) { + if (activeQueues.contains(queue)) { + return QueueStage.ACTIVE; + } else if (inactiveQueues.contains(queue)) { + return QueueStage.INACTIVE; } + return QueueStage.NONE; + } - public boolean addTask(final Runnable whenDone) { - if (this.isDone()) { - // Run - this.tasks(); - if (whenDone != null) { - whenDone.run(); + public boolean isStage(LocalBlockQueue queue, QueueStage stage) { + switch (stage) { + case ACTIVE: + return activeQueues.contains(queue); + case INACTIVE: + return inactiveQueues.contains(queue); + case NONE: + return !activeQueues.contains(queue) && !inactiveQueues.contains(queue); + } + return false; + } + + public void enqueue(LocalBlockQueue queue) { + inactiveQueues.remove(queue); + if (queue.size() > 0 && !activeQueues.contains(queue)) { + queue.optimize(); + activeQueues.add(queue); + } + } + + public void dequeue(LocalBlockQueue queue) { + inactiveQueues.remove(queue); + activeQueues.remove(queue); + } + + public List getAllQueues() { + ArrayList list = + new ArrayList<>(activeQueues.size() + inactiveQueues.size()); + list.addAll(inactiveQueues); + list.addAll(activeQueues); + return list; + } + + public List getActiveQueues() { + return new ArrayList<>(activeQueues); + } + + public List getInactiveQueues() { + return new ArrayList<>(inactiveQueues); + } + + public void flush(LocalBlockQueue queue) { + SET_TASK.value1 = Long.MAX_VALUE; + SET_TASK.value2 = queue; + if (SET_TASK.value2 == null) { + return; + } + if (PlotSquared.get().isMainThread(Thread.currentThread())) { + throw new IllegalStateException("Must be flushed on the main thread!"); + } + // Disable the async catcher as it can't discern async vs parallel + SET_TASK.value2.startSet(true); + try { + if (PARALLEL_THREADS <= 1) { + SET_TASK.run(); + } else { + ArrayList threads = new ArrayList<>(); + for (int i = 0; i < PARALLEL_THREADS; i++) { + threads.add(new Thread(SET_TASK)); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + try { + thread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } catch (Throwable e) { + e.printStackTrace(); + } finally { + // Enable it again (note that we are still on the main thread) + SET_TASK.value2.endSet(true); + dequeue(queue); + } + } + + public LocalBlockQueue getNextQueue() { + long now = System.currentTimeMillis(); + while (activeQueues.size() > 0) { + LocalBlockQueue queue = activeQueues.peek(); + if (queue != null && queue.size() > 0) { + queue.setModified(now); + return queue; + } else { + activeQueues.poll(); + } + } + int size = inactiveQueues.size(); + if (size > 0) { + Iterator iter = inactiveQueues.iterator(); + try { + int total = 0; + LocalBlockQueue firstNonEmpty = null; + while (iter.hasNext()) { + LocalBlockQueue queue = iter.next(); + long age = now - queue.getModified(); + total += queue.size(); + if (queue.size() == 0) { + if (age > 1000) { + iter.remove(); } - return true; + continue; + } + if (firstNonEmpty == null) { + firstNonEmpty = queue; + } + if (total > 64) { + firstNonEmpty.setModified(now); + return firstNonEmpty; + } + if (age > 60000) { + queue.setModified(now); + return queue; + } } - if (whenDone != null) { - this.runnables.add(whenDone); - } - return false; + } catch (ConcurrentModificationException e) { + e.printStackTrace(); + } } + return null; + } - public synchronized boolean tasks() { - if (this.runnables.isEmpty()) { - return false; - } - final ArrayList tmp = new ArrayList<>(this.runnables); - this.runnables.clear(); - for (final Runnable runnable : tmp) { - runnable.run(); - } - return true; - } + public boolean isDone() { + return activeQueues.size() == 0 && inactiveQueues.size() == 0; + } - public enum QueueStage { - INACTIVE, ACTIVE, NONE; + public boolean addTask(final Runnable whenDone) { + if (this.isDone()) { + // Run + this.tasks(); + if (whenDone != null) { + whenDone.run(); + } + return true; } + if (whenDone != null) { + this.runnables.add(whenDone); + } + return false; + } + + public synchronized boolean tasks() { + if (this.runnables.isEmpty()) { + return false; + } + final ArrayList tmp = new ArrayList<>(this.runnables); + this.runnables.clear(); + for (final Runnable runnable : tmp) { + runnable.run(); + } + return true; + } + + public enum QueueStage { + INACTIVE, ACTIVE, NONE + } } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/ExpireManager.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/ExpireManager.java index 84f86daa2..2f69b818e 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/ExpireManager.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/ExpireManager.java @@ -19,454 +19,435 @@ import java.util.concurrent.ConcurrentLinkedDeque; public class ExpireManager { - public static ExpireManager IMP; - private final ConcurrentHashMap dates_cache; - private final ConcurrentHashMap account_age_cache; - private volatile HashSet plotsToDelete; - private ArrayDeque tasks; - /** - * 0 = stopped, 1 = stopping, 2 = running - */ - private int running; + public static ExpireManager IMP; + private final ConcurrentHashMap dates_cache; + private final ConcurrentHashMap account_age_cache; + private volatile HashSet plotsToDelete; + private ArrayDeque tasks; + /** + * 0 = stopped, 1 = stopping, 2 = running + */ + private int running; - public ExpireManager() { - tasks = new ArrayDeque<>(); - dates_cache = new ConcurrentHashMap<>(); - account_age_cache = new ConcurrentHashMap<>(); + public ExpireManager() { + tasks = new ArrayDeque<>(); + dates_cache = new ConcurrentHashMap<>(); + account_age_cache = new ConcurrentHashMap<>(); + } + + public void addTask(ExpiryTask task) { + PlotSquared.debug("Adding new expiry task!"); + this.tasks.add(task); + } + + public void handleJoin(PlotPlayer pp) { + storeDate(pp.getUUID(), System.currentTimeMillis()); + if (plotsToDelete != null && !plotsToDelete.isEmpty()) { + for (Plot plot : pp.getPlots()) { + plotsToDelete.remove(plot); + } } + confirmExpiry(pp); + } - public void addTask(ExpiryTask task) { - PlotSquared.debug("Adding new expiry task!"); - this.tasks.add(task); - } - - public void handleJoin(PlotPlayer pp) { - storeDate(pp.getUUID(), System.currentTimeMillis()); - if (plotsToDelete != null && !plotsToDelete.isEmpty()) { - for (Plot plot : pp.getPlots()) { - plotsToDelete.remove(plot); - } - } + public void handleEntry(PlotPlayer pp, Plot plot) { + if (plotsToDelete != null && !plotsToDelete.isEmpty() && pp + .hasPermission("plots.admin.command.autoclear") && plotsToDelete.contains(plot)) { + if (!isExpired(new ArrayDeque<>(tasks), plot).isEmpty()) { confirmExpiry(pp); + } else { + plotsToDelete.remove(plot); + confirmExpiry(pp); + } } + } - public void handleEntry(PlotPlayer pp, Plot plot) { - if (plotsToDelete != null && !plotsToDelete.isEmpty() && pp - .hasPermission("plots.admin.command.autoclear") && plotsToDelete.contains(plot)) { - if (!isExpired(new ArrayDeque<>(tasks), plot).isEmpty()) { - confirmExpiry(pp); - } else { - plotsToDelete.remove(plot); - confirmExpiry(pp); - } - } + /** + * Gets the account last joined - first joined (or Long.MAX_VALUE) + * + * @return result + */ + public long getAccountAge(UUID uuid) { + Long value = this.account_age_cache.get(uuid); + return value == null ? Long.MAX_VALUE : value; + } + + public long getTimestamp(UUID uuid) { + Long value = this.dates_cache.get(uuid); + return value == null ? 0 : value; + } + + public void updateExpired(Plot plot) { + if (plotsToDelete != null && !plotsToDelete.isEmpty() && plotsToDelete.contains(plot)) { + if (isExpired(new ArrayDeque<>(tasks), plot).isEmpty()) { + plotsToDelete.remove(plot); + } } + } - /** - * Gets the account last joined - first joined (or Long.MAX_VALUE) - * - * @param uuid - * @return result - */ - public long getAccountAge(UUID uuid) { - Long value = this.account_age_cache.get(uuid); - return value == null ? Long.MAX_VALUE : value; + public void confirmExpiry(final PlotPlayer pp) { + if (pp.getMeta("ignoreExpireTask") != null) { + return; } - - public long getTimestamp(UUID uuid) { - Long value = this.dates_cache.get(uuid); - return value == null ? 0 : value; - } - - public void updateExpired(Plot plot) { - if (plotsToDelete != null && !plotsToDelete.isEmpty() && plotsToDelete.contains(plot)) { - if (isExpired(new ArrayDeque<>(tasks), plot).isEmpty()) { - plotsToDelete.remove(plot); - } - } - } - - public void confirmExpiry(final PlotPlayer pp) { - if (pp.getMeta("ignoreExpireTask") != null) { - return; - } - if (plotsToDelete != null && !plotsToDelete.isEmpty() && pp - .hasPermission("plots.admin.command.autoclear")) { - final int num = plotsToDelete.size(); - while (!plotsToDelete.isEmpty()) { - Iterator iter = plotsToDelete.iterator(); - final Plot current = iter.next(); - if (!isExpired(new ArrayDeque<>(tasks), current).isEmpty()) { - TaskManager.runTask(new Runnable() { - @Override public void run() { - pp.setMeta("ignoreExpireTask", true); - pp.teleport(current.getCenter()); - pp.deleteMeta("ignoreExpireTask"); - PlotMessage msg = new PlotMessage().text( - num + " " + (num > 1 ? "plots are" : "plot is") + " expired: ") - .color("$1").text(current.toString()).color("$2") - .suggest("/plot list expired").tooltip("/plot list expired") - //.text("\n - ").color("$3").text("Delete all (/plot delete expired)").color("$2").command("/plot delete expired") - .text("\n - ").color("$3").text("Delete this (/plot delete)") - .color("$2").suggest("/plot delete").tooltip("/plot delete") - .text("\n - ").color("$3").text("Remind later (/plot set keep 1d)") - .color("$2").suggest("/plot set keep 1d") - .tooltip("/plot set keep 1d").text("\n - ").color("$3") - .text("Keep this (/plot set keep true)").color("$2") - .suggest("/plot set keep true").tooltip("/plot set keep true") - .text("\n - ").color("$3").text("Don't show me this").color("$2") - .suggest("/plot toggle clear-confirmation") - .tooltip("/plot toggle clear-confirmation"); - msg.send(pp); - } - }); - return; - } else { - iter.remove(); - } - } - plotsToDelete.clear(); - } - } - - - public boolean cancelTask() { - if (this.running != 2) { - return false; - } - this.running = 1; - return true; - } - - public boolean runAutomatedTask() { - return runTask(new RunnableVal3() { - @Override public void run(Plot plot, Runnable runnable, Boolean confirm) { - if (confirm) { - if (plotsToDelete == null) { - plotsToDelete = new HashSet<>(); - } - plotsToDelete.add(plot); - runnable.run(); - } else { - deleteWithMessage(plot, runnable); - } - } - }); - } - - public Collection isExpired(ArrayDeque applicable, Plot plot) { - // Filter out invalid worlds - for (int i = 0; i < applicable.size(); i++) { - ExpiryTask et = applicable.poll(); - if (et.applies(plot.getArea())) { - applicable.add(et); - } - } - if (applicable.isEmpty()) { - return new ArrayList<>(); - } - boolean shouldCheckAccountAge = false; - - long diff = getAge(plot); - if (diff == 0) { - return new ArrayList<>(); - } - // Filter out non old plots - for (int i = 0; i < applicable.size(); i++) { - ExpiryTask et = applicable.poll(); - if (et.applies(diff)) { - applicable.add(et); - shouldCheckAccountAge |= et.getSettings().SKIP_ACCOUNT_AGE_DAYS != -1; - } - } - if (applicable.isEmpty()) { - return new ArrayList<>(); - } - // Check account age - if (shouldCheckAccountAge) { - long accountAge = getAge(plot); - for (int i = 0; i < applicable.size(); i++) { - ExpiryTask et = applicable.poll(); - if (et.appliesAccountAge(accountAge)) { - applicable.add(et); - } - } - if (applicable.isEmpty()) { - return new ArrayList<>(); - } - } - - // Run applicable non confirming tasks - for (int i = 0; i < applicable.size(); i++) { - ExpiryTask expiryTask = applicable.poll(); - if (!expiryTask.needsAnalysis() || plot.getArea().TYPE != 0) { - if (!expiryTask.requiresConfirmation()) { - return Collections.singletonList(expiryTask); - } - } - applicable.add(expiryTask); - } - // Run applicable confirming tasks - for (int i = 0; i < applicable.size(); i++) { - ExpiryTask expiryTask = applicable.poll(); - if (!expiryTask.needsAnalysis() || plot.getArea().TYPE != 0) { - return Collections.singletonList(expiryTask); - } - applicable.add(expiryTask); - } - return applicable; - } - - public ArrayDeque getTasks(PlotArea area) { - ArrayDeque queue = new ArrayDeque<>(tasks); - Iterator iter = queue.iterator(); - while (iter.hasNext()) { - if (!iter.next().applies(area)) { - iter.remove(); - } - } - return queue; - } - - public void passesComplexity(PlotAnalysis analysis, Collection applicable, - RunnableVal success, Runnable failure) { - if (analysis != null) { - // Run non confirming tasks - for (ExpiryTask et : applicable) { - if (!et.requiresConfirmation() && et.applies(analysis)) { - success.run(false); - return; - } - } - for (ExpiryTask et : applicable) { - if (et.applies(analysis)) { - success.run(true); - return; - } - } - failure.run(); - } - } - - public boolean runTask(final RunnableVal3 expiredTask) { - if (this.running != 0) { - return false; - } - this.running = 2; - final ConcurrentLinkedDeque plots = - new ConcurrentLinkedDeque(PlotSquared.get().getPlots()); - TaskManager.runTaskAsync(new Runnable() { - @Override public void run() { - final Runnable task = this; - if (ExpireManager.this.running != 2) { - ExpireManager.this.running = 0; - return; - } - long start = System.currentTimeMillis(); - while (!plots.isEmpty()) { - if (ExpireManager.this.running != 2) { - ExpireManager.this.running = 0; - return; - } - Plot plot = plots.poll(); - PlotArea area = plot.getArea(); - final Plot newPlot = area.getPlot(plot.getId()); - final ArrayDeque applicable = new ArrayDeque<>(tasks); - final Collection expired = isExpired(applicable, newPlot); - if (expired.isEmpty()) { - continue; - } - for (ExpiryTask expiryTask : expired) { - if (!expiryTask.needsAnalysis()) { - expiredTask.run(newPlot, new Runnable() { - @Override public void run() { - TaskManager.IMP.taskLaterAsync(task, 1); - } - }, expiryTask.requiresConfirmation()); - return; - } - } - final RunnableVal handleAnalysis = - new RunnableVal() { - @Override public void run(final PlotAnalysis changed) { - passesComplexity(changed, expired, new RunnableVal() { - @Override public void run(Boolean confirmation) { - expiredTask.run(newPlot, new Runnable() { - @Override public void run() { - TaskManager.IMP.taskLaterAsync(task, 1); - } - }, confirmation); - } - }, new Runnable() { - @Override public void run() { - FlagManager - .addPlotFlag(newPlot, Flags.ANALYSIS, changed.asList()); - TaskManager.runTaskLaterAsync(task, 20); - } - }); - } - }; - final Runnable doAnalysis = new Runnable() { - @Override public void run() { - HybridUtils.manager.analyzePlot(newPlot, handleAnalysis); - } - }; - - PlotAnalysis analysis = newPlot.getComplexity(null); - if (analysis != null) { - passesComplexity(analysis, expired, new RunnableVal() { - @Override public void run(Boolean value) { - doAnalysis.run(); - } - }, new Runnable() { - @Override public void run() { - TaskManager.IMP.taskLaterAsync(task, 1); - } - }); - } else { - doAnalysis.run(); - } - return; - } - if (plots.isEmpty()) { - ExpireManager.this.running = 3; - TaskManager.runTaskLater(new Runnable() { - @Override public void run() { - if (ExpireManager.this.running == 3) { - ExpireManager.this.running = 2; - runTask(expiredTask); - } - } - }, 86400000); - } else { - TaskManager.runTaskLaterAsync(task, 20 * 10); - } - } - }); - return true; - } - - public void storeDate(UUID uuid, long time) { - Long existing = this.dates_cache.put(uuid, time); - if (existing != null) { - long diff = time - existing; - if (diff > 0) { - Long account_age = this.account_age_cache.get(uuid); - if (account_age != null) - this.account_age_cache.put(uuid, account_age + diff); - } - } - } - - public void storeAccountAge(UUID uuid, long time) { - this.account_age_cache.put(uuid, time); - } - - public HashSet getPendingExpired() { - return plotsToDelete == null ? new HashSet() : plotsToDelete; - } - - public void deleteWithMessage(Plot plot, Runnable whenDone) { - if (plot.isMerged()) { - plot.unlinkPlot(true, false); - } - for (UUID helper : plot.getTrusted()) { - PlotPlayer player = UUIDHandler.getPlayer(helper); - if (player != null) { - MainUtil.sendMessage(player, C.PLOT_REMOVED_USER, plot.toString()); - } - } - for (UUID helper : plot.getMembers()) { - PlotPlayer player = UUIDHandler.getPlayer(helper); - if (player != null) { - MainUtil.sendMessage(player, C.PLOT_REMOVED_USER, plot.toString()); - } - } - Set plots = plot.getConnectedPlots(); - plot.deletePlot(whenDone); - PlotAnalysis changed = plot.getComplexity(null); - int changes = changed == null ? 0 : changed.changes_sd; - int modified = changed == null ? 0 : changed.changes; - PlotSquared.debug( - "$2[&5Expire&dManager$2] &cDeleted expired plot: " + plot + " User:" + plot.owner - + " Delta:" + changes + "/" + modified + " Connected: " + StringMan - .getString(plots)); - PlotSquared.debug("$4 - Area: " + plot.getArea()); - if (plot.hasOwner()) { - PlotSquared.debug("$4 - Owner: " + UUIDHandler.getName(plot.owner)); + if (plotsToDelete != null && !plotsToDelete.isEmpty() && pp + .hasPermission("plots.admin.command.autoclear")) { + final int num = plotsToDelete.size(); + while (!plotsToDelete.isEmpty()) { + Iterator iter = plotsToDelete.iterator(); + final Plot current = iter.next(); + if (!isExpired(new ArrayDeque<>(tasks), current).isEmpty()) { + TaskManager.runTask(() -> { + pp.setMeta("ignoreExpireTask", true); + pp.teleport(current.getCenter()); + pp.deleteMeta("ignoreExpireTask"); + PlotMessage msg = new PlotMessage().text( + num + " " + (num > 1 ? "plots are" : "plot is") + " expired: ") + .color("$1").text(current.toString()).color("$2") + .suggest("/plot list expired").tooltip("/plot list expired") + //.text("\n - ").color("$3").text("Delete all (/plot delete expired)").color("$2").command("/plot delete expired") + .text("\n - ").color("$3").text("Delete this (/plot delete)") + .color("$2").suggest("/plot delete").tooltip("/plot delete") + .text("\n - ").color("$3").text("Remind later (/plot set keep 1d)") + .color("$2").suggest("/plot set keep 1d") + .tooltip("/plot set keep 1d").text("\n - ").color("$3") + .text("Keep this (/plot set keep true)").color("$2") + .suggest("/plot set keep true").tooltip("/plot set keep true") + .text("\n - ").color("$3").text("Don't show me this").color("$2") + .suggest("/plot toggle clear-confirmation") + .tooltip("/plot toggle clear-confirmation"); + msg.send(pp); + }); + return; } else { - PlotSquared.debug("$4 - Owner: Unowned"); + iter.remove(); } + } + plotsToDelete.clear(); + } + } + + + public boolean cancelTask() { + if (this.running != 2) { + return false; + } + this.running = 1; + return true; + } + + public boolean runAutomatedTask() { + return runTask(new RunnableVal3() { + @Override + public void run(Plot plot, Runnable runnable, Boolean confirm) { + if (confirm) { + if (plotsToDelete == null) { + plotsToDelete = new HashSet<>(); + } + plotsToDelete.add(plot); + runnable.run(); + } else { + deleteWithMessage(plot, runnable); + } + } + }); + } + + public Collection isExpired(ArrayDeque applicable, Plot plot) { + // Filter out invalid worlds + for (int i = 0; i < applicable.size(); i++) { + ExpiryTask et = applicable.poll(); + if (et.applies(plot.getArea())) { + applicable.add(et); + } + } + if (applicable.isEmpty()) { + return new ArrayList<>(); + } + boolean shouldCheckAccountAge = false; + + long diff = getAge(plot); + if (diff == 0) { + return new ArrayList<>(); + } + // Filter out non old plots + for (int i = 0; i < applicable.size(); i++) { + ExpiryTask et = applicable.poll(); + if (et.applies(diff)) { + applicable.add(et); + shouldCheckAccountAge |= et.getSettings().SKIP_ACCOUNT_AGE_DAYS != -1; + } + } + if (applicable.isEmpty()) { + return new ArrayList<>(); + } + // Check account age + if (shouldCheckAccountAge) { + long accountAge = getAge(plot); + for (int i = 0; i < applicable.size(); i++) { + ExpiryTask et = applicable.poll(); + if (et.appliesAccountAge(accountAge)) { + applicable.add(et); + } + } + if (applicable.isEmpty()) { + return new ArrayList<>(); + } } - public long getAge(UUID uuid) { - if (UUIDHandler.getPlayer(uuid) != null) { - return 0; + // Run applicable non confirming tasks + for (int i = 0; i < applicable.size(); i++) { + ExpiryTask expiryTask = applicable.poll(); + if (!expiryTask.needsAnalysis() || plot.getArea().TYPE != 0) { + if (!expiryTask.requiresConfirmation()) { + return Collections.singletonList(expiryTask); } - String name = UUIDHandler.getName(uuid); - if (name != null) { - Long last = this.dates_cache.get(uuid); - if (last == null) { - OfflinePlotPlayer opp; - if (Settings.UUID.NATIVE_UUID_PROVIDER) { - opp = UUIDHandler.getUUIDWrapper().getOfflinePlayer(uuid); - } else { - opp = UUIDHandler.getUUIDWrapper().getOfflinePlayer(name); - } - if (opp != null && (last = opp.getLastPlayed()) != 0) { - this.dates_cache.put(uuid, last); - } else { - return 0; - } - } - if (last == 0) { - return 0; - } - return System.currentTimeMillis() - last; + } + applicable.add(expiryTask); + } + // Run applicable confirming tasks + for (int i = 0; i < applicable.size(); i++) { + ExpiryTask expiryTask = applicable.poll(); + if (!expiryTask.needsAnalysis() || plot.getArea().TYPE != 0) { + return Collections.singletonList(expiryTask); + } + applicable.add(expiryTask); + } + return applicable; + } + + public ArrayDeque getTasks(PlotArea area) { + ArrayDeque queue = new ArrayDeque<>(tasks); + queue.removeIf(expiryTask -> !expiryTask.applies(area)); + return queue; + } + + public void passesComplexity(PlotAnalysis analysis, Collection applicable, + RunnableVal success, Runnable failure) { + if (analysis != null) { + // Run non confirming tasks + for (ExpiryTask et : applicable) { + if (!et.requiresConfirmation() && et.applies(analysis)) { + success.run(false); + return; } + } + for (ExpiryTask et : applicable) { + if (et.applies(analysis)) { + success.run(true); + return; + } + } + failure.run(); + } + } + + public boolean runTask(final RunnableVal3 expiredTask) { + if (this.running != 0) { + return false; + } + this.running = 2; + final ConcurrentLinkedDeque plots = + new ConcurrentLinkedDeque<>(PlotSquared.get().getPlots()); + TaskManager.runTaskAsync(new Runnable() { + @Override + public void run() { + final Runnable task = this; + if (ExpireManager.this.running != 2) { + ExpireManager.this.running = 0; + return; + } + long start = System.currentTimeMillis(); + while (!plots.isEmpty()) { + if (ExpireManager.this.running != 2) { + ExpireManager.this.running = 0; + return; + } + Plot plot = plots.poll(); + PlotArea area = plot.getArea(); + final Plot newPlot = area.getPlot(plot.getId()); + final ArrayDeque applicable = new ArrayDeque<>(tasks); + final Collection expired = isExpired(applicable, newPlot); + if (expired.isEmpty()) { + continue; + } + for (ExpiryTask expiryTask : expired) { + if (!expiryTask.needsAnalysis()) { + expiredTask.run(newPlot, () -> TaskManager.IMP.taskLaterAsync(task, 1), + expiryTask.requiresConfirmation()); + return; + } + } + final RunnableVal handleAnalysis = + new RunnableVal() { + @Override + public void run(final PlotAnalysis changed) { + passesComplexity(changed, expired, new RunnableVal() { + @Override + public void run(Boolean confirmation) { + expiredTask.run(newPlot, + () -> TaskManager.IMP.taskLaterAsync(task, 1), confirmation); + } + }, () -> { + FlagManager + .addPlotFlag(newPlot, Flags.ANALYSIS, changed.asList()); + TaskManager.runTaskLaterAsync(task, 20); + }); + } + }; + final Runnable doAnalysis = () -> HybridUtils.manager + .analyzePlot(newPlot, handleAnalysis); + + PlotAnalysis analysis = newPlot.getComplexity(null); + if (analysis != null) { + passesComplexity(analysis, expired, new RunnableVal() { + @Override + public void run(Boolean value) { + doAnalysis.run(); + } + }, () -> TaskManager.IMP.taskLaterAsync(task, 1)); + } else { + doAnalysis.run(); + } + return; + } + if (plots.isEmpty()) { + ExpireManager.this.running = 3; + TaskManager.runTaskLater(() -> { + if (ExpireManager.this.running == 3) { + ExpireManager.this.running = 2; + runTask(expiredTask); + } + }, 86400000); + } else { + TaskManager.runTaskLaterAsync(task, 20 * 10); + } + } + }); + return true; + } + + public void storeDate(UUID uuid, long time) { + Long existing = this.dates_cache.put(uuid, time); + if (existing != null) { + long diff = time - existing; + if (diff > 0) { + Long account_age = this.account_age_cache.get(uuid); + if (account_age != null) { + this.account_age_cache.put(uuid, account_age + diff); + } + } + } + } + + public void storeAccountAge(UUID uuid, long time) { + this.account_age_cache.put(uuid, time); + } + + public HashSet getPendingExpired() { + return plotsToDelete == null ? new HashSet<>() : plotsToDelete; + } + + public void deleteWithMessage(Plot plot, Runnable whenDone) { + if (plot.isMerged()) { + plot.unlinkPlot(true, false); + } + for (UUID helper : plot.getTrusted()) { + PlotPlayer player = UUIDHandler.getPlayer(helper); + if (player != null) { + MainUtil.sendMessage(player, C.PLOT_REMOVED_USER, plot.toString()); + } + } + for (UUID helper : plot.getMembers()) { + PlotPlayer player = UUIDHandler.getPlayer(helper); + if (player != null) { + MainUtil.sendMessage(player, C.PLOT_REMOVED_USER, plot.toString()); + } + } + Set plots = plot.getConnectedPlots(); + plot.deletePlot(whenDone); + PlotAnalysis changed = plot.getComplexity(null); + int changes = changed == null ? 0 : changed.changes_sd; + int modified = changed == null ? 0 : changed.changes; + PlotSquared.debug( + "$2[&5Expire&dManager$2] &cDeleted expired plot: " + plot + " User:" + plot.owner + + " Delta:" + changes + "/" + modified + " Connected: " + StringMan + .getString(plots)); + PlotSquared.debug("$4 - Area: " + plot.getArea()); + if (plot.hasOwner()) { + PlotSquared.debug("$4 - Owner: " + UUIDHandler.getName(plot.owner)); + } else { + PlotSquared.debug("$4 - Owner: Unowned"); + } + } + + public long getAge(UUID uuid) { + if (UUIDHandler.getPlayer(uuid) != null) { + return 0; + } + String name = UUIDHandler.getName(uuid); + if (name != null) { + Long last = this.dates_cache.get(uuid); + if (last == null) { + OfflinePlotPlayer opp; + if (Settings.UUID.NATIVE_UUID_PROVIDER) { + opp = UUIDHandler.getUUIDWrapper().getOfflinePlayer(uuid); + } else { + opp = UUIDHandler.getUUIDWrapper().getOfflinePlayer(name); + } + if (opp != null && (last = opp.getLastPlayed()) != 0) { + this.dates_cache.put(uuid, last); + } else { + return 0; + } + } + if (last == 0) { return 0; + } + return System.currentTimeMillis() - last; } + return 0; + } - public long getAccountAge(Plot plot) { - if (!plot.hasOwner() || Objects.equals(DBFunc.EVERYONE, plot.owner) - || UUIDHandler.getPlayer(plot.owner) != null || plot.getRunning() > 0) { - return Long.MAX_VALUE; - } - long max = 0; - for (UUID owner : plot.getOwners()) { - long age = getAccountAge(owner); - max = Math.max(age, max); - } - return max; + public long getAccountAge(Plot plot) { + if (!plot.hasOwner() || Objects.equals(DBFunc.EVERYONE, plot.owner) + || UUIDHandler.getPlayer(plot.owner) != null || plot.getRunning() > 0) { + return Long.MAX_VALUE; } + long max = 0; + for (UUID owner : plot.getOwners()) { + long age = getAccountAge(owner); + max = Math.max(age, max); + } + return max; + } - public long getAge(Plot plot) { - if (!plot.hasOwner() || Objects.equals(DBFunc.EVERYONE, plot.owner) - || UUIDHandler.getPlayer(plot.owner) != null || plot.getRunning() > 0) { - return 0; - } - Optional keep = plot.getFlag(Flags.KEEP); - if (keep.isPresent()) { - Object value = keep.get(); - if (value instanceof Boolean) { - if (Boolean.TRUE.equals(value)) { - return 0; - } - } else if (value instanceof Long) { - if ((Long) value > System.currentTimeMillis()) { - return 0; - } - } else { // Invalid? - return 0; - } - } - long min = Long.MAX_VALUE; - for (UUID owner : plot.getOwners()) { - long age = getAge(owner); - if (age < min) { - min = age; - } - } - return min; + public long getAge(Plot plot) { + if (!plot.hasOwner() || Objects.equals(DBFunc.EVERYONE, plot.owner) + || UUIDHandler.getPlayer(plot.owner) != null || plot.getRunning() > 0) { + return 0; } + Optional keep = plot.getFlag(Flags.KEEP); + if (keep.isPresent()) { + Object value = keep.get(); + if (value instanceof Boolean) { + if (Boolean.TRUE.equals(value)) { + return 0; + } + } else if (value instanceof Long) { + if ((Long) value > System.currentTimeMillis()) { + return 0; + } + } else { // Invalid? + return 0; + } + } + long min = Long.MAX_VALUE; + for (UUID owner : plot.getOwners()) { + long age = getAge(owner); + if (age < min) { + min = age; + } + } + return min; + } } diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/ExpiryTask.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/ExpiryTask.java index df1244a12..3a0b82c56 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/ExpiryTask.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/ExpiryTask.java @@ -5,7 +5,6 @@ import com.github.intellectualsites.plotsquared.plot.config.Settings; import com.github.intellectualsites.plotsquared.plot.object.Plot; import com.github.intellectualsites.plotsquared.plot.object.PlotArea; import com.github.intellectualsites.plotsquared.plot.object.PlotFilter; - import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/PlotAnalysis.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/PlotAnalysis.java index b17f3ce47..f11cb429a 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/PlotAnalysis.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/PlotAnalysis.java @@ -118,16 +118,14 @@ public class PlotAnalysis { final AtomicInteger mi = new AtomicInteger(0); - Thread ratingAnalysis = new Thread(new Runnable() { - @Override public void run() { - for (; mi.intValue() < plots.size(); mi.incrementAndGet()) { - int i = mi.intValue(); - Plot plot = plots.get(i); - ratings[i] = (int) ( - (plot.getAverageRating() + plot.getSettings().getRatings().size()) - * 100); - PlotSquared.debug(" | " + plot + " (rating) " + ratings[i]); - } + Thread ratingAnalysis = new Thread(() -> { + for (; mi.intValue() < plots.size(); mi.incrementAndGet()) { + int i = mi.intValue(); + Plot plot = plots.get(i); + ratings[i] = (int) ( + (plot.getAverageRating() + plot.getSettings().getRatings().size()) + * 100); + PlotSquared.debug(" | " + plot + " (rating) " + ratings[i]); } }); ratingAnalysis.start(); @@ -424,9 +422,6 @@ public class PlotAnalysis { /** * A simple array squaring algorithm. * - Used for calculating the variance - * - * @param array - * @return */ public static int[] square(int[] array) { array = array.clone(); @@ -439,8 +434,6 @@ public class PlotAnalysis { /** * An optimized lossy standard deviation algorithm. * - * @param ranks - * @return */ public static int[] getSD(int[]... ranks) { if (ranks.length == 0) { @@ -468,19 +461,13 @@ public class PlotAnalysis { * - Input is an array of int with a max size of 102400
* - A reduced sample space allows for sorting (and ranking in this case) in linear time * - * @param input - * @param input - * @return */ public static int[] rank(int[] input) { return rank(input, 102400); } /** - * An optimized algorithm for ranking a very specific set of inputs - * - * @param input - * @return + * An optimized algorithm for ranking a very specific set of inputs. */ public static int[] rank(int[] input, int size) { int[] cache = new int[size]; diff --git a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/uuid/UUIDWrapper.java b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/uuid/UUIDWrapper.java index 235b51a34..55f3697f7 100644 --- a/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/uuid/UUIDWrapper.java +++ b/Core/src/main/java/com/github/intellectualsites/plotsquared/plot/uuid/UUIDWrapper.java @@ -5,17 +5,17 @@ import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; import java.util.UUID; -public abstract class UUIDWrapper { +public interface UUIDWrapper { - public abstract UUID getUUID(PlotPlayer player); + UUID getUUID(PlotPlayer player); - public abstract UUID getUUID(OfflinePlotPlayer player); + UUID getUUID(OfflinePlotPlayer player); - public abstract UUID getUUID(String name); + UUID getUUID(String name); - public abstract OfflinePlotPlayer getOfflinePlayer(UUID uuid); + OfflinePlotPlayer getOfflinePlayer(UUID uuid); - public abstract OfflinePlotPlayer getOfflinePlayer(String name); + OfflinePlotPlayer getOfflinePlayer(String name); - public abstract OfflinePlotPlayer[] getOfflinePlayers(); + OfflinePlotPlayer[] getOfflinePlayers(); } diff --git a/Core/src/test/java/com/github/intellectualsites/plotsquared/plot/database/AbstractDBTest.java b/Core/src/test/java/com/github/intellectualsites/plotsquared/plot/database/AbstractDBTest.java index 7b29cdf97..cf118c717 100644 --- a/Core/src/test/java/com/github/intellectualsites/plotsquared/plot/database/AbstractDBTest.java +++ b/Core/src/test/java/com/github/intellectualsites/plotsquared/plot/database/AbstractDBTest.java @@ -84,10 +84,7 @@ public class AbstractDBTest implements AbstractDB { @Override public void setFlags(Plot plot, HashMap, Object> flags) { } - @Override public void setFlags(PlotCluster cluster, HashMap, Object> flags) { - } - - @Override public void setClusterName(PlotCluster cluster, String name) { + @Override public void setClusterName(PlotCluster cluster, String name) { } @Override public void setAlias(Plot plot, String alias) { diff --git a/Core/src/test/java/com/github/intellectualsites/plotsquared/plot/util/EventUtilTest.java b/Core/src/test/java/com/github/intellectualsites/plotsquared/plot/util/EventUtilTest.java index 011fbb7f3..f6550ce98 100644 --- a/Core/src/test/java/com/github/intellectualsites/plotsquared/plot/util/EventUtilTest.java +++ b/Core/src/test/java/com/github/intellectualsites/plotsquared/plot/util/EventUtilTest.java @@ -40,11 +40,7 @@ public class EventUtilTest extends EventUtil { return true; } - @Override public boolean callFlagRemove(Flag flag, Object value, PlotCluster cluster) { - return true; - } - - @Override public boolean callMerge(Plot plot, int dir, int max){ + @Override public boolean callMerge(Plot plot, int dir, int max){ return false; } From 9c90928d0779d281275ff76dbd2e315da2269e42 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sat, 2 Feb 2019 16:13:55 +0000 Subject: [PATCH 013/210] Remove the debug and don't created a new BloxkBucket for every air block. --- .../plotsquared/bukkit/util/BukkitHybridUtils.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitHybridUtils.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitHybridUtils.java index 68b845e58..452d04c35 100644 --- a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitHybridUtils.java +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/bukkit/util/BukkitHybridUtils.java @@ -66,6 +66,7 @@ public class BukkitHybridUtils extends HybridUtils { System.gc(); final BlockBucket[][][] oldBlocks = new BlockBucket[256][width][length]; final PlotBlock[][][] newBlocks = new PlotBlock[256][width][length]; + final BlockBucket airBucket = BlockBucket.withSingle(StringPlotBlock.EVERYTHING); PlotArea area = PlotSquared.get().getPlotArea(world, null); @@ -146,8 +147,8 @@ public class BukkitHybridUtils extends HybridUtils { continue; } int y = MainUtil.y_loc[i][j]; - oldBlocks[y][x][z] = - BlockBucket.withSingle(StringPlotBlock.EVERYTHING); + oldBlocks[y][x][z] = airBucket; + } continue; } @@ -163,7 +164,7 @@ public class BukkitHybridUtils extends HybridUtils { int y = MainUtil.y_loc[i][j]; oldBlocks[y][x][z] = result[i][j] != null ? result[i][j] : - BlockBucket.withSingle(StringPlotBlock.EVERYTHING); + airBucket; } } @@ -183,7 +184,7 @@ public class BukkitHybridUtils extends HybridUtils { BlockBucket old = oldBlocks[y][x][z]; try { if (old == null) { - old = BlockBucket.withSingle(StringPlotBlock.EVERYTHING); + old = airBucket; } PlotBlock now = newBlocks[y][x][z]; if (!old.getBlocks().contains(now)) { @@ -228,10 +229,6 @@ public class BukkitHybridUtils extends HybridUtils { types.add(now); } } catch (NullPointerException e) { - PlotSquared.log(old != null ? old.toString() : "old null"); - PlotSquared.log(x); - PlotSquared.log(y); - PlotSquared.log(z); e.printStackTrace(); } } From 51afbdfcdca3d2a8f21ec12e80dc95e9d85ab9b0 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Mon, 4 Feb 2019 13:59:11 +0000 Subject: [PATCH 014/210] Apply correct codestyle --- .../plotsquared/api/PlotAPI.java | 224 + .../plotsquared/commands/Argument.java | 68 + .../plotsquared/commands/Command.java | 596 ++ .../plotsquared/commands/CommandCaller.java | 24 + .../commands/CommandDeclaration.java | 29 + .../configuration/Configuration.java | 87 + .../configuration/ConfigurationOptions.java | 90 + .../configuration/ConfigurationSection.java | 649 ++ .../InvalidConfigurationException.java | 45 + .../configuration/MemoryConfiguration.java | 73 + .../MemoryConfigurationOptions.java | 25 + .../configuration/MemorySection.java | 771 ++ .../configuration/file/FileConfiguration.java | 158 + .../file/FileConfigurationOptions.java | 115 + .../configuration/file/YamlConfiguration.java | 189 + .../file/YamlConfigurationOptions.java | 68 + .../configuration/file/YamlConstructor.java | 46 + .../configuration/file/YamlRepresenter.java | 40 + .../ConfigurationSerializable.java | 34 + .../ConfigurationSerialization.java | 262 + .../DelegateDeserialization.java | 21 + .../serialization/SerializableAs.java | 32 + .../plotsquared/json/JSONArray.java | 815 +++ .../plotsquared/json/JSONException.java | 40 + .../plotsquared/json/JSONObject.java | 1425 ++++ .../plotsquared/json/JSONString.java | 16 + .../plotsquared/json/JSONTokener.java | 384 + .../plotsquared/json/Property.java | 52 + .../plotsquared/json/XML.java | 375 + .../plotsquared/json/XMLTokener.java | 315 + .../plotsquared/plot/IPlotMain.java | 285 + .../plotsquared/plot/Platform.java | 6 + .../plotsquared/plot/PlotSquared.java | 2066 ++++++ .../plotsquared/plot/PlotVersion.java | 45 + .../plotsquared/plot/commands/Add.java | 82 + .../plotsquared/plot/commands/Alias.java | 123 + .../plotsquared/plot/commands/Area.java | 469 ++ .../plotsquared/plot/commands/Auto.java | 256 + .../plotsquared/plot/commands/Biome.java | 38 + .../plotsquared/plot/commands/Buy.java | 72 + .../plotsquared/plot/commands/Chat.java | 14 + .../plotsquared/plot/commands/Claim.java | 99 + .../plotsquared/plot/commands/Clear.java | 68 + .../plotsquared/plot/commands/Cluster.java | 612 ++ .../plot/commands/CommandCategory.java | 56 + .../plotsquared/plot/commands/Comment.java | 74 + .../plotsquared/plot/commands/Condense.java | 209 + .../plotsquared/plot/commands/Confirm.java | 31 + .../plotsquared/plot/commands/Continue.java | 45 + .../plotsquared/plot/commands/Copy.java | 54 + .../plot/commands/CreateRoadSchematic.java | 32 + .../plotsquared/plot/commands/Database.java | 184 + .../plotsquared/plot/commands/Debug.java | 46 + .../plot/commands/DebugAllowUnsafe.java | 30 + .../plot/commands/DebugClaimTest.java | 113 + .../plotsquared/plot/commands/DebugExec.java | 429 ++ .../plot/commands/DebugFixFlags.java | 52 + .../plot/commands/DebugImportWorlds.java | 58 + .../plot/commands/DebugLoadTest.java | 17 + .../plotsquared/plot/commands/DebugPaste.java | 146 + .../plot/commands/DebugRoadRegen.java | 41 + .../plot/commands/DebugSaveTest.java | 29 + .../plotsquared/plot/commands/Delete.java | 71 + .../plotsquared/plot/commands/Deny.java | 114 + .../plotsquared/plot/commands/Desc.java | 30 + .../plotsquared/plot/commands/Done.java | 68 + .../plotsquared/plot/commands/Download.java | 95 + .../plotsquared/plot/commands/FlagCmd.java | 299 + .../plot/commands/GenerateDocs.java | 221 + .../plotsquared/plot/commands/Grant.java | 71 + .../plotsquared/plot/commands/Help.java | 91 + .../plotsquared/plot/commands/Inbox.java | 198 + .../plotsquared/plot/commands/Info.java | 155 + .../plotsquared/plot/commands/Kick.java | 92 + .../plotsquared/plot/commands/Leave.java | 48 + .../plotsquared/plot/commands/ListCmd.java | 397 ++ .../plotsquared/plot/commands/Load.java | 179 + .../plot/commands/MainCommand.java | 286 + .../plotsquared/plot/commands/Merge.java | 198 + .../plotsquared/plot/commands/Middle.java | 29 + .../plotsquared/plot/commands/Move.java | 65 + .../plotsquared/plot/commands/Music.java | 69 + .../plotsquared/plot/commands/Near.java | 24 + .../plotsquared/plot/commands/Owner.java | 96 + .../plotsquared/plot/commands/PluginCmd.java | 38 + .../plotsquared/plot/commands/Purge.java | 167 + .../plotsquared/plot/commands/Rate.java | 217 + .../plot/commands/RegenAllRoads.java | 60 + .../plotsquared/plot/commands/Relight.java | 39 + .../plotsquared/plot/commands/Reload.java | 84 + .../plotsquared/plot/commands/Remove.java | 108 + .../plot/commands/RequiredType.java | 16 + .../plotsquared/plot/commands/Save.java | 76 + .../plot/commands/SchematicCmd.java | 222 + .../plotsquared/plot/commands/Set.java | 167 + .../plotsquared/plot/commands/SetCommand.java | 43 + .../plotsquared/plot/commands/SetHome.java | 40 + .../plotsquared/plot/commands/Setup.java | 434 ++ .../plotsquared/plot/commands/SubCommand.java | 39 + .../plotsquared/plot/commands/Swap.java | 54 + .../plotsquared/plot/commands/Target.java | 49 + .../plotsquared/plot/commands/Template.java | 201 + .../plotsquared/plot/commands/Toggle.java | 90 + .../plotsquared/plot/commands/Trim.java | 214 + .../plotsquared/plot/commands/Trust.java | 82 + .../plotsquared/plot/commands/Unlink.java | 58 + .../plotsquared/plot/commands/Visit.java | 142 + .../plot/commands/WE_Anywhere.java | 16 + .../plotsquared/plot/config/C.java | 1070 +++ .../plotsquared/plot/config/Config.java | 440 ++ .../plot/config/Configuration.java | 174 + .../plot/config/ConfigurationNode.java | 89 + .../plotsquared/plot/config/Settings.java | 357 + .../plotsquared/plot/config/Storage.java | 38 + .../plotsquared/plot/database/AbstractDB.java | 341 + .../plotsquared/plot/database/DBFunc.java | 495 ++ .../plotsquared/plot/database/Database.java | 72 + .../plotsquared/plot/database/MySQL.java | 89 + .../plotsquared/plot/database/SQLManager.java | 3082 ++++++++ .../plotsquared/plot/database/SQLite.java | 86 + .../plotsquared/plot/database/StmtMod.java | 39 + .../plotsquared/plot/flag/BooleanFlag.java | 45 + .../plotsquared/plot/flag/DoubleFlag.java | 25 + .../plotsquared/plot/flag/EnumFlag.java | 31 + .../plotsquared/plot/flag/Flag.java | 60 + .../plotsquared/plot/flag/FlagManager.java | 299 + .../plotsquared/plot/flag/Flags.java | 207 + .../plotsquared/plot/flag/GameModeFlag.java | 40 + .../plotsquared/plot/flag/IntegerFlag.java | 41 + .../plot/flag/IntegerListFlag.java | 31 + .../plotsquared/plot/flag/IntervalFlag.java | 41 + .../plotsquared/plot/flag/ListFlag.java | 17 + .../plotsquared/plot/flag/LongFlag.java | 24 + .../plot/flag/PlotBlockListFlag.java | 33 + .../plot/flag/PlotWeatherFlag.java | 35 + .../plotsquared/plot/flag/StringFlag.java | 21 + .../plotsquared/plot/flag/StringListFlag.java | 26 + .../plot/flag/TeleportDenyFlag.java | 39 + .../plot/generator/AugmentedUtils.java | 141 + .../plot/generator/ClassicPlotManager.java | 467 ++ .../plot/generator/ClassicPlotWorld.java | 117 + .../plot/generator/GeneratorWrapper.java | 18 + .../plot/generator/GridPlotManager.java | 10 + .../plot/generator/GridPlotWorld.java | 14 + .../plotsquared/plot/generator/HybridGen.java | 266 + .../plot/generator/HybridPlotManager.java | 225 + .../plot/generator/HybridPlotWorld.java | 283 + .../plot/generator/HybridUtils.java | 381 + .../generator/IndependentPlotGenerator.java | 90 + .../plot/generator/PlotGenerator.java | 37 + .../plot/generator/SquarePlotManager.java | 220 + .../plot/generator/SquarePlotWorld.java | 29 + .../plot/listener/ExtentWrapper.java | 12 + .../plot/listener/PlayerBlockEventType.java | 32 + .../plot/listener/PlotListener.java | 260 + .../plot/listener/ProcessedWEExtent.java | 178 + .../plotsquared/plot/listener/WEExtent.java | 63 + .../plotsquared/plot/listener/WEManager.java | 101 + .../plot/listener/WESubscriber.java | 76 + .../plot/logger/DelegateLogger.java | 18 + .../plotsquared/plot/logger/ILogger.java | 5 + .../plotsquared/plot/object/BlockBucket.java | 276 + .../plotsquared/plot/object/BlockLoc.java | 77 + .../plot/object/BlockRegistry.java | 34 + .../plotsquared/plot/object/ChunkLoc.java | 34 + .../plotsquared/plot/object/ChunkWrapper.java | 43 + .../plotsquared/plot/object/CmdInstance.java | 11 + .../plot/object/ConsolePlayer.java | 131 + .../plotsquared/plot/object/Expression.java | 55 + .../plotsquared/plot/object/FileBytes.java | 12 + .../plotsquared/plot/object/LazyBlock.java | 10 + .../plotsquared/plot/object/LazyResult.java | 19 + .../plot/object/LegacyPlotBlock.java | 60 + .../plotsquared/plot/object/Location.java | 205 + .../plot/object/OfflinePlotPlayer.java | 34 + .../plotsquared/plot/object/Plot.java | 2888 ++++++++ .../plotsquared/plot/object/PlotArea.java | 961 +++ .../plotsquared/plot/object/PlotBlock.java | 136 + .../plotsquared/plot/object/PlotCluster.java | 187 + .../plotsquared/plot/object/PlotFilter.java | 11 + .../plotsquared/plot/object/PlotHandler.java | 19 + .../plotsquared/plot/object/PlotId.java | 180 + .../plot/object/PlotInventory.java | 108 + .../plot/object/PlotItemStack.java | 44 + .../plotsquared/plot/object/PlotLoc.java | 75 + .../plotsquared/plot/object/PlotManager.java | 82 + .../plotsquared/plot/object/PlotMessage.java | 70 + .../plotsquared/plot/object/PlotPlayer.java | 648 ++ .../plotsquared/plot/object/PlotSettings.java | 185 + .../plotsquared/plot/object/PseudoRandom.java | 29 + .../plotsquared/plot/object/Rating.java | 81 + .../plot/object/RegionWrapper.java | 71 + .../plotsquared/plot/object/RunnableVal.java | 18 + .../plotsquared/plot/object/RunnableVal2.java | 20 + .../plotsquared/plot/object/RunnableVal3.java | 22 + .../plotsquared/plot/object/SetupObject.java | 67 + .../plot/object/StringPlotBlock.java | 95 + .../plot/object/StringWrapper.java | 72 + .../plot/object/chat/PlainChatManager.java | 43 + .../plot/object/comment/CommentInbox.java | 64 + .../plot/object/comment/InboxOwner.java | 51 + .../plot/object/comment/InboxPublic.java | 47 + .../plot/object/comment/InboxReport.java | 34 + .../plot/object/comment/PlotComment.java | 22 + .../plot/object/schematic/ItemType.java | 307 + .../plot/object/schematic/PlotItem.java | 22 + .../plot/object/schematic/Schematic.java | 47 + .../plot/object/schematic/StoredEntity.java | 54 + .../stream/AbstractDelegateOutputStream.java | 30 + .../object/worlds/DefaultPlotAreaManager.java | 231 + .../plot/object/worlds/PlotAreaManager.java | 28 + .../plot/object/worlds/SinglePlot.java | 71 + .../plot/object/worlds/SinglePlotArea.java | 139 + .../object/worlds/SinglePlotAreaManager.java | 131 + .../plot/object/worlds/SinglePlotManager.java | 104 + .../object/worlds/SingleWorldGenerator.java | 91 + .../plotsquared/plot/util/AbstractTitle.java | 20 + .../plotsquared/plot/util/ArrayUtil.java | 19 + .../plot/util/ByteArrayUtilities.java | 26 + .../plotsquared/plot/util/ChatManager.java | 22 + .../plotsquared/plot/util/ChunkManager.java | 296 + .../plotsquared/plot/util/CmdConfirm.java | 27 + .../plotsquared/plot/util/CommentManager.java | 65 + .../plotsquared/plot/util/ConsoleColors.java | 87 + .../plotsquared/plot/util/EconHandler.java | 41 + .../plotsquared/plot/util/EntityUtil.java | 76 + .../plotsquared/plot/util/EventUtil.java | 428 ++ .../plot/util/HastebinUtility.java | 65 + .../plotsquared/plot/util/HttpUtil.java | 29 + .../plotsquared/plot/util/IncendoPaster.java | 191 + .../plotsquared/plot/util/InventoryUtil.java | 27 + .../plot/util/LegacyConverter.java | 134 + .../plotsquared/plot/util/LegacyMappings.java | 15 + .../plotsquared/plot/util/MainUtil.java | 867 +++ .../plotsquared/plot/util/MathMan.java | 323 + .../plotsquared/plot/util/Permissions.java | 126 + .../plotsquared/plot/util/PlotGameMode.java | 32 + .../plotsquared/plot/util/PlotWeather.java | 5 + .../plot/util/ReflectionUtils.java | 677 ++ .../plotsquared/plot/util/RegExUtil.java | 15 + .../plot/util/SchematicHandler.java | 463 ++ .../plotsquared/plot/util/SetupUtils.java | 22 + .../plot/util/StringComparison.java | 157 + .../plotsquared/plot/util/StringMan.java | 290 + .../plotsquared/plot/util/TaskManager.java | 168 + .../plotsquared/plot/util/UUIDHandler.java | 169 + .../plot/util/UUIDHandlerImplementation.java | 286 + .../plotsquared/plot/util/WorldUtil.java | 150 + .../plotsquared/plot/util/area/QuadMap.java | 297 + .../plot/util/block/BasicLocalBlockQueue.java | 278 + .../util/block/DelegateLocalBlockQueue.java | 110 + .../plot/util/block/GlobalBlockQueue.java | 303 + .../plot/util/block/LocalBlockQueue.java | 108 + .../util/block/OffsetLocalBlockQueue.java | 24 + .../plot/util/block/QueueProvider.java | 30 + .../util/block/ScopedLocalBlockQueue.java | 98 + .../plot/util/expiry/ExpireManager.java | 449 ++ .../plot/util/expiry/ExpirySettings.java | 4 + .../plot/util/expiry/ExpiryTask.java | 127 + .../plot/util/expiry/PlotAnalysis.java | 552 ++ .../plot/util/helpmenu/HelpMenu.java | 58 + .../plot/util/helpmenu/HelpObject.java | 36 + .../plot/util/helpmenu/HelpPage.java | 37 + .../plotsquared/plot/uuid/UUIDWrapper.java | 21 + Bukkit/src/main/resources/LICENSE | 553 ++ Bukkit/src/main/resources/addplots.js | 18 + Bukkit/src/main/resources/addsigns.js | 12 + Bukkit/src/main/resources/automerge.js | 48 + Bukkit/src/main/resources/bridge.template | Bin 0 -> 5325 bytes Bukkit/src/main/resources/de-DE.yml | 414 ++ Bukkit/src/main/resources/es-ES.yml | 394 ++ Bukkit/src/main/resources/fr-FR.yml | 393 ++ Bukkit/src/main/resources/furthest.js | 33 + Bukkit/src/main/resources/it-IT.yml | 393 ++ Bukkit/src/main/resources/ko-KR.yml | 402 ++ Bukkit/src/main/resources/mycommand.js | 2 + Bukkit/src/main/resources/plugin.properties | 3 + Bukkit/src/main/resources/setbiomes.js | 12 + Bukkit/src/main/resources/skyblock.template | Bin 0 -> 1127 bytes Bukkit/src/main/resources/start.js | 7 + Bukkit/src/main/resources/town.template | Bin 0 -> 1771 bytes Bukkit/src/main/resources/zh-CN.yml | 407 ++ .../plotsquared/plot/FlagTest.java | 51 + .../plot/database/AbstractDBTest.java | 183 + .../plotsquared/plot/util/EventUtilTest.java | 75 + .../configuration/Configuration.java | 2 +- .../configuration/ConfigurationSection.java | 2 +- .../configuration/MemoryConfiguration.java | 2 +- .../configuration/MemorySection.java | 1444 ++-- .../configuration/file/FileConfiguration.java | 2 +- .../plotsquared/plot/IPlotMain.java | 2 +- .../plotsquared/plot/PlotSquared.java | 3870 +++++----- .../plotsquared/plot/commands/Auto.java | 3 +- .../plotsquared/plot/commands/Cluster.java | 3 +- .../plotsquared/plot/commands/Database.java | 307 +- .../plotsquared/plot/commands/DebugExec.java | 8 +- .../plotsquared/plot/commands/DebugPaste.java | 74 +- .../plotsquared/plot/commands/FlagCmd.java | 17 +- .../plotsquared/plot/commands/Merge.java | 4 +- .../plotsquared/plot/commands/Music.java | 7 +- .../plotsquared/plot/commands/Rate.java | 4 +- .../plotsquared/plot/commands/Unlink.java | 6 +- .../plot/config/Configuration.java | 7 +- .../plotsquared/plot/config/Settings.java | 12 +- .../plotsquared/plot/database/DBFunc.java | 3 +- .../plotsquared/plot/database/SQLManager.java | 6260 ++++++++--------- .../plotsquared/plot/flag/FlagManager.java | 8 +- .../plot/generator/ClassicPlotWorld.java | 8 +- .../plotsquared/plot/generator/HybridGen.java | 3 +- .../plot/generator/HybridPlotWorld.java | 28 +- .../plot/listener/PlotListener.java | 17 +- .../plotsquared/plot/listener/WEExtent.java | 8 +- .../plotsquared/plot/listener/WEManager.java | 3 - .../plotsquared/plot/logger/ILogger.java | 3 +- .../plotsquared/plot/object/Expression.java | 3 +- .../plotsquared/plot/object/Plot.java | 5542 ++++++++------- .../plotsquared/plot/object/PlotCluster.java | 19 +- .../plot/object/PlotInventory.java | 37 +- .../plotsquared/plot/object/PlotLoc.java | 6 +- .../plotsquared/plot/object/PlotPlayer.java | 1209 ++-- .../stream/AbstractDelegateOutputStream.java | 38 +- .../object/worlds/DefaultPlotAreaManager.java | 6 +- .../plot/object/worlds/SinglePlot.java | 5 +- .../plotsquared/plot/util/ChunkManager.java | 4 +- .../plotsquared/plot/util/CommentManager.java | 3 +- .../plotsquared/plot/util/IncendoPaster.java | 33 +- .../plotsquared/plot/util/MainUtil.java | 3 +- .../plotsquared/plot/util/StringMan.java | 4 +- .../plot/util/block/GlobalBlockQueue.java | 551 +- .../plot/util/expiry/ExpireManager.java | 798 ++- .../plot/util/expiry/ExpiryTask.java | 1 + .../plot/util/expiry/PlotAnalysis.java | 2 - Core/src/main/resources/addplots.js | 2 +- .../plot/database/AbstractDBTest.java | 2 +- .../plotsquared/plot/util/EventUtilTest.java | 2 +- 335 files changed, 58791 insertions(+), 10363 deletions(-) create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/api/PlotAPI.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/Argument.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/Command.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/CommandCaller.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/CommandDeclaration.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/Configuration.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationOptions.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationSection.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/InvalidConfigurationException.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemoryConfiguration.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemoryConfigurationOptions.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemorySection.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/FileConfiguration.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/FileConfigurationOptions.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfiguration.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfigurationOptions.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConstructor.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlRepresenter.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/ConfigurationSerializable.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/ConfigurationSerialization.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/DelegateDeserialization.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/SerializableAs.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONArray.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONException.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONObject.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONString.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONTokener.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/Property.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/XML.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/XMLTokener.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/IPlotMain.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/Platform.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotVersion.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Add.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Alias.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Area.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Auto.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Biome.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Buy.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Chat.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Claim.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Clear.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Cluster.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/CommandCategory.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Comment.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Condense.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Confirm.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Continue.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Copy.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/CreateRoadSchematic.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Database.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Debug.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugAllowUnsafe.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugClaimTest.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugExec.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugFixFlags.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugImportWorlds.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugLoadTest.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugPaste.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugRoadRegen.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugSaveTest.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Delete.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Deny.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Desc.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Done.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Download.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/GenerateDocs.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Grant.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Help.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Inbox.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Info.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Kick.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Leave.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/ListCmd.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Load.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/MainCommand.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Merge.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Middle.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Move.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Music.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Near.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Owner.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/PluginCmd.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Purge.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Rate.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/RegenAllRoads.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Relight.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Reload.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Remove.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/RequiredType.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Save.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SchematicCmd.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Set.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SetCommand.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SetHome.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Setup.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SubCommand.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Swap.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Target.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Template.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Toggle.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Trim.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Trust.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Unlink.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Visit.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/WE_Anywhere.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/config/C.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/config/Config.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/config/Configuration.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/config/ConfigurationNode.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/config/Settings.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/config/Storage.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/database/AbstractDB.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/database/DBFunc.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/database/Database.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/database/MySQL.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/database/SQLManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/database/SQLite.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/database/StmtMod.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/BooleanFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/DoubleFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/EnumFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/Flag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/FlagManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/Flags.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/GameModeFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/IntegerFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/IntegerListFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/IntervalFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/ListFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/LongFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/PlotBlockListFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/PlotWeatherFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/StringFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/StringListFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/flag/TeleportDenyFlag.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/AugmentedUtils.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/ClassicPlotManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/ClassicPlotWorld.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/GeneratorWrapper.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/GridPlotManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/GridPlotWorld.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridGen.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridPlotWorld.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/HybridUtils.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/IndependentPlotGenerator.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/PlotGenerator.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/SquarePlotManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/generator/SquarePlotWorld.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/listener/ExtentWrapper.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/listener/PlayerBlockEventType.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/listener/PlotListener.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/listener/ProcessedWEExtent.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/listener/WEExtent.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/listener/WEManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/listener/WESubscriber.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/logger/DelegateLogger.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/logger/ILogger.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/BlockBucket.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/BlockLoc.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/BlockRegistry.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/ChunkLoc.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/ChunkWrapper.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/CmdInstance.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/ConsolePlayer.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Expression.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/FileBytes.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/LazyBlock.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/LazyResult.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/LegacyPlotBlock.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Location.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/OfflinePlotPlayer.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Plot.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotArea.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotBlock.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotCluster.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotFilter.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotHandler.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotId.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotInventory.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotItemStack.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotLoc.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotMessage.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotPlayer.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PlotSettings.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/PseudoRandom.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/Rating.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/RegionWrapper.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/RunnableVal.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/RunnableVal2.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/RunnableVal3.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/SetupObject.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/StringPlotBlock.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/StringWrapper.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/chat/PlainChatManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/comment/CommentInbox.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/comment/InboxOwner.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/comment/InboxPublic.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/comment/InboxReport.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/comment/PlotComment.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/schematic/ItemType.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/schematic/PlotItem.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/schematic/Schematic.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/schematic/StoredEntity.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/stream/AbstractDelegateOutputStream.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/DefaultPlotAreaManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/PlotAreaManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlot.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlotArea.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlotAreaManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SinglePlotManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/object/worlds/SingleWorldGenerator.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/AbstractTitle.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ArrayUtil.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ByteArrayUtilities.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ChatManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ChunkManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/CmdConfirm.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/CommentManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ConsoleColors.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/EconHandler.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/EntityUtil.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/EventUtil.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/HastebinUtility.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/HttpUtil.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/IncendoPaster.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/InventoryUtil.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/LegacyConverter.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/LegacyMappings.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/MainUtil.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/MathMan.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/Permissions.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/PlotGameMode.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/PlotWeather.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/ReflectionUtils.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/RegExUtil.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/SchematicHandler.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/SetupUtils.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/StringComparison.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/StringMan.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/TaskManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/UUIDHandler.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/UUIDHandlerImplementation.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/WorldUtil.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/area/QuadMap.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/block/BasicLocalBlockQueue.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/block/DelegateLocalBlockQueue.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/block/GlobalBlockQueue.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/block/LocalBlockQueue.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/block/OffsetLocalBlockQueue.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/block/QueueProvider.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/block/ScopedLocalBlockQueue.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/ExpireManager.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/ExpirySettings.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/ExpiryTask.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/expiry/PlotAnalysis.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/helpmenu/HelpMenu.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/helpmenu/HelpObject.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/util/helpmenu/HelpPage.java create mode 100644 Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/uuid/UUIDWrapper.java create mode 100644 Bukkit/src/main/resources/LICENSE create mode 100644 Bukkit/src/main/resources/addplots.js create mode 100644 Bukkit/src/main/resources/addsigns.js create mode 100644 Bukkit/src/main/resources/automerge.js create mode 100644 Bukkit/src/main/resources/bridge.template create mode 100644 Bukkit/src/main/resources/de-DE.yml create mode 100644 Bukkit/src/main/resources/es-ES.yml create mode 100644 Bukkit/src/main/resources/fr-FR.yml create mode 100644 Bukkit/src/main/resources/furthest.js create mode 100644 Bukkit/src/main/resources/it-IT.yml create mode 100644 Bukkit/src/main/resources/ko-KR.yml create mode 100644 Bukkit/src/main/resources/mycommand.js create mode 100644 Bukkit/src/main/resources/plugin.properties create mode 100644 Bukkit/src/main/resources/setbiomes.js create mode 100644 Bukkit/src/main/resources/skyblock.template create mode 100644 Bukkit/src/main/resources/start.js create mode 100644 Bukkit/src/main/resources/town.template create mode 100644 Bukkit/src/main/resources/zh-CN.yml create mode 100644 Bukkit/src/test/java/com/github/intellectualsites/plotsquared/plot/FlagTest.java create mode 100644 Bukkit/src/test/java/com/github/intellectualsites/plotsquared/plot/database/AbstractDBTest.java create mode 100644 Bukkit/src/test/java/com/github/intellectualsites/plotsquared/plot/util/EventUtilTest.java diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/api/PlotAPI.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/api/PlotAPI.java new file mode 100644 index 000000000..c966903be --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/api/PlotAPI.java @@ -0,0 +1,224 @@ +package com.github.intellectualsites.plotsquared.api; + +import com.github.intellectualsites.plotsquared.configuration.file.YamlConfiguration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.flag.Flag; +import com.github.intellectualsites.plotsquared.plot.flag.Flags; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.ChunkManager; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler; +import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; +import com.github.intellectualsites.plotsquared.plot.util.block.GlobalBlockQueue; +import com.github.intellectualsites.plotsquared.plot.uuid.UUIDWrapper; +import lombok.NoArgsConstructor; + +import java.util.Collections; +import java.util.Set; +import java.util.UUID; + +/** + * PlotSquared API. + * + *

Useful classes: + *

    + *
  • {@link PlotPlayer}
  • + *
  • {@link Plot}
  • + *
  • {@link com.github.intellectualsites.plotsquared.plot.object.Location}
  • + *
  • {@link PlotArea}
  • + *
  • {@link PlotSquared}
  • + *
+ * + * @version 3.3.3 + */ +@SuppressWarnings({"unused", "WeakerAccess"}) @NoArgsConstructor public class PlotAPI { + + /** + * Get all plots. + * + * @return all plots + * @see PlotSquared#getPlots() + */ + public Set getAllPlots() { + return PlotSquared.get().getPlots(); + } + + /** + * Return all plots for a player. + * + * @param player Player, whose plots to search for + * @return all plots that a player owns + */ + public Set getPlayerPlots(PlotPlayer player) { + return PlotSquared.get().getPlots(player); + } + + /** + * Add a plot world. + * + * @param plotArea Plot World Object + * @see PlotSquared#addPlotArea(PlotArea) + */ + public void addPlotArea(PlotArea plotArea) { + PlotSquared.get().addPlotArea(plotArea); + } + + /** + * Returns the PlotSquared configurations file. + * + * @return main configuration + * @see PlotSquared#config + */ + public YamlConfiguration getConfig() { + return PlotSquared.get().config; + } + + /** + * Get the PlotSquared storage file. + * + * @return storage configuration + * @see PlotSquared#storage + */ + public YamlConfiguration getStorage() { + return PlotSquared.get().storage; + } + + /** + * Get the main class for this plugin. Only use this if you really need it. + * + * @return PlotSquared PlotSquared Main Class + * @see PlotSquared + */ + public PlotSquared getMain() { + return PlotSquared.get(); + } + + /** + * ChunkManager class contains several useful methods. + *
    + *
  • Chunk deletion
  • + *
  • Moving or copying regions
  • + *
  • Plot swapping
  • + *
  • Entity Tracking
  • + *
  • Region Regeneration
  • + *
+ * + * @return ChunkManager + * @see ChunkManager + */ + public ChunkManager getChunkManager() { + return ChunkManager.manager; + } + + /** + * Get the block/biome set queue + * + * @return GlobalBlockQueue.IMP + */ + public GlobalBlockQueue getBlockQueue() { + return GlobalBlockQueue.IMP; + } + + /** + * UUIDWrapper class has basic methods for getting UUIDS. It's recommended + * to use the UUIDHandler class instead. + * + * @return UUIDWrapper + * @see UUIDWrapper + */ + public UUIDWrapper getUUIDWrapper() { + return UUIDHandler.getUUIDWrapper(); + } + + /** + * SchematicHandler class contains methods related to pasting, reading + * and writing schematics. + * + * @return SchematicHandler + * @see SchematicHandler + */ + public SchematicHandler getSchematicHandler() { + return SchematicHandler.manager; + } + + /** + * Get a list of PlotAreas in the world. + * + * @param world The world to check for plot areas + * @return A set of PlotAreas + */ + public Set getPlotAreas(String world) { + if (world == null) { + return Collections.emptySet(); + } + return PlotSquared.get().getPlotAreas(world); + } + + /** + * Send a message to the console. The message supports color codes. + * + * @param message the message + * @see MainUtil#sendConsoleMessage(C, String...) + */ + public void sendConsoleMessage(String message) { + PlotSquared.log(message); + } + + /** + * Send a message to the console. + * + * @param caption the message + * @see #sendConsoleMessage(String) + * @see C + */ + public void sendConsoleMessage(C caption) { + sendConsoleMessage(caption.s()); + } + + /** + * Registers a flag for use in plots. + * + * @param flag the flag to register + */ + public void addFlag(Flag flag) { + Flags.registerFlag(flag); + } + + /** + * Gets the PlotSquared class. + * + * @return PlotSquared Class + * @see PlotSquared + */ + public PlotSquared getPlotSquared() { + return PlotSquared.get(); + } + + /** + * Get the PlotPlayer for a UUID. + * + *

Please note that PlotSquared can be configured to provide + * different UUIDs than bukkit + * + * @param uuid the uuid of the player to wrap + * @return a {@code PlotPlayer} + * @see PlotPlayer#wrap(Object) + */ + public PlotPlayer wrapPlayer(UUID uuid) { + return PlotPlayer.wrap(uuid); + } + + /** + * Get the PlotPlayer for a username. + * + * @param player the player to wrap + * @return a {@code PlotPlayer} + * @see PlotPlayer#wrap(Object) + */ + public PlotPlayer wrapPlayer(String player) { + return PlotPlayer.wrap(player); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/Argument.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/Argument.java new file mode 100644 index 000000000..dd5221a3a --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/Argument.java @@ -0,0 +1,68 @@ +package com.github.intellectualsites.plotsquared.commands; + +import com.github.intellectualsites.plotsquared.plot.object.PlotId; + +public abstract class Argument { + + public static final Argument Integer = new Argument("int", 16) { + @Override public Integer parse(String in) { + Integer value = null; + try { + value = java.lang.Integer.parseInt(in); + } catch (Exception ignored) { + } + return value; + } + }; + public static final Argument Boolean = new Argument("boolean", true) { + @Override public Boolean parse(String in) { + Boolean value = null; + if (in.equalsIgnoreCase("true") || in.equalsIgnoreCase("Yes") || in + .equalsIgnoreCase("1")) { + value = true; + } else if (in.equalsIgnoreCase("false") || in.equalsIgnoreCase("No") || in + .equalsIgnoreCase("0")) { + value = false; + } + return value; + } + }; + public static final Argument String = new Argument("String", "Example") { + @Override public String parse(String in) { + return in; + } + }; + public static final Argument PlayerName = + new Argument("PlayerName", "Dinnerbone") { + @Override public String parse(String in) { + return in.length() <= 16 ? in : null; + } + }; + public static final Argument PlotID = + new Argument("PlotID", new PlotId(-6, 3)) { + @Override public PlotId parse(String in) { + return PlotId.fromString(in); + } + }; + private final String name; + private final T example; + + public Argument(String name, T example) { + this.name = name; + this.example = example; + } + + public abstract T parse(String in); + + @Override public final String toString() { + return this.getName(); + } + + public final String getName() { + return this.name; + } + + public final T getExample() { + return this.example; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/Command.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/Command.java new file mode 100644 index 000000000..6bac09a26 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/Command.java @@ -0,0 +1,596 @@ +package com.github.intellectualsites.plotsquared.commands; + +import com.github.intellectualsites.plotsquared.configuration.file.YamlConfiguration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory; +import com.github.intellectualsites.plotsquared.plot.commands.MainCommand; +import com.github.intellectualsites.plotsquared.plot.commands.RequiredType; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.PlotMessage; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3; +import com.github.intellectualsites.plotsquared.plot.util.*; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + +public abstract class Command { + + // May be none + private final ArrayList allCommands = new ArrayList<>(); + private final ArrayList dynamicCommands = new ArrayList<>(); + private final HashMap staticCommands = new HashMap<>(); + + // Parent command (may be null) + private final Command parent; + private final boolean isStatic; + // The command ID + private String id; + private List aliases; + private RequiredType required; + private String usage; + private String description; + private String perm; + private boolean confirmation; + private CommandCategory category; + private Argument[] arguments; + + public Command(Command parent, boolean isStatic, String id, String perm, RequiredType required, + CommandCategory cat) { + this.parent = parent; + this.isStatic = isStatic; + this.id = id; + this.perm = perm; + this.required = required; + this.category = cat; + this.aliases = Arrays.asList(id); + if (this.parent != null) { + this.parent.register(this); + } + } + + public Command(Command parent, boolean isStatic) { + this.parent = parent; + this.isStatic = isStatic; + Annotation cdAnnotation = getClass().getAnnotation(CommandDeclaration.class); + if (cdAnnotation != null) { + CommandDeclaration declaration = (CommandDeclaration) cdAnnotation; + init(declaration); + } + for (final Method method : getClass().getDeclaredMethods()) { + if (method.isAnnotationPresent(CommandDeclaration.class)) { + Class[] types = method.getParameterTypes(); + // final PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 + // whenDone + if (types.length == 5 && types[0] == Command.class && types[1] == PlotPlayer.class + && types[2] == String[].class && types[3] == RunnableVal3.class + && types[4] == RunnableVal2.class) { + Command tmp = new Command(this, true) { + @Override public void execute(PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) { + try { + method.invoke(Command.this, this, player, args, confirm, whenDone); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + }; + tmp.init(method.getAnnotation(CommandDeclaration.class)); + } + } + } + } + + public Command getParent() { + return this.parent; + } + + public String getId() { + return this.id; + } + + public String getFullId() { + if (this.parent != null && this.parent.getParent() != null) { + return this.parent.getFullId() + "." + this.id; + } + return this.id; + } + + public List getCommands(PlotPlayer player) { + List commands = new ArrayList<>(); + for (Command cmd : this.allCommands) { + if (cmd.canExecute(player, false)) { + commands.add(cmd); + } + } + return commands; + } + + public List getCommands(CommandCategory cat, PlotPlayer player) { + List commands = getCommands(player); + if (cat != null) { + Iterator iterator = commands.iterator(); + while (iterator.hasNext()) { + if (iterator.next().category != cat) { + iterator.remove(); + } + } + } + return commands; + } + + public List getCommands() { + return this.allCommands; + } + + public boolean hasConfirmation(PlotPlayer player) { + return this.confirmation && !player.hasPermission(getPermission() + ".confirm.bypass"); + } + + public List getAliases() { + return this.aliases; + } + + public String getDescription() { + return this.description; + } + + public RequiredType getRequiredType() { + return this.required; + } + + public Argument[] getRequiredArguments() { + return this.arguments; + } + + public void setRequiredArguments(Argument[] arguments) { + this.arguments = arguments; + } + + public void init(CommandDeclaration declaration) { + this.id = declaration.command(); + this.perm = declaration.permission(); + this.required = declaration.requiredType(); + this.category = declaration.category(); + HashMap options = new HashMap<>(); + List aliasOptions = new ArrayList<>(); + aliasOptions.add(this.id); + aliasOptions.addAll(Arrays.asList(declaration.aliases())); + options.put("aliases", aliasOptions); + options.put("description", declaration.description()); + options.put("usage", declaration.usage()); + options.put("confirmation", declaration.confirmation()); + boolean set = false; + YamlConfiguration commands = + PlotSquared.get() == null ? new YamlConfiguration() : PlotSquared.get().commands; + for (Map.Entry entry : options.entrySet()) { + String key = this.getFullId() + "." + entry.getKey(); + if (!commands.contains(key)) { + commands.set(key, entry.getValue()); + set = true; + } + } + if (set && PlotSquared.get() != null) { + try { + commands.save(PlotSquared.get().commandsFile); + } catch (IOException e) { + e.printStackTrace(); + + } + } + this.aliases = commands.getStringList(this.getFullId() + ".aliases"); + this.description = commands.getString(this.getFullId() + ".description"); + this.usage = commands.getString(this.getFullId() + ".usage"); + this.confirmation = commands.getBoolean(this.getFullId() + ".confirmation"); + if (this.parent != null) { + this.parent.register(this); + } + } + + public void register(Command command) { + if (command.isStatic) { + for (String alias : command.aliases) { + this.staticCommands.put(alias.toLowerCase(), command); + } + } else { + this.dynamicCommands.add(command); + } + this.allCommands.add(command); + } + + public String getPermission() { + if (this.perm != null && !this.perm.isEmpty()) { + return this.perm; + } + if (this.parent == null) { + return "plots.use"; + } + return "plots." + getFullId(); + } + + public void paginate(PlotPlayer player, List c, int size, int page, + RunnableVal3 add, String baseCommand, String header) { + // Calculate pages & index + if (page < 0) { + page = 0; + } + int totalPages = (int) Math.ceil(c.size() / size); + if (page > totalPages) { + page = totalPages; + } + int max = page * size + size; + if (max > c.size()) { + max = c.size(); + } + // Send the header + header = header.replaceAll("%cur", page + 1 + "").replaceAll("%max", totalPages + 1 + "") + .replaceAll("%amount%", c.size() + "").replaceAll("%word%", "all"); + MainUtil.sendMessage(player, header); + // Send the page content + List subList = c.subList(page * size, max); + int i = page * size; + for (T obj : subList) { + i++; + PlotMessage msg = new PlotMessage(); + add.run(i, obj, msg); + msg.send(player); + } + // Send the footer + if (page < totalPages && page > 0) { // Back | Next + new PlotMessage().text("<-").color("$1").command(baseCommand + " " + page).text(" | ") + .color("$3").text("->").color("$1").command(baseCommand + " " + (page + 2)) + .text(C.CLICKABLE.s()).color("$2").send(player); + return; + } + if (page == 0 && totalPages != 0) { // Next + new PlotMessage().text("<-").color("$3").text(" | ").color("$3").text("->").color("$1") + .command(baseCommand + " " + (0 + 2)).text(C.CLICKABLE.s()).color("$2") + .send(player); + return; + } + if (page == totalPages && totalPages != 0) { // Back + new PlotMessage().text("<-").color("$1").command(baseCommand + " " + page).text(" | ") + .color("$3").text("->").color("$3").text(C.CLICKABLE.s()).color("$2").send(player); + } + } + + /** + * @param player Caller + * @param args Arguments + * @param confirm Instance, Success, Failure + * @return + */ + public void execute(PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) throws CommandException { + if (args.length == 0 || args[0] == null) { + if (this.parent == null) { + MainCommand.getInstance().help.displayHelp(player, null, 0); + } else { + C.COMMAND_SYNTAX.send(player, getUsage()); + } + return; + } + if (this.allCommands == null || this.allCommands.isEmpty()) { + player.sendMessage( + "Not Implemented: https://github.com/IntellectualSites/PlotSquared/issues/new"); + return; + } + Command cmd = getCommand(args[0]); + if (cmd == null) { + if (this.parent != null) { + C.COMMAND_SYNTAX.send(player, getUsage()); + return; + } + // Help command + try { + if (args.length == 0 || MathMan.isInteger(args[0]) + || CommandCategory.valueOf(args[0].toUpperCase()) != null) { + // This will default certain syntax to the help command + // e.g. /plot, /plot 1, /plot claiming + MainCommand.getInstance().help.execute(player, args, null, null); + return; + } + } catch (IllegalArgumentException ignored) { + } + // Command recommendation + MainUtil.sendMessage(player, C.NOT_VALID_SUBCOMMAND); + List commands = getCommands(player); + if (commands.isEmpty()) { + MainUtil + .sendMessage(player, C.DID_YOU_MEAN, MainCommand.getInstance().help.getUsage()); + return; + } + HashSet setargs = new HashSet<>(args.length); + for (String arg : args) { + setargs.add(arg.toLowerCase()); + } + String[] allargs = setargs.toArray(new String[setargs.size()]); + int best = 0; + for (Command current : commands) { + int match = getMatch(allargs, current); + if (match > best) { + cmd = current; + } + } + if (cmd == null) { + cmd = new StringComparison<>(args[0], this.allCommands).getMatchObject(); + } + MainUtil.sendMessage(player, C.DID_YOU_MEAN, cmd.getUsage()); + return; + } + String[] newArgs = Arrays.copyOfRange(args, 1, args.length); + if (!cmd.checkArgs(player, newArgs) || !cmd.canExecute(player, true)) { + return; + } + try { + cmd.execute(player, newArgs, confirm, whenDone); + } catch (CommandException e) { + e.perform(player); + } + } + + public boolean checkArgs(PlotPlayer player, String[] args) { + Argument[] reqArgs = getRequiredArguments(); + if (reqArgs != null && reqArgs.length > 0) { + boolean failed = args.length < reqArgs.length; + String[] baseSplit = getCommandString().split(" "); + String[] fullSplit = getUsage().split(" "); + String base = getCommandString(); + if (fullSplit.length - baseSplit.length < reqArgs.length) { + String[] tmp = new String[baseSplit.length + reqArgs.length]; + System.arraycopy(fullSplit, 0, tmp, 0, fullSplit.length); + fullSplit = tmp; + } + for (int i = 0; i < reqArgs.length; i++) { + fullSplit[i + baseSplit.length] = reqArgs[i].getExample().toString(); + failed = failed || reqArgs[i].parse(args[i]) == null; + } + if (failed) { + C.COMMAND_SYNTAX.send(player, StringMan.join(fullSplit, " ")); + return false; + } + } + return true; + } + + public int getMatch(String[] args, Command cmd) { + int count = 0; + String perm = cmd.getPermission(); + HashSet desc = new HashSet<>(); + for (String alias : cmd.getAliases()) { + if (alias.startsWith(args[0])) { + count += 5; + } + } + Collections.addAll(desc, cmd.getDescription().split(" ")); + for (String arg : args) { + if (perm.startsWith(arg)) { + count++; + } + if (desc.contains(arg)) { + count++; + } + } + String[] usage = cmd.getUsage().split(" "); + for (int i = 0; i < Math.min(4, usage.length); i++) { + int require; + if (usage[i].startsWith("<")) { + require = 1; + } else { + require = 0; + } + String[] split = usage[i].split("\\|| |\\>|\\<|\\[|\\]|\\{|\\}|\\_|\\/"); + for (String aSplit : split) { + for (String arg : args) { + if (StringMan.isEqualIgnoreCase(arg, aSplit)) { + count += 5 - i + require; + } + } + } + } + count += StringMan.intersection(desc, args); + return count; + } + + public Command getCommand(String arg) { + Command cmd = this.staticCommands.get(arg.toLowerCase()); + if (cmd == null) { + for (Command command : this.dynamicCommands) { + if (command.matches(arg)) { + return command; + } + } + } + return cmd; + } + + public Command getCommand(Class clazz) { + for (Command cmd : this.allCommands) { + if (cmd.getClass() == clazz) { + return cmd; + } + } + return null; + } + + public Command getCommandById(String id) { + Command exact = this.staticCommands.get(id); + if (exact != null) { + return exact; + } + for (Command cmd : this.allCommands) { + if (cmd.getId().equals(id)) { + return cmd; + } + } + return null; + } + + public boolean canExecute(PlotPlayer player, boolean message) { + if (player == null) { + return true; + } + if (!this.required.allows(player)) { + if (message) { + MainUtil.sendMessage(player, + this.required == RequiredType.PLAYER ? C.IS_CONSOLE : C.NOT_CONSOLE); + } + } else if (!Permissions.hasPermission(player, getPermission())) { + if (message) { + C.NO_PERMISSION.send(player, getPermission()); + } + } else { + return true; + } + return false; + } + + public boolean matches(String arg) { + arg = arg.toLowerCase(); + return StringMan.isEqual(arg, this.id) || this.aliases.contains(arg); + } + + public String getCommandString() { + String base; + if (this.parent == null) { + return "/" + toString(); + } else { + return this.parent.getCommandString() + " " + toString(); + } + } + + public String getUsage() { + if (this.usage != null && !this.usage.isEmpty()) { + if (this.usage.startsWith("/")) { + return this.usage; + } + return getCommandString() + " " + this.usage; + } + if (this.allCommands.isEmpty()) { + return getCommandString(); + } + StringBuilder args = new StringBuilder("["); + String prefix = ""; + for (Command cmd : this.allCommands) { + args.append(prefix).append(cmd.isStatic ? cmd.toString() : "<" + cmd + ">"); + prefix = "|"; + } + return getCommandString() + " " + args + "]"; + } + + public Collection tabOf(PlotPlayer player, String[] input, boolean space, + String... args) { + if (!space) { + return null; + } + List result = new ArrayList<>(); + int index = input.length - (space ? 0 : 1); + for (String arg : args) { + arg = arg.replace(getCommandString() + " ", ""); + String[] split = arg.split(" "); + if (split.length <= index) { + continue; + } + arg = StringMan.join(Arrays.copyOfRange(split, index, split.length), " "); + Command cmd = new Command(null, false, arg, getPermission(), getRequiredType(), null) { + }; + result.add(cmd); + } + return result; + } + + public Collection tab(PlotPlayer player, String[] args, boolean space) { + switch (args.length) { + case 0: + return this.allCommands; + case 1: + String arg = args[0].toLowerCase(); + if (space) { + Command cmd = getCommand(arg); + if (cmd != null && cmd.canExecute(player, false)) { + return cmd.tab(player, Arrays.copyOfRange(args, 1, args.length), space); + } else { + return null; + } + } else { + Set commands = new HashSet(); + for (Map.Entry entry : this.staticCommands.entrySet()) { + if (entry.getKey().startsWith(arg) && entry.getValue() + .canExecute(player, false)) { + commands.add(entry.getValue()); + } + } + return commands; + } + default: + Command cmd = getCommand(args[0]); + if (cmd != null) { + return cmd.tab(player, Arrays.copyOfRange(args, 1, args.length), space); + } else { + return null; + } + } + } + + @Override public String toString() { + return !this.aliases.isEmpty() ? this.aliases.get(0) : this.id; + } + + @Override public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (getClass() != obj.getClass()) { + return false; + } + Command other = (Command) obj; + if (this.hashCode() != other.hashCode()) { + return false; + } + return this.getFullId().equals(other.getFullId()); + } + + @Override public int hashCode() { + return this.getFullId().hashCode(); + } + + public void checkTrue(boolean mustBeTrue, C message, Object... args) { + if (!mustBeTrue) { + throw new CommandException(message, args); + } + } + + public T check(T object, C message, Object... args) { + if (object == null) { + throw new CommandException(message, args); + } + return object; + } + + public enum CommandResult { + FAILURE, SUCCESS + } + + + public static class CommandException extends RuntimeException { + private final Object[] args; + private final C message; + + public CommandException(C message, Object... args) { + this.message = message; + this.args = args; + } + + public void perform(PlotPlayer player) { + if (player != null && message != null) { + message.send(player, args); + } + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/CommandCaller.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/CommandCaller.java new file mode 100644 index 000000000..3b5ee295e --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/CommandCaller.java @@ -0,0 +1,24 @@ +package com.github.intellectualsites.plotsquared.commands; + +import com.github.intellectualsites.plotsquared.plot.commands.RequiredType; + +public interface CommandCaller { + + /** + * Send the player a message. + * + * @param message the message to send + */ + void sendMessage(String message); + + /** + * Check the player's permissions. Will be cached if permission caching is enabled. + * + * @param permission the name of the permission + */ + boolean hasPermission(String permission); + + boolean isPermissionSet(String permission); + + RequiredType getSuperCaller(); +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/CommandDeclaration.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/CommandDeclaration.java new file mode 100644 index 000000000..851a03174 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/commands/CommandDeclaration.java @@ -0,0 +1,29 @@ +package com.github.intellectualsites.plotsquared.commands; + +import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory; +import com.github.intellectualsites.plotsquared.plot.commands.RequiredType; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) +public @interface CommandDeclaration { + + String command(); + + String[] aliases() default {}; + + String permission() default ""; + + String usage() default ""; + + String description() default ""; + + RequiredType requiredType() default RequiredType.NONE; + + CommandCategory category() default CommandCategory.INFO; + + boolean confirmation() default false; +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/Configuration.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/Configuration.java new file mode 100644 index 000000000..9d694c1ec --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/Configuration.java @@ -0,0 +1,87 @@ +package com.github.intellectualsites.plotsquared.configuration; + +import javax.annotation.Nonnull; +import java.util.Map; + +/** + * Represents a source of configurable options and settings. + */ +public interface Configuration extends ConfigurationSection { + /** + * Sets the default value of the given path as provided. + *

+ *

If no source {@link Configuration} was provided as a default + * collection, then a new {@link MemoryConfiguration} will be created to + * hold the new default value.

+ *

+ *

If value is null, the value will be removed from the default + * Configuration source.

+ * + * @param path Path of the value to set. + * @param value Value to set the default to. + * @throws IllegalArgumentException Thrown if path is null. + */ + @Override void addDefault(@Nonnull String path, Object value); + + /** + * Sets the default values of the given paths as provided. + *

+ *

If no source {@link Configuration} was provided as a default + * collection, then a new {@link MemoryConfiguration} will be created to + * hold the new default values.

+ * + * @param defaults A map of Path->Values to add to defaults. + * @throws IllegalArgumentException Thrown if defaults is null. + */ + void addDefaults(Map defaults); + + /** + * Sets the default values of the given paths as provided. + *

+ *

If no source {@link Configuration} was provided as a default + * collection, then a new {@link MemoryConfiguration} will be created to + * hold the new default value.

+ *

+ *

This method will not hold a reference to the specified Configuration, + * nor will it automatically update if that Configuration ever changes. If + * you check this, you should set the default source with {@link + * #setDefaults(Configuration)}.

+ * + * @param defaults A configuration holding a list of defaults to copy. + * @throws IllegalArgumentException Thrown if defaults is null or this. + */ + void addDefaults(Configuration defaults); + + /** + * Gets the source {@link Configuration} for this configuration. + *

+ *

+ * If no configuration source was set, but default values were added, then + * a {@link MemoryConfiguration} will be returned. If no source was set + * and no defaults were set, then this method will return null.

+ * + * @return Configuration source for default values, or null if none exist. + */ + Configuration getDefaults(); + + /** + * Sets the source of all default values for this {@link Configuration}. + *

+ *

+ * If a previous source was set, or previous default values were defined, + * then they will not be copied to the new source.

+ * + * @param defaults New source of default values for this configuration. + * @throws IllegalArgumentException Thrown if defaults is null or this. + */ + void setDefaults(Configuration defaults); + + /** + * Gets the {@link ConfigurationOptions} for this {@link Configuration}. + *

+ *

All setters through this method are chainable.

+ * + * @return Options for this configuration + */ + ConfigurationOptions options(); +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationOptions.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationOptions.java new file mode 100644 index 000000000..f86016031 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationOptions.java @@ -0,0 +1,90 @@ +package com.github.intellectualsites.plotsquared.configuration; + +/** + * Various settings for controlling the input and output of a {@link + * Configuration}. + */ +class ConfigurationOptions { + private final Configuration configuration; + private char pathSeparator = '.'; + private boolean copyDefaults = false; + + protected ConfigurationOptions(Configuration configuration) { + this.configuration = configuration; + } + + /** + * Returns the {@link Configuration} that this object is responsible for. + * + * @return Parent configuration + */ + public Configuration configuration() { + return configuration; + } + + /** + * Gets the char that will be used to separate {@link + * ConfigurationSection}s. + * + *

This value does not affect how the {@link Configuration} is stored, + * only in how you access the data. The default value is '.'. + * + * @return Path separator + */ + char pathSeparator() { + return pathSeparator; + } + + /** + * Sets the char that will be used to separate {@link + * ConfigurationSection}s. + * + *

This value does not affect how the {@link Configuration} is stored, + * only in how you access the data. The default value is '.'. + * + * @param value Path separator + * @return This object, for chaining + */ + public ConfigurationOptions pathSeparator(char value) { + pathSeparator = value; + return this; + } + + /** + * Checks if the {@link Configuration} should copy values from its default + * {@link Configuration} directly. + * + *

If this is true, all values in the default Configuration will be + * directly copied, making it impossible to distinguish between values + * that were set and values that are provided by default. As a result, + * {@link ConfigurationSection#contains(String)} will always + * return the same value as {@link + * ConfigurationSection#isSet(String)}. The default value is + * false. + * + * @return Whether or not defaults are directly copied + */ + boolean copyDefaults() { + return copyDefaults; + } + + /** + * Sets if the {@link Configuration} should copy values from its default + * {@link Configuration} directly. + * + *

If this is true, all values in the default Configuration will be + * directly copied, making it impossible to distinguish between values + * that were set and values that are provided by default. As a result, + * {@link ConfigurationSection#contains(String)} will always + * return the same value as {@link + * ConfigurationSection#isSet(String)}. The default value is + * false. + * + * @param value Whether or not defaults are directly copied + * @return This object, for chaining + */ + public ConfigurationOptions copyDefaults(boolean value) { + copyDefaults = value; + return this; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationSection.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationSection.java new file mode 100644 index 000000000..9e15a9030 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/ConfigurationSection.java @@ -0,0 +1,649 @@ +package com.github.intellectualsites.plotsquared.configuration; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Represents a section of a {@link Configuration}. + */ +public interface ConfigurationSection { + + /** + * Gets a set containing all keys in this section. + * + *

If deep is set to true, then this will contain all the keys within any + * child {@link ConfigurationSection}s (and their children, etc). These + * will be in a valid path notation for you to use. + * + *

If deep is set to false, then this will contain only the keys of any + * direct children, and not their own children. + * + * @param deep Whether or not to get a deep list, as opposed to a shallow + * list. + * @return Set of keys contained within this ConfigurationSection. + */ + Set getKeys(boolean deep); + + /** + * Gets a Map containing all keys and their values for this section. + * + *

If deep is set to true, then this will contain all the keys and values + * within any child {@link ConfigurationSection}s (and their children, + * etc). These keys will be in a valid path notation for you to use. + * + *

If deep is set to false, then this will contain only the keys and + * values of any direct children, and not their own children. + * + * @param deep Whether or not to get a deep list, as opposed to a shallow + * list. + * @return Map of keys and values of this section. + */ + Map getValues(boolean deep); + + /** + * Checks if this {@link ConfigurationSection} contains the given path. + * + *

If the value for the requested path does not exist but a default value + * has been specified, this will return true. + * + * @param path Path to check for existence. + * @return True if this section contains the requested path, either via + * default or being set. + * @throws IllegalArgumentException Thrown when path is {@code null}. + */ + boolean contains(@Nonnull String path); + + /** + * Checks if this {@link ConfigurationSection} has a value set for the + * given path. + * + *

If the value for the requested path does not exist but a default value + * has been specified, this will still return false. + * + * @param path Path to check for existence. + * @return True if this section contains the requested path, regardless of + * having a default. + * @throws IllegalArgumentException Thrown when path is {@code null}. + */ + boolean isSet(@Nonnull String path); + + /** + * Gets the path of this {@link ConfigurationSection} from its root {@link + * Configuration}. + * + *

For any {@link Configuration} themselves, this will return an empty + * string. + * + *

If the section is no longer contained within its root for any reason, + * such as being replaced with a different value, + * this may return {@code null}. + * + *

To retrieve the single name of this section, that is, the final part + * of the path returned by this method, you may use {@link #getName()}. + * + * @return Path of this section relative to its root + */ + String getCurrentPath(); + + /** + * Gets the name of this individual {@link ConfigurationSection}, in the + * path. + * + *

This will always be the final part of {@link #getCurrentPath()}, unless + * the section is orphaned. + * + * @return Name of this section + */ + String getName(); + + /** + * Gets the root {@link Configuration} that contains this {@link + * ConfigurationSection} + * + *

For any {@link Configuration} themselves, this will return its own + * object. + * + *

If the section is no longer contained within its root for any reason, + * such as being replaced with a different value, + * this may return {@code null}. + * + * @return Root configuration containing this section. + */ + Configuration getRoot(); + + /** + * Gets the parent {@link ConfigurationSection} that directly contains + * this {@link ConfigurationSection}. + * + *

For any {@link Configuration} themselves, this will return + * {@code null}. + * + *

If the section is no longer contained within its parent for any + * reason, such as being replaced with a different value, this may + * return {@code null}. + * + * @return Parent section containing this section. + */ + ConfigurationSection getParent(); + + /** + * Gets the requested Object by path. + * + *

If the Object does not exist but a default value has been specified, + * this will return the default value. If the Object does not exist and no + * default value was specified, this will return {@code null}. + * + * @param path Path of the Object to get. + * @return Requested Object. + */ + Object get(String path); + + /** + * Gets the requested Object by path, returning a default value if not + * found. + * + *

If the Object does not exist then the specified default value will + * returned regardless of if a default has been identified in the root + * {@link Configuration}. + * + * @param path Path of the Object to get. + * @param defaultValue The default value to return if the path is not found. + * @return Requested Object. + */ + Object getOrDefault(@Nonnull String path, Object defaultValue); + + /** + * Sets the specified path to the given value. + * + *

If value is {@code null}, the entry will be removed. Any + * existing entry will be replaced, regardless of what the new value is. + * + *

Some implementations may have limitations on what you may store. See + * their individual javadoc for details. No implementations should allow + * you to store {@link Configuration}s or {@link ConfigurationSection}s, + * please use {@link #createSection(String)} for that. + * + * @param path Path of the object to set. + * @param value New value to set the path to. + */ + void set(String path, Object value); + + /** + * Creates an empty {@link ConfigurationSection} at the specified path. + * + *

Any value that was previously set at this path will be overwritten. If + * the previous value was itself a {@link ConfigurationSection}, it will + * be orphaned. + * + * @param path Path to create the section at. + * @return Newly created section + */ + ConfigurationSection createSection(String path); + + /** + * Creates a {@link ConfigurationSection} at the specified path, with + * specified values. + * + *

Any value that was previously set at this path will be overwritten. If + * the previous value was itself a {@link ConfigurationSection}, it will + * be orphaned. + * + * @param path Path to create the section at. + * @param map The values to used. + * @return Newly created section + */ + ConfigurationSection createSection(String path, Map map); + + // Primitives + + /** + * Gets the requested String by path. + * + *

If the String does not exist but a default value has been specified, + * this will return the default value. If the String does not exist and no + * default value was specified, this will return {@code null}. + * + * @param path Path of the String to get. + * @return Requested String. + */ + String getString(String path); + + /** + * Gets the requested String by path, returning a default value if not + * found. + * + *

If the String does not exist then the specified default value will + * returned regardless of if a default has been identified in the root + * {@link Configuration}. + * + * @param path Path of the String to get. + * @param def The default value to return if the path is not found or is + * not a String. + * @return Requested String. + */ + String getString(String path, String def); + + /** + * Checks if the specified path is a String. + * + *

If the path exists but is not a String, this will return false. If + * the path does not exist, this will return false. If the path does not + * exist but a default value has been specified, this will check if that + * defaultvalue is a String and return appropriately. + * + * @param path Path of the String to check. + * @return Whether or not the specified path is a String. + */ + boolean isString(String path); + + /** + * Gets the requested int by path. + * + *

If the int does not exist but a default value has been specified, this + * will return the default value. If the int does not exist and no default + * value was specified, this will return 0. + * + * @param path Path of the int to get. + * @return Requested int. + */ + int getInt(String path); + + /** + * Gets the requested int by path, returning a default value if not found. + * + *

If the int does not exist then the specified default value will + * returned regardless of if a default has been identified in the root + * {@link Configuration}. + * + * @param path Path of the int to get. + * @param def The default value to return if the path is not found or is + * not an int. + * @return Requested int. + */ + int getInt(String path, int def); + + /** + * Checks if the specified path is an int. + * + *

If the path exists but is not a int, this will return false. If the + * path does not exist, this will return false. If the path does not exist + * but a default value has been specified, this will check if that default + * value is a int and return appropriately. + * + * @param path Path of the int to check. + * @return Whether or not the specified path is an int. + */ + boolean isInt(String path); + + /** + * Gets the requested boolean by path. + * + *

If the boolean does not exist but a default value has been specified, + * this will return the default value. If the boolean does not exist and + * no default value was specified, this will return false. + * + * @param path Path of the boolean to get. + * @return Requested boolean. + */ + boolean getBoolean(String path); + + /** + * Gets the requested boolean by path, returning a default value if not + * found. + * + *

If the boolean does not exist then the specified default value will + * returned regardless of if a default has been identified in the root + * {@link Configuration}. + * + * @param path Path of the boolean to get. + * @param defaultValue The default value to return if the path is not found or is + * not a boolean. + * @return Requested boolean. + */ + boolean getBoolean(String path, boolean defaultValue); + + /** + * Checks if the specified path is a boolean. + * + *

If the path exists but is not a boolean, this will return false. If the + * path does not exist, this will return false. If the path does not exist + * but a default value has been specified, this will check if that default + * value is a boolean and return appropriately. + * + * @param path Path of the boolean to check. + * @return Whether or not the specified path is a boolean. + */ + boolean isBoolean(String path); + + /** + * Gets the requested double by path. + * + *

If the double does not exist but a default value has been specified, + * this will return the default value. If the double does not exist and no + * default value was specified, this will return 0. + * + * @param path Path of the double to get. + * @return Requested double. + */ + double getDouble(String path); + + /** + * Gets the requested double by path, returning a default value if not + * found. + * + *

If the double does not exist then the specified default value will + * returned regardless of if a default has been identified in the root + * {@link Configuration}. + * + * @param path Path of the double to get. + * @param defaultValue The default value to return if the path is not found or is + * not a double. + * @return Requested double. + */ + double getDouble(String path, double defaultValue); + + /** + * Checks if the specified path is a double. + * + *

If the path exists but is not a double, this will return false. If the + * path does not exist, this will return false. If the path does not exist + * but a default value has been specified, this will check if that default + * value is a double and return appropriately. + * + * @param path Path of the double to check. + * @return Whether or not the specified path is a double. + */ + boolean isDouble(String path); + + /** + * Gets the requested long by path. + * + *

If the long does not exist but a default value has been specified, this + * will return the default value. If the long does not exist and no + * default value was specified, this will return 0. + * + * @param path Path of the long to get. + * @return Requested long. + */ + long getLong(String path); + + /** + * Gets the requested long by path, returning a default value if not + * found. + * + *

If the long does not exist then the specified default value will + * returned regardless of if a default has been identified in the root + * {@link Configuration}. + * + * @param path Path of the long to get. + * @param def The default value to return if the path is not found or is + * not a long. + * @return Requested long. + */ + long getLong(String path, long def); + + /** + * Checks if the specified path is a long. + * + *

If the path exists but is not a long, this will return false. If the + * path does not exist, this will return false. If the path does not exist + * but a default value has been specified, this will check if that default + * value is a long and return appropriately. + * + * @param path Path of the long to check. + * @return Whether or not the specified path is a long. + */ + boolean isLong(String path); + + // Java + + /** + * Gets the requested List by path. + * + *

If the List does not exist but a default value has been specified, this + * will return the default value. If the List does not exist and no + * default value was specified, this will return null. + * + * @param path Path of the List to get. + * @return Requested List. + */ + List getList(String path); + + /** + * Gets the requested List by path, returning a default value if not + * found. + * + *

If the List does not exist then the specified default value will + * returned regardless of if a default has been identified in the root + * {@link Configuration}. + * + * @param path Path of the List to get. + * @param def The default value to return if the path is not found or is + * not a List. + * @return Requested List. + */ + List getList(String path, List def); + + /** + * Checks if the specified path is a List. + * + *

If the path exists but is not a List, this will return false. If the + * path does not exist, this will return false. If the path does not exist + * but a default value has been specified, this will check if that default + * value is a List and return appropriately. + * + * @param path Path of the List to check. + * @return Whether or not the specified path is a List. + */ + boolean isList(String path); + + /** + * Gets the requested List of String by path. + * + *

If the List does not exist but a default value has been specified, + * this will return the default value. If the List does not exist and no + * default value was specified, this will return an empty List. + * + *

This method will attempt to cast any values into a String if possible, + * but may miss any values out if they are not compatible. + * + * @param path Path of the List to get. + * @return Requested List of String. + */ + List getStringList(String path); + + /** + * Gets the requested List of Integer by path. + * + *

If the List does not exist but a default value has been specified, + * this will return the default value. If the List does not exist and no + * default value was specified, this will return an empty List. + * + *

This method will attempt to cast any values into a Integer if + * possible, but may miss any values out if they are not compatible. + * + * @param path Path of the List to get. + * @return Requested List of Integer. + */ + List getIntegerList(String path); + + /** + * Gets the requested List of Boolean by path. + * + *

If the List does not exist but a default value has been specified, + * this will return the default value. If the List does not exist and no + * default value was specified, this will return an empty List. + * + *

This method will attempt to cast any values into a Boolean if + * possible, but may miss any values out if they are not compatible. + * + * @param path Path of the List to get. + * @return Requested List of Boolean. + */ + List getBooleanList(String path); + + /** + * Gets the requested List of Double by path. + * + *

If the List does not exist but a default value has been specified, + * this will return the default value. If the List does not exist and no + * default value was specified, this will return an empty List. + * + *

This method will attempt to cast any values into a Double if possible, + * but may miss any values out if they are not compatible. + * + * @param path Path of the List to get. + * @return Requested List of Double. + */ + List getDoubleList(String path); + + /** + * Gets the requested List of Float by path. + * + *

If the List does not exist but a default value has been specified, + * this will return the default value. If the List does not exist and no + * default value was specified, this will return an empty List. + * + *

This method will attempt to cast any values into a Float if possible, + * but may miss any values out if they are not compatible. + * + * @param path Path of the List to get. + * @return Requested List of Float. + */ + List getFloatList(String path); + + /** + * Gets the requested List of Long by path. + * + *

If the List does not exist but a default value has been specified, + * this will return the default value. If the List does not exist and no + * default value was specified, this will return an empty List. + * + *

This method will attempt to cast any values into a Long if possible, + * but may miss any values out if they are not compatible. + * + * @param path Path of the List to get. + * @return Requested List of Long. + */ + List getLongList(String path); + + /** + * Gets the requested List of Byte by path. + * + *

If the List does not exist but a default value has been specified, + * this will return the default value. If the List does not exist and no + * default value was specified, this will return an empty List. + * + *

This method will attempt to cast any values into a Byte if possible, + * but may miss any values out if they are not compatible. + * + * @param path Path of the List to get. + * @return Requested List of Byte. + */ + List getByteList(String path); + + /** + * Gets the requested List of Character by path. + * + *

If the List does not exist but a default value has been specified, + * this will return the default value. If the List does not exist and no + * default value was specified, this will return an empty List. + * + *

This method will attempt to cast any values into a Character if + * possible, but may miss any values out if they are not compatible. + * + * @param path Path of the List to get. + * @return Requested List of Character. + */ + List getCharacterList(String path); + + /** + * Gets the requested List of Short by path. + * + *

If the List does not exist but a default value has been specified, + * this will return the default value. If the List does not exist and no + * default value was specified, this will return an empty List. + * + *

This method will attempt to cast any values into a Short if + * possible, but may miss any values out if they are not compatible. + * + * @param path Path of the List to get. + * @return Requested List of Short. + */ + List getShortList(String path); + + /** + * Gets the requested List of Maps by path. + * + *

If the List does not exist but a default value has been specified, + * this will return the default value. If the List does not exist and no + * default value was specified, this will return an empty List. + *

This method will attempt to cast any values into a Map if possible, + * but may miss any values out if they are not compatible. + * + * @param path Path of the List to get. + * @return Requested List of Maps. + */ + List> getMapList(String path); + + /** + * Gets the requested ConfigurationSection by path. + * + *

If the ConfigurationSection does not exist but a default value has + * been specified, this will return the default value. If the + * ConfigurationSection does not exist and no default value was specified, + * this will return {@code null}. + * + * @param path Path of the ConfigurationSection to get. + * @return Requested ConfigurationSection. + */ + ConfigurationSection getConfigurationSection(String path); + + /** + * Checks if the specified path is a ConfigurationSection. + * + *

If the path exists but is not a ConfigurationSection, this will return + * false. If the path does not exist, this will return false. If the path + * does not exist but a default value has been specified, this will check + * if that default value is a ConfigurationSection and return + * appropriately. + * + * @param path Path of the ConfigurationSection to check. + * @return Whether or not the specified path is a ConfigurationSection. + */ + boolean isConfigurationSection(String path); + + /** + * Gets the equivalent {@link ConfigurationSection} from the default + * {@link Configuration} defined in {@link #getRoot()}. + * + *

If the root contains no defaults, or the defaults doesn't contain a + * value for this path, or the value at this path is not a {@link + * ConfigurationSection} then this will return {@code null}. + * + * @return Equivalent section in root configuration + */ + ConfigurationSection getDefaultSection(); + + /** + * Sets the default value in the root at the given path as provided. + * + *

If no source {@link Configuration} was provided as a default + * collection, then a new {@link MemoryConfiguration} will be created to + * hold the new default value. + * + *

If value is {@code null}, the value will be removed from the + * default Configuration source. + * + *

If the value as returned by {@link #getDefaultSection()} is + * {@code null}, then this will create a new section at the path, + * replacing anything that may have existed there previously. + * + * @param path Path of the value to set + * @param value Value to set the default to + * @throws IllegalArgumentException Thrown if path is {@code null} + */ + void addDefault(@Nonnull String path, Object value); +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/InvalidConfigurationException.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/InvalidConfigurationException.java new file mode 100644 index 000000000..e9c099ed1 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/InvalidConfigurationException.java @@ -0,0 +1,45 @@ +package com.github.intellectualsites.plotsquared.configuration; + +/** + * Exception thrown when attempting to load an invalid {@link Configuration}. + */ +@SuppressWarnings("serial") public class InvalidConfigurationException extends Exception { + + /** + * Creates a new instance of InvalidConfigurationException without a + * message or cause. + */ + public InvalidConfigurationException() { + } + + /** + * Constructs an instance of InvalidConfigurationException with the + * specified message. + * + * @param msg The details of the exception. + */ + public InvalidConfigurationException(String msg) { + super(msg); + } + + /** + * Constructs an instance of InvalidConfigurationException with the + * specified cause. + * + * @param cause The cause of the exception. + */ + public InvalidConfigurationException(Throwable cause) { + super(cause); + } + + /** + * Constructs an instance of InvalidConfigurationException with the + * specified message and cause. + * + * @param cause The cause of the exception. + * @param msg The details of the exception. + */ + public InvalidConfigurationException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemoryConfiguration.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemoryConfiguration.java new file mode 100644 index 000000000..d1677c54d --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemoryConfiguration.java @@ -0,0 +1,73 @@ +package com.github.intellectualsites.plotsquared.configuration; + +import javax.annotation.Nonnull; +import java.util.Map; + +/** + * This is a {@link Configuration} implementation that does not save or load + * from any source, and stores all values in memory only. + * This is useful for temporary Configurations for providing defaults. + */ +public class MemoryConfiguration extends MemorySection implements Configuration { + protected Configuration defaults; + protected MemoryConfigurationOptions options; + + /** + * Creates an empty {@link MemoryConfiguration} with no default values. + */ + public MemoryConfiguration() { + } + + /** + * Creates an empty {@link MemoryConfiguration} using the specified {@link + * Configuration} as a source for all default values. + * + * @param defaults Default value provider + * @throws IllegalArgumentException Thrown if defaults is null + */ + public MemoryConfiguration(Configuration defaults) { + this.defaults = defaults; + } + + @Override public void addDefault(@Nonnull String path, Object value) { + if (this.defaults == null) { + this.defaults = new MemoryConfiguration(); + } + + this.defaults.set(path, value); + } + + @Override public void addDefaults(Map defaults) { + for (Map.Entry entry : defaults.entrySet()) { + addDefault(entry.getKey(), entry.getValue()); + } + } + + @Override public void addDefaults(Configuration defaults) { + addDefaults(defaults.getValues(true)); + } + + @Override public Configuration getDefaults() { + return this.defaults; + } + + @Override public void setDefaults(Configuration defaults) { + if (defaults == null) { + throw new NullPointerException("Defaults may not be null"); + } + + this.defaults = defaults; + } + + @Override public ConfigurationSection getParent() { + return null; + } + + @Override public MemoryConfigurationOptions options() { + if (this.options == null) { + this.options = new MemoryConfigurationOptions(this); + } + + return this.options; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemoryConfigurationOptions.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemoryConfigurationOptions.java new file mode 100644 index 000000000..971ea1e70 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemoryConfigurationOptions.java @@ -0,0 +1,25 @@ +package com.github.intellectualsites.plotsquared.configuration; + +/** + * Various settings for controlling the input and output of a {@link + * MemoryConfiguration}. + */ +public class MemoryConfigurationOptions extends ConfigurationOptions { + protected MemoryConfigurationOptions(MemoryConfiguration configuration) { + super(configuration); + } + + @Override public MemoryConfiguration configuration() { + return (MemoryConfiguration) super.configuration(); + } + + @Override public MemoryConfigurationOptions copyDefaults(boolean value) { + super.copyDefaults(value); + return this; + } + + @Override public MemoryConfigurationOptions pathSeparator(char value) { + super.pathSeparator(value); + return this; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemorySection.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemorySection.java new file mode 100644 index 000000000..26f6760c8 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/MemorySection.java @@ -0,0 +1,771 @@ +package com.github.intellectualsites.plotsquared.configuration; + +import javax.annotation.Nonnull; +import java.util.*; + +/** + * A type of {@link ConfigurationSection} that is stored in memory. + */ +public class MemorySection implements ConfigurationSection { + + protected final Map map = new LinkedHashMap<>(); + private final Configuration root; + private final ConfigurationSection parent; + private final String path; + private final String fullPath; + + /** + * Creates an empty MemorySection for use as a root {@link Configuration} section. + * + *

Note that calling this without being yourself a {@link Configuration} + * will throw an exception! + * + * @throws IllegalStateException Thrown if this is not a {@link Configuration} root. + */ + protected MemorySection() { + if (!(this instanceof Configuration)) { + throw new IllegalStateException( + "Cannot construct a root MemorySection when not a Configuration"); + } + + this.path = ""; + this.fullPath = ""; + this.parent = null; + this.root = (Configuration) this; + } + + /** + * Creates an empty MemorySection with the specified parent and path. + * + * @param parent Parent section that contains this own section. + * @param path Path that you may access this section from via the root {@link Configuration}. + * @throws IllegalArgumentException Thrown is parent or path is null, or if parent contains no + * root Configuration. + */ + protected MemorySection(ConfigurationSection parent, String path) { + this.path = path; + this.parent = parent; + this.root = parent.getRoot(); + + if (this.root == null) { + throw new NullPointerException("Path may not be orphaned"); + } + + this.fullPath = createPath(parent, path); + } + + public static double toDouble(Object obj, double def) { + if (obj instanceof Number) { + return ((Number) obj).doubleValue(); + } + if (obj instanceof String) { + try { + return Double.parseDouble((String) obj); + } catch (NumberFormatException ignored) { + } + } else if (obj instanceof List) { + List val = (List) obj; + if (!val.isEmpty()) { + return toDouble(val.get(0), def); + } + } + return def; + } + + public static int toInt(Object obj, int def) { + if (obj instanceof Number) { + return ((Number) obj).intValue(); + } + if (obj instanceof String) { + try { + return Integer.parseInt((String) obj); + } catch (NumberFormatException ignored) { + } + } else if (obj instanceof List) { + List val = (List) obj; + if (!val.isEmpty()) { + return toInt(val.get(0), def); + } + } + return def; + } + + public static long toLong(Object obj, long def) { + if (obj instanceof Number) { + return ((Number) obj).longValue(); + } + if (obj instanceof String) { + try { + return Long.parseLong((String) obj); + } catch (NumberFormatException ignored) { + } + } else if (obj instanceof List) { + List val = (List) obj; + if (!val.isEmpty()) { + return toLong(val.get(0), def); + } + } + return def; + } + + /** + * Creates a full path to the given {@link ConfigurationSection} from its root {@link + * Configuration}. + * + *

You may use this method for any given {@link ConfigurationSection}, not + * only {@link MemorySection}. + * + * @param section Section to create a path for. + * @param key Name of the specified section. + * @return Full path of the section from its root. + */ + public static String createPath(ConfigurationSection section, String key) { + return createPath(section, key, section.getRoot()); + } + + /** + * Creates a relative path to the given {@link ConfigurationSection} from the given relative + * section. + * + *

You may use this method for any given {@link ConfigurationSection}, not + * only {@link MemorySection}. + * + * @param section Section to create a path for. + * @param key Name of the specified section. + * @param relativeTo Section to create the path relative to. + * @return Full path of the section from its root. + */ + public static String createPath(ConfigurationSection section, String key, + ConfigurationSection relativeTo) { + Configuration root = section.getRoot(); + if (root == null) { + throw new IllegalStateException("Cannot create path without a root"); + } + char separator = root.options().pathSeparator(); + + StringBuilder builder = new StringBuilder(); + for (ConfigurationSection parent = section; + (parent != null) && (parent != relativeTo); parent = parent.getParent()) { + if (builder.length() > 0) { + builder.insert(0, separator); + } + + builder.insert(0, parent.getName()); + } + + if ((key != null) && !key.isEmpty()) { + if (builder.length() > 0) { + builder.append(separator); + } + + builder.append(key); + } + + return builder.toString(); + } + + @Override public Set getKeys(boolean deep) { + Set result = new LinkedHashSet<>(); + + Configuration root = getRoot(); + if ((root != null) && root.options().copyDefaults()) { + ConfigurationSection defaults = getDefaultSection(); + + if (defaults != null) { + result.addAll(defaults.getKeys(deep)); + } + } + + mapChildrenKeys(result, this, deep); + + return result; + } + + @Override public Map getValues(boolean deep) { + Map result = new LinkedHashMap<>(); + + Configuration root = getRoot(); + if ((root != null) && root.options().copyDefaults()) { + ConfigurationSection defaults = getDefaultSection(); + + if (defaults != null) { + result.putAll(defaults.getValues(deep)); + } + } + + mapChildrenValues(result, this, deep); + + return result; + } + + @Override public boolean contains(@Nonnull String path) { + return get(path) != null; + } + + @Override public boolean isSet(@Nonnull String path) { + Configuration root = getRoot(); + if (root == null) { + return false; + } + if (root.options().copyDefaults()) { + return contains(path); + } + return getOrDefault(path, null) != null; + } + + @Override public String getCurrentPath() { + return this.fullPath; + } + + @Override public String getName() { + return this.path; + } + + @Override public Configuration getRoot() { + return this.root; + } + + @Override public ConfigurationSection getParent() { + return this.parent; + } + + @Override public void addDefault(@Nonnull String path, Object value) { + Configuration root = getRoot(); + if (root == null) { + throw new IllegalStateException("Cannot add default without root"); + } + if (root == this) { + throw new UnsupportedOperationException( + "Unsupported addDefault(String, Object) implementation"); + } + root.addDefault(createPath(this, path), value); + } + + @Override public ConfigurationSection getDefaultSection() { + Configuration root = getRoot(); + Configuration defaults = root == null ? null : root.getDefaults(); + + if (defaults != null) { + if (defaults.isConfigurationSection(getCurrentPath())) { + return defaults.getConfigurationSection(getCurrentPath()); + } + } + + return null; + } + + @Override public void set(String path, Object value) { + Configuration root = getRoot(); + if (root == null) { + throw new IllegalStateException("Cannot use section without a root"); + } + + char separator = root.options().pathSeparator(); + // i1 is the leading (higher) index + // i2 is the trailing (lower) index + int i1 = -1; + int i2; + ConfigurationSection section = this; + while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) { + String node = path.substring(i2, i1); + ConfigurationSection subSection = section.getConfigurationSection(node); + if (subSection == null) { + section = section.createSection(node); + } else { + section = subSection; + } + } + + String key = path.substring(i2); + if (section == this) { + if (value == null) { + this.map.remove(key); + } else { + this.map.put(key, value); + } + } else { + section.set(key, value); + } + } + + @Override public Object get(String path) { + return getOrDefault(path, getDefault(path)); + } + + @Override public Object getOrDefault(@Nonnull String path, Object defaultValue) { + if (path.isEmpty()) { + return this; + } + + Configuration root = getRoot(); + if (root == null) { + throw new IllegalStateException("Cannot access section without a root"); + } + + char separator = root.options().pathSeparator(); + // i1 is the leading (higher) index + // i2 is the trailing (lower) index + int i1 = -1; + int i2; + ConfigurationSection section = this; + while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) { + section = section.getConfigurationSection(path.substring(i2, i1)); + if (section == null) { + return defaultValue; + } + } + + String key = path.substring(i2); + if (section == this) { + Object result = this.map.get(key); + if (result == null) { + return defaultValue; + } else { + return result; + } + } + return section.getOrDefault(key, defaultValue); + } + + @Override public ConfigurationSection createSection(String path) { + Configuration root = getRoot(); + if (root == null) { + throw new IllegalStateException("Cannot create section without a root"); + } + + char separator = root.options().pathSeparator(); + // i1 is the leading (higher) index + // i2 is the trailing (lower) index + int i1 = -1; + int i2; + ConfigurationSection section = this; + while ((i1 = path.indexOf(separator, i2 = i1 + 1)) != -1) { + String node = path.substring(i2, i1); + ConfigurationSection subSection = section.getConfigurationSection(node); + if (subSection == null) { + section = section.createSection(node); + } else { + section = subSection; + } + } + + String key = path.substring(i2); + if (section == this) { + ConfigurationSection result = new MemorySection(this, key); + this.map.put(key, result); + return result; + } + return section.createSection(key); + } + + @Override public ConfigurationSection createSection(String path, Map map) { + ConfigurationSection section = createSection(path); + + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() instanceof Map) { + section.createSection(entry.getKey().toString(), (Map) entry.getValue()); + } else { + section.set(entry.getKey().toString(), entry.getValue()); + } + } + + return section; + } + + // Primitives + @Override public String getString(String path) { + Object def = getDefault(path); + return getString(path, def != null ? def.toString() : null); + } + + @Override public String getString(String path, String def) { + Object val = getOrDefault(path, def); + if (val != null) { + return val.toString(); + } else { + return def; + } + } + + @Override public boolean isString(String path) { + Object val = get(path); + return val instanceof String; + } + + @Override public int getInt(String path) { + Object def = getDefault(path); + return getInt(path, toInt(def, 0)); + } + + @Override public int getInt(String path, int def) { + Object val = getOrDefault(path, def); + return toInt(val, def); + } + + @Override public boolean isInt(String path) { + Object val = get(path); + return val instanceof Integer; + } + + @Override public boolean getBoolean(String path) { + Object def = getDefault(path); + if (def instanceof Boolean) { + return getBoolean(path, (Boolean) def); + } else { + return getBoolean(path, false); + } + } + + @Override public boolean getBoolean(String path, boolean defaultValue) { + Object val = getOrDefault(path, defaultValue); + if (val instanceof Boolean) { + return (Boolean) val; + } else { + return defaultValue; + } + } + + @Override public boolean isBoolean(String path) { + Object val = get(path); + return val instanceof Boolean; + } + + @Override public double getDouble(String path) { + Object def = getDefault(path); + return getDouble(path, toDouble(def, 0)); + } + + @Override public double getDouble(String path, double defaultValue) { + Object val = getOrDefault(path, defaultValue); + return toDouble(val, defaultValue); + } + + @Override public boolean isDouble(String path) { + Object val = get(path); + return val instanceof Double; + } + + @Override public long getLong(String path) { + Object def = getDefault(path); + return getLong(path, toLong(def, 0)); + } + + @Override public long getLong(String path, long def) { + Object val = getOrDefault(path, def); + return toLong(val, def); + } + + @Override public boolean isLong(String path) { + Object val = get(path); + return val instanceof Long; + } + + // Java + @Override public List getList(String path) { + Object def = getDefault(path); + return getList(path, def instanceof List ? (List) def : null); + } + + @Override public List getList(String path, List def) { + Object val = getOrDefault(path, def); + return (List) ((val instanceof List) ? val : def); + } + + @Override public boolean isList(String path) { + Object val = get(path); + return val instanceof List; + } + + @Override public List getStringList(String path) { + List list = getList(path); + + if (list == null) { + return new ArrayList<>(0); + } + + List result = new ArrayList<>(); + + for (Object object : list) { + if ((object instanceof String) || isPrimitiveWrapper(object)) { + result.add(String.valueOf(object)); + } + } + + return result; + } + + @Override public List getIntegerList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Integer) { + result.add((Integer) object); + } else if (object instanceof String) { + try { + result.add(Integer.valueOf((String) object)); + } catch (NumberFormatException ignored) { + } + } else if (object instanceof Character) { + result.add((int) (Character) object); + } else if (object instanceof Number) { + result.add(((Number) object).intValue()); + } + } + + return result; + } + + @Override public List getBooleanList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Boolean) { + result.add((Boolean) object); + } else if (object instanceof String) { + if (Boolean.TRUE.toString().equals(object)) { + result.add(true); + } else if (Boolean.FALSE.toString().equals(object)) { + result.add(false); + } + } + } + + return result; + } + + @Override public List getDoubleList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Double) { + result.add((Double) object); + } else if (object instanceof String) { + try { + result.add(Double.valueOf((String) object)); + } catch (NumberFormatException ignored) { + } + } else if (object instanceof Character) { + result.add((double) (Character) object); + } else if (object instanceof Number) { + result.add(((Number) object).doubleValue()); + } + } + + return result; + } + + @Override public List getFloatList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Float) { + result.add((Float) object); + } else if (object instanceof String) { + try { + result.add(Float.valueOf((String) object)); + } catch (NumberFormatException ignored) { + } + } else if (object instanceof Character) { + result.add((float) (Character) object); + } else if (object instanceof Number) { + result.add(((Number) object).floatValue()); + } + } + + return result; + } + + @Override public List getLongList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Long) { + result.add((Long) object); + } else if (object instanceof String) { + try { + result.add(Long.valueOf((String) object)); + } catch (NumberFormatException ignored) { + } + } else if (object instanceof Character) { + result.add((long) (Character) object); + } else if (object instanceof Number) { + result.add(((Number) object).longValue()); + } + } + + return result; + } + + @Override public List getByteList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Byte) { + result.add((Byte) object); + } else if (object instanceof String) { + try { + result.add(Byte.valueOf((String) object)); + } catch (NumberFormatException ignored) { + } + } else if (object instanceof Character) { + result.add((byte) ((Character) object).charValue()); + } else if (object instanceof Number) { + result.add(((Number) object).byteValue()); + } + } + + return result; + } + + @Override public List getCharacterList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Character) { + result.add((Character) object); + } else if (object instanceof String) { + String str = (String) object; + + if (str.length() == 1) { + result.add(str.charAt(0)); + } + } else if (object instanceof Number) { + result.add((char) ((Number) object).intValue()); + } + } + + return result; + } + + @Override public List getShortList(String path) { + List list = getList(path); + + List result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Short) { + result.add((Short) object); + } else if (object instanceof String) { + try { + result.add(Short.valueOf((String) object)); + } catch (NumberFormatException ignored) { + } + } else if (object instanceof Character) { + result.add((short) ((Character) object).charValue()); + } else if (object instanceof Number) { + result.add(((Number) object).shortValue()); + } + } + + return result; + } + + @Override public List> getMapList(String path) { + List list = getList(path); + List> result = new ArrayList<>(); + + for (Object object : list) { + if (object instanceof Map) { + result.add((Map) object); + } + } + + return result; + } + + @Override public ConfigurationSection getConfigurationSection(String path) { + Object val = getOrDefault(path, null); + if (val != null) { + return (val instanceof ConfigurationSection) ? (ConfigurationSection) val : null; + } + + val = getOrDefault(path, getDefault(path)); + return (val instanceof ConfigurationSection) ? createSection(path) : null; + } + + @Override public boolean isConfigurationSection(String path) { + Object val = get(path); + return val instanceof ConfigurationSection; + } + + protected boolean isPrimitiveWrapper(Object input) { + return (input instanceof Integer) || (input instanceof Boolean) + || (input instanceof Character) || (input instanceof Byte) || (input instanceof Short) + || (input instanceof Double) || (input instanceof Long) || (input instanceof Float); + } + + protected Object getDefault(String path) { + Configuration root = getRoot(); + Configuration defaults = root == null ? null : root.getDefaults(); + return (defaults == null) ? null : defaults.get(createPath(this, path)); + } + + protected void mapChildrenKeys(Set output, ConfigurationSection section, boolean deep) { + if (section instanceof MemorySection) { + MemorySection sec = (MemorySection) section; + + for (Map.Entry entry : sec.map.entrySet()) { + output.add(createPath(section, entry.getKey(), this)); + + if (deep && (entry.getValue() instanceof ConfigurationSection)) { + ConfigurationSection subsection = (ConfigurationSection) entry.getValue(); + mapChildrenKeys(output, subsection, deep); + } + } + } else { + Set keys = section.getKeys(deep); + + for (String key : keys) { + output.add(createPath(section, key, this)); + } + } + } + + protected void mapChildrenValues(Map output, ConfigurationSection section, + boolean deep) { + if (section instanceof MemorySection) { + MemorySection sec = (MemorySection) section; + + for (Map.Entry entry : sec.map.entrySet()) { + output.put(createPath(section, entry.getKey(), this), entry.getValue()); + + if (entry.getValue() instanceof ConfigurationSection) { + if (deep) { + mapChildrenValues(output, (ConfigurationSection) entry.getValue(), deep); + } + } + } + } else { + Map values = section.getValues(deep); + + for (Map.Entry entry : values.entrySet()) { + output.put(createPath(section, entry.getKey(), this), entry.getValue()); + } + } + } + + @Override public String toString() { + Configuration root = getRoot(); + if (root == null) { + return getClass().getSimpleName() + "[path='" + getCurrentPath() + "', root='" + null + + "']"; + } else { + return getClass().getSimpleName() + "[path='" + getCurrentPath() + "', root='" + root + .getClass().getSimpleName() + "']"; + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/FileConfiguration.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/FileConfiguration.java new file mode 100644 index 000000000..bc0b375e9 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/FileConfiguration.java @@ -0,0 +1,158 @@ +package com.github.intellectualsites.plotsquared.configuration.file; + +import com.github.intellectualsites.plotsquared.configuration.Configuration; +import com.github.intellectualsites.plotsquared.configuration.InvalidConfigurationException; +import com.github.intellectualsites.plotsquared.configuration.MemoryConfiguration; + +import javax.annotation.Nonnull; +import java.io.*; +import java.nio.charset.StandardCharsets; + +/** + * This is a base class for all File based implementations of {@link + * Configuration}. + */ +public abstract class FileConfiguration extends MemoryConfiguration { + + /** + * Creates an empty {@link FileConfiguration} with no default values. + */ + FileConfiguration() { + } + + /** + * Creates an empty {@link FileConfiguration} using the specified {@link + * Configuration} as a source for all default values. + * + * @param defaults Default value provider + */ + public FileConfiguration(Configuration defaults) { + super(defaults); + } + + /** + * Saves this {@link FileConfiguration} to the specified location. + * + *

If the file does not exist, it will be created. If already exists, it + * will be overwritten. If it cannot be overwritten or created, an + * exception will be thrown. + * + *

This method will save using the system default encoding, or possibly + * using UTF8. + * + * @param file File to save to. + * @throws IOException Thrown when the given file cannot be written to for + * any reason. + */ + public void save(File file) throws IOException { + File parent = file.getParentFile(); + if (parent != null) { + parent.mkdirs(); + } + + String data = saveToString(); + + try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), + StandardCharsets.UTF_8)) { + writer.write(data); + } + } + + /** + * Saves this {@link FileConfiguration} to a string, and returns it. + * + * @return String containing this configuration. + */ + public abstract String saveToString(); + + /** + * Loads this {@link FileConfiguration} from the specified location. + * + *

All the values contained within this configuration will be removed, + * leaving only settings and defaults, and the new values will be loaded + * from the given file. + * + *

If the file cannot be loaded for any reason, an exception will be + * thrown. + * + * @param file File to load from. + * @throws FileNotFoundException Thrown when the given file cannot be + * opened. + * @throws IOException Thrown when the given file cannot be read. + * @throws InvalidConfigurationException Thrown when the given file is not + * a valid Configuration. + * @throws IllegalArgumentException Thrown when file is null. + */ + public void load(@Nonnull File file) throws IOException, InvalidConfigurationException { + + FileInputStream stream = new FileInputStream(file); + + load(new InputStreamReader(stream, StandardCharsets.UTF_8)); + } + + /** + * Loads this {@link FileConfiguration} from the specified reader. + * + *

All the values contained within this configuration will be removed, + * leaving only settings and defaults, and the new values will be loaded + * from the given stream. + * + * @param reader the reader to load from + * @throws IOException thrown when underlying reader throws an IOException + * @throws InvalidConfigurationException thrown when the reader does not + * represent a valid Configuration + */ + public void load(Reader reader) throws IOException, InvalidConfigurationException { + + StringBuilder builder = new StringBuilder(); + + try (BufferedReader input = reader instanceof BufferedReader ? + (BufferedReader) reader : + new BufferedReader(reader)) { + String line; + + while ((line = input.readLine()) != null) { + builder.append(line); + builder.append('\n'); + } + } + + loadFromString(builder.toString()); + } + + /** + * Loads this {@link FileConfiguration} from the specified string, as + * opposed to from file. + * + *

All the values contained within this configuration will be removed, + * leaving only settings and defaults, and the new values will be loaded + * from the given string. + * + *

If the string is invalid in any way, an exception will be thrown. + * + * @param contents Contents of a Configuration to load. + * @throws InvalidConfigurationException Thrown if the specified string is + * invalid. + */ + public abstract void loadFromString(String contents) throws InvalidConfigurationException; + + /** + * Compiles the header for this {@link FileConfiguration} and returns the + * result. + * + *

This will use the header from {@link #options()} -> {@link + * FileConfigurationOptions#header()}, respecting the rules of {@link + * FileConfigurationOptions#copyHeader()} if set. + * + * @return Compiled header + */ + protected abstract String buildHeader(); + + @Override public FileConfigurationOptions options() { + if (this.options == null) { + this.options = new FileConfigurationOptions(this); + } + + return (FileConfigurationOptions) this.options; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/FileConfigurationOptions.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/FileConfigurationOptions.java new file mode 100644 index 000000000..a216d0566 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/FileConfigurationOptions.java @@ -0,0 +1,115 @@ +package com.github.intellectualsites.plotsquared.configuration.file; + +import com.github.intellectualsites.plotsquared.configuration.Configuration; +import com.github.intellectualsites.plotsquared.configuration.MemoryConfiguration; +import com.github.intellectualsites.plotsquared.configuration.MemoryConfigurationOptions; + +/** + * Various settings for controlling the input and output of a {@link + * FileConfiguration}. + */ +public class FileConfigurationOptions extends MemoryConfigurationOptions { + private String header = null; + private boolean copyHeader = true; + + protected FileConfigurationOptions(MemoryConfiguration configuration) { + super(configuration); + } + + @Override public FileConfiguration configuration() { + return (FileConfiguration) super.configuration(); + } + + @Override public FileConfigurationOptions copyDefaults(boolean value) { + super.copyDefaults(value); + return this; + } + + @Override public FileConfigurationOptions pathSeparator(char value) { + super.pathSeparator(value); + return this; + } + + /** + * Gets the header that will be applied to the top of the saved output. + * + *

This header will be commented out and applied directly at the top of + * the generated output of the {@link FileConfiguration}. It is not + * required to include a newline at the end of the header as it will + * automatically be applied, but you may include one if you wish for extra + * spacing. + * + *

{@code null} is a valid value which will indicate that no header] + * is to be applied. The default value is {@code null}. + * + * @return Header + */ + public String header() { + return header; + } + + /** + * Sets the header that will be applied to the top of the saved output. + * + *

This header will be commented out and applied directly at the top of + * the generated output of the {@link FileConfiguration}. It is not + * required to include a newline at the end of the header as it will + * automatically be applied, but you may include one if you wish for extra + * spacing. + * + *

{@code null} is a valid value which will indicate that no header + * is to be applied. + * + * @param value New header + * @return This object, for chaining + */ + public FileConfigurationOptions header(String value) { + header = value; + return this; + } + + /** + * Gets whether or not the header should be copied from a default source. + * + *

If this is true, if a default {@link FileConfiguration} is passed to + * {@link FileConfiguration#setDefaults(Configuration)} + * then upon saving it will use the header from that config, instead of + * the one provided here. + * + *

If no default is set on the configuration, or the default is not of + * type FileConfiguration, or that config has no header ({@link #header()} + * returns null) then the header specified in this configuration will be + * used. + * + *

Defaults to true. + * + * @return Whether or not to copy the header + */ + public boolean copyHeader() { + return copyHeader; + } + + /** + * Sets whether or not the header should be copied from a default source. + * + *

If this is true, if a default {@link FileConfiguration} is passed to + * {@link FileConfiguration#setDefaults(Configuration)} + * then upon saving it will use the header from that config, instead of + * the one provided here. + * + *

If no default is set on the configuration, or the default is not of + * type FileConfiguration, or that config has no header ({@link #header()} + * returns null) then the header specified in this configuration will be + * used. + * + *

Defaults to true. + * + * @param value Whether or not to copy the header + * @return This object, for chaining + */ + public FileConfigurationOptions copyHeader(boolean value) { + copyHeader = value; + + return this; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfiguration.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfiguration.java new file mode 100644 index 000000000..1e694f05a --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfiguration.java @@ -0,0 +1,189 @@ +package com.github.intellectualsites.plotsquared.configuration.file; + +import com.github.intellectualsites.plotsquared.configuration.Configuration; +import com.github.intellectualsites.plotsquared.configuration.ConfigurationSection; +import com.github.intellectualsites.plotsquared.configuration.InvalidConfigurationException; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.error.YAMLException; +import org.yaml.snakeyaml.representer.Representer; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.Map; + +/** + * An implementation of {@link Configuration} which saves all files in Yaml. + * Note that this implementation is not synchronized. + */ +public class YamlConfiguration extends FileConfiguration { + private static final String COMMENT_PREFIX = "# "; + private static final String BLANK_CONFIG = "{}\n"; + private final DumperOptions yamlOptions = new DumperOptions(); + private final Representer yamlRepresenter = new YamlRepresenter(); + private final Yaml yaml = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions); + + /** + * Creates a new {@link YamlConfiguration}, loading from the given file. + * + *

Any errors loading the Configuration will be logged and then ignored. + * If the specified input is not a valid config, a blank config will be + * returned. + * + *

The encoding used may follow the system dependent default. + * + * @param file Input file + * @return Resulting configuration + */ + public static YamlConfiguration loadConfiguration(File file) { + YamlConfiguration config = new YamlConfiguration(); + + try { + config.load(file); + } catch (InvalidConfigurationException | IOException ex) { + try { + File dest = new File(file.getAbsolutePath() + "_broken"); + int i = 0; + while (dest.exists()) { + dest = new File(file.getAbsolutePath() + "_broken_" + i++); + } + Files.copy(file.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING); + PlotSquared.debug("&dCould not read: &7" + file); + PlotSquared.debug("&dRenamed to: &7" + dest.getName()); + PlotSquared.debug("&c============ Full stacktrace ============"); + ex.printStackTrace(); + PlotSquared.debug("&c========================================="); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return config; + } + + @Override public String saveToString() { + yamlOptions.setIndent(options().indent()); + yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + + String header = buildHeader(); + String dump = yaml.dump(getValues(false)); + + if (dump.equals(BLANK_CONFIG)) { + dump = ""; + } + + return header + dump; + } + + @Override public void loadFromString(String contents) throws InvalidConfigurationException { + + Map input; + try { + input = yaml.load(contents); + } catch (YAMLException e) { + throw new InvalidConfigurationException(e); + } catch (ClassCastException ignored) { + throw new InvalidConfigurationException("Top level is not a Map."); + } + + String header = parseHeader(contents); + if (!header.isEmpty()) { + options().header(header); + } + + if (input != null) { + convertMapsToSections(input, this); + } + } + + protected void convertMapsToSections(Map input, ConfigurationSection section) { + for (Map.Entry entry : input.entrySet()) { + String key = entry.getKey().toString(); + Object value = entry.getValue(); + + if (value instanceof Map) { + convertMapsToSections((Map) value, section.createSection(key)); + } else { + section.set(key, value); + } + } + } + + protected String parseHeader(String input) { + String[] lines = input.split("\r?\n", -1); + StringBuilder result = new StringBuilder(); + boolean readingHeader = true; + boolean foundHeader = false; + + for (int i = 0; (i < lines.length) && readingHeader; i++) { + String line = lines[i]; + + if (line.startsWith(COMMENT_PREFIX)) { + if (i > 0) { + result.append('\n'); + } + + if (line.length() > COMMENT_PREFIX.length()) { + result.append(line.substring(COMMENT_PREFIX.length())); + } + + foundHeader = true; + } else if (foundHeader && line.isEmpty()) { + result.append('\n'); + } else if (foundHeader) { + readingHeader = false; + } + } + + return result.toString(); + } + + @Override protected String buildHeader() { + String header = options().header(); + + if (options().copyHeader()) { + Configuration def = getDefaults(); + + if (def instanceof FileConfiguration) { + FileConfiguration fileDefaults = (FileConfiguration) def; + String defaultsHeader = fileDefaults.buildHeader(); + + if ((defaultsHeader != null) && !defaultsHeader.isEmpty()) { + return defaultsHeader; + } + } + } + + if (header == null) { + return ""; + } + + StringBuilder builder = new StringBuilder(); + String[] lines = header.split("\r?\n", -1); + boolean startedHeader = false; + + for (int i = lines.length - 1; i >= 0; i--) { + builder.insert(0, '\n'); + + if (startedHeader || !lines[i].isEmpty()) { + builder.insert(0, lines[i]); + builder.insert(0, COMMENT_PREFIX); + startedHeader = true; + } + } + + return builder.toString(); + } + + @Override public YamlConfigurationOptions options() { + if (options == null) { + options = new YamlConfigurationOptions(this); + } + + return (YamlConfigurationOptions) options; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfigurationOptions.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfigurationOptions.java new file mode 100644 index 000000000..730527652 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConfigurationOptions.java @@ -0,0 +1,68 @@ +package com.github.intellectualsites.plotsquared.configuration.file; + +/** + * Various settings for controlling the input and output of a {@link + * YamlConfiguration}. + */ +public class YamlConfigurationOptions extends FileConfigurationOptions { + private int indent = 2; + + YamlConfigurationOptions(YamlConfiguration configuration) { + super(configuration); + } + + @Override public YamlConfiguration configuration() { + return (YamlConfiguration) super.configuration(); + } + + @Override public YamlConfigurationOptions copyDefaults(boolean value) { + super.copyDefaults(value); + return this; + } + + @Override public YamlConfigurationOptions pathSeparator(char value) { + super.pathSeparator(value); + return this; + } + + @Override public YamlConfigurationOptions header(String value) { + super.header(value); + return this; + } + + @Override public YamlConfigurationOptions copyHeader(boolean value) { + super.copyHeader(value); + return this; + } + + /** + * Gets how much spaces should be used to indent each line. + * + *

The minimum value this may be is 2, and the maximum is 9. + * + * @return How much to indent by + */ + int indent() { + return indent; + } + + /** + * Sets how much spaces should be used to indent each line. + * + *

The minimum value this may be is 2, and the maximum is 9. + * + * @param value New indent + * @return This object, for chaining + */ + public YamlConfigurationOptions indent(int value) { + if (value < 2) { + throw new IllegalArgumentException("Indent must be at least 2 characters"); + } + if (value > 9) { + throw new IllegalArgumentException("Indent cannot be greater than 9 characters"); + } + + indent = value; + return this; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConstructor.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConstructor.java new file mode 100644 index 000000000..cdc5eb821 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlConstructor.java @@ -0,0 +1,46 @@ +package com.github.intellectualsites.plotsquared.configuration.file; + +import com.github.intellectualsites.plotsquared.configuration.serialization.ConfigurationSerialization; +import org.yaml.snakeyaml.constructor.SafeConstructor; +import org.yaml.snakeyaml.error.YAMLException; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.nodes.Tag; + +import java.util.LinkedHashMap; +import java.util.Map; + +class YamlConstructor extends SafeConstructor { + + YamlConstructor() { + yamlConstructors.put(Tag.MAP, new ConstructCustomObject()); + } + + private class ConstructCustomObject extends ConstructYamlMap { + @Override public Object construct(final Node node) { + if (node.isTwoStepsConstruction()) { + throw new YAMLException("Unexpected referential mapping structure. Node: " + node); + } + + final Map raw = (Map) super.construct(node); + + if (raw.containsKey(ConfigurationSerialization.SERIALIZED_TYPE_KEY)) { + final Map typed = new LinkedHashMap<>(raw.size()); + for (final Map.Entry entry : raw.entrySet()) { + typed.put(entry.getKey().toString(), entry.getValue()); + } + + try { + return ConfigurationSerialization.deserializeObject(typed); + } catch (final IllegalArgumentException ex) { + throw new YAMLException("Could not deserialize object", ex); + } + } + + return raw; + } + + @Override public void construct2ndStep(final Node node, final Object object) { + throw new YAMLException("Unexpected referential mapping structure. Node: " + node); + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlRepresenter.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlRepresenter.java new file mode 100644 index 000000000..ebe1aebee --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/file/YamlRepresenter.java @@ -0,0 +1,40 @@ +package com.github.intellectualsites.plotsquared.configuration.file; + +import com.github.intellectualsites.plotsquared.configuration.ConfigurationSection; +import com.github.intellectualsites.plotsquared.configuration.serialization.ConfigurationSerializable; +import com.github.intellectualsites.plotsquared.configuration.serialization.ConfigurationSerialization; +import org.yaml.snakeyaml.nodes.Node; +import org.yaml.snakeyaml.representer.Representer; + +import java.util.LinkedHashMap; +import java.util.Map; + +class YamlRepresenter extends Representer { + + YamlRepresenter() { + this.multiRepresenters.put(ConfigurationSection.class, new RepresentConfigurationSection()); + this.multiRepresenters + .put(ConfigurationSerializable.class, new RepresentConfigurationSerializable()); + } + + private class RepresentConfigurationSection extends RepresentMap { + + @Override public Node representData(Object data) { + return super.representData(((ConfigurationSection) data).getValues(false)); + } + } + + + private class RepresentConfigurationSerializable extends RepresentMap { + + @Override public Node representData(Object data) { + ConfigurationSerializable serializable = (ConfigurationSerializable) data; + Map values = new LinkedHashMap<>(); + values.put(ConfigurationSerialization.SERIALIZED_TYPE_KEY, + ConfigurationSerialization.getAlias(serializable.getClass())); + values.putAll(serializable.serialize()); + + return super.representData(values); + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/ConfigurationSerializable.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/ConfigurationSerializable.java new file mode 100644 index 000000000..f83e7a468 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/ConfigurationSerializable.java @@ -0,0 +1,34 @@ +package com.github.intellectualsites.plotsquared.configuration.serialization; + +import java.util.Map; + +/** + * Represents an object that may be serialized. + *

These objects MUST implement one of the following, in addition to + * the methods as defined by this interface: + *

    + *
  • A static method "deserialize" that accepts a single {@link Map}< + * {@link String}, {@link Object}> and returns the class.
  • + *
  • A static method "valueOf" that accepts a single {@link Map}<{@link + * String}, {@link Object}> and returns the class.
  • + *
  • A constructor that accepts a single {@link Map}<{@link String}, + * {@link Object}>.
  • + *
+ * In addition to implementing this interface, you must register the class + * with {@link ConfigurationSerialization#registerClass(Class)}. + * + * @see DelegateDeserialization + * @see SerializableAs + */ +public interface ConfigurationSerializable { + + /** + * Creates a Map representation of this class. + * + *

This class must provide a method to restore this class, as defined in + * the {@link ConfigurationSerializable} interface javadoc. + * + * @return Map containing the current state of this class + */ + Map serialize(); +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/ConfigurationSerialization.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/ConfigurationSerialization.java new file mode 100644 index 000000000..0783b4af5 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/ConfigurationSerialization.java @@ -0,0 +1,262 @@ +package com.github.intellectualsites.plotsquared.configuration.serialization; + +import com.github.intellectualsites.plotsquared.configuration.Configuration; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Utility class for storing and retrieving classes for {@link Configuration}. + */ +public class ConfigurationSerialization { + + public static final String SERIALIZED_TYPE_KEY = "=="; + private static final Map> aliases = + new HashMap<>(); + private final Class clazz; + + protected ConfigurationSerialization(Class clazz) { + this.clazz = clazz; + } + + /** + * Attempts to deserialize the given arguments into a new instance of the + * given class. + *

+ *

The class must implement {@link ConfigurationSerializable}, including + * the extra methods as specified in the javadoc of + * ConfigurationSerializable.

+ *

+ *

If a new instance could not be made, an example being the class not + * fully implementing the interface, null will be returned.

+ * + * @param args Arguments for deserialization + * @param clazz Class to deserialize into + * @return New instance of the specified class + */ + public static ConfigurationSerializable deserializeObject(Map args, + Class clazz) { + return new ConfigurationSerialization(clazz).deserialize(args); + } + + /** + * Attempts to deserialize the given arguments into a new instance of the + *

+ * given class. + *

+ * The class must implement {@link ConfigurationSerializable}, including + * the extra methods as specified in the javadoc of + * ConfigurationSerializable.

+ *

+ *

+ * If a new instance could not be made, an example being the class not + * fully implementing the interface, null will be returned.

+ * + * @param args Arguments for deserialization + * @return New instance of the specified class + */ + public static ConfigurationSerializable deserializeObject(Map args) { + Class clazz = null; + + if (args.containsKey(SERIALIZED_TYPE_KEY)) { + try { + String alias = (String) args.get(SERIALIZED_TYPE_KEY); + + if (alias == null) { + throw new IllegalArgumentException("Cannot have null alias"); + } + clazz = getClassByAlias(alias); + if (clazz == null) { + throw new IllegalArgumentException( + "Specified class does not exist ('" + alias + "')"); + } + } catch (ClassCastException ex) { + ex.fillInStackTrace(); + throw ex; + } + } else { + throw new IllegalArgumentException( + "Args doesn't contain type key ('" + SERIALIZED_TYPE_KEY + "')"); + } + + return new ConfigurationSerialization(clazz).deserialize(args); + } + + /** + * Registers the given {@link ConfigurationSerializable} class by its + * alias. + * + * @param clazz Class to register + */ + public static void registerClass(Class clazz) { + DelegateDeserialization delegate = clazz.getAnnotation(DelegateDeserialization.class); + + if (delegate == null) { + registerClass(clazz, getAlias(clazz)); + registerClass(clazz, clazz.getName()); + } + } + + /** + * Registers the given alias to the specified {@link + * ConfigurationSerializable} class. + * + * @param clazz Class to register + * @param alias Alias to register as + * @see SerializableAs + */ + public static void registerClass(Class clazz, + String alias) { + aliases.put(alias, clazz); + } + + /** + * Unregisters the specified alias to a {@link ConfigurationSerializable} + * + * @param alias Alias to unregister + */ + public static void unregisterClass(String alias) { + aliases.remove(alias); + } + + /** + * Unregisters any aliases for the specified {@link + * ConfigurationSerializable} class. + * + * @param clazz Class to unregister + */ + public static void unregisterClass(Class clazz) { + while (aliases.values().remove(clazz)) { + } + } + + /** + * Attempts to get a registered {@link ConfigurationSerializable} class by + * its alias. + * + * @param alias Alias of the serializable + * @return Registered class, or null if not found + */ + public static Class getClassByAlias(String alias) { + return aliases.get(alias); + } + + /** + * Gets the correct alias for the given {@link ConfigurationSerializable} + * class. + * + * @param clazz Class to get alias for + * @return Alias to use for the class + */ + public static String getAlias(Class clazz) { + DelegateDeserialization delegate = clazz.getAnnotation(DelegateDeserialization.class); + + if (delegate != null) { + if (delegate.value() == clazz) { + delegate = null; + } else { + return getAlias(delegate.value()); + } + } + + SerializableAs alias = clazz.getAnnotation(SerializableAs.class); + + if (alias != null) { + return alias.value(); + } + + return clazz.getName(); + } + + protected Method getMethod(String name, boolean isStatic) { + try { + Method method = this.clazz.getDeclaredMethod(name, Map.class); + + if (!ConfigurationSerializable.class.isAssignableFrom(method.getReturnType())) { + return null; + } + if (Modifier.isStatic(method.getModifiers()) != isStatic) { + return null; + } + + return method; + } catch (NoSuchMethodException | SecurityException ignored) { + return null; + } + } + + protected Constructor getConstructor() { + try { + return this.clazz.getConstructor(Map.class); + } catch (NoSuchMethodException | SecurityException ignored) { + return null; + } + } + + protected ConfigurationSerializable deserializeViaMethod(Method method, Map args) { + try { + ConfigurationSerializable result = + (ConfigurationSerializable) method.invoke(null, args); + + if (result == null) { + Logger.getLogger(ConfigurationSerialization.class.getName()).log(Level.SEVERE, + "Could not call method '" + method.toString() + "' of " + this.clazz + + " for deserialization: method returned null"); + } else { + return result; + } + } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException ex) { + Logger.getLogger(ConfigurationSerialization.class.getName()).log(Level.SEVERE, + "Could not call method '" + method.toString() + "' of " + this.clazz + + " for deserialization", + ex instanceof InvocationTargetException ? ex.getCause() : ex); + } + + return null; + } + + protected ConfigurationSerializable deserializeViaCtor( + Constructor ctor, Map args) { + try { + return ctor.newInstance(args); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | InstantiationException ex) { + Logger.getLogger(ConfigurationSerialization.class.getName()).log(Level.SEVERE, + "Could not call constructor '" + ctor.toString() + "' of " + this.clazz + + " for deserialization", + ex instanceof InvocationTargetException ? ex.getCause() : ex); + } + + return null; + } + + public ConfigurationSerializable deserialize(Map args) { + if (args == null) { + throw new NullPointerException("Args must not be null"); + } + ConfigurationSerializable result = null; + Method method = getMethod("deserialize", true); + if (method != null) { + result = deserializeViaMethod(method, args); + } + if (result == null) { + method = getMethod("valueOf", true); + if (method != null) { + result = deserializeViaMethod(method, args); + } + } + if (result == null) { + Constructor constructor = getConstructor(); + if (constructor != null) { + result = deserializeViaCtor(constructor, args); + } + } + + return result; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/DelegateDeserialization.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/DelegateDeserialization.java new file mode 100644 index 000000000..8a071cb2e --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/DelegateDeserialization.java @@ -0,0 +1,21 @@ +package com.github.intellectualsites.plotsquared.configuration.serialization; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Applies to a {@link ConfigurationSerializable} that will delegate all + * deserialization to another {@link ConfigurationSerializable}. + */ +@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) +public @interface DelegateDeserialization { + /** + * Which class should be used as a delegate for this classes + * deserialization + * + * @return Delegate class + */ + Class value(); +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/SerializableAs.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/SerializableAs.java new file mode 100644 index 000000000..79b50998c --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/configuration/serialization/SerializableAs.java @@ -0,0 +1,32 @@ +package com.github.intellectualsites.plotsquared.configuration.serialization; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Represents an "alias" that a {@link ConfigurationSerializable} may be + * stored as. + * If this is not present on a {@link ConfigurationSerializable} class, it + * will use the fully qualified name of the class. + *

+ * This value will be stored in the configuration so that the configuration + * deserialization can determine what type it is. + *

+ * Using this annotation on any other class than a {@link + * ConfigurationSerializable} will have no effect. + * + * @see ConfigurationSerialization#registerClass(Class, String) + */ +@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface SerializableAs { + /** + * This is the name your class will be stored and retrieved as. + *

+ * This name MUST be unique. We recommend using names such as + * "MyPluginThing" instead of "Thing". + * + * @return Name to serialize the class as. + */ + String value(); +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONArray.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONArray.java new file mode 100644 index 000000000..62ee01329 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONArray.java @@ -0,0 +1,815 @@ +package com.github.intellectualsites.plotsquared.json; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; + +/** + * A JSONArray is an ordered sequence of values. Its external text form is a string wrapped in square brackets with + * commas separating the values. The internal form is an object having {@code get} and {@code opt} methods for + * accessing the values by index, and {@code put} methods for adding or replacing values. The values can be any of + * these types: {@code Boolean}, {@code JSONArray}, {@code JSONObject}, {@code Number}, + * {@code String}, or the {@code JSONObject.NULL object}. + * + *

The constructor can convert a JSON text into a Java object. The {@code toString} method converts to JSON text. + * + *

A {@code get} method returns a value if one can be found, and throws an exception if one cannot be found. An + * {@code opt} method returns a default value instead of throwing an exception, and so is useful for obtaining + * optional values. + * + *

The generic {@code get()} and {@code opt()} methods return an object which you can cast or query for type. + * There are also typed {@code get} and {@code opt} methods that do type checking and type coercion for you. + * + *

The texts produced by the {@code toString} methods strictly conform to JSON syntax rules. The constructors are + * more forgiving in the texts they will accept:

  • An extra {@code ,} (comma) may appear + * just before the closing bracket.
  • The {@code null} value will be inserted when there is {@code ,} + *  (comma) elision.
  • Strings may be quoted with {@code '} (single + * quote).
  • Strings do not need to be quoted at all if they do not begin with a quote or single quote, + * and if they do not contain leading or trailing spaces, and if they do not contain any of these characters: {@code { } + * [ ] / \ : , #} and if they do not look like numbers and if they are not the reserved words {@code true}, + * {@code false}, or {@code null}.
+ * + * @author JSON.org + * @version 2014-05-03 + */ +public class JSONArray { + /** + * The arrayList where the JSONArray's properties are kept. + */ + private final ArrayList myArrayList; + + /** + * Construct an empty JSONArray. + */ + public JSONArray() { + this.myArrayList = new ArrayList(); + } + + /** + * Construct a JSONArray from a JSONTokener. + * + * @param x A JSONTokener + * @throws JSONException If there is a syntax error. + */ + public JSONArray(JSONTokener x) throws JSONException { + this(); + if (x.nextClean() != '[') { + throw x.syntaxError("A JSONArray text must start with '['"); + } + if (x.nextClean() != ']') { + x.back(); + for (; ; ) { + if (x.nextClean() == ',') { + x.back(); + this.myArrayList.add(JSONObject.NULL); + } else { + x.back(); + this.myArrayList.add(x.nextValue()); + } + switch (x.nextClean()) { + case ',': + if (x.nextClean() == ']') { + return; + } + x.back(); + break; + case ']': + return; + default: + throw x.syntaxError("Expected a ',' or ']'"); + } + } + } + } + + /** + * Construct a JSONArray from a source JSON text. + * + * @param source A string that begins with {@code [} (left bracket) and ends with + * {@code ]}  (right bracket). + * @throws JSONException If there is a syntax error. + */ + public JSONArray(String source) throws JSONException { + this(new JSONTokener(source)); + } + + /** + * Construct a JSONArray from a Collection. + * + * @param collection A Collection. + */ + public JSONArray(Collection collection) { + this.myArrayList = new ArrayList(); + if (collection != null) { + for (Object aCollection : collection) { + this.myArrayList.add(JSONObject.wrap(aCollection)); + } + } + } + + /** + * Construct a JSONArray from an array + * + * @throws JSONException If not an array. + */ + public JSONArray(Object array) throws JSONException { + this(); + if (array.getClass().isArray()) { + int length = Array.getLength(array); + for (int i = 0; i < length; i += 1) { + this.put(JSONObject.wrap(Array.get(array, i))); + } + } else { + throw new JSONException( + "JSONArray initial value should be a string or collection or array."); + } + } + + /** + * Get the object value associated with an index. + * + * @param index The index must be between 0 and length() - 1. + * @return An object value. + * @throws JSONException If there is no value for the index. + */ + public Object get(int index) throws JSONException { + Object object = opt(index); + if (object == null) { + throw new JSONException("JSONArray[" + index + "] not found."); + } + return object; + } + + /** + * Get the boolean value associated with an index. The string values "true" and "false" are converted to boolean. + * + * @param index The index must be between 0 and length() - 1. + * @return The truth. + * @throws JSONException If there is no value for the index or if the value is not convertible to boolean. + */ + public boolean getBoolean(int index) throws JSONException { + Object object = get(index); + if (object.equals(Boolean.FALSE) || ((object instanceof String) && ((String) object) + .equalsIgnoreCase("false"))) { + return false; + } else if (object.equals(Boolean.TRUE) || ((object instanceof String) && ((String) object) + .equalsIgnoreCase("true"))) { + return true; + } + throw new JSONException("JSONArray[" + index + "] is not a boolean."); + } + + /** + * Get the double value associated with an index. + * + * @param index The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException If the key is not found or if the value cannot be converted to a number. + */ + public double getDouble(int index) throws JSONException { + Object object = get(index); + try { + return object instanceof Number ? + ((Number) object).doubleValue() : + Double.parseDouble((String) object); + } catch (NumberFormatException ignored) { + throw new JSONException("JSONArray[" + index + "] is not a number."); + } + } + + /** + * Get the int value associated with an index. + * + * @param index The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException If the key is not found or if the value is not a number. + */ + public int getInt(int index) throws JSONException { + Object object = get(index); + try { + return object instanceof Number ? + ((Number) object).intValue() : + Integer.parseInt((String) object); + } catch (NumberFormatException ignored) { + throw new JSONException("JSONArray[" + index + "] is not a number."); + } + } + + /** + * Get the JSONArray associated with an index. + * + * @param index The index must be between 0 and length() - 1. + * @return A JSONArray value. + * @throws JSONException If there is no value for the index. or if the value is not a JSONArray + */ + public JSONArray getJSONArray(int index) throws JSONException { + Object object = get(index); + if (object instanceof JSONArray) { + return (JSONArray) object; + } + throw new JSONException("JSONArray[" + index + "] is not a JSONArray."); + } + + /** + * Get the JSONObject associated with an index. + * + * @param index subscript + * @return A JSONObject value. + * @throws JSONException If there is no value for the index or if the value is not a JSONObject + */ + public JSONObject getJSONObject(int index) throws JSONException { + Object object = get(index); + if (object instanceof JSONObject) { + return (JSONObject) object; + } + throw new JSONException("JSONArray[" + index + "] is not a JSONObject."); + } + + /** + * Get the long value associated with an index. + * + * @param index The index must be between 0 and length() - 1. + * @return The value. + * @throws JSONException If the key is not found or if the value cannot be converted to a number. + */ + public long getLong(int index) throws JSONException { + Object object = get(index); + try { + return object instanceof Number ? + ((Number) object).longValue() : + Long.parseLong((String) object); + } catch (NumberFormatException ignored) { + throw new JSONException("JSONArray[" + index + "] is not a number."); + } + } + + /** + * Get the string associated with an index. + * + * @param index The index must be between 0 and length() - 1. + * @return A string value. + * @throws JSONException If there is no string value for the index. + */ + public String getString(int index) throws JSONException { + Object object = get(index); + if (object instanceof String) { + return (String) object; + } + throw new JSONException("JSONArray[" + index + "] not a string."); + } + + /** + * Determine if the value is null. + * + * @param index The index must be between 0 and length() - 1. + * @return true if the value at the index is null, or if there is no value. + */ + public boolean isNull(int index) { + return JSONObject.NULL.equals(opt(index)); + } + + /** + * Make a string from the contents of this JSONArray. The {@code separator} string is inserted between each + * element. Warning: This method assumes that the data structure is acyclical. + * + * @param separator A string that will be inserted between the elements. + * @return a string. + * @throws JSONException If the array contains an invalid number. + */ + public String join(String separator) throws JSONException { + int len = length(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < len; i += 1) { + if (i > 0) { + sb.append(separator); + } + sb.append(JSONObject.valueToString(this.myArrayList.get(i))); + } + return sb.toString(); + } + + /** + * Get the number of elements in the JSONArray, included nulls. + * + * @return The length (or size). + */ + public int length() { + return this.myArrayList.size(); + } + + /** + * Get the optional object value associated with an index. + * + * @param index The index must be between 0 and length() - 1. + * @return An object value, or null if there is no object at that index. + */ + public Object opt(int index) { + return ((index < 0) || (index >= length())) ? null : this.myArrayList.get(index); + } + + /** + * Get the optional boolean value associated with an index. It returns false if there is no value at that index, or + * if the value is not Boolean.TRUE or the String "true". + * + * @param index The index must be between 0 and length() - 1. + * @return The truth. + */ + public boolean optBoolean(int index) { + return this.optBoolean(index, false); + } + + /** + * Get the optional boolean value associated with an index. It returns the defaultValue if there is no value at that + * index or if it is not a Boolean or the String "true" or "false" (case insensitive). + * + * @param index The index must be between 0 and length() - 1. + * @param defaultValue A boolean default. + * @return The truth. + */ + public boolean optBoolean(int index, boolean defaultValue) { + try { + return getBoolean(index); + } catch (JSONException ignored) { + return defaultValue; + } + } + + /** + * Get the optional double value associated with an index. NaN is returned if there is no value for the index, or if + * the value is not a number and cannot be converted to a number. + * + * @param index The index must be between 0 and length() - 1. + * @return The value. + */ + public double optDouble(int index) { + return this.optDouble(index, Double.NaN); + } + + /** + * Get the optional double value associated with an index. The defaultValue is returned if there is no value for the + * index, or if the value is not a number and cannot be converted to a number. + * + * @param index subscript + * @param defaultValue The default value. + * @return The value. + */ + public double optDouble(int index, double defaultValue) { + try { + return getDouble(index); + } catch (JSONException ignored) { + return defaultValue; + } + } + + /** + * Get the optional int value associated with an index. Zero is returned if there is no value for the index, or if + * the value is not a number and cannot be converted to a number. + * + * @param index The index must be between 0 and length() - 1. + * @return The value. + */ + public int optInt(int index) { + return this.optInt(index, 0); + } + + /** + * Get the optional int value associated with an index. The defaultValue is returned if there is no value for the + * index, or if the value is not a number and cannot be converted to a number. + * + * @param index The index must be between 0 and length() - 1. + * @param defaultValue The default value. + * @return The value. + */ + public int optInt(int index, int defaultValue) { + try { + return getInt(index); + } catch (JSONException ignored) { + return defaultValue; + } + } + + /** + * Get the optional JSONArray associated with an index. + * + * @param index subscript + * @return A JSONArray value, or null if the index has no value, or if the value is not a JSONArray. + */ + public JSONArray optJSONArray(int index) { + Object o = opt(index); + return o instanceof JSONArray ? (JSONArray) o : null; + } + + /** + * Get the optional JSONObject associated with an index. Null is returned if the key is not found, or null if the + * index has no value, or if the value is not a JSONObject. + * + * @param index The index must be between 0 and length() - 1. + * @return A JSONObject value. + */ + public JSONObject optJSONObject(int index) { + Object o = opt(index); + return o instanceof JSONObject ? (JSONObject) o : null; + } + + /** + * Get the optional long value associated with an index. Zero is returned if there is no value for the index, or if + * the value is not a number and cannot be converted to a number. + * + * @param index The index must be between 0 and length() - 1. + * @return The value. + */ + public long optLong(int index) { + return this.optLong(index, 0); + } + + /** + * Get the optional long value associated with an index. The defaultValue + * is returned if there is no value for the index, or if the value is not a + * number and cannot be converted to a number. + * + * @param index The index must be between 0 and length() - 1. + * @param defaultValue The default value. + * @return The value. + */ + public long optLong(int index, long defaultValue) { + try { + return getLong(index); + } catch (JSONException ignored) { + return defaultValue; + } + } + + /** + * Get the optional string value associated with an index. It returns an + * empty string if there is no value at that index. If the value is not a + * string and is not null, then it is converted to a string. + * + * @param index The index must be between 0 and length() - 1. + * @return A String value. + */ + public String optString(int index) { + return this.optString(index, ""); + } + + /** + * Get the optional string associated with an index. The defaultValue is + * returned if the key is not found. + * + * @param index The index must be between 0 and length() - 1. + * @param defaultValue The default value. + * @return A String value. + */ + public String optString(int index, String defaultValue) { + Object object = opt(index); + return JSONObject.NULL.equals(object) ? defaultValue : object.toString(); + } + + /** + * Append a boolean value. This increases the array's length by one. + * + * @param value A boolean value. + * @return this. + */ + public JSONArray put(boolean value) { + this.put(value ? Boolean.TRUE : Boolean.FALSE); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONArray which + * is produced from a Collection. + * + * @param value A Collection value. + * @return this. + */ + public JSONArray put(Collection value) { + this.put(new JSONArray(value)); + return this; + } + + /** + * Append a double value. This increases the array's length by one. + * + * @param value A double value. + * @return this. + * @throws JSONException if the value is not finite. + */ + public JSONArray put(double value) throws JSONException { + Double d = value; + JSONObject.testValidity(d); + this.put(d); + return this; + } + + /** + * Append an int value. This increases the array's length by one. + * + * @param value An int value. + * @return this. + */ + public JSONArray put(int value) { + this.put(Integer.valueOf(value)); + return this; + } + + /** + * Append an long value. This increases the array's length by one. + * + * @param value A long value. + * @return this. + */ + public JSONArray put(long value) { + this.put(Long.valueOf(value)); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONObject which + * is produced from a Map. + * + * @param value A Map value. + * @return this. + */ + public JSONArray put(Map value) { + this.put(new JSONObject(value)); + return this; + } + + /** + * Append an object value. This increases the array's length by one. + * + * @param value An object value. The value should be a Boolean, Double, + * Integer, JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. + * @return this. + */ + public JSONArray put(Object value) { + this.myArrayList.add(value); + return this; + } + + /** + * Put or replace a boolean value in the JSONArray. If the index is greater than the length of the JSONArray, then + * null elements will be added as necessary to pad it out. + * + * @param index The subscript. + * @param value A boolean value. + * @return this. + * @throws JSONException If the index is negative. + */ + public JSONArray put(int index, boolean value) throws JSONException { + this.put(index, value ? Boolean.TRUE : Boolean.FALSE); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONArray which + * is produced from a Collection. + * + * @param index The subscript. + * @param value A Collection value. + * @return this. + * @throws JSONException If the index is negative or if the value is not + * finite. + */ + public JSONArray put(int index, Collection value) throws JSONException { + this.put(index, new JSONArray(value)); + return this; + } + + /** + * Put or replace a double value. If the index is greater than the length + * of the JSONArray, then null elements will be added as necessary to pad + * it out. + * + * @param index The subscript. + * @param value A double value. + * @return this. + * @throws JSONException If the index is negative or if the value is not + * finite. + */ + public JSONArray put(int index, double value) throws JSONException { + this.put(index, new Double(value)); + return this; + } + + /** + * Put or replace an int value. If the index is greater than the length of the JSONArray, then null elements will be + * added as necessary to pad it out. + * + * @param index The subscript. + * @param value An int value. + * @return this. + * @throws JSONException If the index is negative. + */ + public JSONArray put(int index, int value) throws JSONException { + this.put(index, Integer.valueOf(value)); + return this; + } + + /** + * Put or replace a long value. If the index is greater than the length of the JSONArray, then null elements will be + * added as necessary to pad it out. + * + * @param index The subscript. + * @param value A long value. + * @return this. + * @throws JSONException If the index is negative. + */ + public JSONArray put(int index, long value) throws JSONException { + this.put(index, Long.valueOf(value)); + return this; + } + + /** + * Put a value in the JSONArray, where the value will be a JSONObject that + * is produced from a Map. + * + * @param index The subscript. + * @param value The Map value. + * @return this. + * @throws JSONException If the index is negative or if the the value is an + * invalid number. + */ + public JSONArray put(int index, Map value) throws JSONException { + this.put(index, new JSONObject(value)); + return this; + } + + /** + * Put or replace an object value in the JSONArray. If the index is greater than the length of the JSONArray, then + * null elements will be added as necessary to pad it out. + * + * @param index The subscript. + * @param value The value to put into the array. The value should be a Boolean, Double, Integer, JSONArray, + * JSONObject, Long, or String, or the JSONObject.NULL object. + * @return this. + * @throws JSONException If the index is negative or if the the value is an invalid number. + */ + public JSONArray put(int index, Object value) throws JSONException { + JSONObject.testValidity(value); + if (index < 0) { + throw new JSONException("JSONArray[" + index + "] not found."); + } + if (index < length()) { + this.myArrayList.set(index, value); + } else { + while (index != length()) { + this.put(JSONObject.NULL); + } + this.put(value); + } + return this; + } + + /** + * Remove an index and close the hole. + * + * @param index The index of the element to be removed. + * @return The value that was associated with the index, or null if there was no value. + */ + public Object remove(int index) { + return (index >= 0) && (index < length()) ? this.myArrayList.remove(index) : null; + } + + /** + * Determine if two JSONArrays are similar. They must contain similar sequences. + * + * @param other The other JSONArray + * @return true if they are equal + */ + public boolean similar(Object other) { + if (!(other instanceof JSONArray)) { + return false; + } + int len = length(); + if (len != ((JSONArray) other).length()) { + return false; + } + for (int i = 0; i < len; i += 1) { + Object valueThis = get(i); + Object valueOther = ((JSONArray) other).get(i); + if (valueThis instanceof JSONObject) { + if (!((JSONObject) valueThis).similar(valueOther)) { + return false; + } + } else if (valueThis instanceof JSONArray) { + if (!((JSONArray) valueThis).similar(valueOther)) { + return false; + } + } else if (!valueThis.equals(valueOther)) { + return false; + } + } + return true; + } + + /** + * Produce a JSONObject by combining a JSONArray of names with the values of this JSONArray. + * + * @param names A JSONArray containing a list of key strings. These will be paired with the values. + * @return A JSONObject, or null if there are no names or if this JSONArray has no values. + * @throws JSONException If any of the names are null. + */ + public JSONObject toJSONObject(JSONArray names) throws JSONException { + if ((names == null) || (names.length() == 0) || (length() == 0)) { + return null; + } + JSONObject jo = new JSONObject(); + for (int i = 0; i < names.length(); i += 1) { + jo.put(names.getString(i), opt(i)); + } + return jo; + } + + /** + * Make a JSON text of this JSONArray. For compactness, no unnecessary whitespace is added. If it is not possible to + * produce a syntactically correct JSON text then null will be returned instead. This could occur if the array + * contains an invalid number. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return a printable, displayable, transmittable representation of the array. + */ + @Override public String toString() { + try { + return this.toString(0); + } catch (JSONException ignored) { + return null; + } + } + + /** + * Make a prettyprinted JSON text of this JSONArray. Warning: This method assumes that the data structure is + * acyclical. + * + * @param indentFactor The number of spaces to add to each level of indentation. + * @return a printable, displayable, transmittable representation of the object, beginning with + * {@code [} (left bracket) and ending with {@code ]}  (right + * bracket). + * @throws JSONException + */ + public String toString(int indentFactor) throws JSONException { + StringWriter sw = new StringWriter(); + synchronized (sw.getBuffer()) { + return this.write(sw, indentFactor, 0).toString(); + } + } + + /** + * Write the contents of the JSONArray as JSON text to a writer. For compactness, no whitespace is added. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return The writer. + * @throws JSONException + */ + public Writer write(Writer writer) throws JSONException { + return this.write(writer, 0, 0); + } + + /** + * Write the contents of the JSONArray as JSON text to a writer. For compactness, no whitespace is added. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @param indentFactor The number of spaces to add to each level of indentation. + * @param indent The indention of the top level. + * @return The writer. + * @throws JSONException + */ + Writer write(Writer writer, int indentFactor, int indent) throws JSONException { + try { + boolean commanate = false; + int length = length(); + writer.write('['); + if (length == 1) { + JSONObject.writeValue(writer, this.myArrayList.get(0), indentFactor, indent); + } else if (length != 0) { + int newindent = indent + indentFactor; + for (int i = 0; i < length; i += 1) { + if (commanate) { + writer.write(','); + } + if (indentFactor > 0) { + writer.write('\n'); + } + JSONObject.indent(writer, newindent); + JSONObject.writeValue(writer, this.myArrayList.get(i), indentFactor, newindent); + commanate = true; + } + if (indentFactor > 0) { + writer.write('\n'); + } + JSONObject.indent(writer, indent); + } + writer.write(']'); + return writer; + } catch (IOException e) { + throw new JSONException(e); + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONException.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONException.java new file mode 100644 index 000000000..67de10815 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONException.java @@ -0,0 +1,40 @@ +package com.github.intellectualsites.plotsquared.json; + +/** + * The JSONException is thrown by the JSON.org classes when things are amiss. + * + * @author JSON.org + * @version 2014-05-03 + */ +public class JSONException extends RuntimeException { + private static final long serialVersionUID = 0; + private Throwable cause; + + /** + * Constructs a JSONException with an explanatory message. + * + * @param message Detail about the reason for the exception. + */ + public JSONException(final String message) { + super(message); + } + + /** + * Constructs a new JSONException with the specified cause. + * + * @param cause The cause. + */ + public JSONException(final Throwable cause) { + super(cause.getMessage()); + this.cause = cause; + } + + /** + * Returns the cause of this exception or null if the cause is nonexistent or unknown. + * + * @return the cause of this exception or null if the cause is nonexistent or unknown. + */ + @Override public Throwable getCause() { + return cause; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONObject.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONObject.java new file mode 100644 index 000000000..9a84920dc --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONObject.java @@ -0,0 +1,1425 @@ +package com.github.intellectualsites.plotsquared.json; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.Map.Entry; + +/** + * A JSONObject is an unordered collection of name/value pairs. Its external form is a string wrapped in curly braces + * with colons between the names and values, and commas between the values and names. The internal form is an object + * having get and opt methods for accessing the values by name, and put methods + * for adding or replacing values by name. The values can be any of these types: Boolean, + * JSONArray, JSONObject, Number, String, or the + * JSONObject.NULL object. A JSONObject constructor can be used to convert an external form JSON text into + * an internal form whose values can be retrieved with the get and opt methods, or to convert + * values into a JSON text using the put and toString methods. A get method + * returns a value if one can be found, and throws an exception if one cannot be found. An opt method + * returns a default value instead of throwing an exception, and so is useful for obtaining optional values. + *

+ * The generic get() and opt() methods return an object, which you can cast or query for type. + * There are also typed get and opt methods that do type checking and type coercion for you. + * The opt methods differ from the get methods in that they do not throw. Instead, they return a specified value, such + * as null. + *

+ * The put methods add or replace values in an object. For example, + * + * + *

+ * myString = new JSONObject().put("JSON", "Hello, World!").toString();
+ * 
+ *

+ * produces the string {"JSON": "Hello, World"}. + *

+ * The texts produced by the toString methods strictly conform to the JSON syntax rules. The constructors + * are more forgiving in the texts they will accept:

  • An extra , (comma) may + * appear just before the closing brace.
  • Strings may be quoted with ' (single + * quote).
  • Strings do not need to be quoted at all if they do not begin with a quote or single quote, + * and if they do not contain leading or trailing spaces, and if they do not contain any of these characters: { } + * [ ] / \ : , # and if they do not look like numbers and if they are not the reserved words true, + * false, or null.
+ * + * @author JSON.org + * @version 2014-05-03 + */ +public class JSONObject { + /** + * It is sometimes more convenient and less ambiguous to have a NULL object than to use Java's + * null value. JSONObject.NULL.equals(null) returns true. + * JSONObject.NULL.toString() returns "null". + */ + public static final Object NULL = new Null(); + /** + * The map where the JSONObject's properties are kept. + */ + private final Map map; + + /** + * Construct an empty JSONObject. + */ + public JSONObject() { + this.map = new HashMap(); + } + + /** + * Construct a JSONObject from a subset of another JSONObject. An array of strings is used to identify the keys that + * should be copied. Missing keys are ignored. + * + * @param jo A JSONObject. + * @param names An array of strings. + * @throws JSONException + * @throws JSONException If a value is a non-finite number or if a name is duplicated. + */ + public JSONObject(JSONObject jo, String[] names) { + this(); + for (String name : names) { + try { + putOnce(name, jo.opt(name)); + } catch (JSONException ignore) { + } + } + } + + /** + * Construct a JSONObject from a JSONTokener. + * + * @param x A JSONTokener object containing the source string. + * @throws JSONException If there is a syntax error in the source string or a duplicated key. + */ + public JSONObject(JSONTokener x) throws JSONException { + this(); + char c; + String key; + if (x.nextClean() != '{') { + throw x.syntaxError("A JSONObject text must begin with '{'"); + } + for (; ; ) { + c = x.nextClean(); + switch (c) { + case 0: + throw x.syntaxError("A JSONObject text must end with '}'"); + case '}': + return; + default: + x.back(); + key = x.nextValue().toString(); + } + // The key is followed by ':'. + c = x.nextClean(); + if (c != ':') { + throw x.syntaxError("Expected a ':' after a key"); + } + putOnce(key, x.nextValue()); + // Pairs are separated by ','. + switch (x.nextClean()) { + case ';': + case ',': + if (x.nextClean() == '}') { + return; + } + x.back(); + break; + case '}': + return; + default: + throw x.syntaxError("Expected a ',' or '}'"); + } + } + } + + /** + * Construct a JSONObject from a Map. + * + * @param map A map object that can be used to initialize the contents of the JSONObject. + * @throws JSONException + */ + public JSONObject(Map map) { + this.map = new HashMap(); + if (map != null) { + for (Entry entry : map.entrySet()) { + Object value = entry.getValue(); + if (value != null) { + this.map.put(entry.getKey(), wrap(value)); + } + } + } + } + + /** + * Construct a JSONObject from an Object using bean getters. It reflects on all of the public methods of the object. + * For each of the methods with no parameters and a name starting with "get" or "is" + * followed by an uppercase letter, the method is invoked, and a key and the value returned from the getter method + * are put into the new JSONObject. + *

+ * The key is formed by removing the "get" or "is" prefix. If the second remaining + * character is not upper case, then the first character is converted to lower case. + *

+ * For example, if an object has a method named "getPluginName", and if the result of calling + * object.getPluginName() is "Larry Fine", then the JSONObject will contain "name": "Larry + * Fine". + * + * @param bean An object that has getter methods that should be used to make a JSONObject. + */ + public JSONObject(Object bean) { + this(); + populateMap(bean); + } + + /** + * Construct a JSONObject from an Object, using reflection to find the public members. The resulting JSONObject's + * keys will be the strings from the names array, and the values will be the field values associated with those keys + * in the object. If a key is not found or not visible, then it will not be copied into the new JSONObject. + * + * @param object An object that has fields that should be used to make a JSONObject. + * @param names An array of strings, the names of the fields to be obtained from the object. + */ + public JSONObject(Object object, String names[]) { + this(); + Class c = object.getClass(); + for (String name : names) { + try { + putOpt(name, c.getField(name).get(object)); + } catch (JSONException | SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException ignore) { + } + } + } + + /** + * Construct a JSONObject from a source JSON text string. This is the most commonly used JSONObject constructor. + * + * @param source A string beginning with { (left brace) and ending with + * }  (right brace). + * @throws JSONException If there is a syntax error in the source string or a duplicated key. + */ + public JSONObject(String source) throws JSONException { + this(new JSONTokener(source)); + } + + /** + * Construct a JSONObject from a ResourceBundle. + * + * @param baseName The ResourceBundle base name. + * @param locale The Locale to load the ResourceBundle for. + * @throws JSONException If any JSONExceptions are detected. + */ + public JSONObject(String baseName, Locale locale) throws JSONException { + this(); + ResourceBundle bundle = ResourceBundle + .getBundle(baseName, locale, Thread.currentThread().getContextClassLoader()); + // Iterate through the keys in the bundle. + Enumeration keys = bundle.getKeys(); + while (keys.hasMoreElements()) { + Object key = keys.nextElement(); + if (key != null) { + // Go through the path, ensuring that there is a nested + // JSONObject for each + // segment except the last. Add the value using the last + // segment's name into + // the deepest nested JSONObject. + String[] path = ((String) key).split("\\."); + int last = path.length - 1; + JSONObject target = this; + for (int i = 0; i < last; i += 1) { + String segment = path[i]; + JSONObject nextTarget = target.optJSONObject(segment); + if (nextTarget == null) { + nextTarget = new JSONObject(); + target.put(segment, nextTarget); + } + target = nextTarget; + } + target.put(path[last], bundle.getString((String) key)); + } + } + } + + /** + * Produce a string from a double. The string "null" will be returned if the number is not finite. + * + * @param d A double. + * @return A String. + */ + public static String doubleToString(double d) { + if (Double.isInfinite(d) || Double.isNaN(d)) { + return "null"; + } + // Shave off trailing zeros and decimal point, if possible. + String string = Double.toString(d); + if ((string.indexOf('.') > 0) && (string.indexOf('e') < 0) && (string.indexOf('E') < 0)) { + while (string.endsWith("0")) { + string = string.substring(0, string.length() - 1); + } + if (string.endsWith(".")) { + string = string.substring(0, string.length() - 1); + } + } + return string; + } + + /** + * Get an array of field names from a JSONObject. + * + * @return An array of field names, or null if there are no names. + */ + public static String[] getNames(JSONObject jo) { + int length = jo.length(); + if (length == 0) { + return null; + } + Iterator iterator = jo.keys(); + String[] names = new String[length]; + int i = 0; + while (iterator.hasNext()) { + names[i] = iterator.next(); + i += 1; + } + return names; + } + + /** + * Get an array of field names from an Object. + * + * @return An array of field names, or null if there are no names. + */ + public static String[] getNames(Object object) { + if (object == null) { + return null; + } + Class klass = object.getClass(); + Field[] fields = klass.getFields(); + int length = fields.length; + if (length == 0) { + return null; + } + String[] names = new String[length]; + for (int i = 0; i < length; i += 1) { + names[i] = fields[i].getName(); + } + return names; + } + + /** + * Produce a string from a Number. + * + * @param number A Number + * @return A String. + * @throws JSONException If n is a non-finite number. + */ + public static String numberToString(Number number) throws JSONException { + if (number == null) { + throw new JSONException("Null pointer"); + } + testValidity(number); + // Shave off trailing zeros and decimal point, if possible. + String string = number.toString(); + if ((string.indexOf('.') > 0) && (string.indexOf('e') < 0) && (string.indexOf('E') < 0)) { + while (string.endsWith("0")) { + string = string.substring(0, string.length() - 1); + } + if (string.endsWith(".")) { + string = string.substring(0, string.length() - 1); + } + } + return string; + } + + /** + * Produce a string in double quotes with backslash sequences in all the right places. A backslash will be inserted + * control character or an unescaped quote or backslash. + * + * @param string A String + * @return A String correctly formatted for insertion in a JSON text. + */ + public static String quote(String string) { + StringWriter sw = new StringWriter(); + synchronized (sw.getBuffer()) { + try { + return quote(string, sw).toString(); + } catch (IOException ignored) { + // will never happen - we are writing to a string writer + return ""; + } + } + } + + public static Writer quote(String string, Writer w) throws IOException { + if ((string == null) || string.isEmpty()) { + w.write("\"\""); + return w; + } + char b; + char c = 0; + String hhhh; + int i; + int len = string.length(); + w.write('"'); + for (i = 0; i < len; i += 1) { + b = c; + c = string.charAt(i); + switch (c) { + case '\\': + case '"': + w.write('\\'); + w.write(c); + break; + case '/': + if (b == '<') { + w.write('\\'); + } + w.write(c); + break; + case '\b': + w.write("\\b"); + break; + case '\t': + w.write("\\t"); + break; + case '\n': + w.write("\\n"); + break; + case '\f': + w.write("\\f"); + break; + case '\r': + w.write("\\r"); + break; + default: + if ((c < ' ') || ((c >= '\u0080') && (c < '\u00a0')) || ((c >= '\u2000') && (c + < '\u2100'))) { + w.write("\\u"); + hhhh = Integer.toHexString(c); + w.write("0000", 0, 4 - hhhh.length()); + w.write(hhhh); + } else { + w.write(c); + } + } + } + w.write('"'); + return w; + } + + /** + * Try to convert a string into a number, boolean, or null. If the string can't be converted, return the string. + * + * @param string A String. + * @return A simple JSON value. + */ + public static Object stringToValue(String string) { + Double d; + if (string.isEmpty()) { + return string; + } + if (string.equalsIgnoreCase("true")) { + return Boolean.TRUE; + } + if (string.equalsIgnoreCase("false")) { + return Boolean.FALSE; + } + if (string.equalsIgnoreCase("null")) { + return JSONObject.NULL; + } + /* + * If it might be a number, try converting it. If a number cannot be + * produced, then the value will just be a string. + */ + char b = string.charAt(0); + if (((b >= '0') && (b <= '9')) || (b == '-')) { + try { + if ((string.indexOf('.') > -1) || (string.indexOf('e') > -1) || (string.indexOf('E') + > -1)) { + d = Double.valueOf(string); + if (!d.isInfinite() && !d.isNaN()) { + return d; + } + } else { + Long myLong = Long.valueOf(string); + if (string.equals(myLong.toString())) { + if (myLong == myLong.intValue()) { + return myLong.intValue(); + } else { + return myLong; + } + } + } + } catch (NumberFormatException ignore) { + } + } + return string; + } + + /** + * Throw an exception if the object is a NaN or infinite number. + * + * @param o The object to test. + * @throws JSONException If o is a non-finite number. + */ + public static void testValidity(Object o) throws JSONException { + if (o != null) { + if (o instanceof Double) { + if (((Double) o).isInfinite() || ((Double) o).isNaN()) { + throw new JSONException("JSON does not allow non-finite numbers."); + } + } else if (o instanceof Float) { + if (((Float) o).isInfinite() || ((Float) o).isNaN()) { + throw new JSONException("JSON does not allow non-finite numbers."); + } + } + } + } + + /** + * Make a JSON text of an Object value. If the object has an value.toJSONString() method, then that method will be + * used to produce the JSON text. The method is required to produce a strictly conforming text. If the object does + * not contain a toJSONString method (which is the most common case), then a text will be produced by other means. + * If the value is an array or Collection, then a JSONArray will be made from it and its toJSONString method will be + * called. If the value is a MAP, then a JSONObject will be made from it and its toJSONString method will be called. + * Otherwise, the value's toString method will be called, and the result will be quoted. + *

+ *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @param value The value to be serialized. + * @return a printable, displayable, transmittable representation of the object, beginning with + * { (left brace) and ending with } (right + * brace). + * @throws JSONException If the value is or contains an invalid number. + */ + public static String valueToString(Object value) throws JSONException { + if ((value == null) || value.equals(null)) { + return "null"; + } + if (value instanceof JSONString) { + Object object; + try { + object = ((JSONString) value).toJSONString(); + } catch (Exception e) { + throw new JSONException(e); + } + if (object != null) { + return (String) object; + } + throw new JSONException("Bad value from toJSONString: " + object); + } + if (value instanceof Number) { + return numberToString((Number) value); + } + if ((value instanceof Boolean) || (value instanceof JSONObject) + || (value instanceof JSONArray)) { + return value.toString(); + } + if (value instanceof Map) { + return new JSONObject((Map) value).toString(); + } + if (value instanceof Collection) { + return new JSONArray((Collection) value).toString(); + } + if (value.getClass().isArray()) { + return new JSONArray(value).toString(); + } + return quote(value.toString()); + } + + /** + * Wrap an object, if necessary. If the object is null, return the NULL object. If it is an array or collection, + * wrap it in a JSONArray. If it is a map, wrap it in a JSONObject. If it is a standard property (Double, String, et + * al) then it is already wrapped. Otherwise, if it comes from one of the java packages, turn it into a string. And + * if it doesn't, try to wrap it in a JSONObject. If the wrapping fails, then null is returned. + * + * @param object The object to wrap + * @return The wrapped value + */ + public static Object wrap(Object object) { + try { + if (object == null) { + return NULL; + } + if ((object instanceof JSONObject) || (object instanceof JSONArray) || NULL + .equals(object) || (object instanceof JSONString) || (object instanceof Byte) + || (object instanceof Character) || (object instanceof Short) + || (object instanceof Integer) || (object instanceof Long) + || (object instanceof Boolean) || (object instanceof Float) + || (object instanceof Double) || (object instanceof String)) { + return object; + } + if (object instanceof Collection) { + return new JSONArray((Collection) object); + } + if (object.getClass().isArray()) { + return new JSONArray(object); + } + if (object instanceof Map) { + return new JSONObject((Map) object); + } + Package objectPackage = object.getClass().getPackage(); + String objectPackageName = objectPackage != null ? objectPackage.getName() : ""; + if (objectPackageName.startsWith("java.") || objectPackageName.startsWith("javax.") || ( + object.getClass().getClassLoader() == null)) { + return object.toString(); + } + return new JSONObject(object); + } catch (JSONException ignored) { + return null; + } + } + + static final Writer writeValue(Writer writer, Object value, int indentFactor, int indent) + throws JSONException, IOException { + if ((value == null) || value.equals(null)) { + writer.write("null"); + } else if (value instanceof JSONObject) { + ((JSONObject) value).write(writer, indentFactor, indent); + } else if (value instanceof JSONArray) { + ((JSONArray) value).write(writer, indentFactor, indent); + } else if (value instanceof Map) { + new JSONObject((Map) value).write(writer, indentFactor, indent); + } else if (value instanceof Collection) { + new JSONArray((Collection) value).write(writer, indentFactor, indent); + } else if (value.getClass().isArray()) { + new JSONArray(value).write(writer, indentFactor, indent); + } else if (value instanceof Number) { + writer.write(numberToString((Number) value)); + } else if (value instanceof Boolean) { + writer.write(value.toString()); + } else if (value instanceof JSONString) { + Object o; + try { + o = ((JSONString) value).toJSONString(); + } catch (Exception e) { + throw new JSONException(e); + } + writer.write(o != null ? o.toString() : quote(value.toString())); + } else { + quote(value.toString(), writer); + } + return writer; + } + + static final void indent(Writer writer, int indent) throws IOException { + for (int i = 0; i < indent; i += 1) { + writer.write(' '); + } + } + + /** + * Accumulate values under a key. It is similar to the put method except that if there is already an object stored + * under the key then a JSONArray is stored under the key to hold all of the accumulated values. If there is already + * a JSONArray, then the new value is appended to it. In contrast, the put method replaces the previous value. + *

+ * If only one value is accumulated that is not a JSONArray, then the result will be the same as using put. But if + * multiple values are accumulated, then the result will be like append. + * + * @param key A key string. + * @param value An object to be accumulated under the key. + * @return this. + * @throws JSONException If the value is an invalid number or if the key is null. + */ + public JSONObject accumulate(String key, Object value) throws JSONException { + testValidity(value); + Object object = opt(key); + if (object == null) { + this.put(key, value instanceof JSONArray ? new JSONArray().put(value) : value); + } else if (object instanceof JSONArray) { + ((JSONArray) object).put(value); + } else { + this.put(key, new JSONArray().put(object).put(value)); + } + return this; + } + + /** + * Append values to the array under a key. If the key does not exist in the JSONObject, then the key is put in the + * JSONObject with its value being a JSONArray containing the value parameter. If the key was already associated + * with a JSONArray, then the value parameter is appended to it. + * + * @param key A key string. + * @param value An object to be accumulated under the key. + * @return this. + * @throws JSONException If the key is null or if the current value associated with the key is not a JSONArray. + */ + public JSONObject append(String key, Object value) throws JSONException { + testValidity(value); + Object object = opt(key); + if (object == null) { + this.put(key, new JSONArray().put(value)); + } else if (object instanceof JSONArray) { + this.put(key, ((JSONArray) object).put(value)); + } else { + throw new JSONException("JSONObject[" + key + "] is not a JSONArray."); + } + return this; + } + + /** + * Get the value object associated with a key. + * + * @param key A key string. + * @return The object associated with the key. + * @throws JSONException if the key is not found. + */ + public Object get(String key) throws JSONException { + if (key == null) { + throw new JSONException("Null key."); + } + Object object = opt(key); + if (object == null) { + throw new JSONException("JSONObject[" + quote(key) + "] not found."); + } + return object; + } + + /** + * Get the boolean value associated with a key. + * + * @param key A key string. + * @return The truth. + * @throws JSONException if the value is not a Boolean or the String "true" or "false". + */ + public boolean getBoolean(String key) throws JSONException { + Object object = get(key); + if (object.equals(Boolean.FALSE) || ((object instanceof String) && ((String) object) + .equalsIgnoreCase("false"))) { + return false; + } else if (object.equals(Boolean.TRUE) || ((object instanceof String) && ((String) object) + .equalsIgnoreCase("true"))) { + return true; + } + throw new JSONException("JSONObject[" + quote(key) + "] is not a Boolean."); + } + + /** + * Get the double value associated with a key. + * + * @param key A key string. + * @return The numeric value. + * @throws JSONException if the key is not found or if the value is not a Number object and cannot be converted to a + * number. + */ + public double getDouble(String key) throws JSONException { + Object object = get(key); + try { + return object instanceof Number ? + ((Number) object).doubleValue() : + Double.parseDouble((String) object); + } catch (NumberFormatException ignored) { + throw new JSONException("JSONObject[" + quote(key) + "] is not a number."); + } + } + + /** + * Get the int value associated with a key. + * + * @param key A key string. + * @return The integer value. + * @throws JSONException if the key is not found or if the value cannot be converted to an integer. + */ + public int getInt(String key) throws JSONException { + Object object = get(key); + try { + return object instanceof Number ? + ((Number) object).intValue() : + Integer.parseInt((String) object); + } catch (NumberFormatException ignored) { + throw new JSONException("JSONObject[" + quote(key) + "] is not an int."); + } + } + + /** + * Get the JSONArray value associated with a key. + * + * @param key A key string. + * @return A JSONArray which is the value. + * @throws JSONException if the key is not found or if the value is not a JSONArray. + */ + public JSONArray getJSONArray(String key) throws JSONException { + Object object = get(key); + if (object instanceof JSONArray) { + return (JSONArray) object; + } + throw new JSONException("JSONObject[" + quote(key) + "] is not a JSONArray."); + } + + /** + * Get the JSONObject value associated with a key. + * + * @param key A key string. + * @return A JSONObject which is the value. + * @throws JSONException if the key is not found or if the value is not a JSONObject. + */ + public JSONObject getJSONObject(String key) throws JSONException { + Object object = get(key); + if (object instanceof JSONObject) { + return (JSONObject) object; + } + throw new JSONException("JSONObject[" + quote(key) + "] is not a JSONObject."); + } + + /** + * Get the long value associated with a key. + * + * @param key A key string. + * @return The long value. + * @throws JSONException if the key is not found or if the value cannot be converted to a long. + */ + public long getLong(String key) throws JSONException { + Object object = get(key); + try { + return object instanceof Number ? + ((Number) object).longValue() : + Long.parseLong((String) object); + } catch (NumberFormatException ignored) { + throw new JSONException("JSONObject[" + quote(key) + "] is not a long."); + } + } + + /** + * Get the string associated with a key. + * + * @param key A key string. + * @return A string which is the value. + * @throws JSONException if there is no string value for the key. + */ + public String getString(String key) throws JSONException { + Object object = get(key); + if (object instanceof String) { + return (String) object; + } + throw new JSONException("JSONObject[" + quote(key) + "] not a string."); + } + + /** + * Determine if the JSONObject contains a specific key. + * + * @param key A key string. + * @return true if the key exists in the JSONObject. + */ + public boolean has(String key) { + return this.map.containsKey(key); + } + + /** + * Increment a property of a JSONObject. If there is no such property, create one with a value of 1. If there is + * such a property, and if it is an Integer, Long, Double, or Float, then add one to it. + * + * @param key A key string. + * @return this. + * @throws JSONException If there is already a property with this name that is not an Integer, Long, Double, or + * Float. + */ + public JSONObject increment(String key) throws JSONException { + Object value = opt(key); + if (value == null) { + this.put(key, 1); + } else if (value instanceof Integer) { + this.put(key, (Integer) value + 1); + } else if (value instanceof Long) { + this.put(key, (Long) value + 1); + } else if (value instanceof Double) { + this.put(key, (Double) value + 1); + } else if (value instanceof Float) { + this.put(key, (Float) value + 1); + } else { + throw new JSONException("Unable to increment [" + quote(key) + "]."); + } + return this; + } + + /** + * Determine if the value associated with the key is null or if there is no value. + * + * @param key A key string. + * @return true if there is no value associated with the key or if the value is the JSONObject.NULL object. + */ + public boolean isNull(String key) { + return JSONObject.NULL.equals(opt(key)); + } + + /** + * Get an enumeration of the keys of the JSONObject. + * + * @return An iterator of the keys. + */ + public Iterator keys() { + return keySet().iterator(); + } + + /** + * Get a set of keys of the JSONObject. + * + * @return A keySet. + */ + public Set keySet() { + return this.map.keySet(); + } + + /** + * Get the number of keys stored in the JSONObject. + * + * @return The number of keys in the JSONObject. + */ + public int length() { + return this.map.size(); + } + + /** + * Produce a JSONArray containing the names of the elements of this JSONObject. + * + * @return A JSONArray containing the key strings, or null if the JSONObject is empty. + */ + public JSONArray names() { + JSONArray ja = new JSONArray(); + Iterator keys = keys(); + while (keys.hasNext()) { + ja.put(keys.next()); + } + return ja.length() == 0 ? null : ja; + } + + /** + * Get an optional value associated with a key. + * + * @param key A key string. + * @return An object which is the value, or null if there is no value. + */ + public Object opt(String key) { + return key == null ? null : this.map.get(key); + } + + /** + * Get an optional boolean associated with a key. It returns false if there is no such key, or if the value is not + * Boolean.TRUE or the String "true". + * + * @param key A key string. + * @return The truth. + */ + public boolean optBoolean(String key) { + return this.optBoolean(key, false); + } + + /** + * Get an optional boolean associated with a key. It returns the defaultValue if there is no such key, or if it is + * not a Boolean or the String "true" or "false" (case insensitive). + * + * @param key A key string. + * @param defaultValue The default. + * @return The truth. + */ + public boolean optBoolean(String key, boolean defaultValue) { + try { + return getBoolean(key); + } catch (JSONException ignored) { + return defaultValue; + } + } + + /** + * Get an optional double associated with a key, or NaN if there is no such key or if its value is not a number. If + * the value is a string, an attempt will be made to evaluate it as a number. + * + * @param key A string which is the key. + * @return An object which is the value. + */ + public double optDouble(String key) { + return this.optDouble(key, Double.NaN); + } + + /** + * Get an optional double associated with a key, or the defaultValue if there is no such key or if its value is not + * a number. If the value is a string, an attempt will be made to evaluate it as a number. + * + * @param key A key string. + * @param defaultValue The default. + * @return An object which is the value. + */ + public double optDouble(String key, double defaultValue) { + try { + return getDouble(key); + } catch (JSONException ignored) { + return defaultValue; + } + } + + /** + * Get an optional int value associated with a key, or zero if there is no such key or if the value is not a number. + * If the value is a string, an attempt will be made to evaluate it as a number. + * + * @param key A key string. + * @return An object which is the value. + */ + public int optInt(String key) { + return this.optInt(key, 0); + } + + /** + * Get an optional int value associated with a key, or the default if there is no such key or if the value is not a + * number. If the value is a string, an attempt will be made to evaluate it as a number. + * + * @param key A key string. + * @param defaultValue The default. + * @return An object which is the value. + */ + public int optInt(String key, int defaultValue) { + try { + return getInt(key); + } catch (JSONException ignored) { + return defaultValue; + } + } + + /** + * Get an optional JSONArray associated with a key. It returns null if there is no such key, or if its value is not + * a JSONArray. + * + * @param key A key string. + * @return A JSONArray which is the value. + */ + public JSONArray optJSONArray(String key) { + Object o = opt(key); + return o instanceof JSONArray ? (JSONArray) o : null; + } + + /** + * Get an optional JSONObject associated with a key. It returns null if there is no such key, or if its value is not + * a JSONObject. + * + * @param key A key string. + * @return A JSONObject which is the value. + */ + public JSONObject optJSONObject(String key) { + Object object = opt(key); + return object instanceof JSONObject ? (JSONObject) object : null; + } + + /** + * Get an optional long value associated with a key, or zero if there is no such key or if the value is not a + * number. If the value is a string, an attempt will be made to evaluate it as a number. + * + * @param key A key string. + * @return An object which is the value. + */ + public long optLong(String key) { + return this.optLong(key, 0); + } + + /** + * Get an optional long value associated with a key, or the default if there is no such key or if the value is not a + * number. If the value is a string, an attempt will be made to evaluate it as a number. + * + * @param key A key string. + * @param defaultValue The default. + * @return An object which is the value. + */ + public long optLong(String key, long defaultValue) { + try { + return getLong(key); + } catch (JSONException ignored) { + return defaultValue; + } + } + + /** + * Get an optional string associated with a key. It returns an empty string if there is no such key. If the value is + * not a string and is not null, then it is converted to a string. + * + * @param key A key string. + * @return A string which is the value. + */ + public String optString(String key) { + return this.optString(key, ""); + } + + /** + * Get an optional string associated with a key. It returns the defaultValue if there is no such key. + * + * @param key A key string. + * @param defaultValue The default. + * @return A string which is the value. + */ + public String optString(String key, String defaultValue) { + Object object = opt(key); + return NULL.equals(object) ? defaultValue : object.toString(); + } + + private void populateMap(Object bean) { + Class klass = bean.getClass(); + // If klass is a System class then set includeSuperClass to false. + boolean includeSuperClass = klass.getClassLoader() != null; + Method[] methods = includeSuperClass ? klass.getMethods() : klass.getDeclaredMethods(); + for (Method method : methods) { + try { + if (Modifier.isPublic(method.getModifiers())) { + String name = method.getName(); + String key = ""; + if (name.startsWith("get")) { + if ("getClass".equals(name) || "getDeclaringClass".equals(name)) { + key = ""; + } else { + key = name.substring(3); + } + } else if (name.startsWith("is")) { + key = name.substring(2); + } + if (!key.isEmpty() && Character.isUpperCase(key.charAt(0)) && ( + method.getParameterTypes().length == 0)) { + if (key.length() == 1) { + key = key.toLowerCase(); + } else if (!Character.isUpperCase(key.charAt(1))) { + key = key.substring(0, 1).toLowerCase() + key.substring(1); + } + Object result = method.invoke(bean, (Object[]) null); + if (result != null) { + this.map.put(key, wrap(result)); + } + } + } + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ignore) { + } + } + } + + /** + * Put a key/boolean pair in the JSONObject. + * + * @param key A key string. + * @param value A boolean which is the value. + * @return this. + * @throws JSONException If the key is null. + */ + public JSONObject put(String key, boolean value) throws JSONException { + this.put(key, value ? Boolean.TRUE : Boolean.FALSE); + return this; + } + + /** + * Put a key/value pair in the JSONObject, where the value will be a JSONArray which is produced from a Collection. + * + * @param key A key string. + * @param value A Collection value. + * @return this. + * @throws JSONException + */ + public JSONObject put(String key, Collection value) throws JSONException { + this.put(key, new JSONArray(value)); + return this; + } + + /** + * Put a key/double pair in the JSONObject. + * + * @param key A key string. + * @param value A double which is the value. + * @return this. + * @throws JSONException If the key is null or if the number is invalid. + */ + public JSONObject put(String key, double value) throws JSONException { + this.put(key, new Double(value)); + return this; + } + + /** + * Put a key/int pair in the JSONObject. + * + * @param key A key string. + * @param value An int which is the value. + * @return this. + * @throws JSONException If the key is null. + */ + public JSONObject put(String key, int value) throws JSONException { + this.put(key, Integer.valueOf(value)); + return this; + } + + /** + * Put a key/long pair in the JSONObject. + * + * @param key A key string. + * @param value A long which is the value. + * @return this. + * @throws JSONException If the key is null. + */ + public JSONObject put(String key, long value) throws JSONException { + this.put(key, Long.valueOf(value)); + return this; + } + + /** + * Put a key/value pair in the JSONObject, where the value will be a JSONObject which is produced from a Map. + * + * @param key A key string. + * @param value A Map value. + * @return this. + * @throws JSONException + */ + public JSONObject put(String key, Map value) throws JSONException { + this.put(key, new JSONObject(value)); + return this; + } + + /** + * Put a key/value pair in the JSONObject. If the value is null, then the key will be removed from the JSONObject if + * it is present. + * + * @param key A key string. + * @param value An object which is the value. It should be of one of these types: Boolean, Double, Integer, + * JSONArray, JSONObject, Long, String, or the JSONObject.NULL object. + * @return this. + * @throws JSONException If the value is non-finite number or if the key is null. + */ + public JSONObject put(String key, Object value) throws JSONException { + if (key == null) { + throw new NullPointerException("Null key."); + } + if (value != null) { + testValidity(value); + this.map.put(key, value); + } else { + remove(key); + } + return this; + } + + /** + * Put a key/value pair in the JSONObject, but only if the key and the value are both non-null, and only if there is + * not already a member with that name. + * + * @param key string + * @param value object + * @return this. + * @throws JSONException if the key is a duplicate + */ + public JSONObject putOnce(String key, Object value) throws JSONException { + if ((key != null) && (value != null)) { + if (opt(key) != null) { + throw new JSONException("Duplicate key \"" + key + "\""); + } + this.put(key, value); + } + return this; + } + + /** + * Put a key/value pair in the JSONObject, but only if the key and the value are both non-null. + * + * @param key A key string. + * @param value An object which is the value. It should be of one of these types: Boolean, Double, Integer, + * JSONArray, JSONObject, Long, String, or the JSONObject.NULL object. + * @return this. + * @throws JSONException If the value is a non-finite number. + */ + public JSONObject putOpt(String key, Object value) throws JSONException { + if ((key != null) && (value != null)) { + this.put(key, value); + } + return this; + } + + /** + * Remove a name and its value, if present. + * + * @param key The name to be removed. + * @return The value that was associated with the name, or null if there was no value. + */ + public Object remove(String key) { + return this.map.remove(key); + } + + /** + * Determine if two JSONObjects are similar. They must contain the same set of names which must be associated with + * similar values. + * + * @param other The other JSONObject + * @return true if they are equal + */ + public boolean similar(Object other) { + try { + if (!(other instanceof JSONObject)) { + return false; + } + Set set = keySet(); + if (!set.equals(((JSONObject) other).keySet())) { + return false; + } + for (String name : set) { + Object valueThis = get(name); + Object valueOther = ((JSONObject) other).get(name); + if (valueThis instanceof JSONObject) { + if (!((JSONObject) valueThis).similar(valueOther)) { + return false; + } + } else if (valueThis instanceof JSONArray) { + if (!((JSONArray) valueThis).similar(valueOther)) { + return false; + } + } else if (!valueThis.equals(valueOther)) { + return false; + } + } + return true; + } catch (JSONException ignored) { + return false; + } + } + + /** + * Produce a JSONArray containing the values of the members of this JSONObject. + * + * @param names A JSONArray containing a list of key strings. This determines the sequence of the values in the + * result. + * @return A JSONArray of values. + * @throws JSONException If any of the values are non-finite numbers. + */ + public JSONArray toJSONArray(JSONArray names) throws JSONException { + if ((names == null) || (names.length() == 0)) { + return null; + } + JSONArray ja = new JSONArray(); + for (int i = 0; i < names.length(); i += 1) { + ja.put(opt(names.getString(i))); + } + return ja; + } + + /** + * Make a JSON text of this JSONObject. For compactness, no whitespace is added. If this would not result in a + * syntactically correct JSON text, then null will be returned instead. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return a printable, displayable, portable, transmittable representation of the object, beginning with + * { (left brace) and ending with } (right + * brace). + */ + @Override public String toString() { + try { + return this.toString(0); + } catch (JSONException ignored) { + return null; + } + } + + /** + * Make a prettyprinted JSON text of this JSONObject. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @param indentFactor The number of spaces to add to each level of indentation. + * @return a printable, displayable, portable, transmittable representation of the object, beginning with + * { (left brace) and ending with } (right + * brace). + * @throws JSONException If the object contains an invalid number. + */ + public String toString(int indentFactor) throws JSONException { + StringWriter w = new StringWriter(); + synchronized (w.getBuffer()) { + return this.write(w, indentFactor, 0).toString(); + } + } + + /** + * Write the contents of the JSONObject as JSON text to a writer. For compactness, no whitespace is added. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return The writer. + * @throws JSONException + */ + public Writer write(Writer writer) throws JSONException { + return this.write(writer, 0, 0); + } + + /** + * Write the contents of the JSONObject as JSON text to a writer. For compactness, no whitespace is added. + *

+ * Warning: This method assumes that the data structure is acyclical. + * + * @return The writer. + * @throws JSONException + */ + Writer write(Writer writer, int indentFactor, int indent) throws JSONException { + try { + boolean commanate = false; + int length = length(); + Iterator keys = keys(); + writer.write('{'); + if (length == 1) { + Object key = keys.next(); + writer.write(quote(key.toString())); + writer.write(':'); + if (indentFactor > 0) { + writer.write(' '); + } + writeValue(writer, this.map.get(key), indentFactor, indent); + } else if (length != 0) { + int newindent = indent + indentFactor; + while (keys.hasNext()) { + Object key = keys.next(); + if (commanate) { + writer.write(','); + } + if (indentFactor > 0) { + writer.write('\n'); + } + indent(writer, newindent); + writer.write(quote(key.toString())); + writer.write(':'); + if (indentFactor > 0) { + writer.write(' '); + } + writeValue(writer, this.map.get(key), indentFactor, newindent); + commanate = true; + } + if (indentFactor > 0) { + writer.write('\n'); + } + indent(writer, indent); + } + writer.write('}'); + return writer; + } catch (IOException exception) { + throw new JSONException(exception); + } + } + + /** + * JSONObject.NULL is equivalent to the value that JavaScript calls null, whilst Java's null is equivalent to the + * value that JavaScript calls undefined. + */ + private static final class Null { + /** + * There is only intended to be a single instance of the NULL object, so the clone method returns itself. + * + * @return NULL. + */ + @Override protected final Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException ignored) { + return this; + } + } + + /** + * A Null object is equal to the null value and to itself. + * + * @param object An object to test for nullness. + * @return true if the object parameter is the JSONObject.NULL object or null. + */ + @Override public boolean equals(Object object) { + return (object == null) || (object == this); + } + + /** + * Get the "null" string value. + * + * @return The string "null". + */ + @Override public String toString() { + return "null"; + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONString.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONString.java new file mode 100644 index 000000000..019776e58 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONString.java @@ -0,0 +1,16 @@ +package com.github.intellectualsites.plotsquared.json; + +/** + * The JSONString interface allows a toJSONString() method so that a class can change the + * behavior of JSONObject.toString(), JSONArray.toString(), and + * JSONWriter.value(Object). The toJSONString method will be used instead of the + * default behavior of using the Object's toString() method and quoting the result. + */ +public interface JSONString { + /** + * The toJSONString method allows a class to produce its own JSON serialization. + * + * @return A strictly syntactically correct JSON text. + */ + String toJSONString(); +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONTokener.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONTokener.java new file mode 100644 index 000000000..290b9ea0b --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/JSONTokener.java @@ -0,0 +1,384 @@ +package com.github.intellectualsites.plotsquared.json; + +import java.io.*; + +/** + * A JSONTokener takes a source string and extracts characters and tokens from it. It is used by the JSONObject and + * JSONArray constructors to parse JSON source strings. + * + * @author JSON.org + * @version 2014-05-03 + */ +public class JSONTokener { + private final Reader reader; + private long character; + private boolean eof; + private long index; + private long line; + private char previous; + private boolean usePrevious; + + /** + * Construct a JSONTokener from a Reader. + * + * @param reader A reader. + */ + public JSONTokener(final Reader reader) { + this.reader = reader.markSupported() ? reader : new BufferedReader(reader); + eof = false; + usePrevious = false; + previous = 0; + index = 0; + character = 1; + line = 1; + } + + /** + * Construct a JSONTokener from an InputStream. + * + * @param inputStream The source. + */ + public JSONTokener(final InputStream inputStream) throws JSONException { + this(new InputStreamReader(inputStream)); + } + + /** + * Construct a JSONTokener from a string. + * + * @param s A source string. + */ + public JSONTokener(final String s) { + this(new StringReader(s)); + } + + /** + * Get the hex value of a character (base16). + * + * @param c A character between '0' and '9' or between 'A' and 'F' or between 'a' and 'f'. + * @return An int between 0 and 15, or -1 if c was not a hex digit. + */ + public static int dehexchar(final char c) { + if ((c >= '0') && (c <= '9')) { + return c - '0'; + } + if ((c >= 'A') && (c <= 'F')) { + return c - ('A' - 10); + } + if ((c >= 'a') && (c <= 'f')) { + return c - ('a' - 10); + } + return -1; + } + + /** + * Back up one character. This provides a sort of lookahead capability, so that you can test for a digit or letter + * before attempting to parse the next number or identifier. + */ + public void back() throws JSONException { + if (usePrevious || (index <= 0)) { + throw new JSONException("Stepping back two steps is not supported"); + } + index -= 1; + character -= 1; + usePrevious = true; + eof = false; + } + + public boolean end() { + return eof && !usePrevious; + } + + /** + * Determine if the source string still contains characters that next() can consume. + * + * @return true if not yet at the end of the source. + */ + public boolean more() throws JSONException { + this.next(); + if (end()) { + return false; + } + back(); + return true; + } + + /** + * Get the next character in the source string. + * + * @return The next character, or 0 if past the end of the source string. + */ + public char next() throws JSONException { + int c; + if (usePrevious) { + usePrevious = false; + c = previous; + } else { + try { + c = reader.read(); + } catch (final IOException exception) { + throw new JSONException(exception); + } + if (c <= 0) { // End of stream + eof = true; + c = 0; + } + } + index += 1; + if (previous == '\r') { + line += 1; + character = c == '\n' ? 0 : 1; + } else if (c == '\n') { + line += 1; + character = 0; + } else { + character += 1; + } + previous = (char) c; + return previous; + } + + /** + * Consume the next character, and check that it matches a specified character. + * + * @param c The character to match. + * @return The character. + * @throws JSONException if the character does not match. + */ + public char next(final char c) throws JSONException { + final char n = this.next(); + if (n != c) { + throw syntaxError("Expected '" + c + "' and instead saw '" + n + "'"); + } + return n; + } + + /** + * Get the next n characters. + * + * @param n The number of characters to take. + * @return A string of n characters. + * @throws JSONException Substring bounds error if there are not n characters remaining in the source string. + */ + public String next(final int n) throws JSONException { + if (n == 0) { + return ""; + } + final char[] chars = new char[n]; + int pos = 0; + while (pos < n) { + chars[pos] = this.next(); + if (end()) { + throw syntaxError("Substring bounds error"); + } + pos += 1; + } + return new String(chars); + } + + /** + * Get the next char in the string, skipping whitespace. + * + * @return A character, or 0 if there are no more characters. + * @throws JSONException + */ + public char nextClean() throws JSONException { + for (; ; ) { + final char c = this.next(); + if ((c == 0) || (c > ' ')) { + return c; + } + } + } + + /** + * Return the characters up to the next close quote character. Backslash processing is done. The formal JSON format + * does not allow strings in single quotes, but an implementation is allowed to accept them. + * + * @param quote The quoting character, either "  (double quote) or ' + *  (single quote). + * @return A String. + * @throws JSONException Unterminated string. + */ + public String nextString(final char quote) throws JSONException { + char c; + final StringBuilder sb = new StringBuilder(); + for (; ; ) { + c = this.next(); + switch (c) { + case 0: + case '\n': + case '\r': + throw syntaxError("Unterminated string"); + case '\\': + c = this.next(); + switch (c) { + case 'b': + sb.append('\b'); + break; + case 't': + sb.append('\t'); + break; + case 'n': + sb.append('\n'); + break; + case 'f': + sb.append('\f'); + break; + case 'r': + sb.append('\r'); + break; + case 'u': + sb.append((char) Integer.parseInt(this.next(4), 16)); + break; + case '"': + case '\'': + case '\\': + case '/': + sb.append(c); + break; + default: + throw syntaxError("Illegal escape."); + } + break; + default: + if (c == quote) { + return sb.toString(); + } + sb.append(c); + } + } + } + + /** + * Get the text up but not including the specified character or the end of line, whichever comes first. + * + * @param delimiter A delimiter character. + * @return A string. + */ + public String nextTo(final char delimiter) throws JSONException { + final StringBuilder sb = new StringBuilder(); + for (; ; ) { + final char c = this.next(); + if ((c == delimiter) || (c == 0) || (c == '\n') || (c == '\r')) { + if (c != 0) { + back(); + } + return sb.toString().trim(); + } + sb.append(c); + } + } + + /** + * Get the text up but not including one of the specified delimiter characters or the end of line, whichever comes + * first. + * + * @param delimiters A set of delimiter characters. + * @return A string, trimmed. + */ + public String nextTo(final String delimiters) throws JSONException { + char c; + final StringBuilder sb = new StringBuilder(); + for (; ; ) { + c = this.next(); + if ((delimiters.indexOf(c) >= 0) || (c == 0) || (c == '\n') || (c == '\r')) { + if (c != 0) { + back(); + } + return sb.toString().trim(); + } + sb.append(c); + } + } + + /** + * Get the next value. The value can be a Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the + * JSONObject.NULL object. + * + * @return An object. + * @throws JSONException If syntax error. + */ + public Object nextValue() throws JSONException { + char c = nextClean(); + String string; + switch (c) { + case '"': + case '\'': + return nextString(c); + case '{': + back(); + return new JSONObject(this); + case '[': + back(); + return new JSONArray(this); + } + /* + * Handle unquoted text. This could be the values true, false, or + * null, or it can be a number. An implementation (such as this one) + * is allowed to also accept non-standard forms. + * Accumulate characters until we reach the end of the text or a + * formatting character. + */ + final StringBuilder sb = new StringBuilder(); + while ((c >= ' ') && (",:]}/\\\"[{;=#".indexOf(c) < 0)) { + sb.append(c); + c = this.next(); + } + back(); + string = sb.toString().trim(); + if (string.isEmpty()) { + throw syntaxError("Missing value"); + } + return JSONObject.stringToValue(string); + } + + /** + * Skip characters until the next character is the requested character. If the requested character is not found, no + * characters are skipped. + * + * @param to A character to skip to. + * @return The requested character, or zero if the requested character is not found. + */ + public char skipTo(final char to) throws JSONException { + char c; + try { + final long startIndex = index; + final long startCharacter = character; + final long startLine = line; + reader.mark(1000000); + do { + c = this.next(); + if (c == 0) { + reader.reset(); + index = startIndex; + character = startCharacter; + line = startLine; + return 0; + } + } while (c != to); + } catch (final IOException exception) { + throw new JSONException(exception); + } + back(); + return c; + } + + /** + * Make a JSONException to signal a syntax error. + * + * @param message The error message. + * @return A JSONException object, suitable for throwing + */ + public JSONException syntaxError(final String message) { + return new JSONException(message + toString()); + } + + /** + * Make a printable string of this JSONTokener. + * + * @return " at {index} [character {character} line {line}]" + */ + @Override public String toString() { + return " at " + index + " [character " + character + " line " + line + "]"; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/Property.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/Property.java new file mode 100644 index 000000000..7ace1989b --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/Property.java @@ -0,0 +1,52 @@ +package com.github.intellectualsites.plotsquared.json; + +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Properties; + +/** + * Converts a Property file data into JSONObject and back. + * + * @author JSON.org + * @version 2014-05-03 + */ +public class Property { + /** + * Converts a property file object into a JSONObject. The property file object is a table of name value pairs. + * + * @param properties java.util.Properties + * @return JSONObject + * @throws JSONException + */ + public static JSONObject toJSONObject(final java.util.Properties properties) + throws JSONException { + final JSONObject jo = new JSONObject(); + if ((properties != null) && !properties.isEmpty()) { + final Enumeration enumProperties = properties.propertyNames(); + while (enumProperties.hasMoreElements()) { + final String name = (String) enumProperties.nextElement(); + jo.put(name, properties.getProperty(name)); + } + } + return jo; + } + + /** + * Converts the JSONObject into a property file object. + * + * @param jo JSONObject + * @return java.util.Properties + * @throws JSONException + */ + public static Properties toProperties(final JSONObject jo) throws JSONException { + final Properties properties = new Properties(); + if (jo != null) { + final Iterator keys = jo.keys(); + while (keys.hasNext()) { + final String name = keys.next(); + properties.put(name, jo.getString(name)); + } + } + return properties; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/XML.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/XML.java new file mode 100644 index 000000000..51a0cdb10 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/XML.java @@ -0,0 +1,375 @@ +package com.github.intellectualsites.plotsquared.json; + +import java.util.Iterator; + +/** + * This provides static methods to convert an XML text into a JSONObject, and to covert a JSONObject into an XML text. + * + * @author JSON.org + * @version 2014-05-03 + */ +class XML { + + static final Character AMP = '&'; + static final Character APOS = '\''; + static final Character BANG = '!'; + static final Character EQ = '='; + static final Character GT = '>'; + static final Character LT = '<'; + static final Character QUEST = '?'; + static final Character QUOT = '"'; + static final Character SLASH = '/'; + + static String escape(String string) { + StringBuilder sb = new StringBuilder(string.length()); + for (int i = 0, length = string.length(); i < length; i++) { + char c = string.charAt(i); + switch (c) { + case '&': + sb.append("&"); + break; + case '<': + sb.append("<"); + break; + case '>': + sb.append(">"); + break; + case '"': + sb.append("""); + break; + case '\'': + sb.append("'"); + break; + default: + sb.append(c); + } + } + return sb.toString(); + } + + /** + * Throw an exception if the string contains whitespace. Whitespace is not allowed in tagNames and attributes. + * + * @param string A string. + * @throws JSONException + */ + static void noSpace(String string) throws JSONException { + int length = string.length(); + if (length == 0) { + throw new JSONException("Empty string."); + } + for (char c : string.toCharArray()) { + if (Character.isWhitespace(c)) { + throw new JSONException('\'' + string + "' contains a space character."); + } + } + } + + /** + * Scan the content following the named tag, attaching it to the context. + * + * @param x The XMLTokener containing the source string. + * @param context The JSONObject that will include the new material. + * @param name The tag name. + * @return true if the close tag is processed. + * @throws JSONException + */ + private static boolean parse(XMLTokener x, JSONObject context, String name) + throws JSONException { + // Test for and skip past these forms: + // + // + // + // + // Report errors for these forms: + // <> + // <= + // << + Object token = x.nextToken(); + // "); + return false; + } + x.back(); + } else if (c == '[') { + token = x.nextToken(); + if ("CDATA".equals(token)) { + if (x.next() == '[') { + string = x.nextCDATA(); + if (!string.isEmpty()) { + context.accumulate("content", string); + } + return false; + } + } + throw x.syntaxError("Expected 'CDATA['"); + } + int i = 1; + do { + token = x.nextMeta(); + if (token == null) { + throw x.syntaxError("Missing '>' after ' 0); + return false; + } else if (token == QUEST) { + // "); + return false; + } else if (token == SLASH) { + // Close tag + } else if (token == SLASH) { + if (x.nextToken() != GT) { + throw x.syntaxError("Misshaped tag"); + } + if (jsonobject.length() > 0) { + context.accumulate(tagName, jsonobject); + } else { + context.accumulate(tagName, ""); + } + return false; + // Content, between <...> and + } else if (token == GT) { + for (; ; ) { + token = x.nextContent(); + if (token == null) { + if (tagName != null) { + throw x.syntaxError("Unclosed tag " + tagName); + } + return false; + } else if (token instanceof String) { + string = (String) token; + if (!string.isEmpty()) { + jsonobject.accumulate("content", XML.stringToValue(string)); + } + // Nested element + } else if (token == LT) { + if (parse(x, jsonobject, tagName)) { + if (jsonobject.length() == 0) { + context.accumulate(tagName, ""); + } else if ((jsonobject.length() == 1) && (jsonobject.opt("content") + != null)) { + context.accumulate(tagName, jsonobject.opt("content")); + } else { + context.accumulate(tagName, jsonobject); + } + return false; + } + } + } + } else { + throw x.syntaxError("Misshaped tag"); + } + } + } + } + + /** + * Try to convert a string into a number, boolean, or null. If the string can't be converted, return the string. + * This is much less ambitious than JSONObject.stringToValue, especially because it does not attempt to convert plus + * forms, octal forms, hex forms, or E forms lacking decimal points. + * + * @param string A String. + * @return A simple JSON value. + */ + static Object stringToValue(String string) { + if ("true".equalsIgnoreCase(string)) { + return Boolean.TRUE; + } + if ("false".equalsIgnoreCase(string)) { + return Boolean.FALSE; + } + if ("null".equalsIgnoreCase(string)) { + return JSONObject.NULL; + } + //If it might be a number, try converting it, first as a Long, and then as a Double. If that doesn't work, return the string. + try { + char initial = string.charAt(0); + if ((initial == '-') || ((initial >= '0') && (initial <= '9'))) { + Long value = Long.valueOf(string); + if (value.toString().equals(string)) { + return value; + } + } + } catch (NumberFormatException ignore) { + try { + Double value = Double.valueOf(string); + if (value.toString().equals(string)) { + return value; + } + } catch (NumberFormatException ignored) { + } + } + return string; + } + + public static JSONObject toJSONObject(String string) throws JSONException { + JSONObject jo = new JSONObject(); + XMLTokener x = new XMLTokener(string); + while (x.more() && x.skipPast("<")) { + parse(x, jo, null); + } + return jo; + } + + /** + * Convert a JSONObject into a well-formed, element-normal XML string. + * + * @param object A JSONObject. + * @return A string. + * @throws JSONException + */ + public static String toString(Object object) throws JSONException { + return toString(object, null); + } + + /** + * Convert a JSONObject into a well-formed, element-normal XML string. + * + * @param object A JSONObject. + * @param tagName The optional name of the enclosing tag. + * @return A string. + * @throws JSONException + */ + public static String toString(Object object, String tagName) throws JSONException { + StringBuilder sb = new StringBuilder(); + int i; + JSONArray ja; + int length; + String string; + if (object instanceof JSONObject) { + // Emit + if (tagName != null) { + sb.append('<'); + sb.append(tagName); + sb.append('>'); + } + // Loop thru the keys. + JSONObject jo = (JSONObject) object; + Iterator keys = jo.keys(); + while (keys.hasNext()) { + String key = keys.next(); + Object value = jo.opt(key); + if (value == null) { + value = ""; + } + string = value instanceof String ? (String) value : null; + // Emit content in body + if ("content".equals(key)) { + if (value instanceof JSONArray) { + ja = (JSONArray) value; + length = ja.length(); + for (i = 0; i < length; i += 1) { + if (i > 0) { + sb.append('\n'); + } + sb.append(escape(ja.get(i).toString())); + } + } else { + sb.append(escape(value.toString())); + } + // Emit an array of similar keys + } else if (value instanceof JSONArray) { + ja = (JSONArray) value; + length = ja.length(); + for (i = 0; i < length; i += 1) { + value = ja.get(i); + if (value instanceof JSONArray) { + sb.append('<'); + sb.append(key); + sb.append('>'); + sb.append(toString(value)); + sb.append("'); + } else { + sb.append(toString(value, key)); + } + } + } else if ("".equals(value)) { + sb.append('<'); + sb.append(key); + sb.append("/>"); + // Emit a new tag + } else { + sb.append(toString(value, key)); + } + } + if (tagName != null) { + // Emit the close tag + sb.append("'); + } + return sb.toString(); + // XML does not have good support for arrays. If an array appears in + // a place + // where XML is lacking, synthesize an element. + } else { + if (object.getClass().isArray()) { + object = new JSONArray(object); + } + if (object instanceof JSONArray) { + ja = (JSONArray) object; + length = ja.length(); + for (i = 0; i < length; i += 1) { + sb.append(toString(ja.opt(i), tagName == null ? "array" : tagName)); + } + return sb.toString(); + } else { + string = escape(object.toString()); + return (tagName == null) ? + '"' + string + '"' : + string.isEmpty() ? + '<' + tagName + "/>" : + '<' + tagName + '>' + string + "'; + } + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/XMLTokener.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/XMLTokener.java new file mode 100644 index 000000000..96d65541f --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/json/XMLTokener.java @@ -0,0 +1,315 @@ +package com.github.intellectualsites.plotsquared.json; + +import java.util.HashMap; + +/** + * The XMLTokener extends the JSONTokener to provide additional methods for the parsing of XML texts. + * + * @author JSON.org + * @version 2014-05-03 + */ +public class XMLTokener extends JSONTokener { + /** + * The table of entity values. It initially contains Character values for amp, apos, gt, lt, quot. + */ + public static final HashMap entity; + + static { + entity = new HashMap<>(8); + entity.put("amp", XML.AMP); + entity.put("apos", XML.APOS); + entity.put("gt", XML.GT); + entity.put("lt", XML.LT); + entity.put("quot", XML.QUOT); + } + + /** + * Construct an XMLTokener from a string. + * + * @param s A source string. + */ + public XMLTokener(final String s) { + super(s); + } + + /** + * Get the text in the CDATA block. + * + * @return The string up to the ]]>. + * @throws JSONException If the ]]> is not found. + */ + public String nextCDATA() throws JSONException { + final StringBuilder sb = new StringBuilder(); + for (; ; ) { + char c = next(); + if (end()) { + throw syntaxError("Unclosed CDATA"); + } + sb.append(c); + int i = sb.length() - 3; + if ((i >= 0) && (sb.charAt(i) == ']') && (sb.charAt(i + 1) == ']') && (sb.charAt(i + 2) + == '>')) { + sb.setLength(i); + return sb.toString(); + } + } + } + + /** + * Get the next XML outer token, trimming whitespace. There are two kinds of tokens: the '<' character which begins + * a markup tag, and the content text between markup tags. + * + * @return A string, or a '<' Character, or null if there is no more source text. + * @throws JSONException + */ + public Object nextContent() throws JSONException { + char c; + do { + c = next(); + } while (Character.isWhitespace(c)); + if (c == 0) { + return null; + } + if (c == '<') { + return XML.LT; + } + StringBuilder sb = new StringBuilder(); + for (; ; ) { + if ((c == '<') || (c == 0)) { + back(); + return sb.toString().trim(); + } + if (c == '&') { + sb.append(nextEntity('&')); + } else { + sb.append(c); + } + c = next(); + } + } + + /** + * Return the next entity. These entities are translated to Characters: & " > < + * ". + * + * @param ampersand An ampersand character. + * @return A Character or an entity String if the entity is not recognized. + * @throws JSONException If missing ';' in XML entity. + */ + public Object nextEntity(final char ampersand) throws JSONException { + final StringBuilder sb = new StringBuilder(); + for (; ; ) { + final char c = next(); + if (Character.isLetterOrDigit(c) || (c == '#')) { + sb.append(Character.toLowerCase(c)); + } else if (c == ';') { + break; + } else { + throw syntaxError("Missing ';' in XML entity: &" + sb); + } + } + final String string = sb.toString(); + final Object object = entity.get(string); + return object != null ? object : ampersand + string + ';'; + } + + /** + * Returns the next XML meta token. This is used for skipping over and structures. + * + * @return Syntax characters (< > / = ! ?) are returned as Character, and strings and names are + * returned as Boolean. We don't care what the values actually are. + * @throws JSONException If a string is not properly closed or if the XML is badly structured. + */ + public Object nextMeta() throws JSONException { + char c; + do { + c = next(); + } while (Character.isWhitespace(c)); + char q; + switch (c) { + case 0: + throw syntaxError("Misshaped meta tag"); + case '<': + return XML.LT; + case '>': + return XML.GT; + case '/': + return XML.SLASH; + case '=': + return XML.EQ; + case '!': + return XML.BANG; + case '?': + return XML.QUEST; + case '"': + case '\'': + q = c; + for (; ; ) { + c = next(); + if (c == 0) { + throw syntaxError("Unterminated string"); + } + if (c == q) { + return Boolean.TRUE; + } + } + default: + for (; ; ) { + c = next(); + if (Character.isWhitespace(c)) { + return Boolean.TRUE; + } + switch (c) { + case 0: + case '<': + case '>': + case '/': + case '=': + case '!': + case '?': + case '"': + case '\'': + back(); + return Boolean.TRUE; + } + } + } + } + + /** + * Get the next XML Token. These tokens are found inside of angle brackets. It may be one of these characters: + * / >= ! ? or it may be a string wrapped in single quotes or double quotes, or it may be a name. + * + * @return a String or a Character. + * @throws JSONException If the XML is not well formed. + */ + public Object nextToken() throws JSONException { + char c; + do { + c = next(); + } while (Character.isWhitespace(c)); + char q; + StringBuilder sb; + switch (c) { + case 0: + throw syntaxError("Misshaped element"); + case '<': + throw syntaxError("Misplaced '<'"); + case '>': + return XML.GT; + case '/': + return XML.SLASH; + case '=': + return XML.EQ; + case '!': + return XML.BANG; + case '?': + return XML.QUEST; + // Quoted string + case '"': + case '\'': + q = c; + sb = new StringBuilder(); + for (; ; ) { + c = next(); + if (c == 0) { + throw syntaxError("Unterminated string"); + } + if (c == q) { + return sb.toString(); + } + if (c == '&') { + sb.append(nextEntity('&')); + } else { + sb.append(c); + } + } + default: + // Name + sb = new StringBuilder(); + for (; ; ) { + sb.append(c); + c = next(); + if (Character.isWhitespace(c)) { + return sb.toString(); + } + switch (c) { + case 0: + return sb.toString(); + case '>': + case '/': + case '=': + case '!': + case '?': + case '[': + case ']': + back(); + return sb.toString(); + case '<': + case '"': + case '\'': + throw syntaxError("Bad character in a name"); + } + } + } + } + + /** + * Skip characters until past the requested string. If it is not found, we are left at the end of the source with a + * result of false. + * + * @param to A string to skip past. + * @throws JSONException + */ + public boolean skipPast(final String to) throws JSONException { + char c; + int i; + final int length = to.length(); + final char[] circle = new char[length]; + /* + * First fill the circle buffer with as many characters as are in the + * to string. If we reach an early end, bail. + */ + for (i = 0; i < length; i += 1) { + c = next(); + if (c == 0) { + return false; + } + circle[i] = c; + } + /* We will loop, possibly for all of the remaining characters. */ + for (int offset = 0; ; ) { + int j = offset; + boolean b = true; + /* Compare the circle buffer with the to string. */ + for (i = 0; i < length; i += 1) { + if (circle[j] != to.charAt(i)) { + b = false; + break; + } + j += 1; + if (j >= length) { + j -= length; + } + } + /* If we exit the loop with b intact, then victory is ours. */ + if (b) { + return true; + } + /* Get the next character. If there isn't one, then defeat is ours. */ + c = next(); + if (c == 0) { + return false; + } + /* + * Shove the character in the circle buffer and advance the + * circle offset. The offset is mod n. + */ + circle[offset] = c; + offset += 1; + if (offset >= length) { + offset -= length; + } + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/IPlotMain.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/IPlotMain.java new file mode 100644 index 000000000..2f6559a4e --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/IPlotMain.java @@ -0,0 +1,285 @@ +package com.github.intellectualsites.plotsquared.plot; + +import com.github.intellectualsites.plotsquared.plot.generator.GeneratorWrapper; +import com.github.intellectualsites.plotsquared.plot.generator.HybridUtils; +import com.github.intellectualsites.plotsquared.plot.generator.IndependentPlotGenerator; +import com.github.intellectualsites.plotsquared.plot.logger.ILogger; +import com.github.intellectualsites.plotsquared.plot.object.BlockRegistry; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.*; +import com.github.intellectualsites.plotsquared.plot.util.block.QueueProvider; + +import java.io.File; +import java.util.List; + +public interface IPlotMain extends ILogger { + + /** + * Log a message to console. + * + * @param message The message to log + */ + void log(String message); + + /** + * Get the `PlotSquared` directory. + * + * @return The plugin directory + */ + File getDirectory(); + + /** + * Get the directory containing all the worlds. + * + * @return The directory containing the worlds + */ + File getWorldContainer(); + + /** + * Wrap a player into a PlotPlayer object. + * + * @param player The player to convert to a PlotPlayer + * @return A PlotPlayer + */ + PlotPlayer wrapPlayer(Object player); + + /** + * Disable the implementation. + * + *

    + *
  • If a full disable isn't feasibly, just disable what it can. + *
+ */ + void disable(); + + /** + * Completely shut down the plugin + */ + void shutdown(); + + /** + * Get the version of the PlotSquared being used. + * + * @return the plugin version + */ + int[] getPluginVersion(); + + /** + * Get the version of the PlotSquared being used as a string. + * + * @return the plugin version as a string + */ + String getPluginVersionString(); + + /** + * Usually PlotSquared + * + * @return + */ + default String getPluginName() { + return "PlotSquared"; + } + + /** + * Get the version of Minecraft that is running. + * + * @return + */ + int[] getServerVersion(); + + /** + * Get the server implementation name and version + */ + String getServerImplementation(); + + /** + * Get the NMS package prefix. + * + * @return The NMS package prefix + */ + String getNMSPackage(); + + /** + * Get the schematic handler. + * + * @return The {@link SchematicHandler} + */ + SchematicHandler initSchematicHandler(); + + /** + * Get the Chat Manager. + * + * @return The {@link ChatManager} + */ + ChatManager initChatManager(); + + /** + * The task manager will run and manage Minecraft tasks. + * + * @return + */ + TaskManager getTaskManager(); + + /** + * Run the task that will kill road mobs. + */ + void runEntityTask(); + + /** + * Register the implementation specific commands. + */ + void registerCommands(); + + /** + * Register the protection system. + */ + void registerPlayerEvents(); + + /** + * Register inventory related events. + */ + void registerInventoryEvents(); + + /** + * Register plot plus related events. + */ + void registerPlotPlusEvents(); + + /** + * Register force field events. + */ + void registerForceFieldEvents(); + + /** + * Register the WorldEdit hook. + */ + boolean initWorldEdit(); + + /** + * Get the economy provider. + * + * @return + */ + EconHandler getEconomyHandler(); + + /** + * Get the {@link QueueProvider} class. + * + * @return + */ + QueueProvider initBlockQueue(); + + /** + * Get the {@link WorldUtil} class. + * + * @return + */ + WorldUtil initWorldUtil(); + + /** + * Get the EventUtil class. + * + * @return + */ + EventUtil initEventUtil(); + + /** + * Get the chunk manager. + * + * @return + */ + ChunkManager initChunkManager(); + + /** + * Get the {@link SetupUtils} class. + * + * @return + */ + SetupUtils initSetupUtils(); + + /** + * Get {@link HybridUtils} class. + * + * @return + */ + HybridUtils initHybridUtils(); + + /** + * Start Metrics. + */ + void startMetrics(); + + /** + * If a world is already loaded, set the generator (use NMS if required). + * + * @param world The world to set the generator + */ + void setGenerator(String world); + + /** + * Get the {@link UUIDHandlerImplementation} which will cache and + * provide UUIDs. + * + * @return + */ + UUIDHandlerImplementation initUUIDHandler(); + + /** + * Get the {@link InventoryUtil} class (used for implementation specific + * inventory guis). + * + * @return + */ + InventoryUtil initInventoryUtil(); + + /** + * Unregister a PlotPlayer from cache e.g. if they have logged off. + * + * @param player + */ + void unregister(PlotPlayer player); + + /** + * Get the generator wrapper for a world (world) and generator (name). + * + * @param world + * @param name + * @return + */ + GeneratorWrapper getGenerator(String world, String name); + + GeneratorWrapper wrapPlotGenerator(String world, IndependentPlotGenerator generator); + + /** + * Register the chunk processor which will clean out chunks that have too + * many blockstates or entities. + */ + void registerChunkProcessor(); + + /** + * Register the world initialization events (used to keep track of worlds + * being generated). + */ + void registerWorldEvents(); + + /** + * Usually HybridGen + * + * @return Default implementation generator + */ + IndependentPlotGenerator getDefaultGenerator(); + + /** + * Get the class that will manage player titles. + * + * @return + */ + AbstractTitle initTitleManager(); + + List getPluginIds(); + + BlockRegistry getBlockRegistry(); + + LegacyMappings getLegacyMappings(); + +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/Platform.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/Platform.java new file mode 100644 index 000000000..9dfbf2ffb --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/Platform.java @@ -0,0 +1,6 @@ +package com.github.intellectualsites.plotsquared.plot; + +public enum Platform { + Bukkit, Sponge, Spigot + +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java new file mode 100644 index 000000000..63bbf8142 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotSquared.java @@ -0,0 +1,2066 @@ +package com.github.intellectualsites.plotsquared.plot; + +import com.github.intellectualsites.plotsquared.configuration.ConfigurationSection; +import com.github.intellectualsites.plotsquared.configuration.MemorySection; +import com.github.intellectualsites.plotsquared.configuration.file.YamlConfiguration; +import com.github.intellectualsites.plotsquared.configuration.serialization.ConfigurationSerialization; +import com.github.intellectualsites.plotsquared.plot.commands.WE_Anywhere; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Configuration; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.config.Storage; +import com.github.intellectualsites.plotsquared.plot.database.*; +import com.github.intellectualsites.plotsquared.plot.generator.GeneratorWrapper; +import com.github.intellectualsites.plotsquared.plot.generator.HybridPlotWorld; +import com.github.intellectualsites.plotsquared.plot.generator.HybridUtils; +import com.github.intellectualsites.plotsquared.plot.generator.IndependentPlotGenerator; +import com.github.intellectualsites.plotsquared.plot.listener.WESubscriber; +import com.github.intellectualsites.plotsquared.plot.logger.ILogger; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.object.worlds.DefaultPlotAreaManager; +import com.github.intellectualsites.plotsquared.plot.object.worlds.PlotAreaManager; +import com.github.intellectualsites.plotsquared.plot.object.worlds.SinglePlotArea; +import com.github.intellectualsites.plotsquared.plot.object.worlds.SinglePlotAreaManager; +import com.github.intellectualsites.plotsquared.plot.util.*; +import com.github.intellectualsites.plotsquared.plot.util.block.GlobalBlockQueue; +import com.github.intellectualsites.plotsquared.plot.util.expiry.ExpireManager; +import com.github.intellectualsites.plotsquared.plot.util.expiry.ExpiryTask; +import com.sk89q.worldedit.WorldEdit; +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; + +import javax.annotation.Nullable; +import java.io.*; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.sql.SQLException; +import java.util.*; +import java.util.Map.Entry; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +/** + * An implementation of the core, with a static getter for easy access. + */ +@SuppressWarnings({"unused", "WeakerAccess"}) public class PlotSquared { + + private static final Set EMPTY_SET = Collections.unmodifiableSet(Collections.emptySet()); + private static PlotSquared instance; + // Implementation + public final IPlotMain IMP; + // Current thread + private final Thread thread; + // WorldEdit instance + public WorldEdit worldedit; + public File styleFile; + public File configFile; + public File worldsFile; + public File commandsFile; + public File translationFile; + public YamlConfiguration style; + public YamlConfiguration config; + public YamlConfiguration worlds; + public YamlConfiguration storage; + public YamlConfiguration commands; + // Temporary hold the plots/clusters before the worlds load + public HashMap> clusters_tmp; + public HashMap> plots_tmp; + // Implementation logger + @Setter @Getter private ILogger logger; + // Platform / Version / Update URL + private PlotVersion version; + // Files and configuration + @Getter private File jarFile = null; // This file + private File storageFile; + @Getter private PlotAreaManager plotAreaManager; + + /** + * Initialize PlotSquared with the desired Implementation class. + * + * @param iPlotMain Implementation of {@link IPlotMain} used + * @param platform The platform being used + */ + public PlotSquared(final IPlotMain iPlotMain, final String platform) { + if (instance != null) { + throw new IllegalStateException("Cannot re-initialize the PlotSquared singleton"); + } + instance = this; + + this.thread = Thread.currentThread(); + this.IMP = iPlotMain; + this.logger = iPlotMain; + Settings.PLATFORM = platform; + + // + // Register configuration serializable classes + // + ConfigurationSerialization.registerClass(PlotBlock.class, "PlotBlock"); + ConfigurationSerialization.registerClass(BlockBucket.class, "BlockBucket"); + + try { + new ReflectionUtils(this.IMP.getNMSPackage()); + try { + URL url = PlotSquared.class.getProtectionDomain().getCodeSource().getLocation(); + this.jarFile = new File( + new URL(url.toURI().toString().split("\\!")[0].replaceAll("jar:file", "file")) + .toURI().getPath()); + } catch (MalformedURLException | URISyntaxException | SecurityException e) { + e.printStackTrace(); + this.jarFile = new File(this.IMP.getDirectory().getParentFile(), "PlotSquared.jar"); + if (!this.jarFile.exists()) { + this.jarFile = new File(this.IMP.getDirectory().getParentFile(), + "PlotSquared-" + platform + ".jar"); + } + } + TaskManager.IMP = this.IMP.getTaskManager(); + + // World Util. Has to be done before config files are loaded + WorldUtil.IMP = this.IMP.initWorldUtil(); + + if (!setupConfigs()) { + return; + } + this.translationFile = MainUtil.getFile(this.IMP.getDirectory(), + Settings.Paths.TRANSLATIONS + File.separator + IMP.getPluginName() + + ".use_THIS.yml"); + C.load(this.translationFile); + + // Setup plotAreaManager + if (Settings.Enabled_Components.WORLDS) { + this.plotAreaManager = new SinglePlotAreaManager(); + } else { + this.plotAreaManager = new DefaultPlotAreaManager(); + } + + // Database + if (Settings.Enabled_Components.DATABASE) { + setupDatabase(); + } + // Comments + CommentManager.registerDefaultInboxes(); + // Kill entities + if (Settings.Enabled_Components.KILL_ROAD_MOBS + || Settings.Enabled_Components.KILL_ROAD_VEHICLES) { + this.IMP.runEntityTask(); + } + if (Settings.Enabled_Components.EVENTS) { + this.IMP.registerPlayerEvents(); + this.IMP.registerInventoryEvents(); + this.IMP.registerPlotPlusEvents(); + } + // Required + this.IMP.registerWorldEvents(); + if (Settings.Enabled_Components.METRICS) { + this.IMP.startMetrics(); + } else { + PlotSquared.log(C.CONSOLE_PLEASE_ENABLE_METRICS.f(IMP.getPluginName())); + } + if (Settings.Enabled_Components.CHUNK_PROCESSOR) { + this.IMP.registerChunkProcessor(); + } + // create UUIDWrapper + UUIDHandler.implementation = this.IMP.initUUIDHandler(); + if (Settings.Enabled_Components.UUID_CACHE) { + startUuidCatching(); + } else { + // Start these separately + UUIDHandler.add(new StringWrapper("*"), DBFunc.EVERYONE); + startExpiryTasks(); + } + // create event util class + EventUtil.manager = this.IMP.initEventUtil(); + // create Hybrid utility class + HybridUtils.manager = this.IMP.initHybridUtils(); + // Inventory utility class + InventoryUtil.manager = this.IMP.initInventoryUtil(); + // create setup util class + SetupUtils.manager = this.IMP.initSetupUtils(); + // Set block + GlobalBlockQueue.IMP = new GlobalBlockQueue(IMP.initBlockQueue(), 1); + GlobalBlockQueue.IMP.runTask(); + // Set chunk + ChunkManager.manager = this.IMP.initChunkManager(); + // Schematic handler + SchematicHandler.manager = this.IMP.initSchematicHandler(); + // Titles + AbstractTitle.TITLE_CLASS = this.IMP.initTitleManager(); + // Chat + ChatManager.manager = this.IMP.initChatManager(); + // Commands + if (Settings.Enabled_Components.COMMANDS) { + this.IMP.registerCommands(); + } + // WorldEdit + if (Settings.Enabled_Components.WORLDEDIT_RESTRICTIONS) { + try { + if (this.IMP.initWorldEdit()) { + PlotSquared.debug(IMP.getPluginName() + " hooked into WorldEdit."); + this.worldedit = WorldEdit.getInstance(); + WorldEdit.getInstance().getEventBus().register(new WESubscriber()); + if (Settings.Enabled_Components.COMMANDS) { + new WE_Anywhere(); + } + + } + } catch (Throwable e) { + PlotSquared.debug( + "Incompatible version of WorldEdit, please upgrade: http://builds.enginehub.org/job/worldedit?branch=master"); + } + } + // Economy + if (Settings.Enabled_Components.ECONOMY) { + TaskManager + .runTask(() -> EconHandler.manager = PlotSquared.this.IMP.getEconomyHandler()); + } + +/* // Check for updates + if (Settings.Enabled_Components.UPDATER) { + updater = new Updater(); + TaskManager.IMP.taskAsync(new Runnable() { + @Override public void run() { + updater.update(getPlatform(), getVersion()); + } + }); + TaskManager.IMP.taskRepeatAsync(new Runnable() { + @Override public void run() { + updater.update(getPlatform(), getVersion()); + } + }, 36000); + }*/ + + // World generators: + final ConfigurationSection section = this.worlds.getConfigurationSection("worlds"); + if (section != null) { + for (String world : section.getKeys(false)) { + if (world.equals("CheckingPlotSquaredGenerator")) { + continue; + } + if (WorldUtil.IMP.isWorld(world)) { + this.IMP.setGenerator(world); + } + } + TaskManager.runTaskLater(() -> { + for (String world : section.getKeys(false)) { + if (world.equals("CheckingPlotSquaredGenerator")) { + continue; + } + if (!WorldUtil.IMP.isWorld(world) && !world.equals("*")) { + debug( + "&c`" + world + "` was not properly loaded - " + IMP.getPluginName() + + " will now try to load it properly: "); + debug( + "&8 - &7Are you trying to delete this world? Remember to remove it from the settings.yml, bukkit.yml and multiverse worlds.yml"); + debug( + "&8 - &7Your world management plugin may be faulty (or non existent)"); + PlotSquared.this.IMP.setGenerator(world); + } + } + }, 1); + } + + // Copy files + copyFile("addplots.js", Settings.Paths.SCRIPTS); + copyFile("addsigns.js", Settings.Paths.SCRIPTS); + copyFile("automerge.js", Settings.Paths.SCRIPTS); + copyFile("furthest.js", Settings.Paths.SCRIPTS); + copyFile("mycommand.js", Settings.Paths.SCRIPTS); + copyFile("setbiomes.js", Settings.Paths.SCRIPTS); + copyFile("start.js", Settings.Paths.SCRIPTS); + copyFile("town.template", Settings.Paths.TEMPLATES); + copyFile("skyblock.template", Settings.Paths.TEMPLATES); + copyFile("bridge.template", Settings.Paths.TEMPLATES); + copyFile("de-DE.yml", Settings.Paths.TRANSLATIONS); + copyFile("es-ES.yml", Settings.Paths.TRANSLATIONS); + copyFile("zh-CN.yml", Settings.Paths.TRANSLATIONS); + copyFile("it-IT.yml", Settings.Paths.TRANSLATIONS); + copyFile("ko-KR.yml", Settings.Paths.TRANSLATIONS); + copyFile("fr-FR.yml", Settings.Paths.TRANSLATIONS); + showDebug(); + } catch (Throwable e) { + e.printStackTrace(); + } + + PlotSquared.log(C.ENABLED.f(IMP.getPluginName())); + } + + /** + * Get an instance of PlotSquared. + * + * @return instance of PlotSquared + */ + public static PlotSquared get() { + return PlotSquared.instance; + } + + public static IPlotMain imp() { + if (instance != null) { + return instance.IMP; + } + return null; + } + + /** + * Log a message to the IPlotMain logger. + * + * @param message Message to log + * @see IPlotMain#log(String) + */ + public static void log(Object message) { + if (message == null || message.toString().isEmpty()) { + return; + } + if (PlotSquared.get() == null || PlotSquared.get().getLogger() == null) { + System.out.printf("[P2][Info] %s\n", StringMan.getString(message)); + } else { + PlotSquared.get().getLogger().log(StringMan.getString(message)); + } + } + + /** + * Log a message to the IPlotMain logger. + * + * @param message Message to log + * @see IPlotMain#log(String) + */ + public static void debug(@Nullable Object message) { + if (Settings.DEBUG) { + if (PlotSquared.get() == null || PlotSquared.get().getLogger() == null) { + System.out.printf("[P2][Debug] %s\n", StringMan.getString(message)); + } else { + PlotSquared.get().getLogger().log(StringMan.getString(message)); + } + } + } + + private void startUuidCatching() { + TaskManager.runTaskLater(() -> { + debug("Starting UUID caching"); + UUIDHandler.startCaching(() -> { + UUIDHandler.add(new StringWrapper("*"), DBFunc.EVERYONE); + foreachPlotRaw(new RunnableVal() { + @Override public void run(Plot plot) { + if (plot.hasOwner() && plot.temp != -1) { + if (UUIDHandler.getName(plot.owner) == null) { + UUIDHandler.implementation.unknown.add(plot.owner); + } + } + } + }); + startExpiryTasks(); + }); + }, 20); + } + + private void startExpiryTasks() { + if (Settings.Enabled_Components.PLOT_EXPIRY) { + ExpireManager.IMP = new ExpireManager(); + ExpireManager.IMP.runAutomatedTask(); + for (Settings.Auto_Clear settings : Settings.AUTO_CLEAR.getInstances()) { + ExpiryTask task = new ExpiryTask(settings); + ExpireManager.IMP.addTask(task); + } + } + } + + public boolean isMainThread(Thread thread) { + return this.thread == thread; + } + + /** + * Check if `version` is >= `version2`. + * + * @param version First version + * @param version2 Second version + * @return true if `version` is >= `version2` + */ + public boolean checkVersion(int[] version, int... version2) { + return version[0] > version2[0] || version[0] == version2[0] && version[1] > version2[1] + || version[0] == version2[0] && version[1] == version2[1] && version[2] >= version2[2]; + } + + /** + * Get the current PlotSquared version. + * + * @return current version in config or null + */ + public PlotVersion getVersion() { + return this.version; + } + + /** + * Get the server platform this plugin is running on this is running on. + *

+ *

This will be either Bukkit or Sponge

+ * + * @return the server implementation + */ + public String getPlatform() { + return Settings.PLATFORM; + } + + public PlotManager getPlotManager(Plot plot) { + return plot.getArea().manager; + } + + public PlotManager getPlotManager(Location location) { + PlotArea pa = getPlotAreaAbs(location); + return pa != null ? pa.manager : null; + } + + /** + * Add a global reference to a plot world. + * + * @param plotArea the {@code PlotArea} to add. + * @see #removePlotArea(PlotArea) To remove the reference + */ + public void addPlotArea(PlotArea plotArea) { + HashMap plots; + if (plots_tmp == null || (plots = plots_tmp.remove(plotArea.toString())) == null) { + if (plotArea.TYPE == 2) { + plots = this.plots_tmp != null ? this.plots_tmp.get(plotArea.worldname) : null; + if (plots != null) { + Iterator> iterator = plots.entrySet().iterator(); + while (iterator.hasNext()) { + Entry next = iterator.next(); + PlotId id = next.getKey(); + if (plotArea.contains(id)) { + next.getValue().setArea(plotArea); + iterator.remove(); + } + } + } + } + } else { + for (Plot entry : plots.values()) { + entry.setArea(plotArea); + } + } + Set clusters; + if (clusters_tmp == null || (clusters = clusters_tmp.remove(plotArea.toString())) == null) { + if (plotArea.TYPE == 2) { + clusters = + this.clusters_tmp != null ? this.clusters_tmp.get(plotArea.worldname) : null; + if (clusters != null) { + Iterator iterator = clusters.iterator(); + while (iterator.hasNext()) { + PlotCluster next = iterator.next(); + if (next.intersects(plotArea.getMin(), plotArea.getMax())) { + next.setArea(plotArea); + iterator.remove(); + } + } + } + } + } else { + for (PlotCluster cluster : clusters) { + cluster.setArea(plotArea); + } + } + plotAreaManager.addPlotArea(plotArea); + plotArea.setupBorder(); + } + + /** + * Remove a plot world reference. + * + * @param area the {@code PlotArea} to remove + */ + public void removePlotArea(PlotArea area) { + plotAreaManager.removePlotArea(area); + setPlotsTmp(area); + } + + public void removePlotAreas(String world) { + for (PlotArea area : getPlotAreas(world)) { + if (area.worldname.equals(world)) { + removePlotArea(area); + } + } + } + + private void setPlotsTmp(PlotArea area) { + if (this.plots_tmp == null) { + this.plots_tmp = new HashMap<>(); + } + HashMap map = + this.plots_tmp.computeIfAbsent(area.toString(), k -> new HashMap<>()); + for (Plot plot : area.getPlots()) { + map.put(plot.getId(), plot); + } + if (this.clusters_tmp == null) { + this.clusters_tmp = new HashMap<>(); + } + this.clusters_tmp.put(area.toString(), area.getClusters()); + } + + public Set getClusters(String world) { + Set set = new HashSet<>(); + for (PlotArea area : getPlotAreas(world)) { + set.addAll(area.getClusters()); + } + return Collections.unmodifiableSet(set); + + } + + /** + * Get all the base plots in a single set (for merged plots it just returns the bottom plot). + * + * @return Set of base Plots + */ + public Set getBasePlots() { + int size = getPlotCount(); + final Set result = new HashSet<>(size); + foreachPlotArea(new RunnableVal() { + @Override public void run(PlotArea value) { + for (Plot plot : value.getPlots()) { + if (!plot.isBasePlot()) { + continue; + } + result.add(plot); + } + } + }); + return Collections.unmodifiableSet(result); + } + + public List sortPlotsByTemp(Collection plots) { + int max = 0; + int overflowCount = 0; + for (Plot plot : plots) { + if (plot.temp > 0) { + if (plot.temp > max) { + max = plot.temp; + } + } else { + overflowCount++; + } + } + Plot[] array = new Plot[max + 1]; + List overflow = new ArrayList<>(overflowCount); + for (Plot plot : plots) { + if (plot.temp <= 0) { + overflow.add(plot); + } else { + array[plot.temp] = plot; + } + } + ArrayList result = new ArrayList<>(plots.size()); + for (Plot plot : array) { + if (plot != null) { + result.add(plot); + } + } + overflow.sort(Comparator.comparingInt(Plot::hashCode)); + result.addAll(overflow); + return result; + } + + /** + * Sort plots by hashcode. + * + * @param plots the collection of plots to sort + * @return the sorted collection {@link #sortPlots(Collection, SortType, PlotArea)} which has + * additional checks before calling this + */ + // TODO: Re-evaluate this (previously public and deprecated), as it's being used internally + private ArrayList sortPlotsByHash(Collection plots) { + int hardmax = 256000; + int max = 0; + int overflowSize = 0; + for (Plot plot : plots) { + int hash = MathMan.getPositiveId(plot.hashCode()); + if (hash > max) { + if (hash >= hardmax) { + overflowSize++; + } else { + max = hash; + } + } + } + hardmax = Math.min(hardmax, max); + Plot[] cache = new Plot[hardmax + 1]; + List overflow = new ArrayList<>(overflowSize); + ArrayList extra = new ArrayList<>(); + for (Plot plot : plots) { + int hash = MathMan.getPositiveId(plot.hashCode()); + if (hash < hardmax) { + if (hash >= 0) { + cache[hash] = plot; + } else { + extra.add(plot); + } + } else if (Math.abs(plot.getId().x) > 15446 || Math.abs(plot.getId().y) > 15446) { + extra.add(plot); + } else { + overflow.add(plot); + } + } + Plot[] overflowArray = overflow.toArray(new Plot[overflow.size()]); + sortPlotsByHash(overflowArray); + ArrayList result = new ArrayList<>(cache.length + overflowArray.length); + for (Plot plot : cache) { + if (plot != null) { + result.add(plot); + } + } + Collections.addAll(result, overflowArray); + result.addAll(extra); + return result; + } + + private void sortPlotsByHash(Plot[] input) { + List[] bucket = new ArrayList[32]; + for (int i = 0; i < bucket.length; i++) { + bucket[i] = new ArrayList<>(); + } + boolean maxLength = false; + int placement = 1; + while (!maxLength) { + maxLength = true; + for (Plot i : input) { + int tmp = MathMan.getPositiveId(i.hashCode()) / placement; + bucket[tmp & 31].add(i); + if (maxLength && tmp > 0) { + maxLength = false; + } + } + int a = 0; + for (int b = 0; b < 32; b++) { + for (Plot i : bucket[b]) { + input[a++] = i; + } + bucket[b].clear(); + } + placement *= 32; + } + } + + private ArrayList sortPlotsByTimestamp(Collection plots) { + int hardMax = 256000; + int max = 0; + int overflowSize = 0; + for (Plot plot : plots) { + int hash = MathMan.getPositiveId(plot.hashCode()); + if (hash > max) { + if (hash >= hardMax) { + overflowSize++; + } else { + max = hash; + } + } + } + hardMax = Math.min(hardMax, max); + Plot[] cache = new Plot[hardMax + 1]; + List overflow = new ArrayList<>(overflowSize); + ArrayList extra = new ArrayList<>(); + for (Plot plot : plots) { + int hash = MathMan.getPositiveId(plot.hashCode()); + if (hash < hardMax) { + if (hash >= 0) { + cache[hash] = plot; + } else { + extra.add(plot); + } + } else if (Math.abs(plot.getId().x) > 15446 || Math.abs(plot.getId().y) > 15446) { + extra.add(plot); + } else { + overflow.add(plot); + } + } + Plot[] overflowArray = overflow.toArray(new Plot[overflow.size()]); + sortPlotsByHash(overflowArray); + ArrayList result = new ArrayList<>(cache.length + overflowArray.length); + for (Plot plot : cache) { + if (plot != null) { + result.add(plot); + } + } + Collections.addAll(result, overflowArray); + result.addAll(extra); + return result; + } + + /** + * Sort plots by creation timestamp. + */ + + private List sortPlotsByModified(Collection input) { + List list; + if (input instanceof List) { + list = (List) input; + } else { + list = new ArrayList<>(input); + } + list.sort(Comparator.comparingLong(a -> ExpireManager.IMP.getTimestamp(a.owner))); + return list; + } + + /** + * Sort a collection of plots by world (with a priority world), then by hashcode. + * + * @param plots the plots to sort + * @param type The sorting method to use for each world (timestamp, or hash) + * @param priorityArea Use null, "world", or "gibberish" if you want default world order + * @return ArrayList of plot + */ + public ArrayList sortPlots(Collection plots, SortType type, + final PlotArea priorityArea) { + // group by world + // sort each + HashMap> map = new HashMap<>(); + int totalSize = getPlotCount(); + if (plots.size() == totalSize) { + for (PlotArea area : plotAreaManager.getAllPlotAreas()) { + map.put(area, area.getPlots()); + } + } else { + for (PlotArea area : plotAreaManager.getAllPlotAreas()) { + map.put(area, new ArrayList<>(0)); + } + Collection lastList = null; + PlotArea lastWorld = null; + for (Plot plot : plots) { + if (lastWorld == plot.getArea()) { + lastList.add(plot); + } else { + lastWorld = plot.getArea(); + lastList = map.get(lastWorld); + lastList.add(plot); + } + } + } + List areas = Arrays.asList(plotAreaManager.getAllPlotAreas()); + areas.sort((a, b) -> { + if (priorityArea != null) { + if (a.equals(priorityArea)) { + return -1; + } else if (b.equals(priorityArea)) { + return 1; + } + } + return a.hashCode() - b.hashCode(); + }); + ArrayList toReturn = new ArrayList<>(plots.size()); + for (PlotArea area : areas) { + switch (type) { + case CREATION_DATE: + toReturn.addAll(sortPlotsByTemp(map.get(area))); + break; + case CREATION_DATE_TIMESTAMP: + toReturn.addAll(sortPlotsByTimestamp(map.get(area))); + break; + case DISTANCE_FROM_ORIGIN: + toReturn.addAll(sortPlotsByHash(map.get(area))); + break; + case LAST_MODIFIED: + toReturn.addAll(sortPlotsByModified(map.get(area))); + break; + default: + break; + } + } + return toReturn; + } + + /** + * A more generic way to filter plots - make your own method if you need complex filters. + * + * @param filters the filter + * @return a filtered set of plots + */ + public Set getPlots(final PlotFilter... filters) { + final HashSet set = new HashSet<>(); + foreachPlotArea(new RunnableVal() { + @Override public void run(PlotArea value) { + for (PlotFilter filter : filters) { + if (!filter.allowsArea(value)) { + return; + } + } + loop: + for (Entry entry2 : value.getPlotEntries()) { + Plot plot = entry2.getValue(); + for (PlotFilter filter : filters) { + if (!filter.allowsPlot(plot)) { + continue loop; + } + } + set.add(plot); + } + } + }); + return set; + } + + /** + * Get all the plots in a single set. + * + * @return Set of Plots + */ + public Set getPlots() { + int size = getPlotCount(); + final Set result = new HashSet<>(size); + foreachPlotArea(new RunnableVal() { + @Override public void run(PlotArea value) { + result.addAll(value.getPlots()); + } + }); + return result; + } + + //TODO look at uncommenting or deleting tis. Is it useful and will it work? + //If it is readded make sure there is proper javadoc documentation for it. +/* + public void setPlots(HashMap> plots) { + if (this.plots_tmp == null) { + this.plots_tmp = new HashMap<>(); + } + for (Entry> entry : plots.entrySet()) { + String world = entry.getKey(); + PlotArea area = getPlotArea(world, null); + if (area == null) { + HashMap map = this.plots_tmp + .computeIfAbsent(world, k -> new HashMap<>()); + map.putAll(entry.getValue()); + } else { + for (Plot plot : entry.getValue().values()) { + plot.setArea(area); + area.addPlot(plot); + } + } + } + } +*/ + + /** + * Get all the plots owned by a player name. + * + * @param world the world + * @param player the plot owner + * @return Set of Plot + */ + public Set getPlots(String world, String player) { + final UUID uuid = UUIDHandler.getUUID(player, null); + return getPlots(world, uuid); + } + + /** + * Get all the plots owned by a player name. + * + * @param area the PlotArea + * @param player the plot owner + * @return Set of Plot + */ + public Set getPlots(PlotArea area, String player) { + UUID uuid = UUIDHandler.getUUID(player, null); + return getPlots(area, uuid); + } + + /** + * Get all plots by a PlotPlayer. + * + * @param world the world + * @param player the plot owner + * @return Set of plot + */ + public Set getPlots(String world, PlotPlayer player) { + return getPlots(world, player.getUUID()); + } + + /** + * Get all plots by a PlotPlayer. + * + * @param area the PlotArea + * @param player the plot owner + * @return Set of plot + */ + public Set getPlots(PlotArea area, PlotPlayer player) { + return getPlots(area, player.getUUID()); + } + + /** + * Get all plots by a UUID in a world. + * + * @param world the world + * @param uuid the plot owner + * @return Set of plot + */ + public Set getPlots(String world, UUID uuid) { + final Set plots = new HashSet<>(); + for (final Plot plot : getPlots(world)) { + if (plot.hasOwner() && plot.isOwnerAbs(uuid)) { + plots.add(plot); + } + } + return Collections.unmodifiableSet(plots); + } + + /** + * Get all plots by a UUID in an area. + * + * @param area the {@code PlotArea} + * @param uuid the plot owner + * @return Set of plots + */ + public Set getPlots(PlotArea area, UUID uuid) { + final Set plots = new HashSet<>(); + for (Plot plot : getPlots(area)) { + if (plot.hasOwner() && plot.isOwnerAbs(uuid)) { + plots.add(plot); + } + } + return Collections.unmodifiableSet(plots); + } + + /** + * Check if a plot world. + * + * @param world the world + * @return if a plot world is registered + * @see #getPlotAreaByString(String) to get the PlotArea object + */ + public boolean hasPlotArea(String world) { + return plotAreaManager.getPlotAreas(world, null).length != 0; + } + + public Collection getPlots(String world) { + final Set set = new HashSet<>(); + foreachPlotArea(world, new RunnableVal() { + @Override public void run(PlotArea value) { + set.addAll(value.getPlots()); + } + }); + return set; + } + + /** + * Get the plots for a PlotPlayer. + * + * @param player the player to retrieve the plots for + * @return Set of Plot + */ + public Set getPlots(PlotPlayer player) { + return getPlots(player.getUUID()); + } + + public Collection getPlots(PlotArea area) { + return area == null ? EMPTY_SET : area.getPlots(); + } + + public Plot getPlot(PlotArea area, PlotId id) { + return area == null ? null : id == null ? null : area.getPlot(id); + } + + public Set getBasePlots(PlotPlayer player) { + return getBasePlots(player.getUUID()); + } + + /** + * Get the plots for a UUID. + * + * @param uuid the plot owner + * @return Set of Plot's owned by the player + */ + public Set getPlots(final UUID uuid) { + final Set plots = new HashSet<>(); + foreachPlot(new RunnableVal() { + @Override public void run(Plot value) { + if (value.isOwnerAbs(uuid)) { + plots.add(value); + } + } + }); + return Collections.unmodifiableSet(plots); + } + + public boolean hasPlot(final UUID uuid) { + for (final PlotArea area : plotAreaManager.getAllPlotAreas()) { + if (area.hasPlot(uuid)) { + return true; + } + } + return false; + } + + public Set getBasePlots(final UUID uuid) { + final Set plots = new HashSet<>(); + foreachBasePlot(new RunnableVal() { + @Override public void run(Plot value) { + if (value.isOwner(uuid)) { + plots.add(value); + } + } + }); + return Collections.unmodifiableSet(plots); + } + + /** + * Get the plots for a UUID. + * + * @param uuid the UUID of the owner + * @return Set of Plot + */ + public Set getPlotsAbs(final UUID uuid) { + final Set plots = new HashSet<>(); + foreachPlot(new RunnableVal() { + @Override public void run(Plot value) { + if (value.isOwnerAbs(uuid)) { + plots.add(value); + } + } + }); + return Collections.unmodifiableSet(plots); + } + + /** + * Unregister a plot from local memory (does not call DB). + * + * @param plot the plot to remove + * @param callEvent If to call an event about the plot being removed + * @return true if plot existed | false if it didn't + */ + public boolean removePlot(Plot plot, boolean callEvent) { + if (plot == null) { + return false; + } + if (callEvent) { + EventUtil.manager.callDelete(plot); + } + if (plot.getArea().removePlot(plot.getId())) { + PlotId last = (PlotId) plot.getArea().getMeta("lastPlot"); + int last_max = Math.max(Math.abs(last.x), Math.abs(last.y)); + int this_max = Math.max(Math.abs(plot.getId().x), Math.abs(plot.getId().y)); + if (this_max < last_max) { + plot.getArea().setMeta("lastPlot", plot.getId()); + } + return true; + } + return false; + } + + /** + * This method is called by the PlotGenerator class normally. + *
    + *
  • Initializes the PlotArea and PlotManager classes + *
  • Registers the PlotArea and PlotManager classes + *
  • Loads (and/or generates) the PlotArea configuration + *
  • Sets up the world border if configured + *
+ * + *

If loading an augmented plot world: + *

    + *
  • Creates the AugmentedPopulator classes + *
  • Injects the AugmentedPopulator classes if required + *
+ * + * @param world the world to load + * @param baseGenerator The generator for that world, or null + */ + public void loadWorld(String world, GeneratorWrapper baseGenerator) { + if (world.equals("CheckingPlotSquaredGenerator")) { + return; + } + this.plotAreaManager.addWorld(world); + Set worlds; + if (this.worlds.contains("worlds")) { + worlds = this.worlds.getConfigurationSection("worlds").getKeys(false); + } else { + worlds = new HashSet<>(); + } + String path = "worlds." + world; + ConfigurationSection worldSection = this.worlds.getConfigurationSection(path); + int type; + if (worldSection != null) { + type = worldSection.getInt("generator.type", 0); + } else { + type = 0; + } + if (type == 0) { + if (plotAreaManager.getPlotAreas(world, null).length != 0) { + debug("World possibly already loaded: " + world); + return; + } + IndependentPlotGenerator plotGenerator; + if (baseGenerator != null && baseGenerator.isFull()) { + plotGenerator = baseGenerator.getPlotGenerator(); + } else if (worldSection != null) { + String secondaryGeneratorName = worldSection.getString("generator.plugin"); + GeneratorWrapper secondaryGenerator = + this.IMP.getGenerator(world, secondaryGeneratorName); + if (secondaryGenerator != null && secondaryGenerator.isFull()) { + plotGenerator = secondaryGenerator.getPlotGenerator(); + } else { + String primaryGeneratorName = worldSection.getString("generator.init"); + GeneratorWrapper primaryGenerator = + this.IMP.getGenerator(world, primaryGeneratorName); + if (primaryGenerator != null && primaryGenerator.isFull()) { + plotGenerator = primaryGenerator.getPlotGenerator(); + } else { + return; + } + } + } else { + return; + } + // Conventional plot generator + PlotArea plotArea = plotGenerator.getNewPlotArea(world, null, null, null); + PlotManager plotManager = plotGenerator.getNewPlotManager(); + PlotSquared.log(C.PREFIX + "&aDetected world load for '" + world + "'"); + PlotSquared.log(C.PREFIX + "&3 - generator: &7" + baseGenerator + ">" + plotGenerator); + PlotSquared.log(C.PREFIX + "&3 - plotworld: &7" + plotArea.getClass().getName()); + PlotSquared + .log(C.PREFIX + "&3 - plotAreaManager: &7" + plotManager.getClass().getName()); + if (!this.worlds.contains(path)) { + this.worlds.createSection(path); + worldSection = this.worlds.getConfigurationSection(path); + } + plotArea.saveConfiguration(worldSection); + plotArea.loadDefaultConfiguration(worldSection); + try { + this.worlds.save(this.worldsFile); + } catch (IOException e) { + e.printStackTrace(); + } + // Now add it + addPlotArea(plotArea); + plotGenerator.initialize(plotArea); + } else { + if (!worlds.contains(world)) { + return; + } + ConfigurationSection areasSection = worldSection.getConfigurationSection("areas"); + if (areasSection == null) { + if (plotAreaManager.getPlotAreas(world, null).length != 0) { + debug("World possibly already loaded: " + world); + return; + } + PlotSquared.log(C.PREFIX + "&aDetected world load for '" + world + "'"); + String gen_string = worldSection.getString("generator.plugin", IMP.getPluginName()); + if (type == 2) { + Set clusters = + this.clusters_tmp != null ? this.clusters_tmp.get(world) : new HashSet<>(); + if (clusters == null) { + throw new IllegalArgumentException("No cluster exists for world: " + world); + } + ArrayDeque toLoad = new ArrayDeque<>(); + for (PlotCluster cluster : clusters) { + PlotId pos1 = cluster.getP1(); // Cluster pos1 + PlotId pos2 = cluster.getP2(); // Cluster pos2 + String name = cluster.getName(); // Cluster name + String fullId = name + "-" + pos1 + "-" + pos2; + worldSection.createSection("areas." + fullId); + DBFunc.replaceWorld(world, world + ";" + name, pos1, pos2); // NPE + + PlotSquared.log(C.PREFIX + "&3 - " + name + "-" + pos1 + "-" + pos2); + GeneratorWrapper areaGen = this.IMP.getGenerator(world, gen_string); + if (areaGen == null) { + throw new IllegalArgumentException("Invalid Generator: " + gen_string); + } + PlotArea pa = + areaGen.getPlotGenerator().getNewPlotArea(world, name, pos1, pos2); + pa.saveConfiguration(worldSection); + pa.loadDefaultConfiguration(worldSection); + try { + this.worlds.save(this.worldsFile); + } catch (IOException e) { + e.printStackTrace(); + } + PlotSquared + .log(C.PREFIX + "&c | &9generator: &7" + baseGenerator + ">" + areaGen); + PlotSquared.log(C.PREFIX + "&c | &9plotworld: &7" + pa); + PlotSquared.log(C.PREFIX + "&c | &9manager: &7" + pa); + PlotSquared.log(C.PREFIX + "&cNote: &7Area created for cluster:" + name + + " (invalid or old configuration?)"); + areaGen.getPlotGenerator().initialize(pa); + areaGen.augment(pa); + toLoad.add(pa); + } + for (PlotArea area : toLoad) { + addPlotArea(area); + } + return; + } + GeneratorWrapper areaGen = this.IMP.getGenerator(world, gen_string); + if (areaGen == null) { + throw new IllegalArgumentException("Invalid Generator: " + gen_string); + } + PlotArea pa = areaGen.getPlotGenerator().getNewPlotArea(world, null, null, null); + pa.saveConfiguration(worldSection); + pa.loadDefaultConfiguration(worldSection); + try { + this.worlds.save(this.worldsFile); + } catch (IOException e) { + e.printStackTrace(); + } + PlotSquared.log(C.PREFIX + "&3 - generator: &7" + baseGenerator + ">" + areaGen); + PlotSquared.log(C.PREFIX + "&3 - plotworld: &7" + pa); + PlotSquared.log(C.PREFIX + "&3 - plotAreaManager: &7" + pa.getPlotManager()); + areaGen.getPlotGenerator().initialize(pa); + areaGen.augment(pa); + addPlotArea(pa); + return; + } + if (type == 1) { + throw new IllegalArgumentException( + "Invalid type for multi-area world. Expected `2`, got `" + 1 + "`"); + } + for (String areaId : areasSection.getKeys(false)) { + PlotSquared.log(C.PREFIX + "&3 - " + areaId); + String[] split = areaId.split("(?<=[^;-])-"); + if (split.length != 3) { + throw new IllegalArgumentException("Invalid Area identifier: " + areaId + + ". Expected form `--`"); + } + String name = split[0]; + PlotId pos1 = PlotId.fromString(split[1]); + PlotId pos2 = PlotId.fromString(split[2]); + if (pos1 == null || pos2 == null || name.isEmpty()) { + throw new IllegalArgumentException("Invalid Area identifier: " + areaId + + ". Expected form `--`"); + } + PlotArea existing = getPlotArea(world, name); + if (existing != null && name.equals(existing.id)) { + continue; + } + ConfigurationSection section = areasSection.getConfigurationSection(areaId); + YamlConfiguration clone = new YamlConfiguration(); + for (String key : section.getKeys(true)) { + if (section.get(key) instanceof MemorySection) { + continue; + } + if (!clone.contains(key)) { + clone.set(key, section.get(key)); + } + } + for (String key : worldSection.getKeys(true)) { + if (worldSection.get(key) instanceof MemorySection) { + continue; + } + if (!key.startsWith("areas") && !clone.contains(key)) { + clone.set(key, worldSection.get(key)); + } + } + String gen_string = clone.getString("generator.plugin", IMP.getPluginName()); + GeneratorWrapper areaGen = this.IMP.getGenerator(world, gen_string); + if (areaGen == null) { + throw new IllegalArgumentException("Invalid Generator: " + gen_string); + } + PlotArea pa = areaGen.getPlotGenerator().getNewPlotArea(world, name, pos1, pos2); + pa.saveConfiguration(clone); + // netSections is the combination of + for (String key : clone.getKeys(true)) { + if (clone.get(key) instanceof MemorySection) { + continue; + } + if (!worldSection.contains(key)) { + worldSection.set(key, clone.get(key)); + } else { + Object value = worldSection.get(key); + if (!Objects.equals(value, clone.get(key))) { + section.set(key, clone.get(key)); + } + } + } + pa.loadDefaultConfiguration(clone); + try { + this.worlds.save(this.worldsFile); + } catch (IOException e) { + e.printStackTrace(); + } + PlotSquared.log(C.PREFIX + "&aDetected area load for '" + world + "'"); + PlotSquared.log(C.PREFIX + "&c | &9generator: &7" + baseGenerator + ">" + areaGen); + PlotSquared.log(C.PREFIX + "&c | &9plotworld: &7" + pa); + PlotSquared.log(C.PREFIX + "&c | &9manager: &7" + pa.getPlotManager()); + areaGen.getPlotGenerator().initialize(pa); + areaGen.augment(pa); + addPlotArea(pa); + } + } + } + + /** + * Setup the configuration for a plot world based on world arguments. + * + * + * e.g. /mv create <world> normal -g PlotSquared:<args> + * + * @param world The name of the world + * @param args The arguments + * @param generator the plot generator + * @return boolean | if valid arguments were provided + */ + public boolean setupPlotWorld(String world, String args, IndependentPlotGenerator generator) { + if (args != null && !args.isEmpty()) { + // save configuration + + final List validArguments = Arrays + .asList("s=", "size=", "g=", "gap=", "h=", "height=", "f=", "floor=", "m=", "main=", + "w=", "wall=", "b=", "border="); + + // Calculate the number of expected arguments + int expected = 0; + for (final String validArgument : validArguments) { + if (args.toLowerCase(Locale.ENGLISH).contains(validArgument)) { + expected += 1; + } + } + + String[] split = args.toLowerCase(Locale.ENGLISH).split(","); + + if (split.length > expected) { + // This means we have multi-block block buckets + String[] combinedArgs = new String[expected]; + int index = 0; + + StringBuilder argBuilder = new StringBuilder(); + outer: + for (final String string : split) { + for (final String validArgument : validArguments) { + if (string.contains(validArgument)) { + if (!argBuilder.toString().isEmpty()) { + combinedArgs[index++] = argBuilder.toString(); + argBuilder = new StringBuilder(); + } + argBuilder.append(string); + continue outer; + } + } + if (argBuilder.toString().charAt(argBuilder.length() - 1) != '=') { + argBuilder.append(","); + } + argBuilder.append(string); + } + + if (!argBuilder.toString().isEmpty()) { + combinedArgs[index] = argBuilder.toString(); + } + + split = combinedArgs; + } + + HybridPlotWorld plotworld = new HybridPlotWorld(world, null, generator, null, null); + for (String element : split) { + String[] pair = element.split("="); + if (pair.length != 2) { + PlotSquared.log("&cNo value provided for: &7" + element); + return false; + } + String key = pair[0].toLowerCase(); + String value = pair[1]; + String base = "worlds." + world + "."; + try { + switch (key) { + case "s": + case "size": + this.worlds.set(base + "plot.size", + Configuration.INTEGER.parseString(value).shortValue()); + break; + case "g": + case "gap": + this.worlds.set(base + "road.width", + Configuration.INTEGER.parseString(value).shortValue()); + break; + case "h": + case "height": + this.worlds.set(base + "road.height", + Configuration.INTEGER.parseString(value).shortValue()); + this.worlds.set(base + "plot.height", + Configuration.INTEGER.parseString(value).shortValue()); + this.worlds.set(base + "wall.height", + Configuration.INTEGER.parseString(value).shortValue()); + break; + case "f": + case "floor": + this.worlds.set(base + "plot.floor", + Configuration.BLOCK_BUCKET.parseString(value).toString()); + break; + case "m": + case "main": + this.worlds.set(base + "plot.filling", + Configuration.BLOCK_BUCKET.parseString(value).toString()); + break; + case "w": + case "wall": + this.worlds.set(base + "wall.filling", + Configuration.BLOCK_BUCKET.parseString(value).toString()); + break; + case "b": + case "border": + this.worlds.set(base + "wall.block", + Configuration.BLOCK_BUCKET.parseString(value).toString()); + break; + default: + PlotSquared.log("&cKey not found: &7" + element); + return false; + } + } catch (Exception e) { + e.printStackTrace(); + PlotSquared.log("&cInvalid value: &7" + value + " in arg " + element); + return false; + } + } + try { + ConfigurationSection section = + this.worlds.getConfigurationSection("worlds." + world); + plotworld.saveConfiguration(section); + plotworld.loadConfiguration(section); + this.worlds.save(this.worldsFile); + } catch (IOException e) { + e.printStackTrace(); + } + } + return true; + } + + public boolean canUpdate(@NonNull final String current, @NonNull final String other) { + final String s1 = normalisedVersion(current); + final String s2 = normalisedVersion(other); + return s1.compareTo(s2) < 0; + } + + public String normalisedVersion(@NonNull final String version) { + final String[] split = Pattern.compile(".", Pattern.LITERAL).split(version); + final StringBuilder sb = new StringBuilder(); + for (final String s : split) { + sb.append(String.format("%" + 4 + 's', s)); + } + return sb.toString(); + } + + public boolean update(PlotPlayer sender, URL url) { + try { + String name = this.jarFile.getName(); + File newJar = new File("plugins/update/" + name); + MainUtil.sendMessage(sender, "$1Downloading from provided URL: &7" + url); + URLConnection con = url.openConnection(); + try (InputStream stream = con.getInputStream()) { + File parent = newJar.getParentFile(); + if (!parent.exists()) { + parent.mkdirs(); + } + MainUtil.sendMessage(sender, "$2 - Output: " + newJar); + if (!newJar.delete()) { + MainUtil.sendMessage(sender, "Failed to update " + IMP.getPluginName() + ""); + MainUtil.sendMessage(sender, "Jar file failed to delete."); + MainUtil.sendMessage(sender, " - Please update manually"); + } + Files.copy(stream, newJar.toPath()); + } + MainUtil.sendMessage(sender, + "$1The update will take effect when the server is restarted next"); + return true; + } catch (IOException e) { + MainUtil.sendMessage(sender, "Failed to update " + IMP.getPluginName() + ""); + MainUtil.sendMessage(sender, " - Please update manually"); + PlotSquared.log("============ Stacktrace ============"); + e.printStackTrace(); + PlotSquared.log("===================================="); + } + return false; + } + + /** + * Copy a file from inside the jar to a location + * + * @param file Name of the file inside PlotSquared.jar + * @param folder The output location relative to /plugins/PlotSquared/ + */ + public void copyFile(String file, String folder) { + try { + File output = this.IMP.getDirectory(); + if (!output.exists()) { + output.mkdirs(); + } + File newFile = MainUtil.getFile(output, folder + File.separator + file); + if (newFile.exists()) { + return; + } + try (InputStream stream = this.IMP.getClass().getResourceAsStream(file)) { + byte[] buffer = new byte[2048]; + if (stream == null) { + try (ZipInputStream zis = new ZipInputStream( + new FileInputStream(this.jarFile))) { + ZipEntry ze = zis.getNextEntry(); + while (ze != null) { + String name = ze.getName(); + if (name.equals(file)) { + new File(newFile.getParent()).mkdirs(); + try (FileOutputStream fos = new FileOutputStream(newFile)) { + int len; + while ((len = zis.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + } + ze = null; + } else { + ze = zis.getNextEntry(); + } + } + zis.closeEntry(); + } + return; + } + newFile.createNewFile(); + try (FileOutputStream fos = new FileOutputStream(newFile)) { + int len; + while ((len = stream.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + } + } + } catch (IOException e) { + e.printStackTrace(); + PlotSquared.log("&cCould not save " + file); + } + } + + private Map> getPlotsRaw() { + HashMap> map = new HashMap<>(); + for (PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + Map map2 = map.get(area.toString()); + if (map2 == null) { + map.put(area.toString(), area.getPlotsRaw()); + } else { + map2.putAll(area.getPlotsRaw()); + } + } + return map; + } + + /** + * Close the database connection. + */ + public void disable() { + try { + // Validate that all data in the db is correct + final HashSet plots = new HashSet<>(); + try { + foreachPlotRaw(new RunnableVal() { + @Override public void run(Plot value) { + plots.add(value); + } + }); + } catch (final Exception ignored) { + } + DBFunc.validatePlots(plots); + + // Close the connection + DBFunc.close(); + UUIDHandler.handleShutdown(); + } catch (NullPointerException exception) { + exception.printStackTrace(); + PlotSquared.log("&cCould not close database connection!"); + } + } + + /** + * Setup the database connection. + */ + public void setupDatabase() { + try { + if (DBFunc.dbManager != null) { + DBFunc.dbManager.close(); + } + Database database; + if (Storage.MySQL.USE) { + database = new MySQL(Storage.MySQL.HOST, Storage.MySQL.PORT, Storage.MySQL.DATABASE, + Storage.MySQL.USER, Storage.MySQL.PASSWORD); + } else if (Storage.SQLite.USE) { + File file = MainUtil.getFile(IMP.getDirectory(), Storage.SQLite.DB + ".db"); + database = new SQLite(file); + } else { + PlotSquared.log(C.PREFIX + "&cNo storage type is set!"); + this.IMP.disable(); + return; + } + DBFunc.dbManager = new SQLManager(database, Storage.PREFIX, false); + PlotSquared.log("GETTING PLOTS NOW AND STORING TO PLOTS_TMP"); + for (PlotArea allPlotArea : plotAreaManager.getAllPlotAreas()) { + PlotSquared.log(allPlotArea.toString()); + } + + this.plots_tmp = DBFunc.getPlots(); + if (plotAreaManager instanceof SinglePlotAreaManager) { + SinglePlotArea area = ((SinglePlotAreaManager) plotAreaManager).getArea(); + addPlotArea(area); + ConfigurationSection section = worlds.getConfigurationSection("worlds.*"); + if (section == null) { + section = worlds.createSection("worlds.*"); + } + area.saveConfiguration(section); + area.loadDefaultConfiguration(section); + } + this.clusters_tmp = DBFunc.getClusters(); + } catch (ClassNotFoundException | SQLException e) { + PlotSquared.log( + C.PREFIX + "&cFailed to open DATABASE connection. The plugin will disable itself."); + if (Storage.MySQL.USE) { + PlotSquared.log("$4MYSQL"); + } else if (Storage.SQLite.USE) { + PlotSquared.log("$4SQLITE"); + } + PlotSquared.log( + "&d==== Here is an ugly stacktrace, if you are interested in those things ==="); + e.printStackTrace(); + PlotSquared.log("&d==== End of stacktrace ===="); + PlotSquared.log("&6Please go to the " + IMP.getPluginName() + + " 'storage.yml' and configure the database correctly."); + this.IMP.disable(); + } + } + + /** + * Setup the default configuration. + * + * @throws IOException if the config failed to save + */ + public void setupConfig() throws IOException { + String lastVersionString = this.config.getString("version"); + if (lastVersionString != null) { + String[] split = lastVersionString.split("\\."); + int[] lastVersion = new int[] {Integer.parseInt(split[0]), Integer.parseInt(split[1]), + Integer.parseInt(split[2])}; + if (checkVersion(new int[] {3, 4, 0}, lastVersion)) { + Settings.convertLegacy(configFile); + if (config.contains("worlds")) { + ConfigurationSection worldSection = config.getConfigurationSection("worlds"); + worlds.set("worlds", worldSection); + try { + worlds.save(worldsFile); + } catch (IOException e) { + PlotSquared.debug("Failed to save " + IMP.getPluginName() + " worlds.yml"); + e.printStackTrace(); + } + } + Settings.save(configFile); + } + } + Settings.load(configFile); + try { + InputStream stream = getClass().getResourceAsStream("/plugin.properties"); + BufferedReader br = new BufferedReader(new InputStreamReader(stream)); + //java.util.Scanner scanner = new java.util.Scanner(stream).useDelimiter("\\A"); + String versionString = br.readLine(); + String commitString = br.readLine(); + String dateString = br.readLine(); + //scanner.close(); + br.close(); + this.version = PlotVersion.tryParse(versionString, commitString, dateString); + Settings.DATE = new Date(100 + version.year, version.month, version.day).toGMTString(); + Settings.BUILD = "https://ci.athion.net/job/PlotSquared/" + version.build; + Settings.COMMIT = "https://github.com/IntellectualSites/PlotSquared/commit/" + Integer + .toHexString(version.hash); + System.out.println("Version is " + this.version); + } catch (IOException exception) { + exception.printStackTrace(); + } + Settings.save(configFile); + config = YamlConfiguration.loadConfiguration(configFile); + } + + /** + * Setup all configuration files
- Config: settings.yml
- Storage: storage.yml
- + * Translation: PlotSquared.use_THIS.yml, style.yml
+ */ + public boolean setupConfigs() { + File folder = new File(this.IMP.getDirectory(), "config"); + if (!folder.exists() && !folder.mkdirs()) { + PlotSquared.log(C.PREFIX + + "&cFailed to create the /plugins/config folder. Please create it manually."); + } + try { + this.worldsFile = new File(folder, "worlds.yml"); + if (!this.worldsFile.exists() && !this.worldsFile.createNewFile()) { + PlotSquared.log( + "Could not create the worlds file, please create \"worlds.yml\" manually."); + } + this.worlds = YamlConfiguration.loadConfiguration(this.worldsFile); + + if (this.worlds.contains("worlds")) { + if (!this.worlds.contains("configuration_version") || !this.worlds + .getString("configuration_version") + .equalsIgnoreCase(LegacyConverter.CONFIGURATION_VERSION)) { + // Conversion needed + log(C.LEGACY_CONFIG_FOUND.s()); + try { + com.google.common.io.Files + .copy(this.worldsFile, new File(folder, "worlds.yml.old")); + log(C.LEGACY_CONFIG_BACKUP.s()); + final ConfigurationSection worlds = + this.worlds.getConfigurationSection("worlds"); + final LegacyConverter converter = new LegacyConverter(worlds); + converter.convert(); + this.worlds + .set("configuration_version", LegacyConverter.CONFIGURATION_VERSION); + this.worlds.set("worlds", worlds); // Redundant, but hey... ¯\_(ツ)_/¯ + this.worlds.save(this.worldsFile); + log(C.LEGACY_CONFIG_DONE.s()); + } catch (final Exception e) { + log(C.LEGACY_CONFIG_CONVERSION_FAILED.s()); + e.printStackTrace(); + } + // Disable plugin + this.IMP.shutdown(); + return false; + } + } else { + this.worlds.set("configuration_version", LegacyConverter.CONFIGURATION_VERSION); + } + } catch (IOException ignored) { + PlotSquared.log("Failed to save settings.yml"); + } + try { + this.configFile = new File(folder, "settings.yml"); + if (!this.configFile.exists() && !this.configFile.createNewFile()) { + PlotSquared.log( + "Could not create the settings file, please create \"settings.yml\" manually."); + } + this.config = YamlConfiguration.loadConfiguration(this.configFile); + setupConfig(); + } catch (IOException ignored) { + PlotSquared.log("Failed to save settings.yml"); + } + try { + this.styleFile = MainUtil.getFile(IMP.getDirectory(), + Settings.Paths.TRANSLATIONS + File.separator + "style.yml"); + if (!this.styleFile.exists()) { + if (!this.styleFile.getParentFile().exists()) { + this.styleFile.getParentFile().mkdirs(); + } + if (!this.styleFile.createNewFile()) { + PlotSquared.log( + "Could not create the style file, please create \"translations/style.yml\" manually"); + } + } + this.style = YamlConfiguration.loadConfiguration(this.styleFile); + setupStyle(); + } catch (IOException err) { + err.printStackTrace(); + PlotSquared.log("failed to save style.yml"); + } + try { + this.storageFile = new File(folder, "storage.yml"); + if (!this.storageFile.exists() && !this.storageFile.createNewFile()) { + PlotSquared.log( + "Could not the storage settings file, please create \"storage.yml\" manually."); + } + this.storage = YamlConfiguration.loadConfiguration(this.storageFile); + setupStorage(); + } catch (IOException ignored) { + PlotSquared.log("Failed to save storage.yml"); + } + try { + this.commandsFile = new File(folder, "commands.yml"); + if (!this.commandsFile.exists() && !this.commandsFile.createNewFile()) { + PlotSquared.log( + "Could not the storage settings file, please create \"commands.yml\" manually."); + } + this.commands = YamlConfiguration.loadConfiguration(this.commandsFile); + } catch (IOException ignored) { + PlotSquared.log("Failed to save commands.yml"); + } + try { + this.style.save(this.styleFile); + this.commands.save(this.commandsFile); + } catch (IOException e) { + PlotSquared.log("Configuration file saving failed"); + e.printStackTrace(); + } + return true; + } + + /** + * Setup the storage file (load + save missing nodes). + */ + private void setupStorage() { + Storage.load(storageFile); + Storage.save(storageFile); + storage = YamlConfiguration.loadConfiguration(storageFile); + } + + /** + * Show startup debug information. + */ + private void showDebug() { + if (Settings.DEBUG) { + Map components = Settings.getFields(Settings.Enabled_Components.class); + for (Entry component : components.entrySet()) { + PlotSquared.log(C.PREFIX + String + .format("&cKey: &6%s&c, Value: &6%s", component.getKey(), + component.getValue())); + } + } + } + + /** + * Setup the style.yml file + */ + private void setupStyle() { + if (this.version != null) { + this.style.set("version", this.version.toString()); + } + Map o = new HashMap<>(4); + o.put("color.1", "6"); + o.put("color.2", "7"); + o.put("color.3", "8"); + o.put("color.4", "3"); + if (!this.style.contains("color")) { + for (Entry node : o.entrySet()) { + this.style.set(node.getKey(), node.getValue()); + } + } + } + + /** + * Get the Java version. + * + * @return the java version + */ + public double getJavaVersion() { + return Double.parseDouble(System.getProperty("java.specification.version")); + } + + public void foreachPlotArea(@NonNull final RunnableVal runnable) { + for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + runnable.run(area); + } + } + + public void foreachPlotArea(@NonNull final String world, + @NonNull final RunnableVal runnable) { + final PlotArea[] array = this.plotAreaManager.getPlotAreas(world, null); + if (array == null) { + return; + } + for (final PlotArea area : array) { + runnable.run(area); + } + } + + public void foreachPlot(@NonNull final RunnableVal runnable) { + for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + area.getPlots().forEach(runnable::run); + } + } + + public void foreachPlotRaw(@NonNull final RunnableVal runnable) { + for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + area.getPlots().forEach(runnable::run); + } + if (this.plots_tmp != null) { + for (final HashMap entry : this.plots_tmp.values()) { + entry.values().forEach(runnable::run); + } + } + } + + public void foreachBasePlot(@NonNull final RunnableVal run) { + for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + area.foreachBasePlot(run); + } + } + + public PlotArea getFirstPlotArea() { + PlotArea[] areas = plotAreaManager.getAllPlotAreas(); + return areas.length > 0 ? areas[0] : null; + } + + public int getPlotAreaCount() { + return this.plotAreaManager.getAllPlotAreas().length; + } + + public int getPlotCount() { + int count = 0; + for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + count += area.getPlotCount(); + } + return count; + } + + public Set getPlotAreas() { + final Set set = new HashSet<>(); + Collections.addAll(set, plotAreaManager.getAllPlotAreas()); + return Collections.unmodifiableSet(set); + } + + public boolean isAugmented(@NonNull final String world) { + final PlotArea[] areas = plotAreaManager.getPlotAreas(world, null); + return areas != null && (areas.length > 1 || areas[0].TYPE != 0); + } + + /** + * Get a list of PlotArea objects. + * + * @param world the world + * @return Collection of PlotArea objects + */ + public Set getPlotAreas(@NonNull final String world) { + final Set set = new HashSet<>(); + Collections.addAll(set, plotAreaManager.getPlotAreas(world, null)); + return set; + } + + /** + * Get the relevant plot area for a specified location. + *
    + *
  • If there is only one plot area globally that will be returned. + *
  • If there is only one plot area in the world, it will return that. + *
  • If the plot area for a location cannot be unambiguously + * resolved, null will be returned. + *
+ * Note: An applicable plot area may not include the location i.e. clusters + * + * @param location the location + */ + public PlotArea getApplicablePlotArea(@NonNull final Location location) { + return plotAreaManager.getApplicablePlotArea(location); + } + + public PlotArea getPlotArea(@NonNull final String world, final String id) { + return plotAreaManager.getPlotArea(world, id); + } + + /** + * Get the {@code PlotArea} which contains a location. + *
    + *
  • If the plot area does not contain a location, null + * will be returned. + *
+ * + * @param location the location + * @return the {@link PlotArea} in the location, null if non existent + */ + public PlotArea getPlotAreaAbs(@NonNull final Location location) { + return plotAreaManager.getPlotArea(location); + } + + public PlotArea getPlotAreaByString(@NonNull final String search) { + String[] split = search.split("[;,]"); + PlotArea[] areas = plotAreaManager.getPlotAreas(split[0], null); + if (areas == null) { + for (PlotArea area : plotAreaManager.getAllPlotAreas()) { + if (area.worldname.equalsIgnoreCase(split[0])) { + if (area.id == null || split.length == 2 && area.id + .equalsIgnoreCase(split[1])) { + return area; + } + } + } + return null; + } + if (areas.length == 1) { + return areas[0]; + } else if (split.length == 1) { + return null; + } else { + for (PlotArea area : areas) { + if (StringMan.isEqual(split[1], area.id)) { + return area; + } + } + return null; + } + } + + /** + * Get Plots based on alias + * + * @param alias to search plots + * @param worldname to filter alias to a specific world [optional] null means all worlds + * @return Set<{ + * @ link + * < p> + *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ * Plot + *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ *

+ * }> empty if nothing found + */ + public Set getPlotsByAlias(@Nullable final String alias, + @NonNull final String worldname) { + final Set result = new HashSet<>(); + if (alias != null) { + for (final Plot plot : getPlots()) { + if (alias.equals(plot.getAlias()) && (worldname == null || worldname + .equals(plot.getWorldName()))) { + result.add(plot); + } + } + } + return Collections.unmodifiableSet(result); + } + + public Set getPlotAreas(final String world, final RegionWrapper region) { + final PlotArea[] areas = plotAreaManager.getPlotAreas(world, region); + final Set set = new HashSet<>(); + Collections.addAll(set, areas); + return Collections.unmodifiableSet(set); + } + + public enum SortType { + CREATION_DATE, CREATION_DATE_TIMESTAMP, LAST_MODIFIED, DISTANCE_FROM_ORIGIN + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotVersion.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotVersion.java new file mode 100644 index 000000000..ecb423970 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/PlotVersion.java @@ -0,0 +1,45 @@ +package com.github.intellectualsites.plotsquared.plot; + +public class PlotVersion { + public final int year, month, day, hash, build; + + public PlotVersion(int year, int month, int day, int hash, int build) { + this.year = year; + this.month = month; + this.day = day; + this.hash = hash; + this.build = build; + } + + public PlotVersion(String version, String commit, String date) { + String[] split = version.substring(version.indexOf('=') + 1).split("\\."); + this.build = Integer.parseInt(split[1]); + this.hash = Integer.parseInt(commit.substring(commit.indexOf('=') + 1), 16); + String[] split1 = date.substring(date.indexOf('=') + 1).split("\\."); + this.year = Integer.parseInt(split1[0]); + this.month = Integer.parseInt(split1[1]); + this.day = Integer.parseInt(split1[2]); + } + + public static PlotVersion tryParse(String version, String commit, String date) { + try { + return new PlotVersion(version, commit, date); + } catch (Exception ignore) { + ignore.printStackTrace(); + return new PlotVersion(0, 0, 0, 0, 0); + } + } + + @Override public String toString() { + if (hash == 0 && build == 0) { + return "PlotSquared-" + year + "." + month + "." + day + "-SNAPSHOT"; + } else { + return "PlotSquared-" + year + "." + month + "." + day + "-" + Integer.toHexString(hash) + + "-" + build; + } + } + + public boolean isNewer(PlotVersion other) { + return other.build < this.build; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Add.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Add.java new file mode 100644 index 000000000..03d27555a --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Add.java @@ -0,0 +1,82 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3; +import com.github.intellectualsites.plotsquared.plot.util.EventUtil; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; + +import java.util.Iterator; +import java.util.Set; +import java.util.UUID; + +@CommandDeclaration(command = "add", + description = "Allow a user to build in a plot while you are online", + usage = "/plot add ", category = CommandCategory.SETTINGS, permission = "plots.add", + requiredType = RequiredType.NONE) public class Add extends Command { + + public Add() { + super(MainCommand.getInstance(), true); + } + + @Override public void execute(final PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) throws CommandException { + final Plot plot = check(player.getCurrentPlot(), C.NOT_IN_PLOT); + checkTrue(plot.hasOwner(), C.PLOT_UNOWNED); + checkTrue(plot.isOwner(player.getUUID()) || Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_TRUST), C.NO_PLOT_PERMS); + checkTrue(args.length == 1, C.COMMAND_SYNTAX, getUsage()); + final Set uuids = MainUtil.getUUIDsFromString(args[0]); + checkTrue(!uuids.isEmpty(), C.INVALID_PLAYER, args[0]); + Iterator iter = uuids.iterator(); + int size = plot.getTrusted().size() + plot.getMembers().size(); + while (iter.hasNext()) { + UUID uuid = iter.next(); + if (uuid == DBFunc.EVERYONE && !( + Permissions.hasPermission(player, C.PERMISSION_TRUST_EVERYONE) || Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_TRUST))) { + MainUtil.sendMessage(player, C.INVALID_PLAYER, MainUtil.getName(uuid)); + iter.remove(); + continue; + } + if (plot.isOwner(uuid)) { + MainUtil.sendMessage(player, C.ALREADY_OWNER, MainUtil.getName(uuid)); + iter.remove(); + continue; + } + if (plot.getMembers().contains(uuid)) { + MainUtil.sendMessage(player, C.ALREADY_ADDED, MainUtil.getName(uuid)); + iter.remove(); + continue; + } + size += plot.getTrusted().contains(uuid) ? 0 : 1; + } + checkTrue(!uuids.isEmpty(), null); + checkTrue(size <= plot.getArea().MAX_PLOT_MEMBERS || Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_TRUST), C.PLOT_MAX_MEMBERS); + confirm.run(this, new Runnable() { + @Override // Success + public void run() { + for (UUID uuid : uuids) { + if (uuid != DBFunc.EVERYONE) { + if (!plot.removeTrusted(uuid)) { + if (plot.getDenied().contains(uuid)) { + plot.removeDenied(uuid); + } + } + } + plot.addMember(uuid); + EventUtil.manager.callMember(player, plot, uuid, true); + MainUtil.sendMessage(player, C.MEMBER_ADDED); + } + } + }, null); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Alias.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Alias.java new file mode 100644 index 000000000..2eeb0a49d --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Alias.java @@ -0,0 +1,123 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.StringWrapper; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.MathMan; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; +import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; + +@CommandDeclaration(command = "setalias", permission = "plots.alias", + description = "Set the plot name", usage = "/plot alias ", + aliases = {"alias", "sa", "name", "rename", "setname", "seta", "nameplot"}, + category = CommandCategory.SETTINGS, requiredType = RequiredType.NONE) public class Alias + extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + + if (args.length == 0) { + C.COMMAND_SYNTAX.send(player, "/plot alias "); + return false; + } + + Location loc = player.getLocation(); + Plot plot = loc.getPlotAbs(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + + if (!plot.hasOwner()) { + sendMessage(player, C.PLOT_NOT_CLAIMED); + return false; + } + + if (!plot.isOwner(player.getUUID())) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + + boolean result = false; + + switch (args[0].toLowerCase()) { + case "set": + if (args.length != 2) { + C.COMMAND_SYNTAX.send(player, "/plot alias "); + return false; + } + + if (canExecuteCommand(player, C.PERMISSION_ALIAS_SET, false) || canExecuteCommand( + player, C.PERMISSION_ALIAS_SET_OBSOLETE, false)) { + result = setAlias(player, plot, args[1]); + } else { + MainUtil.sendMessage(player, C.NO_PERMISSION); + } + + break; + case "remove": + if (canExecuteCommand(player, C.PERMISSION_ALIAS_REMOVE, true)) { + result = removeAlias(player, plot); + } + break; + default: + C.COMMAND_SYNTAX.send(player, "/plot alias "); + result = false; + } + + return result; + } + + + private boolean setAlias(PlotPlayer player, Plot plot, String alias) { + if (alias.isEmpty()) { + C.COMMAND_SYNTAX.send(player, "/plot alias "); + return false; + } + if (alias.length() >= 50) { + MainUtil.sendMessage(player, C.ALIAS_TOO_LONG); + return false; + } + if (alias.contains(" ")) { + C.NOT_VALID_VALUE.send(player); + return false; + } + if (MathMan.isInteger(alias)) { + C.NOT_VALID_VALUE.send(player); + return false; + } + for (Plot p : PlotSquared.get().getPlots(plot.getArea())) { + if (p.getAlias().equalsIgnoreCase(alias)) { + MainUtil.sendMessage(player, C.ALIAS_IS_TAKEN); + return false; + } + } + if (UUIDHandler.nameExists(new StringWrapper(alias)) || PlotSquared.get() + .hasPlotArea(alias)) { + MainUtil.sendMessage(player, C.ALIAS_IS_TAKEN); + return false; + } + plot.setAlias(alias); + MainUtil.sendMessage(player, C.ALIAS_SET_TO.s().replaceAll("%alias%", alias)); + return true; + } + + private boolean removeAlias(PlotPlayer player, Plot plot) { + plot.setAlias(null); + MainUtil.sendMessage(player, C.ALIAS_REMOVED.s()); + return true; + } + + private boolean canExecuteCommand(PlotPlayer player, C caption, boolean sendMessage) { + if (!Permissions.hasPermission(player, caption)) { + if (sendMessage) { + MainUtil.sendMessage(player, C.NO_PERMISSION); + } + return false; + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Area.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Area.java new file mode 100644 index 000000000..ee7c1cb23 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Area.java @@ -0,0 +1,469 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.configuration.ConfigurationSection; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Configuration; +import com.github.intellectualsites.plotsquared.plot.generator.AugmentedUtils; +import com.github.intellectualsites.plotsquared.plot.generator.HybridPlotWorld; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.*; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Objects; +import java.util.Set; + +@CommandDeclaration(command = "area", permission = "plots.area", + category = CommandCategory.ADMINISTRATION, requiredType = RequiredType.NONE, + description = "Create a new PlotArea", aliases = "world", + usage = "/plot area ", confirmation = true) public class Area + extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + if (args.length == 0) { + C.COMMAND_SYNTAX.send(player, getUsage()); + return false; + } + switch (args[0].toLowerCase()) { + case "c": + case "setup": + case "create": + if (!Permissions.hasPermission(player, C.PERMISSION_AREA_CREATE)) { + C.NO_PERMISSION.send(player, C.PERMISSION_AREA_CREATE); + return false; + } + switch (args.length) { + case 1: + C.COMMAND_SYNTAX + .send(player, "/plot area create [world[:id]] [=]..."); + return false; + case 2: + switch (args[1].toLowerCase()) { + case "pos1": { // Set position 1 + HybridPlotWorld area = player.getMeta("area_create_area"); + if (area == null) { + C.COMMAND_SYNTAX.send(player, + "/plot area create [world[:id]] [=]..."); + return false; + } + Location location = player.getLocation(); + player.setMeta("area_pos1", location); + C.SET_ATTRIBUTE.send(player, "area_pos1", + location.getX() + "," + location.getZ()); + MainUtil.sendMessage(player, + "You will now set pos2: /plot area create pos2" + + "\nNote: The chosen plot size may result in the created area not exactly matching your second position."); + return true; + } + case "pos2": // Set position 2 and finish creation for type=2 (partial) + final HybridPlotWorld area = player.getMeta("area_create_area"); + if (area == null) { + C.COMMAND_SYNTAX.send(player, + "/plot area create [world[:id]] [=]..."); + return false; + } + Location pos1 = player.getLocation(); + Location pos2 = player.getMeta("area_pos1"); + int dx = Math.abs(pos1.getX() - pos2.getX()); + int dz = Math.abs(pos1.getZ() - pos2.getZ()); + int numX = Math.max(1, + (dx + 1 + area.ROAD_WIDTH + area.SIZE / 2) / area.SIZE); + int numZ = Math.max(1, + (dz + 1 + area.ROAD_WIDTH + area.SIZE / 2) / area.SIZE); + int ddx = dx - (numX * area.SIZE - area.ROAD_WIDTH); + int ddz = dz - (numZ * area.SIZE - area.ROAD_WIDTH); + int bx = Math.min(pos1.getX(), pos2.getX()) + ddx; + int bz = Math.min(pos1.getZ(), pos2.getZ()) + ddz; + int tx = Math.max(pos1.getX(), pos2.getX()) - ddx; + int tz = Math.max(pos1.getZ(), pos2.getZ()) - ddz; + int lower = (area.ROAD_WIDTH & 1) == 0 ? + area.ROAD_WIDTH / 2 - 1 : + area.ROAD_WIDTH / 2; + final int offsetX = bx - (area.ROAD_WIDTH == 0 ? 0 : lower); + final int offsetZ = bz - (area.ROAD_WIDTH == 0 ? 0 : lower); + final RegionWrapper region = new RegionWrapper(bx, tx, bz, tz); + Set areas = + PlotSquared.get().getPlotAreas(area.worldname, region); + if (!areas.isEmpty()) { + C.CLUSTER_INTERSECTION + .send(player, areas.iterator().next().toString()); + return false; + } + final SetupObject object = new SetupObject(); + object.world = area.worldname; + object.id = area.id; + object.terrain = area.TERRAIN; + object.type = area.TYPE; + object.min = new PlotId(1, 1); + object.max = new PlotId(numX, numZ); + object.plotManager = PlotSquared.imp().getPluginName(); + object.setupGenerator = PlotSquared.imp().getPluginName(); + object.step = area.getSettingNodes(); + final String path = + "worlds." + area.worldname + ".areas." + area.id + '-' + + object.min + '-' + object.max; + Runnable run = () -> { + if (offsetX != 0) { + PlotSquared.get().worlds + .set(path + ".road.offset.x", offsetX); + } + if (offsetZ != 0) { + PlotSquared.get().worlds + .set(path + ".road.offset.z", offsetZ); + } + final String world = SetupUtils.manager.setupWorld(object); + if (WorldUtil.IMP.isWorld(world)) { + PlotSquared.get().loadWorld(world, null); + C.SETUP_FINISHED.send(player); + player.teleport(WorldUtil.IMP.getSpawn(world)); + if (area.TERRAIN != 3) { + ChunkManager.largeRegionTask(world, region, + new RunnableVal() { + @Override public void run(ChunkLoc value) { + AugmentedUtils + .generate(world, value.x, value.z, + null); + } + }, null); + } + } else { + MainUtil.sendMessage(player, + "An error occurred while creating the world: " + + area.worldname); + } + }; + if (hasConfirmation(player)) { + CmdConfirm.addPending(player, + getCommandString() + " create pos2 (Creates world)", run); + } else { + run.run(); + } + return true; + } + default: // Start creation + final SetupObject object = new SetupObject(); + String[] split = args[1].split(":"); + String id; + if (split.length == 2) { + id = split[1]; + } else { + id = null; + } + object.world = split[0]; + final HybridPlotWorld pa = new HybridPlotWorld(object.world, id, + PlotSquared.get().IMP.getDefaultGenerator(), null, null); + PlotArea other = PlotSquared.get().getPlotArea(pa.worldname, id); + if (other != null && Objects.equals(pa.id, other.id)) { + C.SETUP_WORLD_TAKEN.send(player, pa.toString()); + return false; + } + Set areas = PlotSquared.get().getPlotAreas(pa.worldname); + if (!areas.isEmpty()) { + PlotArea area = areas.iterator().next(); + pa.TYPE = area.TYPE; + } + pa.SIZE = (short) (pa.PLOT_WIDTH + pa.ROAD_WIDTH); + for (int i = 2; i < args.length; i++) { + String[] pair = args[i].split("="); + if (pair.length != 2) { + C.COMMAND_SYNTAX.send(player, getCommandString() + + " create [world[:id]] [=]..."); + return false; + } + switch (pair[0].toLowerCase()) { + case "s": + case "size": + pa.PLOT_WIDTH = Integer.parseInt(pair[1]); + pa.SIZE = (short) (pa.PLOT_WIDTH + pa.ROAD_WIDTH); + break; + case "g": + case "gap": + pa.ROAD_WIDTH = Integer.parseInt(pair[1]); + pa.SIZE = (short) (pa.PLOT_WIDTH + pa.ROAD_WIDTH); + break; + case "h": + case "height": + int value = Integer.parseInt(pair[1]); + pa.PLOT_HEIGHT = value; + pa.ROAD_HEIGHT = value; + pa.WALL_HEIGHT = value; + break; + case "f": + case "floor": + pa.TOP_BLOCK = Configuration.BLOCK_BUCKET.parseString(pair[1]); + break; + case "m": + case "main": + pa.MAIN_BLOCK = Configuration.BLOCK_BUCKET.parseString(pair[1]); + break; + case "w": + case "wall": + pa.WALL_FILLING = + Configuration.BLOCK_BUCKET.parseString(pair[1]); + break; + case "b": + case "border": + pa.WALL_BLOCK = Configuration.BLOCK_BUCKET.parseString(pair[1]); + break; + case "terrain": + pa.TERRAIN = Integer.parseInt(pair[1]); + object.terrain = pa.TERRAIN; + break; + case "type": + pa.TYPE = Integer.parseInt(pair[1]); + object.type = pa.TYPE; + break; + default: + C.COMMAND_SYNTAX.send(player, getCommandString() + + " create [world[:id]] [=]..."); + return false; + } + } + if (pa.TYPE != 2) { + if (WorldUtil.IMP.isWorld(pa.worldname)) { + C.SETUP_WORLD_TAKEN.send(player, pa.worldname); + return false; + } + Runnable run = () -> { + String path = "worlds." + pa.worldname; + if (!PlotSquared.get().worlds.contains(path)) { + PlotSquared.get().worlds.createSection(path); + } + ConfigurationSection section = + PlotSquared.get().worlds.getConfigurationSection(path); + pa.saveConfiguration(section); + pa.loadConfiguration(section); + object.plotManager = PlotSquared.imp().getPluginName(); + object.setupGenerator = PlotSquared.imp().getPluginName(); + String world = SetupUtils.manager.setupWorld(object); + if (WorldUtil.IMP.isWorld(world)) { + C.SETUP_FINISHED.send(player); + player.teleport(WorldUtil.IMP.getSpawn(world)); + } else { + MainUtil.sendMessage(player, + "An error occurred while creating the world: " + + pa.worldname); + } + try { + PlotSquared.get().worlds.save(PlotSquared.get().worldsFile); + } catch (IOException e) { + e.printStackTrace(); + } + }; + if (hasConfirmation(player)) { + CmdConfirm.addPending(player, + getCommandString() + ' ' + StringMan.join(args, " "), run); + } else { + run.run(); + } + return true; + } + if (pa.id == null) { + C.COMMAND_SYNTAX.send(player, getCommandString() + + " create [world[:id]] [=]..."); + return false; + } + if (WorldUtil.IMP.isWorld(pa.worldname)) { + if (!player.getLocation().getWorld().equals(pa.worldname)) { + player.teleport(WorldUtil.IMP.getSpawn(pa.worldname)); + } + } else { + object.terrain = 0; + object.type = 0; + SetupUtils.manager.setupWorld(object); + player.teleport(WorldUtil.IMP.getSpawn(pa.worldname)); + } + player.setMeta("area_create_area", pa); + MainUtil.sendMessage(player, + "$1Go to the first corner and use: $2 " + getCommandString() + + " create pos1"); + break; + } + return true; + case "i": + case "info": { + if (!Permissions.hasPermission(player, C.PERMISSION_AREA_INFO)) { + C.NO_PERMISSION.send(player, C.PERMISSION_AREA_INFO); + return false; + } + PlotArea area; + switch (args.length) { + case 1: + area = player.getApplicablePlotArea(); + break; + case 2: + area = PlotSquared.get().getPlotAreaByString(args[1]); + break; + default: + C.COMMAND_SYNTAX.send(player, getCommandString() + " info [area]"); + return false; + } + if (area == null) { + if (args.length == 2) { + C.NOT_VALID_PLOT_WORLD.send(player, args[1]); + } else { + C.NOT_IN_PLOT_WORLD.send(player); + } + return false; + } + String name; + double percent; + int claimed = area.getPlotCount(); + int clusters = area.getClusters().size(); + String region; + String generator = String.valueOf(area.getGenerator()); + if (area.TYPE == 2) { + PlotId min = area.getMin(); + PlotId max = area.getMax(); + name = area.worldname + ';' + area.id + ';' + min + ';' + max; + int size = (max.x - min.x + 1) * (max.y - min.y + 1); + percent = claimed == 0 ? 0 : size / (double) claimed; + region = area.getRegion().toString(); + } else { + name = area.worldname; + percent = claimed == 0 ? 0 : 100d * claimed / Integer.MAX_VALUE; + region = "N/A"; + } + String value = "&r$1NAME: " + name + "\n$1Type: $2" + area.TYPE + "\n$1Terrain: $2" + + area.TERRAIN + "\n$1Usage: $2" + String.format("%.2f", percent) + '%' + + "\n$1Claimed: $2" + claimed + "\n$1Clusters: $2" + clusters + "\n$1Region: $2" + + region + "\n$1Generator: $2" + generator; + MainUtil.sendMessage(player, + C.PLOT_INFO_HEADER.s() + '\n' + value + '\n' + C.PLOT_INFO_FOOTER.s(), false); + return true; + } + case "l": + case "list": + if (!Permissions.hasPermission(player, C.PERMISSION_AREA_LIST)) { + C.NO_PERMISSION.send(player, C.PERMISSION_AREA_LIST); + return false; + } + int page; + switch (args.length) { + case 1: + page = 0; + break; + case 2: + if (MathMan.isInteger(args[1])) { + page = Integer.parseInt(args[1]) - 1; + break; + } + default: + C.COMMAND_SYNTAX.send(player, getCommandString() + " list [#]"); + return false; + } + ArrayList areas = new ArrayList<>(PlotSquared.get().getPlotAreas()); + paginate(player, areas, 8, page, + new RunnableVal3() { + @Override public void run(Integer i, PlotArea area, PlotMessage message) { + String name; + double percent; + int claimed = area.getPlotCount(); + int clusters = area.getClusters().size(); + String region; + String generator = String.valueOf(area.getGenerator()); + if (area.TYPE == 2) { + PlotId min = area.getMin(); + PlotId max = area.getMax(); + name = area.worldname + ';' + area.id + ';' + min + ';' + max; + int size = (max.x - min.x + 1) * (max.y - min.y + 1); + percent = claimed == 0 ? 0 : size / (double) claimed; + region = area.getRegion().toString(); + } else { + name = area.worldname; + percent = claimed == 0 ? + 0 : + Short.MAX_VALUE * Short.MAX_VALUE / (double) claimed; + region = "N/A"; + } + PlotMessage tooltip = new PlotMessage().text("Claimed=").color("$1") + .text(String.valueOf(claimed)).color("$2").text("\nUsage=") + .color("$1").text(String.format("%.2f", percent) + '%').color("$2") + .text("\nClusters=").color("$1").text(String.valueOf(clusters)) + .color("$2").text("\nRegion=").color("$1").text(region).color("$2") + .text("\nGenerator=").color("$1").text(generator).color("$2"); + + // type / terrain + String visit = "/plot area tp " + area.toString(); + message.text("[").color("$3").text(String.valueOf(i)).command(visit) + .tooltip(visit).color("$1").text("]").color("$3").text(' ' + name) + .tooltip(tooltip).command(getCommandString() + " info " + area) + .color("$1").text(" - ").color("$2") + .text(area.TYPE + ":" + area.TERRAIN).color("$3"); + } + }, "/plot area list", C.AREA_LIST_HEADER_PAGED.s()); + return true; + case "regen": + case "clear": + case "reset": + case "regenerate": { + if (!Permissions.hasPermission(player, C.PERMISSION_AREA_REGEN)) { + C.NO_PERMISSION.send(player, C.PERMISSION_AREA_REGEN); + return false; + } + final PlotArea area = player.getApplicablePlotArea(); + if (area == null) { + C.NOT_IN_PLOT_WORLD.send(player); + return false; + } + if (area.TYPE != 2) { + MainUtil.sendMessage(player, + "$4Stop the server and delete: " + area.worldname + "/region"); + return false; + } + ChunkManager + .largeRegionTask(area.worldname, area.getRegion(), new RunnableVal() { + @Override public void run(ChunkLoc value) { + AugmentedUtils.generate(area.worldname, value.x, value.z, null); + } + }, () -> player.sendMessage("Regen complete")); + return true; + } + case "goto": + case "v": + case "teleport": + case "visit": + case "tp": + if (!Permissions.hasPermission(player, C.PERMISSION_AREA_TP)) { + C.NO_PERMISSION.send(player, C.PERMISSION_AREA_TP); + return false; + } + if (args.length != 2) { + C.COMMAND_SYNTAX.send(player, "/plot visit [area]"); + return false; + } + PlotArea area = PlotSquared.get().getPlotAreaByString(args[1]); + if (area == null) { + C.NOT_VALID_PLOT_WORLD.send(player, args[1]); + return false; + } + Location center; + if (area.TYPE != 2) { + center = WorldUtil.IMP.getSpawn(area.worldname); + } else { + RegionWrapper region = area.getRegion(); + center = + new Location(area.worldname, region.minX + (region.maxX - region.minX) / 2, + 0, region.minZ + (region.maxZ - region.minZ) / 2); + center.setY(1 + WorldUtil.IMP + .getHighestBlock(area.worldname, center.getX(), center.getZ())); + } + player.teleport(center); + return true; + case "delete": + case "remove": + MainUtil.sendMessage(player, + "$1World creation settings may be stored in multiple locations:" + + "\n$3 - $2Bukkit bukkit.yml" + "\n$3 - $2" + PlotSquared.imp() + .getPluginName() + " settings.yml" + + "\n$3 - $2Multiverse worlds.yml (or any world management plugin)" + + "\n$1Stop the server and delete it from these locations."); + return true; + } + C.COMMAND_SYNTAX.send(player, getUsage()); + return false; + } + +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Auto.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Auto.java new file mode 100644 index 000000000..5035c1480 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Auto.java @@ -0,0 +1,256 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.*; + +import javax.annotation.Nullable; +import java.util.Set; + +@CommandDeclaration(command = "auto", permission = "plots.auto", + category = CommandCategory.CLAIMING, requiredType = RequiredType.NONE, + description = "Claim the nearest plot", aliases = "a", usage = "/plot auto [length,width]") +public class Auto extends SubCommand { + + @Deprecated public static PlotId getNextPlotId(PlotId id, int step) { + return id.getNextId(step); + } + + private static boolean checkAllowedPlots(PlotPlayer player, PlotArea plotarea, + @Nullable Integer allowed_plots, int size_x, int size_z) { + if (allowed_plots == null) + allowed_plots = player.getAllowedPlots(); + int currentPlots = + Settings.Limit.GLOBAL ? player.getPlotCount() : player.getPlotCount(plotarea.worldname); + int diff = currentPlots - allowed_plots; + if (diff + size_x * size_z > 0) { + if (diff < 0) { + MainUtil.sendMessage(player, C.CANT_CLAIM_MORE_PLOTS_NUM, -diff + ""); + return false; + } else if (player.hasPersistentMeta("grantedPlots")) { + int grantedPlots = + ByteArrayUtilities.bytesToInteger(player.getPersistentMeta("grantedPlots")); + if (grantedPlots - diff < size_x * size_z) { + player.removePersistentMeta("grantedPlots"); + MainUtil.sendMessage(player, C.CANT_CLAIM_MORE_PLOTS); + return false; + } else { + int left = grantedPlots - diff - size_x * size_z; + if (left == 0) { + player.removePersistentMeta("grantedPlots"); + } else { + player.setPersistentMeta("grantedPlots", + ByteArrayUtilities.integerToBytes(left)); + } + MainUtil.sendMessage(player, C.REMOVED_GRANTED_PLOT, "" + left, + "" + (grantedPlots - left)); + } + } else { + MainUtil.sendMessage(player, C.CANT_CLAIM_MORE_PLOTS); + return false; + } + } + return true; + } + + /** + * Teleport the player home, or claim a new plot + * + * @param player + * @param area + * @param start + * @param schem + */ + public static void homeOrAuto(final PlotPlayer player, final PlotArea area, PlotId start, + final String schem) { + Set plots = player.getPlots(); + if (!plots.isEmpty()) { + plots.iterator().next().teleportPlayer(player); + } else { + autoClaimSafe(player, area, start, schem); + } + } + + /** + * Claim a new plot for a player + * + * @param player + * @param area + * @param start + * @param schem + */ + public static void autoClaimSafe(final PlotPlayer player, final PlotArea area, PlotId start, + final String schem) { + autoClaimSafe(player, area, start, schem, null); + } + + /** + * Claim a new plot for a player + * + * @param player + * @param area + * @param start + * @param schem + */ + public static void autoClaimSafe(final PlotPlayer player, final PlotArea area, PlotId start, + final String schem, @Nullable final Integer allowed_plots) { + player.setMeta(Auto.class.getName(), true); + autoClaimFromDatabase(player, area, start, new RunnableVal() { + @Override public void run(final Plot plot) { + TaskManager.IMP.sync(new RunnableVal() { + @Override public void run(Object ignore) { + player.deleteMeta(Auto.class.getName()); + if (plot == null) { + MainUtil.sendMessage(player, C.NO_FREE_PLOTS); + } else if (checkAllowedPlots(player, area, allowed_plots, 1, 1)) { + plot.claim(player, true, schem, false); + if (area.AUTO_MERGE) { + plot.autoMerge(-1, Integer.MAX_VALUE, player.getUUID(), true); + } + } else { + DBFunc.delete(plot); + } + } + }); + } + }); + } + + public static void autoClaimFromDatabase(final PlotPlayer player, final PlotArea area, + PlotId start, final RunnableVal whenDone) { + final Plot plot = area.getNextFreePlot(player, start); + if (plot == null) { + whenDone.run(null); + return; + } + whenDone.value = plot; + plot.owner = player.getUUID(); + DBFunc.createPlotSafe(plot, whenDone, new Runnable() { + @Override public void run() { + autoClaimFromDatabase(player, area, plot.getId(), whenDone); + } + }); + } + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + PlotArea plotarea = player.getApplicablePlotArea(); + if (plotarea == null) { + if (EconHandler.manager != null) { + for (PlotArea area : PlotSquared.get().getPlotAreaManager().getAllPlotAreas()) { + if (EconHandler.manager + .hasPermission(area.worldname, player.getName(), "plots.auto")) { + if (plotarea != null) { + plotarea = null; + break; + } + plotarea = area; + } + } + } + if (plotarea == null) { + MainUtil.sendMessage(player, C.NOT_IN_PLOT_WORLD); + return false; + } + } + int size_x = 1; + int size_z = 1; + String schematic = null; + if (args.length > 0) { + if (Permissions.hasPermission(player, C.PERMISSION_AUTO_MEGA)) { + try { + String[] split = args[0].split(",|;"); + size_x = Integer.parseInt(split[0]); + size_z = Integer.parseInt(split[1]); + if (size_x < 1 || size_z < 1) { + MainUtil.sendMessage(player, "&cError: size<=0"); + } + if (args.length > 1) { + schematic = args[1]; + } + } catch (NumberFormatException ignored) { + size_x = 1; + size_z = 1; + schematic = args[0]; + // PlayerFunctions.sendMessage(plr, + // "&cError: Invalid size (X,Y)"); + // return false; + } + } else { + schematic = args[0]; + // PlayerFunctions.sendMessage(plr, C.NO_PERMISSION); + // return false; + } + } + if (size_x * size_z > Settings.Claim.MAX_AUTO_AREA) { + MainUtil.sendMessage(player, C.CANT_CLAIM_MORE_PLOTS_NUM, + Settings.Claim.MAX_AUTO_AREA + ""); + return false; + } + final int allowed_plots = player.getAllowedPlots(); + if (player.getMeta(Auto.class.getName(), false) || !checkAllowedPlots(player, plotarea, + allowed_plots, size_x, size_z)) + return false; + + if (schematic != null && !schematic.isEmpty()) { + if (!plotarea.SCHEMATICS.contains(schematic.toLowerCase())) { + sendMessage(player, C.SCHEMATIC_INVALID, "non-existent: " + schematic); + return true; + } + if (!Permissions.hasPermission(player, C.PERMISSION_CLAIM_SCHEMATIC.f(schematic)) + && !Permissions.hasPermission(player, C.PERMISSION_ADMIN_COMMAND_SCHEMATIC)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_CLAIM_SCHEMATIC.f(schematic)); + return true; + } + } + if (EconHandler.manager != null && plotarea.USE_ECONOMY) { + Expression costExp = plotarea.PRICES.get("claim"); + double cost = costExp.evaluate((double) (Settings.Limit.GLOBAL ? + player.getPlotCount() : + player.getPlotCount(plotarea.worldname))); + cost = (size_x * size_z) * cost; + if (cost > 0d) { + if (EconHandler.manager.getMoney(player) < cost) { + sendMessage(player, C.CANNOT_AFFORD_PLOT, "" + cost); + return true; + } + EconHandler.manager.withdrawMoney(player, cost); + sendMessage(player, C.REMOVED_BALANCE, cost + ""); + } + } + // TODO handle type 2 the same as normal worlds! + if (size_x == 1 && size_z == 1) { + autoClaimSafe(player, plotarea, null, schematic, allowed_plots); + return true; + } else { + if (plotarea.TYPE == 2) { + MainUtil.sendMessage(player, C.NO_FREE_PLOTS); + return false; + } + while (true) { + PlotId start = plotarea.getMeta("lastPlot", new PlotId(0, 0)).getNextId(1); + PlotId end = new PlotId(start.x + size_x - 1, start.y + size_z - 1); + if (plotarea.canClaim(player, start, end)) { + plotarea.setMeta("lastPlot", start); + for (int i = start.x; i <= end.x; i++) { + for (int j = start.y; j <= end.y; j++) { + Plot plot = plotarea.getPlotAbs(new PlotId(i, j)); + boolean teleport = i == end.x && j == end.y; + plot.claim(player, teleport, null); + } + } + if (!plotarea.mergePlots(MainUtil.getPlotSelectionIds(start, end), true)) { + return false; + } + break; + } + plotarea.setMeta("lastPlot", start); + } + return true; + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Biome.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Biome.java new file mode 100644 index 000000000..82a573949 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Biome.java @@ -0,0 +1,38 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.StringMan; +import com.github.intellectualsites.plotsquared.plot.util.WorldUtil; + +@CommandDeclaration(command = "setbiome", permission = "plots.set.biome", + description = "Set the plot biome", usage = "/plot biome [biome]", + aliases = {"biome", "sb", "setb", "b"}, category = CommandCategory.APPEARANCE, + requiredType = RequiredType.NONE) public class Biome extends SetCommand { + + @Override public boolean set(final PlotPlayer player, final Plot plot, final String value) { + int biome = WorldUtil.IMP.getBiomeFromString(value); + if (biome == -1) { + String biomes = + StringMan.join(WorldUtil.IMP.getBiomeList(), C.BLOCK_LIST_SEPARATER.s()); + C.NEED_BIOME.send(player); + MainUtil.sendMessage(player, C.SUBCOMMAND_SET_OPTIONS_HEADER.s() + biomes); + return false; + } + if (plot.getRunning() > 0) { + MainUtil.sendMessage(player, C.WAIT_FOR_TIMER); + return false; + } + plot.addRunning(); + plot.setBiome(value.toUpperCase(), new Runnable() { + @Override public void run() { + plot.removeRunning(); + MainUtil.sendMessage(player, C.BIOME_SET_TO.s() + value.toLowerCase()); + } + }); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Buy.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Buy.java new file mode 100644 index 000000000..25f9484b1 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Buy.java @@ -0,0 +1,72 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.flag.Flags; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3; +import com.github.intellectualsites.plotsquared.plot.util.EconHandler; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; + +import java.util.Optional; +import java.util.Set; + +@CommandDeclaration(command = "buy", description = "Buy the plot you are standing on", + usage = "/plot buy", permission = "plots.buy", category = CommandCategory.CLAIMING, + requiredType = RequiredType.NONE) public class Buy extends Command { + + public Buy() { + super(MainCommand.getInstance(), true); + } + + @Override public void execute(final PlotPlayer player, String[] args, + RunnableVal3 confirm, + final RunnableVal2 whenDone) { + check(EconHandler.manager, C.ECON_DISABLED); + final Plot plot; + if (args.length != 0) { + checkTrue(args.length == 1, C.COMMAND_SYNTAX, getUsage()); + plot = check(MainUtil.getPlotFromString(player, args[0], true), null); + } else { + plot = check(player.getCurrentPlot(), C.NOT_IN_PLOT); + } + checkTrue(plot.hasOwner(), C.PLOT_UNOWNED); + checkTrue(!plot.isOwner(player.getUUID()), C.CANNOT_BUY_OWN); + Set plots = plot.getConnectedPlots(); + checkTrue(player.getPlotCount() + plots.size() <= player.getAllowedPlots(), + C.CANT_CLAIM_MORE_PLOTS); + Optional flag = plot.getFlag(Flags.PRICE); + if (!flag.isPresent()) { + throw new CommandException(C.NOT_FOR_SALE); + } + final double price = flag.get(); + checkTrue(player.getMoney() >= price, C.CANNOT_AFFORD_PLOT); + player.withdraw(price); + confirm.run(this, new Runnable() { + @Override // Success + public void run() { + C.REMOVED_BALANCE.send(player, price); + EconHandler.manager + .depositMoney(UUIDHandler.getUUIDWrapper().getOfflinePlayer(plot.owner), price); + PlotPlayer owner = UUIDHandler.getPlayer(plot.owner); + if (owner != null) { + C.PLOT_SOLD.send(owner, plot.getId(), player.getName(), price); + } + plot.removeFlag(Flags.PRICE); + plot.setOwner(player.getUUID()); + C.CLAIMED.send(player); + whenDone.run(Buy.this, CommandResult.SUCCESS); + } + }, new Runnable() { + @Override // Failure + public void run() { + player.deposit(price); + whenDone.run(Buy.this, CommandResult.FAILURE); + } + }); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Chat.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Chat.java new file mode 100644 index 000000000..453a6a8ac --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Chat.java @@ -0,0 +1,14 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; + +@CommandDeclaration(command = "chat", description = "Toggle plot chat on or off", + usage = "/plot chat [on|off]", permission = "plots.chat", category = CommandCategory.CHAT, + requiredType = RequiredType.NONE) public class Chat extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + MainCommand.getInstance().toggle.chat(this, player, new String[0], null, null); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Claim.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Claim.java new file mode 100644 index 000000000..e49155b8d --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Claim.java @@ -0,0 +1,99 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.ByteArrayUtilities; +import com.github.intellectualsites.plotsquared.plot.util.EconHandler; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; +import com.github.intellectualsites.plotsquared.plot.util.TaskManager; + +@CommandDeclaration(command = "claim", aliases = "c", + description = "Claim the current plot you're standing on", category = CommandCategory.CLAIMING, + requiredType = RequiredType.NONE, permission = "plots.claim", usage = "/plot claim") +public class Claim extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + String schematic = ""; + if (args.length >= 1) { + schematic = args[0]; + } + Location loc = player.getLocation(); + final Plot plot = loc.getPlotAbs(); + if (plot == null) { + return sendMessage(player, C.NOT_IN_PLOT); + } + int currentPlots = + Settings.Limit.GLOBAL ? player.getPlotCount() : player.getPlotCount(loc.getWorld()); + int grants = 0; + if (currentPlots >= player.getAllowedPlots()) { + if (player.hasPersistentMeta("grantedPlots")) { + grants = + ByteArrayUtilities.bytesToInteger(player.getPersistentMeta("grantedPlots")); + if (grants <= 0) { + player.removePersistentMeta("grantedPlots"); + return sendMessage(player, C.CANT_CLAIM_MORE_PLOTS); + } + } else { + return sendMessage(player, C.CANT_CLAIM_MORE_PLOTS); + } + } + if (!plot.canClaim(player)) { + return sendMessage(player, C.PLOT_IS_CLAIMED); + } + final PlotArea area = plot.getArea(); + if (!schematic.isEmpty()) { + if (area.SCHEMATIC_CLAIM_SPECIFY) { + if (!area.SCHEMATICS.contains(schematic.toLowerCase())) { + return sendMessage(player, C.SCHEMATIC_INVALID, "non-existent: " + schematic); + } + if (!Permissions.hasPermission(player, C.PERMISSION_CLAIM_SCHEMATIC.f(schematic)) + && !Permissions.hasPermission(player, C.PERMISSION_ADMIN_COMMAND_SCHEMATIC)) { + return sendMessage(player, C.NO_SCHEMATIC_PERMISSION, schematic); + } + } + } + int border = area.getBorder(); + if (border != Integer.MAX_VALUE && plot.getDistanceFromOrigin() > border) { + return !sendMessage(player, C.BORDER); + } + if ((EconHandler.manager != null) && area.USE_ECONOMY) { + Expression costExr = area.PRICES.get("claim"); + double cost = costExr.evaluate((double) currentPlots); + if (cost > 0d) { + if (EconHandler.manager.getMoney(player) < cost) { + return sendMessage(player, C.CANNOT_AFFORD_PLOT, "" + cost); + } + EconHandler.manager.withdrawMoney(player, cost); + sendMessage(player, C.REMOVED_BALANCE, cost + ""); + } + } + if (grants > 0) { + if (grants == 1) { + player.removePersistentMeta("grantedPlots"); + } else { + player.setPersistentMeta("grantedPlots", + ByteArrayUtilities.integerToBytes(grants - 1)); + } + sendMessage(player, C.REMOVED_GRANTED_PLOT, "1", "" + (grants - 1)); + } + if (plot.canClaim(player)) { + plot.owner = player.getUUID(); + final String finalSchematic = schematic; + DBFunc.createPlotSafe(plot, () -> TaskManager.IMP.sync(new RunnableVal() { + @Override public void run(Object value) { + plot.claim(player, true, finalSchematic, false); + if (area.AUTO_MERGE) { + plot.autoMerge(-1, Integer.MAX_VALUE, player.getUUID(), true); + } + } + }), () -> sendMessage(player, C.PLOT_NOT_CLAIMED)); + return true; + } else { + sendMessage(player, C.PLOT_NOT_CLAIMED); + } + return false; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Clear.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Clear.java new file mode 100644 index 000000000..efd6b1525 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Clear.java @@ -0,0 +1,68 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.flag.FlagManager; +import com.github.intellectualsites.plotsquared.plot.flag.Flags; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; +import com.github.intellectualsites.plotsquared.plot.util.block.GlobalBlockQueue; + +@CommandDeclaration(command = "clear", description = "Clear the plot you stand on", + permission = "plots.clear", category = CommandCategory.APPEARANCE, usage = "/plot clear", + aliases = "reset", confirmation = true) public class Clear extends Command { + + // Note: To clear a specific plot use /plot clear + // The syntax also works with any command: /plot + + public Clear() { + super(MainCommand.getInstance(), true); + } + + @Override public void execute(final PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) throws CommandException { + checkTrue(args.length == 0, C.COMMAND_SYNTAX, getUsage()); + final Plot plot = check(player.getCurrentPlot(), C.NOT_IN_PLOT); + checkTrue(plot.isOwner(player.getUUID()) || Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_CLEAR), C.NO_PLOT_PERMS); + checkTrue(plot.getRunning() == 0, C.WAIT_FOR_TIMER); + checkTrue(!Settings.Done.RESTRICT_BUILDING || !Flags.DONE.isSet(plot) || Permissions + .hasPermission(player, C.PERMISSION_CONTINUE), C.DONE_ALREADY_DONE); + confirm.run(this, new Runnable() { + @Override public void run() { + final long start = System.currentTimeMillis(); + boolean result = plot.clear(true, false, new Runnable() { + @Override public void run() { + plot.unlink(); + GlobalBlockQueue.IMP.addTask(new Runnable() { + @Override public void run() { + plot.removeRunning(); + // If the state changes, then mark it as no longer done + if (plot.getFlag(Flags.DONE).isPresent()) { + FlagManager.removePlotFlag(plot, Flags.DONE); + } + if (plot.getFlag(Flags.ANALYSIS).isPresent()) { + FlagManager.removePlotFlag(plot, Flags.ANALYSIS); + } + MainUtil.sendMessage(player, C.CLEARING_DONE, + "" + (System.currentTimeMillis() - start)); + } + }); + } + }); + if (!result) { + MainUtil.sendMessage(player, C.WAIT_FOR_TIMER); + } else { + plot.addRunning(); + } + } + }, null); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Cluster.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Cluster.java new file mode 100644 index 000000000..b4b24021f --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Cluster.java @@ -0,0 +1,612 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; +import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +@CommandDeclaration(command = "cluster", aliases = "clusters", + category = CommandCategory.ADMINISTRATION, requiredType = RequiredType.NONE, + permission = "plots.cluster", description = "Manage a plot cluster") public class Cluster + extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + + // list, create, delete, resize, invite, kick, leave, helpers, tp, sethome + if (args.length == 0) { + // return arguments + MainUtil.sendMessage(player, C.CLUSTER_AVAILABLE_ARGS); + return false; + } + String sub = args[0].toLowerCase(); + switch (sub) { + case "l": + case "list": { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_LIST)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_LIST); + return false; + } + if (args.length != 1) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot cluster list"); + return false; + } + PlotArea area = player.getApplicablePlotArea(); + if (area == null) { + C.NOT_IN_PLOT_WORLD.send(player); + return false; + } + Set clusters = area.getClusters(); + MainUtil.sendMessage(player, C.CLUSTER_LIST_HEADING, clusters.size() + ""); + for (PlotCluster cluster : clusters) { + // Ignore unmanaged clusters + String name = "'" + cluster.getName() + "' : " + cluster.toString(); + if (player.getUUID().equals(cluster.owner)) { + MainUtil.sendMessage(player, C.CLUSTER_LIST_ELEMENT, "&a" + name); + } else if (cluster.helpers.contains(player.getUUID())) { + MainUtil.sendMessage(player, C.CLUSTER_LIST_ELEMENT, "&3" + name); + } else if (cluster.invited.contains(player.getUUID())) { + MainUtil.sendMessage(player, C.CLUSTER_LIST_ELEMENT, "&9" + name); + } else { + MainUtil.sendMessage(player, C.CLUSTER_LIST_ELEMENT, cluster.toString()); + } + } + return true; + } + case "c": + case "create": { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_CREATE)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_CREATE); + return false; + } + PlotArea area = player.getApplicablePlotArea(); + if (area == null) { + C.NOT_IN_PLOT_WORLD.send(player); + return false; + } + if (args.length != 4) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, + "/plot cluster create "); + return false; + } + int currentClusters = Settings.Limit.GLOBAL ? + player.getClusterCount() : + player.getPlotCount(player.getLocation().getWorld()); + if (currentClusters >= player.getAllowedPlots()) { + return sendMessage(player, C.CANT_CLAIM_MORE_CLUSTERS); + } + // check pos1 / pos2 + PlotId pos1 = PlotId.fromString(args[2]); + PlotId pos2 = PlotId.fromString(args[3]); + if (pos1 == null || pos2 == null) { + MainUtil.sendMessage(player, C.NOT_VALID_PLOT_ID); + return false; + } + // check if name is taken + String name = args[1]; + if (area.getCluster(name) != null) { + MainUtil.sendMessage(player, C.ALIAS_IS_TAKEN); + return false; + } + if (pos2.x < pos1.x || pos2.y < pos1.y) { + PlotId tmp = new PlotId(Math.min(pos1.x, pos2.x), Math.min(pos1.y, pos2.y)); + pos2 = new PlotId(Math.max(pos1.x, pos2.x), Math.max(pos1.y, pos2.y)); + pos1 = tmp; + } + //check if overlap + PlotCluster cluster = area.getFirstIntersectingCluster(pos1, pos2); + if (cluster != null) { + MainUtil.sendMessage(player, C.CLUSTER_INTERSECTION, cluster.getName()); + return false; + } + // Check if it occupies existing plots + if (!area.contains(pos1) || !area.contains(pos2)) { + C.CLUSTER_OUTSIDE.send(player, area); + return false; + } + Set plots = area.getPlotSelectionOwned(pos1, pos2); + if (!plots.isEmpty()) { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_CREATE_OTHER)) { + UUID uuid = player.getUUID(); + for (Plot plot : plots) { + if (!plot.isOwner(uuid)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_CLUSTER_CREATE_OTHER); + return false; + } + } + } + } + // Check allowed cluster size + cluster = new PlotCluster(area, pos1, pos2, player.getUUID()); + int current; + if (Settings.Limit.GLOBAL) { + current = player.getPlayerClusterCount(); + } else { + current = player.getPlayerClusterCount(player.getLocation().getWorld()); + } + int allowed = Permissions.hasPermissionRange(player, C.PERMISSION_CLUSTER_SIZE, + Settings.Limit.MAX_PLOTS); + if (current + cluster.getArea() > allowed) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_CLUSTER_SIZE + "." + (current + cluster.getArea())); + return false; + } + // create cluster + cluster.settings.setAlias(name); + area.addCluster(cluster); + DBFunc.createCluster(cluster); + // Add any existing plots to the current cluster + for (Plot plot : plots) { + if (plot.hasOwner()) { + if (!cluster.isAdded(plot.owner)) { + cluster.invited.add(plot.owner); + DBFunc.setInvited(cluster, plot.owner); + } + } + } + MainUtil.sendMessage(player, C.CLUSTER_ADDED); + return true; + } + case "disband": + case "del": + case "delete": { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_DELETE)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_DELETE); + return false; + } + if (args.length != 1 && args.length != 2) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot cluster delete [name]"); + return false; + } + PlotArea area = player.getApplicablePlotArea(); + if (area == null) { + C.NOT_IN_PLOT_WORLD.send(player); + return false; + } + PlotCluster cluster; + if (args.length == 2) { + cluster = area.getCluster(args[1]); + if (cluster == null) { + MainUtil.sendMessage(player, C.INVALID_CLUSTER, args[1]); + return false; + } + } else { + cluster = area.getCluster(player.getLocation()); + if (cluster == null) { + MainUtil.sendMessage(player, C.NOT_IN_CLUSTER); + return false; + } + } + if (!cluster.owner.equals(player.getUUID())) { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_DELETE_OTHER)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_CLUSTER_DELETE_OTHER); + return false; + } + } + DBFunc.delete(cluster); + MainUtil.sendMessage(player, C.CLUSTER_DELETED); + return true; + } + case "res": + case "resize": { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_RESIZE)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_RESIZE); + return false; + } + if (args.length != 3) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, + "/plot cluster resize "); + return false; + } + // check pos1 / pos2 + PlotId pos1 = PlotId.fromString(args[1]); + PlotId pos2 = PlotId.fromString(args[2]); + if (pos1 == null || pos2 == null) { + MainUtil.sendMessage(player, C.NOT_VALID_PLOT_ID); + return false; + } + if (pos2.x < pos1.x || pos2.y < pos1.y) { + pos1 = new PlotId(Math.min(pos1.x, pos2.x), Math.min(pos1.y, pos2.y)); + pos2 = new PlotId(Math.max(pos1.x, pos2.x), Math.max(pos1.y, pos2.y)); + } + // check if in cluster + PlotArea area = player.getApplicablePlotArea(); + if (area == null) { + C.NOT_IN_PLOT_WORLD.send(player); + return false; + } + PlotCluster cluster = area.getCluster(player.getLocation()); + if (cluster == null) { + MainUtil.sendMessage(player, C.NOT_IN_CLUSTER); + return false; + } + if (!cluster.hasHelperRights(player.getUUID())) { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_RESIZE_OTHER)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_CLUSTER_RESIZE_OTHER); + return false; + } + } + //check if overlap + PlotCluster intersect = area.getFirstIntersectingCluster(pos1, pos2); + if (intersect != null) { + MainUtil.sendMessage(player, C.CLUSTER_INTERSECTION, intersect.getName()); + return false; + } + Set existing = area.getPlotSelectionOwned(cluster.getP1(), cluster.getP2()); + Set newPlots = area.getPlotSelectionOwned(pos1, pos2); + // Set removed = (HashSet) existing.clone(); + Set removed = new HashSet<>(existing); + + removed.removeAll(newPlots); + // Check expand / shrink + if (!removed.isEmpty()) { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_RESIZE_SHRINK)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_CLUSTER_RESIZE_SHRINK); + return false; + } + } + newPlots.removeAll(existing); + if (!newPlots.isEmpty()) { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_RESIZE_EXPAND)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_CLUSTER_RESIZE_EXPAND); + return false; + } + } + // Check allowed cluster size + int current; + if (Settings.Limit.GLOBAL) { + current = player.getPlayerClusterCount(); + } else { + current = player.getPlayerClusterCount(player.getLocation().getWorld()); + } + current -= cluster.getArea() + (1 + pos2.x - pos1.x) * (1 + pos2.y - pos1.y); + int allowed = Permissions + .hasPermissionRange(player, C.PERMISSION_CLUSTER, Settings.Limit.MAX_PLOTS); + if (current + cluster.getArea() > allowed) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_CLUSTER.s() + "." + (current + cluster.getArea())); + return false; + } + // resize cluster + DBFunc.resizeCluster(cluster, pos1, pos2); + MainUtil.sendMessage(player, C.CLUSTER_RESIZED); + return true; + } + case "add": + case "inv": + case "invite": { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_INVITE)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_INVITE); + return false; + } + if (args.length != 2) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot cluster invite "); + return false; + } + // check if in cluster + PlotArea area = player.getApplicablePlotArea(); + if (area == null) { + C.NOT_IN_PLOT_WORLD.send(player); + return false; + } + PlotCluster cluster = area.getCluster(player.getLocation()); + if (cluster == null) { + MainUtil.sendMessage(player, C.NOT_IN_CLUSTER); + return false; + } + if (!cluster.hasHelperRights(player.getUUID())) { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_INVITE_OTHER)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_CLUSTER_INVITE_OTHER); + return false; + } + } + // check uuid + UUID uuid = UUIDHandler.getUUID(args[1], null); + if (uuid == null) { + MainUtil.sendMessage(player, C.INVALID_PLAYER, args[2]); + return false; + } + if (!cluster.isAdded(uuid)) { + // add the user if not added + cluster.invited.add(uuid); + DBFunc.setInvited(cluster, uuid); + PlotPlayer player2 = UUIDHandler.getPlayer(uuid); + if (player2 != null) { + MainUtil.sendMessage(player2, C.CLUSTER_INVITED, cluster.getName()); + } + } + MainUtil.sendMessage(player, C.CLUSTER_ADDED_USER); + return true; + } + case "k": + case "remove": + case "kick": { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_KICK)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_KICK); + return false; + } + if (args.length != 2) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot cluster kick "); + return false; + } + PlotArea area = player.getApplicablePlotArea(); + if (area == null) { + C.NOT_IN_PLOT_WORLD.send(player); + return false; + } + PlotCluster cluster = area.getCluster(player.getLocation()); + if (cluster == null) { + MainUtil.sendMessage(player, C.NOT_IN_CLUSTER); + return false; + } + if (!cluster.hasHelperRights(player.getUUID())) { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_KICK_OTHER)) { + MainUtil + .sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_KICK_OTHER); + return false; + } + } + // check uuid + UUID uuid = UUIDHandler.getUUID(args[1], null); + if (uuid == null) { + MainUtil.sendMessage(player, C.INVALID_PLAYER, args[1]); + return false; + } + // Can't kick if the player is yourself, the owner, or not added to the cluster + if (uuid.equals(player.getUUID()) || uuid.equals(cluster.owner) || !cluster + .isAdded(uuid)) { + MainUtil.sendMessage(player, C.CANNOT_KICK_PLAYER, cluster.getName()); + return false; + } + if (cluster.helpers.contains(uuid)) { + cluster.helpers.remove(uuid); + DBFunc.removeHelper(cluster, uuid); + } + cluster.invited.remove(uuid); + DBFunc.removeInvited(cluster, uuid); + PlotPlayer player2 = UUIDHandler.getPlayer(uuid); + if (player2 != null) { + MainUtil.sendMessage(player2, C.CLUSTER_REMOVED, cluster.getName()); + } + for (Plot plot : new ArrayList<>( + PlotSquared.get().getPlots(player2.getLocation().getWorld(), uuid))) { + PlotCluster current = plot.getCluster(); + if (current != null && current.equals(cluster)) { + plot.unclaim(); + } + } + MainUtil.sendMessage(player2, C.CLUSTER_KICKED_USER); + return true; + } + case "quit": + case "leave": { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_LEAVE)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_LEAVE); + return false; + } + if (args.length != 1 && args.length != 2) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot cluster leave [name]"); + return false; + } + PlotArea area = player.getApplicablePlotArea(); + if (area == null) { + C.NOT_IN_PLOT_WORLD.send(player); + return false; + } + PlotCluster cluster; + if (args.length == 2) { + cluster = area.getCluster(args[1]); + if (cluster == null) { + MainUtil.sendMessage(player, C.INVALID_CLUSTER, args[1]); + return false; + } + } else { + cluster = area.getCluster(player.getLocation()); + if (cluster == null) { + MainUtil.sendMessage(player, C.NOT_IN_CLUSTER); + return false; + } + } + UUID uuid = player.getUUID(); + if (!cluster.isAdded(uuid)) { + MainUtil.sendMessage(player, C.CLUSTER_NOT_ADDED); + return false; + } + if (uuid.equals(cluster.owner)) { + MainUtil.sendMessage(player, C.CLUSTER_CANNOT_LEAVE); + return false; + } + if (cluster.helpers.contains(uuid)) { + cluster.helpers.remove(uuid); + DBFunc.removeHelper(cluster, uuid); + } + cluster.invited.remove(uuid); + DBFunc.removeInvited(cluster, uuid); + MainUtil.sendMessage(player, C.CLUSTER_REMOVED, cluster.getName()); + for (Plot plot : new ArrayList<>( + PlotSquared.get().getPlots(player.getLocation().getWorld(), uuid))) { + PlotCluster current = plot.getCluster(); + if (current != null && current.equals(cluster)) { + plot.unclaim(); + } + } + return true; + } + case "members": + case "admin": + case "helper": + case "helpers": { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_HELPERS)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_HELPERS); + return false; + } + if (args.length != 3) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, + "/plot cluster helpers "); + return false; + } + PlotArea area = player.getApplicablePlotArea(); + if (area == null) { + C.NOT_IN_PLOT_WORLD.send(player); + return false; + } + PlotCluster cluster = area.getCluster(player.getLocation()); + if (cluster == null) { + MainUtil.sendMessage(player, C.NOT_IN_CLUSTER); + return false; + } + UUID uuid = UUIDHandler.getUUID(args[2], null); + if (uuid == null) { + MainUtil.sendMessage(player, C.INVALID_PLAYER, args[2]); + return false; + } + if (args[1].equalsIgnoreCase("add")) { + cluster.helpers.add(uuid); + DBFunc.setHelper(cluster, uuid); + return MainUtil.sendMessage(player, C.CLUSTER_ADDED_HELPER); + } + if (args[1].equalsIgnoreCase("remove")) { + cluster.helpers.remove(uuid); + DBFunc.removeHelper(cluster, uuid); + return MainUtil.sendMessage(player, C.CLUSTER_REMOVED_HELPER); + } + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, + "/plot cluster helpers "); + return false; + } + case "spawn": + case "home": + case "tp": { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_TP)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_TP); + return false; + } + if (args.length != 2) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot cluster tp "); + return false; + } + PlotArea area = player.getApplicablePlotArea(); + if (area == null) { + C.NOT_IN_PLOT_WORLD.send(player); + return false; + } + PlotCluster cluster = area.getCluster(args[1]); + if (cluster == null) { + MainUtil.sendMessage(player, C.INVALID_CLUSTER, args[1]); + return false; + } + UUID uuid = player.getUUID(); + if (!cluster.isAdded(uuid)) { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_TP_OTHER)) { + MainUtil + .sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_TP_OTHER); + return false; + } + } + player.teleport(cluster.getHome()); + return MainUtil.sendMessage(player, C.CLUSTER_TELEPORTING); + } + case "i": + case "info": + case "show": + case "information": { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_INFO)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_INFO); + return false; + } + if (args.length != 1 && args.length != 2) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot cluster info [name]"); + return false; + } + PlotArea area = player.getApplicablePlotArea(); + if (area == null) { + C.NOT_IN_PLOT_WORLD.send(player); + return false; + } + PlotCluster cluster; + if (args.length == 2) { + cluster = area.getCluster(args[1]); + if (cluster == null) { + MainUtil.sendMessage(player, C.INVALID_CLUSTER, args[1]); + return false; + } + } else { + cluster = area.getCluster(player.getLocation()); + if (cluster == null) { + MainUtil.sendMessage(player, C.NOT_IN_CLUSTER); + return false; + } + } + String id = cluster.toString(); + String owner = UUIDHandler.getName(cluster.owner); + if (owner == null) { + owner = "unknown"; + } + String name = cluster.getName(); + String size = (cluster.getP2().x - cluster.getP1().x + 1) + "x" + ( + cluster.getP2().y - cluster.getP1().y + 1); + String rights = cluster.isAdded(player.getUUID()) + ""; + String message = C.CLUSTER_INFO.s(); + message = message.replaceAll("%id%", id); + message = message.replaceAll("%owner%", owner); + message = message.replaceAll("%name%", name); + message = message.replaceAll("%size%", size); + message = message.replaceAll("%rights%", rights); + MainUtil.sendMessage(player, message); + return true; + } + case "sh": + case "setspawn": + case "sethome": + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_SETHOME)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_CLUSTER_SETHOME); + return false; + } + if (args.length != 1 && args.length != 2) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot cluster sethome"); + return false; + } + PlotArea area = player.getApplicablePlotArea(); + if (area == null) { + C.NOT_IN_PLOT_WORLD.send(player); + return false; + } + PlotCluster cluster = area.getCluster(player.getLocation()); + if (cluster == null) { + MainUtil.sendMessage(player, C.NOT_IN_CLUSTER); + return false; + } + if (!cluster.hasHelperRights(player.getUUID())) { + if (!Permissions.hasPermission(player, C.PERMISSION_CLUSTER_SETHOME_OTHER)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_CLUSTER_SETHOME_OTHER); + return false; + } + } + Location base = cluster.getClusterBottom(); + Location relative = player.getLocation().subtract(base.getX(), 0, base.getZ()); + BlockLoc blockloc = new BlockLoc(relative.getX(), relative.getY(), relative.getZ()); + cluster.settings.setPosition(blockloc); + DBFunc.setPosition(cluster, + relative.getX() + "," + relative.getY() + "," + relative.getZ()); + return MainUtil.sendMessage(player, C.POSITION_SET); + } + MainUtil.sendMessage(player, C.CLUSTER_AVAILABLE_ARGS); + return false; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/CommandCategory.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/CommandCategory.java new file mode 100644 index 000000000..4aeacf85c --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/CommandCategory.java @@ -0,0 +1,56 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +/** + * CommandCategory. + */ +public enum CommandCategory { + /** + * Claiming CommandConfig. + * Such as: /plot claim + */ + CLAIMING("Claiming"), /** + * Teleportation CommandConfig. + * Such as: /plot visit + */ + TELEPORT("Teleport"), /** + * Protection. + */ + SETTINGS("Protection"), /** + * Chat. + */ + CHAT("Chat"), /** + * Web. + */ + SCHEMATIC("Web"), /** + * Cosmetic. + */ + APPEARANCE("Cosmetic"), /** + * Information CommandConfig. + * Such as: /plot info + */ + INFO("Info"), /** + * Debug CommandConfig. + * Such as: /plot debug + */ + DEBUG("Debug"), /** + * Administration commands. + */ + ADMINISTRATION("Admin"); + /** + * The category name (Readable). + */ + private final String name; + + /** + * Constructor. + * + * @param name readable name + */ + CommandCategory(String name) { + this.name = name; + } + + @Override public String toString() { + return this.name; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Comment.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Comment.java new file mode 100644 index 000000000..775450517 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Comment.java @@ -0,0 +1,74 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotId; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.comment.CommentInbox; +import com.github.intellectualsites.plotsquared.plot.object.comment.PlotComment; +import com.github.intellectualsites.plotsquared.plot.util.CommentManager; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.StringMan; +import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; + +import java.util.Arrays; +import java.util.Map.Entry; + +@CommandDeclaration(command = "comment", aliases = {"msg"}, description = "Comment on a plot", + category = CommandCategory.CHAT, requiredType = RequiredType.NONE, permission = "plots.comment") +public class Comment extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + if (args.length < 2) { + sendMessage(player, C.COMMENT_SYNTAX, + StringMan.join(CommentManager.inboxes.keySet(), "|")); + return false; + } + CommentInbox inbox = CommentManager.inboxes.get(args[0].toLowerCase()); + if (inbox == null) { + sendMessage(player, C.COMMENT_SYNTAX, + StringMan.join(CommentManager.inboxes.keySet(), "|")); + return false; + } + Location loc = player.getLocation(); + PlotId id = PlotId.fromString(args[1]); + Plot plot = MainUtil.getPlotFromString(player, args[1], false); + int index; + if (plot == null) { + index = 1; + plot = loc.getPlotAbs(); + } else { + if (args.length < 4) { + sendMessage(player, C.COMMENT_SYNTAX, + StringMan.join(CommentManager.inboxes.keySet(), "|")); + return false; + } + index = 2; + } + if (!inbox.canWrite(plot, player)) { + sendMessage(player, C.NO_PERM_INBOX, ""); + return false; + } + String message = StringMan.join(Arrays.copyOfRange(args, index, args.length), " "); + PlotComment comment = + new PlotComment(loc.getWorld(), id, message, player.getName(), inbox.toString(), + System.currentTimeMillis()); + boolean result = inbox.addComment(plot, comment); + if (!result) { + sendMessage(player, C.NO_PLOT_INBOX, ""); + sendMessage(player, C.COMMENT_SYNTAX, + StringMan.join(CommentManager.inboxes.keySet(), "|")); + return false; + } + for (Entry entry : UUIDHandler.getPlayers().entrySet()) { + PlotPlayer pp = entry.getValue(); + if (pp.getAttribute("chatspy")) { + MainUtil.sendMessage(pp, "/plot comment " + StringMan.join(args, " ")); + } + } + sendMessage(player, C.COMMENT_ADDED); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Condense.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Condense.java new file mode 100644 index 000000000..44d0e5593 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Condense.java @@ -0,0 +1,209 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; +import com.github.intellectualsites.plotsquared.plot.object.PlotId; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.MathMan; +import com.github.intellectualsites.plotsquared.plot.util.TaskManager; +import com.github.intellectualsites.plotsquared.plot.util.WorldUtil; + +import java.util.*; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +@CommandDeclaration(command = "condense", permission = "plots.admin", + description = "Condense a plotworld", category = CommandCategory.ADMINISTRATION, + requiredType = RequiredType.CONSOLE) public class Condense extends SubCommand { + + public static boolean TASK = false; + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + if (args.length != 2 && args.length != 3) { + MainUtil.sendMessage(player, "/plot condense [radius]"); + return false; + } + PlotArea area = PlotSquared.get().getPlotAreaByString(args[0]); + if (area == null || !WorldUtil.IMP.isWorld(area.worldname)) { + MainUtil.sendMessage(player, "INVALID AREA"); + return false; + } + switch (args[1].toLowerCase()) { + case "start": { + if (args.length == 2) { + MainUtil.sendMessage(player, + "/plot condense " + area.toString() + " start "); + return false; + } + if (Condense.TASK) { + MainUtil.sendMessage(player, "TASK ALREADY STARTED"); + return false; + } + if (!MathMan.isInteger(args[2])) { + MainUtil.sendMessage(player, "INVALID RADIUS"); + return false; + } + int radius = Integer.parseInt(args[2]); + ArrayList plots = new ArrayList<>(PlotSquared.get().getPlots(area)); + // remove non base plots + Iterator iterator = plots.iterator(); + int maxSize = 0; + ArrayList sizes = new ArrayList<>(); + while (iterator.hasNext()) { + Plot plot = iterator.next(); + if (!plot.isBasePlot()) { + iterator.remove(); + continue; + } + int size = plot.getConnectedPlots().size(); + if (size > maxSize) { + maxSize = size; + } + sizes.add(size - 1); + } + // Sort plots by size (buckets?)] + //noinspection unchecked + ArrayList[] buckets = new ArrayList[maxSize]; + for (int i = 0; i < plots.size(); i++) { + Plot plot = plots.get(i); + int size = sizes.get(i); + ArrayList array = buckets[size]; + if (array == null) { + array = new ArrayList<>(); + buckets[size] = array; + } + array.add(plot); + } + final ArrayList allPlots = new ArrayList<>(plots.size()); + for (int i = buckets.length - 1; i >= 0; i--) { + ArrayList array = buckets[i]; + if (array != null) { + allPlots.addAll(array); + } + } + int size = allPlots.size(); + int minimumRadius = (int) Math.ceil(Math.sqrt(size) / 2 + 1); + if (radius < minimumRadius) { + MainUtil.sendMessage(player, "RADIUS TOO SMALL"); + return false; + } + List toMove = new ArrayList<>(getPlots(allPlots, radius)); + final List free = new ArrayList<>(); + PlotId start = new PlotId(0, 0); + while (start.x <= minimumRadius && start.y <= minimumRadius) { + Plot plot = area.getPlotAbs(start); + if (plot != null && !plot.hasOwner()) { + free.add(plot.getId()); + } + start = Auto.getNextPlotId(start, 1); + } + if (free.isEmpty() || toMove.isEmpty()) { + MainUtil.sendMessage(player, "NO FREE PLOTS FOUND"); + return false; + } + MainUtil.sendMessage(player, "TASK STARTED..."); + Runnable run = new Runnable() { + @Override public void run() { + if (!Condense.TASK) { + MainUtil.sendMessage(player, "TASK CANCELLED."); + } + if (allPlots.isEmpty()) { + Condense.TASK = false; + MainUtil.sendMessage(player, + "TASK COMPLETE. PLEASE VERIFY THAT NO NEW PLOTS HAVE BEEN CLAIMED DURING TASK."); + return; + } + final Runnable task = this; + final Plot origin = allPlots.remove(0); + int i = 0; + while (free.size() > i) { + final Plot possible = origin.getArea().getPlotAbs(free.get(i)); + if (possible.hasOwner()) { + free.remove(i); + continue; + } + i++; + final AtomicBoolean result = new AtomicBoolean(false); + result.set(origin.move(possible, () -> { + if (result.get()) { + MainUtil.sendMessage(player, + "Moving: " + origin + " -> " + possible); + TaskManager.runTaskLater(task, 1); + } + }, false)); + if (result.get()) { + break; + } + } + if (free.isEmpty()) { + Condense.TASK = false; + MainUtil.sendMessage(player, "TASK FAILED. NO FREE PLOTS FOUND!"); + return; + } + if (i >= free.size()) { + MainUtil.sendMessage(player, "SKIPPING COMPLEX PLOT: " + origin); + } + } + }; + Condense.TASK = true; + TaskManager.runTaskAsync(run); + return true; + } + case "stop": + if (!Condense.TASK) { + MainUtil.sendMessage(player, "TASK ALREADY STOPPED"); + return false; + } + Condense.TASK = false; + MainUtil.sendMessage(player, "TASK STOPPED"); + return true; + case "info": + if (args.length == 2) { + MainUtil.sendMessage(player, + "/plot condense " + area.toString() + " info "); + return false; + } + if (!MathMan.isInteger(args[2])) { + MainUtil.sendMessage(player, "INVALID RADIUS"); + return false; + } + int radius = Integer.parseInt(args[2]); + Collection plots = area.getPlots(); + int size = plots.size(); + int minimumRadius = (int) Math.ceil(Math.sqrt(size) / 2 + 1); + if (radius < minimumRadius) { + MainUtil.sendMessage(player, "RADIUS TOO SMALL"); + return false; + } + int maxMove = getPlots(plots, minimumRadius).size(); + int userMove = getPlots(plots, radius).size(); + MainUtil.sendMessage(player, "=== DEFAULT EVAL ==="); + MainUtil.sendMessage(player, "MINIMUM RADIUS: " + minimumRadius); + MainUtil.sendMessage(player, "MAXIMUM MOVES: " + maxMove); + MainUtil.sendMessage(player, "=== INPUT EVAL ==="); + MainUtil.sendMessage(player, "INPUT RADIUS: " + radius); + MainUtil.sendMessage(player, "ESTIMATED MOVES: " + userMove); + MainUtil.sendMessage(player, + "ESTIMATED TIME: No idea, times will drastically change based on the system performance and load"); + MainUtil.sendMessage(player, "&e - Radius is measured in plot width"); + return true; + } + MainUtil.sendMessage(player, + "/plot condense " + area.worldname + " [radius]"); + return false; + } + + public Set getPlots(Collection plots, int radius) { + HashSet outside = new HashSet<>(); + for (Plot plot : plots) { + if (plot.getId().x > radius || plot.getId().x < -radius || plot.getId().y > radius + || plot.getId().y < -radius) { + outside.add(plot.getId()); + } + } + return outside; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Confirm.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Confirm.java new file mode 100644 index 000000000..b33bd4dab --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Confirm.java @@ -0,0 +1,31 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.object.CmdInstance; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.CmdConfirm; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.TaskManager; + +@CommandDeclaration(command = "confirm", permission = "plots.use", + description = "Confirm an action", category = CommandCategory.INFO) public class Confirm + extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + CmdInstance command = CmdConfirm.getPending(player); + if (command == null) { + MainUtil.sendMessage(player, C.FAILED_CONFIRM); + return false; + } + CmdConfirm.removePending(player); + if ((System.currentTimeMillis() - command.timestamp) + > Settings.Confirmation.CONFIRMATION_TIMEOUT_SECONDS * 1000) { + MainUtil.sendMessage(player, C.EXPIRED_CONFIRM); + return false; + } + TaskManager.runTask(command.command); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Continue.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Continue.java new file mode 100644 index 000000000..68bf8c786 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Continue.java @@ -0,0 +1,45 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.flag.Flags; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; + +@CommandDeclaration(command = "continue", + description = "Continue a plot that was previously marked as done", + permission = "plots.continue", category = CommandCategory.SETTINGS, + requiredType = RequiredType.NONE) public class Continue extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + Plot plot = player.getCurrentPlot(); + if ((plot == null) || !plot.hasOwner()) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_CONTINUE)) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + if (!plot.hasFlag(Flags.DONE)) { + MainUtil.sendMessage(player, C.DONE_NOT_DONE); + return false; + } + int size = plot.getConnectedPlots().size(); + if (Settings.Done.COUNTS_TOWARDS_LIMIT && (player.getAllowedPlots() + < player.getPlotCount() + size)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_ADMIN_COMMAND_CONTINUE); + return false; + } + if (plot.getRunning() > 0) { + MainUtil.sendMessage(player, C.WAIT_FOR_TIMER); + return false; + } + plot.removeFlag(Flags.DONE); + MainUtil.sendMessage(player, C.DONE_REMOVED); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Copy.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Copy.java new file mode 100644 index 000000000..8303ef042 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Copy.java @@ -0,0 +1,54 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; + +@CommandDeclaration(command = "copy", permission = "plots.copy", aliases = {"copypaste"}, + category = CommandCategory.CLAIMING, description = "Copy a plot", usage = "/plot copy ", + requiredType = RequiredType.NONE) public class Copy extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + Location loc = player.getLocation(); + Plot plot1 = loc.getPlotAbs(); + if (plot1 == null) { + return !MainUtil.sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot1.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN.s())) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + if (args.length != 1) { + C.COMMAND_SYNTAX.send(player, getUsage()); + return false; + } + Plot plot2 = MainUtil.getPlotFromString(player, args[0], true); + if (plot2 == null) { + return false; + } + if (plot1.equals(plot2)) { + MainUtil.sendMessage(player, C.NOT_VALID_PLOT_ID); + C.COMMAND_SYNTAX.send(player, getUsage()); + return false; + } + if (!plot1.getArea().isCompatible(plot2.getArea())) { + C.PLOTWORLD_INCOMPATIBLE.send(player); + return false; + } + if (plot1.copy(plot2, new Runnable() { + @Override public void run() { + MainUtil.sendMessage(player, C.COPY_SUCCESS); + } + })) { + return true; + } else { + MainUtil.sendMessage(player, C.REQUIRES_UNOWNED); + return false; + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/CreateRoadSchematic.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/CreateRoadSchematic.java new file mode 100644 index 000000000..acc47a64e --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/CreateRoadSchematic.java @@ -0,0 +1,32 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.generator.HybridPlotWorld; +import com.github.intellectualsites.plotsquared.plot.generator.HybridUtils; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; + +@CommandDeclaration(command = "createroadschematic", aliases = {"crs"}, + category = CommandCategory.ADMINISTRATION, requiredType = RequiredType.NONE, + permission = "plots.createroadschematic", + description = "Add a road schematic to your world using the roads around your current plot", + usage = "/plot createroadschematic") public class CreateRoadSchematic extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + Location loc = player.getLocation(); + Plot plot = loc.getPlotAbs(); + if (plot == null) { + return sendMessage(player, C.NOT_IN_PLOT); + } + if (!(loc.getPlotArea() instanceof HybridPlotWorld)) { + return sendMessage(player, C.NOT_IN_PLOT_WORLD); + } + HybridUtils.manager.setupRoadSchematic(plot); + MainUtil.sendMessage(player, + "$1Saved new road schematic. To test the road, fly to a few other plots and use /plot debugroadregen"); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Database.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Database.java new file mode 100644 index 000000000..e94850121 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Database.java @@ -0,0 +1,184 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.database.MySQL; +import com.github.intellectualsites.plotsquared.plot.database.SQLManager; +import com.github.intellectualsites.plotsquared.plot.database.SQLite; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; +import com.github.intellectualsites.plotsquared.plot.object.PlotId; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.worlds.SinglePlotArea; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.TaskManager; + +import java.io.File; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; + +@CommandDeclaration(command = "database", aliases = {"convert"}, + category = CommandCategory.ADMINISTRATION, permission = "plots.database", + description = "Convert/Backup Storage", requiredType = RequiredType.CONSOLE, + usage = "/plot database [area] ") public class Database + extends SubCommand { + + public static void insertPlots(final SQLManager manager, final List plots, + final PlotPlayer player) { + TaskManager.runTaskAsync(() -> { + try { + ArrayList ps = new ArrayList<>(plots); + MainUtil.sendMessage(player, "&6Starting..."); + manager.createPlotsAndData(ps, () -> { + MainUtil.sendMessage(player, "&6Database conversion finished!"); + manager.close(); + }); + } catch (Exception e) { + MainUtil + .sendMessage(player, "Failed to insert plot objects, see stacktrace for info"); + e.printStackTrace(); + } + }); + } + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + if (args.length < 1) { + MainUtil.sendMessage(player, "/plot database [area] "); + return false; + } + List plots; + PlotArea area = PlotSquared.get().getPlotAreaByString(args[0]); + if (area != null) { + plots = PlotSquared.get().sortPlotsByTemp(area.getPlots()); + args = Arrays.copyOfRange(args, 1, args.length); + } else { + plots = PlotSquared.get().sortPlotsByTemp(PlotSquared.get().getPlots()); + } + if (args.length < 1) { + MainUtil.sendMessage(player, "/plot database [world] "); + MainUtil.sendMessage(player, "[arg] indicates an optional argument"); + return false; + } + try { + com.github.intellectualsites.plotsquared.plot.database.Database implementation; + String prefix = ""; + switch (args[0].toLowerCase()) { + case "import": + if (args.length < 2) { + MainUtil + .sendMessage(player, "/plot database import [prefix]"); + return false; + } + File file = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), + args[1].endsWith(".db") ? args[1] : args[1] + ".db"); + if (!file.exists()) { + MainUtil.sendMessage(player, "&6Database does not exist: " + file); + return false; + } + MainUtil.sendMessage(player, "&6Starting..."); + implementation = new SQLite(file); + SQLManager manager = + new SQLManager(implementation, args.length == 3 ? args[2] : "", true); + HashMap> map = manager.getPlots(); + plots = new ArrayList<>(); + for (Entry> entry : map.entrySet()) { + String areaname = entry.getKey(); + PlotArea pa = PlotSquared.get().getPlotAreaByString(areaname); + if (pa != null) { + for (Entry entry2 : entry.getValue().entrySet()) { + Plot plot = entry2.getValue(); + if (pa.getOwnedPlotAbs(plot.getId()) != null) { + if (pa instanceof SinglePlotArea) { + Plot newPlot = pa.getNextFreePlot(null, plot.getId()); + if (newPlot != null) { + PlotId newId = newPlot.getId(); + PlotId id = plot.getId(); + File worldFile = + new File(PlotSquared.imp().getWorldContainer(), + id.toCommaSeparatedString()); + if (worldFile.exists()) { + File newFile = + new File(PlotSquared.imp().getWorldContainer(), + newId.toCommaSeparatedString()); + worldFile.renameTo(newFile); + } + id.x = newId.x; + id.y = newId.y; + id.recalculateHash(); + plot.setArea(pa); + plots.add(plot); + continue; + } + } + MainUtil.sendMessage(player, + "Skipping duplicate plot: " + plot + " | id=" + plot.temp); + continue; + } + plot.setArea(pa); + plots.add(plot); + } + } else { + HashMap plotmap = PlotSquared.get().plots_tmp + .computeIfAbsent(areaname, k -> new HashMap<>()); + plotmap.putAll(entry.getValue()); + } + } + DBFunc.createPlotsAndData(plots, + () -> MainUtil.sendMessage(player, "&6Database conversion finished!")); + return true; + case "mysql": + if (args.length < 6) { + return MainUtil.sendMessage(player, + "/plot database mysql [host] [port] [username] [password] [database] {prefix}"); + } + String host = args[1]; + String port = args[2]; + String username = args[3]; + String password = args[4]; + String database = args[5]; + if (args.length > 6) { + prefix = args[6]; + } + implementation = new MySQL(host, port, database, username, password); + break; + case "sqlite": + if (args.length < 2) { + return MainUtil.sendMessage(player, "/plot database sqlite [file]"); + } + File sqliteFile = + MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), args[1] + ".db"); + implementation = new SQLite(sqliteFile); + break; + default: + return MainUtil.sendMessage(player, "/plot database [sqlite/mysql]"); + } + try { + SQLManager manager = new SQLManager(implementation, prefix, true); + Database.insertPlots(manager, plots, player); + return true; + } catch (ClassNotFoundException | SQLException e) { + MainUtil.sendMessage(player, "$1Failed to save plots, read stacktrace for info"); + MainUtil.sendMessage(player, + "&d==== Here is an ugly stacktrace, if you are interested in those things ==="); + e.printStackTrace(); + MainUtil.sendMessage(player, "&d==== End of stacktrace ===="); + MainUtil + .sendMessage(player, "$1Please make sure you are using the correct arguments!"); + return false; + } + } catch (ClassNotFoundException | SQLException e) { + MainUtil.sendMessage(player, "$1Failed to open connection, read stacktrace for info"); + MainUtil.sendMessage(player, + "&d==== Here is an ugly stacktrace, if you are interested in those things ==="); + e.printStackTrace(); + MainUtil.sendMessage(player, "&d==== End of stacktrace ===="); + MainUtil.sendMessage(player, "$1Please make sure you are using the correct arguments!"); + return false; + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Debug.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Debug.java new file mode 100644 index 000000000..28594982c --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Debug.java @@ -0,0 +1,46 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.StringMan; + +@CommandDeclaration(command = "debug", category = CommandCategory.DEBUG, + description = "Show debug information", usage = "/plot debug [msg]", permission = "plots.admin") +public class Debug extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + if ((args.length > 0) && args[0].equalsIgnoreCase("msg")) { + StringBuilder msg = new StringBuilder(); + for (C caption : C.values()) { + msg.append(caption.s()).append("\n"); + } + MainUtil.sendMessage(player, msg.toString()); + return true; + } + StringBuilder information = new StringBuilder(); + String header = C.DEBUG_HEADER.s(); + String line = C.DEBUG_LINE.s(); + String section = C.DEBUG_SECTION.s(); + information.append(header); + information.append(getSection(section, "PlotArea")); + information.append( + getLine(line, "Plot Worlds", StringMan.join(PlotSquared.get().getPlotAreas(), ", "))); + information.append(getLine(line, "Owned Plots", PlotSquared.get().getPlots().size())); + information.append(getSection(section, "Messages")); + information.append(getLine(line, "Total Messages", C.values().length)); + information.append(getLine(line, "View all captions", "/plot debug msg")); + MainUtil.sendMessage(player, information.toString()); + return true; + } + + private String getSection(String line, String val) { + return line.replaceAll("%val%", val) + "\n"; + } + + private String getLine(String line, String var, Object val) { + return line.replaceAll("%var%", var).replaceAll("%val%", "" + val) + "\n"; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugAllowUnsafe.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugAllowUnsafe.java new file mode 100644 index 000000000..cbfacfae6 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugAllowUnsafe.java @@ -0,0 +1,30 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@CommandDeclaration(command = "debugallowunsafe", + description = "Allow unsafe actions until toggled off", usage = "/plot debugallowunsafe", + category = CommandCategory.DEBUG, requiredType = RequiredType.NONE, + permission = "plots.debugallowunsafe") public class DebugAllowUnsafe extends SubCommand { + + public static final List unsafeAllowed = new ArrayList<>(); + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + + if (unsafeAllowed.contains(player.getUUID())) { + unsafeAllowed.remove(player.getUUID()); + sendMessage(player, C.DEBUGALLOWUNSAFE_OFF); + } else { + unsafeAllowed.add(player.getUUID()); + sendMessage(player, C.DEBUGALLOWUNSAFE_ON); + } + return true; + } + +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugClaimTest.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugClaimTest.java new file mode 100644 index 000000000..01a344369 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugClaimTest.java @@ -0,0 +1,113 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.ChunkManager; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; +import com.github.intellectualsites.plotsquared.plot.util.WorldUtil; +import com.google.common.collect.BiMap; + +import java.util.ArrayList; +import java.util.Map; +import java.util.UUID; + +@CommandDeclaration(command = "debugclaimtest", description = + "If you accidentally delete your database, this command will attempt to restore all plots based on the data from plot signs. " + + "Execution time may vary", category = CommandCategory.DEBUG, + requiredType = RequiredType.CONSOLE, permission = "plots.debugclaimtest") +public class DebugClaimTest extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + if (args.length < 3) { + return !MainUtil.sendMessage(null, + "If you accidentally delete your database, this command will attempt to restore all plots based on the data from the " + + "plot signs. \n\n&cMissing world arg /plot debugclaimtest {world} {PlotId min} {PlotId max}"); + } + PlotArea area = PlotSquared.get().getPlotAreaByString(args[0]); + if (area == null || !WorldUtil.IMP.isWorld(area.worldname)) { + C.NOT_VALID_PLOT_WORLD.send(player, args[0]); + return false; + } + PlotId min, max; + try { + args[1].split(";"); + args[2].split(";"); + min = PlotId.fromString(args[1]); + max = PlotId.fromString(args[2]); + } catch (Exception ignored) { + return !MainUtil.sendMessage(player, + "&cInvalid min/max values. &7The values are to Plot IDs in the format &cX;Y &7where X;Y are the plot coords\nThe conversion " + + "will only check the plots in the selected area."); + } + MainUtil.sendMessage(player, + "&3Sign Block&8->&3Plot&8: &7Beginning sign to plot conversion. This may take a while..."); + MainUtil.sendMessage(player, + "&3Sign Block&8->&3Plot&8: Found an excess of 250,000 chunks. Limiting search radius... (~3.8 min)"); + PlotManager manager = area.getPlotManager(); + ArrayList plots = new ArrayList<>(); + for (PlotId id : MainUtil.getPlotSelectionIds(min, max)) { + Plot plot = area.getPlotAbs(id); + if (plot.hasOwner()) { + MainUtil.sendMessage(player, " - &cDB Already contains: " + plot.getId()); + continue; + } + Location loc = manager.getSignLoc(area, plot); + ChunkLoc chunk = new ChunkLoc(loc.getX() >> 4, loc.getZ() >> 4); + boolean result = ChunkManager.manager.loadChunk(area.worldname, chunk, false); + if (!result) { + continue; + } + String[] lines = WorldUtil.IMP.getSign(loc); + if (lines != null) { + String line = lines[2]; + if (line != null && line.length() > 2) { + line = line.substring(2); + BiMap map = UUIDHandler.getUuidMap(); + UUID uuid = map.get(new StringWrapper(line)); + if (uuid == null) { + for (Map.Entry stringWrapperUUIDEntry : map + .entrySet()) { + if (stringWrapperUUIDEntry.getKey().value.toLowerCase() + .startsWith(line.toLowerCase())) { + uuid = stringWrapperUUIDEntry.getValue(); + break; + } + } + } + if (uuid == null) { + uuid = UUIDHandler.getUUID(line, null); + } + if (uuid != null) { + MainUtil + .sendMessage(player, " - &aFound plot: " + plot.getId() + " : " + line); + plot.setOwner(uuid); + plots.add(plot); + } else { + MainUtil.sendMessage(player, + " - &cInvalid PlayerName: " + plot.getId() + " : " + line); + } + } + } + } + if (!plots.isEmpty()) { + MainUtil.sendMessage(player, + "&3Sign Block&8->&3Plot&8: &7Updating '" + plots.size() + "' plots!"); + DBFunc.createPlotsAndData(plots, new Runnable() { + @Override public void run() { + MainUtil.sendMessage(player, "&6Database update finished!"); + } + }); + for (Plot plot : plots) { + plot.create(); + } + MainUtil.sendMessage(player, "&3Sign Block&8->&3Plot&8: &7Complete!"); + } else { + MainUtil.sendMessage(player, "No plots were found for the given search."); + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugExec.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugExec.java new file mode 100644 index 000000000..01cd1fefc --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugExec.java @@ -0,0 +1,429 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.flag.Flag; +import com.github.intellectualsites.plotsquared.plot.flag.FlagManager; +import com.github.intellectualsites.plotsquared.plot.generator.HybridUtils; +import com.github.intellectualsites.plotsquared.plot.listener.WEManager; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.*; +import com.github.intellectualsites.plotsquared.plot.util.block.GlobalBlockQueue; +import com.github.intellectualsites.plotsquared.plot.util.expiry.ExpireManager; +import com.github.intellectualsites.plotsquared.plot.util.expiry.PlotAnalysis; +import com.google.common.io.Files; + +import javax.script.*; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.sql.Timestamp; +import java.util.*; + +@CommandDeclaration(command = "debugexec", permission = "plots.admin", + description = "Mutli-purpose debug command", aliases = {"exec", "$"}, + category = CommandCategory.DEBUG) public class DebugExec extends SubCommand { + private ScriptEngine engine; + private Bindings scope; + + public DebugExec() { + try { + if (PlotSquared.get() != null) { + File file = new File(PlotSquared.get().IMP.getDirectory(), + Settings.Paths.SCRIPTS + File.separator + "start.js"); + if (file.exists()) { + init(); + String script = StringMan.join(Files.readLines(new File(new File( + PlotSquared.get().IMP.getDirectory() + File.separator + + Settings.Paths.SCRIPTS), "start.js"), StandardCharsets.UTF_8), + System.getProperty("line.separator")); + this.scope.put("THIS", this); + this.scope.put("PlotPlayer", ConsolePlayer.getConsole()); + this.engine.eval(script, this.scope); + } + } + } catch (IOException | ScriptException ignored) { + ignored.printStackTrace(); + } + } + + public ScriptEngine getEngine() { + if (this.engine == null) { + init(); + } + return this.engine; + } + + public Bindings getScope() { + return this.scope; + } + + public void init() { + if (this.engine != null) { + return; + } + this.engine = new ScriptEngineManager(null).getEngineByName("nashorn"); + if (this.engine == null) { + this.engine = new ScriptEngineManager(null).getEngineByName("JavaScript"); + } + ScriptContext context = new SimpleScriptContext(); + this.scope = context.getBindings(ScriptContext.ENGINE_SCOPE); + + // stuff + this.scope.put("MainUtil", new MainUtil()); + this.scope.put("Settings", new Settings()); + this.scope.put("StringMan", new StringMan()); + this.scope.put("MathMan", new MathMan()); + this.scope.put("FlagManager", new FlagManager()); + + // Classes + this.scope.put("Location", Location.class); + this.scope.put("PlotBlock", PlotBlock.class); + this.scope.put("Plot", Plot.class); + this.scope.put("PlotId", PlotId.class); + this.scope.put("Runnable", Runnable.class); + this.scope.put("RunnableVal", RunnableVal.class); + + // Instances + this.scope.put("PS", PlotSquared.get()); + this.scope.put("GlobalBlockQueue", GlobalBlockQueue.IMP); + this.scope.put("ExpireManager", ExpireManager.IMP); + if (PlotSquared.get().worldedit != null) { + this.scope.put("WEManager", new WEManager()); + } + this.scope.put("TaskManager", TaskManager.IMP); + this.scope.put("TitleManager", AbstractTitle.TITLE_CLASS); + this.scope.put("ConsolePlayer", ConsolePlayer.getConsole()); + this.scope.put("SchematicHandler", SchematicHandler.manager); + this.scope.put("ChunkManager", ChunkManager.manager); + this.scope.put("BlockManager", WorldUtil.IMP); + this.scope.put("SetupUtils", SetupUtils.manager); + this.scope.put("EventUtil", EventUtil.manager); + this.scope.put("EconHandler", EconHandler.manager); + this.scope.put("UUIDHandler", UUIDHandler.implementation); + this.scope.put("DBFunc", DBFunc.dbManager); + this.scope.put("HybridUtils", HybridUtils.manager); + this.scope.put("IMP", PlotSquared.get().IMP); + this.scope.put("MainCommand", MainCommand.getInstance()); + + // enums + for (Enum value : C.values()) { + this.scope.put("C_" + value.name(), value); + } + } + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + List allowed_params = Arrays + .asList("analyze", "calibrate-analysis", "remove-flag", "stop-expire", "start-expire", + "seen", "list-scripts", "start-rgar", "stop-rgar", "help", "addcmd", "runasync", + "run", "allcmd", "all"); + if (args.length > 0) { + String arg = args[0].toLowerCase(); + String script; + boolean async = false; + switch (arg) { + case "analyze": { + Plot plot = player.getCurrentPlot(); + if (plot == null) { + MainUtil.sendMessage(player, C.NOT_IN_PLOT); + return false; + } + PlotAnalysis analysis = plot.getComplexity(null); + if (analysis != null) { + MainUtil.sendMessage(player, "Changes/column: " + analysis.changes / 1.0); + return true; + } + MainUtil.sendMessage(player, "$1Starting task..."); + HybridUtils.manager.analyzePlot(plot, new RunnableVal() { + @Override public void run(PlotAnalysis value) { + MainUtil.sendMessage(player, + "$1Done: $2Use $3/plot debugexec analyze$2 for more information"); + } + }); + return true; + } + case "calibrate-analysis": + if (args.length != 2) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, + "/plot debugexec analyze "); + MainUtil.sendMessage(player, + "$1 $2= $1The percentage of plots you want to clear (100 clears 100% of plots so no point calibrating " + + "it)"); + return false; + } + double threshold; + try { + threshold = Integer.parseInt(args[1]) / 100d; + } catch (NumberFormatException ignored) { + MainUtil.sendMessage(player, "$2Invalid threshold: " + args[1]); + MainUtil.sendMessage(player, + "$1 $2= $1The percentage of plots you want to clear as a number between 0 - 100"); + return false; + } + PlotAnalysis.calcOptimalModifiers(() -> MainUtil + .sendMessage(player, "$1Thank you for calibrating plot expiry"), threshold); + return true; + case "stop-expire": + if (ExpireManager.IMP == null || !ExpireManager.IMP.cancelTask()) { + return MainUtil.sendMessage(player, "Task already halted"); + } + return MainUtil.sendMessage(player, "Cancelled task."); + case "remove-flag": + if (args.length != 2) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, + "/plot debugexec remove-flag "); + return false; + } + String flag = args[1]; + for (Plot plot : PlotSquared.get().getBasePlots()) { + Flag flag1 = FlagManager.getFlag(flag); + if (plot.getFlag(flag1).isPresent()) { + plot.removeFlag(flag1); + } + } + return MainUtil.sendMessage(player, "Cleared flag: " + flag); + case "start-rgar": { + if (args.length != 2) { + MainUtil.sendMessage(player, + "&cInvalid syntax: /plot debugexec start-rgar "); + return false; + } + PlotArea area = PlotSquared.get().getPlotAreaByString(args[1]); + if (area == null) { + MainUtil.sendMessage(player, C.NOT_VALID_PLOT_WORLD, args[1]); + return false; + } + boolean result; + if (HybridUtils.regions != null) { + result = + HybridUtils.manager.scheduleRoadUpdate(area, HybridUtils.regions, 0); + } else { + result = HybridUtils.manager.scheduleRoadUpdate(area, 0); + } + if (!result) { + MainUtil.sendMessage(player, + "&cCannot schedule mass schematic update! (Is one already in progress?)"); + return false; + } + return true; + } + case "stop-rgar": + if (!HybridUtils.UPDATE) { + MainUtil.sendMessage(player, "&cTask not running!"); + return false; + } + HybridUtils.UPDATE = false; + MainUtil.sendMessage(player, "&cCancelling task... (Please wait)"); + return true; + case "start-expire": + if (ExpireManager.IMP == null) { + ExpireManager.IMP = new ExpireManager(); + } + if (ExpireManager.IMP.runAutomatedTask()) { + return MainUtil.sendMessage(player, "Started plot expiry task"); + } else { + return MainUtil.sendMessage(player, "Plot expiry task already started"); + } + case "seen": + if (args.length != 2) { + return MainUtil.sendMessage(player, "Use /plot debugexec seen "); + } + UUID uuid = UUIDHandler.getUUID(args[1], null); + if (uuid == null) { + return MainUtil.sendMessage(player, "Player not found: " + args[1]); + } + OfflinePlotPlayer op = UUIDHandler.getUUIDWrapper().getOfflinePlayer(uuid); + if (op == null || op.getLastPlayed() == 0) { + return MainUtil + .sendMessage(player, "Player hasn't connected before: " + args[1]); + } + Timestamp stamp = new Timestamp(op.getLastPlayed()); + Date date = new Date(stamp.getTime()); + MainUtil.sendMessage(player, "PLAYER: " + args[1]); + MainUtil.sendMessage(player, "UUID: " + uuid); + MainUtil.sendMessage(player, "Object: " + date.toGMTString()); + MainUtil.sendMessage(player, "GMT: " + date.toGMTString()); + MainUtil.sendMessage(player, "Local: " + date.toLocaleString()); + return true; + case "h": + case "he": + case "?": + case "help": + MainUtil.sendMessage(player, + "Possible sub commands: /plot debugexec <" + StringMan + .join(allowed_params, "|") + ">"); + return false; + case "addcmd": + try { + final String cmd = StringMan.join(Files.readLines(MainUtil.getFile(new File( + PlotSquared.get().IMP.getDirectory() + File.separator + + Settings.Paths.SCRIPTS), args[1]), StandardCharsets.UTF_8), + System.getProperty("line.separator")); + new Command(MainCommand.getInstance(), true, args[1].split("\\.")[0], null, + RequiredType.NONE, CommandCategory.DEBUG) { + @Override public void execute(PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) { + try { + DebugExec.this.scope.put("PlotPlayer", player); + DebugExec.this.scope.put("args", args); + DebugExec.this.engine.eval(cmd, DebugExec.this.scope); + } catch (ScriptException e) { + e.printStackTrace(); + MainUtil.sendMessage(player, C.COMMAND_WENT_WRONG); + } + } + }; + return true; + } catch (IOException e) { + e.printStackTrace(); + MainUtil + .sendMessage(player, C.COMMAND_SYNTAX, "/plot debugexec addcmd "); + return false; + } + case "runasync": + async = true; + case "run": + try { + script = StringMan.join(Files.readLines(MainUtil.getFile(new File( + PlotSquared.get().IMP.getDirectory() + File.separator + + Settings.Paths.SCRIPTS), args[1]), StandardCharsets.UTF_8), + System.getProperty("line.separator")); + if (args.length > 2) { + HashMap replacements = new HashMap<>(); + for (int i = 2; i < args.length; i++) { + replacements.put("%s" + (i - 2), args[i]); + } + script = StringMan.replaceFromMap(script, replacements); + } + } catch (IOException e) { + e.printStackTrace(); + return false; + } + break; + case "list-scripts": + String path = PlotSquared.get().IMP.getDirectory() + File.separator + + Settings.Paths.SCRIPTS; + File folder = new File(path); + File[] filesArray = folder.listFiles(); + + int page; + switch (args.length) { + case 1: + page = 0; + break; + case 2: + if (MathMan.isInteger(args[1])) { + page = Integer.parseInt(args[1]) - 1; + break; + } + default: + C.COMMAND_SYNTAX.send(player, "/plot debugexec list-scripts [#]"); + return false; + } + + List allFiles = Arrays.asList(filesArray); + paginate(player, allFiles, 8, page, + new RunnableVal3() { + + @Override public void run(Integer i, File file, PlotMessage message) { + String name = file.getName(); + message.text("[").color("$3").text(String.valueOf(i)).color("$1") + .text("]").color("$3").text(' ' + name).color("$1"); + } + }, "/plot debugexec list-scripts", "List of scripts"); + return true; + case "allcmd": + if (args.length < 3) { + C.COMMAND_SYNTAX + .send(player, "/plot debugexec allcmd "); + return false; + } + long start = System.currentTimeMillis(); + Command cmd = MainCommand.getInstance().getCommand(args[3]); + String[] params = Arrays.copyOfRange(args, 4, args.length); + if ("true".equals(args[1])) { + Location loc = player.getMeta(PlotPlayer.META_LOCATION); + Plot plot = player.getMeta(PlotPlayer.META_LAST_PLOT); + for (Plot current : PlotSquared.get().getBasePlots()) { + player.setMeta(PlotPlayer.META_LOCATION, current.getBottomAbs()); + player.setMeta(PlotPlayer.META_LAST_PLOT, current); + cmd.execute(player, params, null, null); + } + if (loc == null) { + player.deleteMeta(PlotPlayer.META_LOCATION); + } else { + player.setMeta(PlotPlayer.META_LOCATION, loc); + } + if (plot == null) { + player.deleteMeta(PlotPlayer.META_LAST_PLOT); + } else { + player.setMeta(PlotPlayer.META_LAST_PLOT, plot); + } + player.sendMessage("&c> " + (System.currentTimeMillis() - start)); + return true; + } + init(); + this.scope.put("_2", params); + this.scope.put("_3", cmd); + script = + "_1=PS.getBasePlots().iterator();while(_1.hasNext()){plot=_1.next();if(" + + args[1] + + "){PlotPlayer.setMeta(\"location\",plot.getBottomAbs());PlotPlayer.setMeta(\"lastplot\",plot);_3.onCommand" + + "(PlotPlayer,_2)}}"; + + break; + case "all": + if (args.length < 3) { + C.COMMAND_SYNTAX.send(player, "/plot debugexec all "); + return false; + } + script = + "_1=PS.getBasePlots().iterator();while(_1.hasNext()){plot=_1.next();if(" + + args[1] + "){" + StringMan + .join(Arrays.copyOfRange(args, 2, args.length), " ") + "}}"; + + break; + default: + script = StringMan.join(args, " "); + } + if (!(player instanceof ConsolePlayer)) { + MainUtil.sendMessage(player, C.NOT_CONSOLE); + return false; + } + init(); + this.scope.put("PlotPlayer", player); + PlotSquared.debug("> " + script); + try { + if (async) { + final String toExec = script; + TaskManager.runTaskAsync(() -> { + long start = System.currentTimeMillis(); + Object result = null; + try { + result = DebugExec.this.engine.eval(toExec, DebugExec.this.scope); + } catch (ScriptException e) { + e.printStackTrace(); + } + PlotSquared + .log("> " + (System.currentTimeMillis() - start) + "ms -> " + result); + }); + } else { + long start = System.currentTimeMillis(); + Object result = this.engine.eval(script, this.scope); + PlotSquared + .log("> " + (System.currentTimeMillis() - start) + "ms -> " + result); + } + return true; + } catch (ScriptException e) { + e.printStackTrace(); + return false; + } + } + return false; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugFixFlags.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugFixFlags.java new file mode 100644 index 000000000..da1e27e61 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugFixFlags.java @@ -0,0 +1,52 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Argument; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.flag.Flag; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.WorldUtil; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; + +@CommandDeclaration(command = "debugfixflags", usage = "/plot debugfixflags ", + permission = "plots.debugfixflags", description = "Attempt to fix all flags for a world", + requiredType = RequiredType.CONSOLE, category = CommandCategory.DEBUG) +public class DebugFixFlags extends SubCommand { + + public DebugFixFlags() { + super(Argument.String); + } + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + PlotArea area = PlotSquared.get().getPlotAreaByString(args[0]); + if (area == null || !WorldUtil.IMP.isWorld(area.worldname)) { + MainUtil.sendMessage(player, C.NOT_VALID_PLOT_WORLD, args[0]); + return false; + } + MainUtil.sendMessage(player, "&8--- &6Starting task &8 ---"); + for (Plot plot : area.getPlots()) { + HashMap, Object> flags = plot.getFlags(); + Iterator, Object>> i = flags.entrySet().iterator(); + boolean changed = false; + while (i.hasNext()) { + if (i.next().getKey() == null) { + changed = true; + i.remove(); + } + } + if (changed) { + DBFunc.setFlags(plot, plot.getFlags()); + } + } + MainUtil.sendMessage(player, "&aDone!"); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugImportWorlds.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugImportWorlds.java new file mode 100644 index 000000000..ddffaf744 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugImportWorlds.java @@ -0,0 +1,58 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.object.PlotId; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3; +import com.github.intellectualsites.plotsquared.plot.object.worlds.PlotAreaManager; +import com.github.intellectualsites.plotsquared.plot.object.worlds.SinglePlotArea; +import com.github.intellectualsites.plotsquared.plot.object.worlds.SinglePlotAreaManager; +import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; +import com.github.intellectualsites.plotsquared.plot.util.WorldUtil; +import com.google.common.base.Charsets; + +import java.io.File; +import java.util.UUID; + +@CommandDeclaration(command = "debugimportworlds", permission = "plots.admin", + description = "Import worlds by player name", requiredType = RequiredType.CONSOLE, + category = CommandCategory.TELEPORT) public class DebugImportWorlds extends Command { + public DebugImportWorlds() { + super(MainCommand.getInstance(), true); + } + + @Override public void execute(PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) throws CommandException { + // UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(Charsets.UTF_8)) + PlotAreaManager pam = PlotSquared.get().getPlotAreaManager(); + if (!(pam instanceof SinglePlotAreaManager)) { + player.sendMessage("Must be a single plot area!"); + return; + } + SinglePlotArea area = ((SinglePlotAreaManager) pam).getArea(); + PlotId id = new PlotId(0, 0); + File container = PlotSquared.imp().getWorldContainer(); + for (File folder : container.listFiles()) { + String name = folder.getName(); + if (!WorldUtil.IMP.isWorld(name) && PlotId.fromString(name) == null) { + UUID uuid = UUIDHandler.getUUID(name, null); + if (uuid == null) { + uuid = + UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)); + } + while (new File(container, id.toCommaSeparatedString()).exists()) { + id = Auto.getNextPlotId(id, 1); + } + File newDir = new File(container, id.toCommaSeparatedString()); + if (folder.renameTo(newDir)) { + area.getPlot(id).setOwner(uuid); + } + } + } + player.sendMessage("Done!"); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugLoadTest.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugLoadTest.java new file mode 100644 index 000000000..f12ce8d1e --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugLoadTest.java @@ -0,0 +1,17 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; + +@CommandDeclaration(command = "debugloadtest", permission = "plots.debugloadtest", + description = "This debug command will force the reload of all plots in the DB", + usage = "/plot debugloadtest", category = CommandCategory.DEBUG, + requiredType = RequiredType.CONSOLE) public class DebugLoadTest extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + PlotSquared.get().plots_tmp = DBFunc.getPlots(); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugPaste.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugPaste.java new file mode 100644 index 000000000..eedba15cf --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugPaste.java @@ -0,0 +1,146 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.IncendoPaster; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.TaskManager; +import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import lombok.NonNull; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +@CommandDeclaration(command = "debugpaste", aliases = "dp", usage = "/plot debugpaste", + description = "Upload settings.yml, worlds.yml, PlotSquared.use_THIS.yml and your latest.log to https://incendo.org", + permission = "plots.debugpaste", category = CommandCategory.DEBUG) public class DebugPaste + extends SubCommand { + + private static String readFile(@NonNull final File file) throws IOException { + final StringBuilder content = new StringBuilder(); + final List lines = new ArrayList<>(); + try (final BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + } + for (int i = Math.max(0, lines.size() - 1000); i < lines.size(); i++) { + content.append(lines.get(i)).append("\n"); + } + return content.toString(); + } + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + TaskManager.runTaskAsync(() -> { + try { + final IncendoPaster incendoPaster = new IncendoPaster("plotsquared"); + + StringBuilder b = new StringBuilder(); + b.append( + "# Welcome to this paste\n# It is meant to provide us at IntellectualSites with better information about your " + + "problem\n\n"); + b.append("# Server Information\n"); + b.append("server.version: ").append(PlotSquared.get().IMP.getServerImplementation()) + .append("\n"); + b.append("online_mode: ").append(UUIDHandler.getUUIDWrapper()).append(';') + .append(!Settings.UUID.OFFLINE).append('\n'); + b.append("plugins:"); + for (String id : PlotSquared.get().IMP.getPluginIds()) { + String[] split = id.split(":"); + String[] split2 = split[0].split(";"); + String enabled = split.length == 2 ? split[1] : "unknown"; + String name = split2[0]; + String version = split2.length == 2 ? split2[1] : "unknown"; + b.append("\n ").append(name).append(":\n ").append("version: '") + .append(version).append('\'').append("\n enabled: ").append(enabled); + } + b.append("\n\n# YAY! Now, let's see what we can find in your JVM\n"); + Runtime runtime = Runtime.getRuntime(); + b.append("memory.free: ").append(runtime.freeMemory()).append('\n'); + b.append("memory.max: ").append(runtime.maxMemory()).append('\n'); + b.append("java.specification.version: '") + .append(System.getProperty("java.specification.version")).append("'\n"); + b.append("java.vendor: '").append(System.getProperty("java.vendor")).append("'\n"); + b.append("java.version: '").append(System.getProperty("java.version")) + .append("'\n"); + b.append("os.arch: '").append(System.getProperty("os.arch")).append("'\n"); + b.append("os.name: '").append(System.getProperty("os.name")).append("'\n"); + b.append("os.version: '").append(System.getProperty("os.version")).append("'\n\n"); + b.append("# Okay :D Great. You are now ready to create your bug report!"); + b.append( + "\n# You can do so at https://github.com/IntellectualSites/PlotSquared/issues"); + b.append("\n# or via our Discord at https://discord.gg/ngZCzbU"); + + incendoPaster.addFile(new IncendoPaster.PasteFile("information", b.toString())); + + try { + final File logFile = + new File(PlotSquared.get().IMP.getDirectory(), "../../logs/latest.log"); + if (Files.size(logFile.toPath()) > 14_000_000) { + throw new IOException("Too big..."); + } + incendoPaster + .addFile(new IncendoPaster.PasteFile("latest.log", readFile(logFile))); + } catch (IOException ignored) { + MainUtil + .sendMessage(player, "&clatest.log is too big to be pasted, will ignore"); + } + + try { + incendoPaster.addFile(new IncendoPaster.PasteFile("settings.yml", + readFile(PlotSquared.get().configFile))); + } catch (final IllegalArgumentException ignored) { + MainUtil.sendMessage(player, "&cSkipping settings.yml because it's empty"); + } + try { + incendoPaster.addFile(new IncendoPaster.PasteFile("worlds.yml", + readFile(PlotSquared.get().worldsFile))); + } catch (final IllegalArgumentException ignored) { + MainUtil.sendMessage(player, "&cSkipping worlds.yml because it's empty"); + } + try { + incendoPaster.addFile(new IncendoPaster.PasteFile("PlotSquared.use_THIS.yml", + readFile(PlotSquared.get().translationFile))); + } catch (final IllegalArgumentException ignored) { + MainUtil.sendMessage(player, + "&cSkipping PlotSquared.use_THIS.yml because it's empty"); + } + + try { + final String rawResponse = incendoPaster.upload(); + final JsonObject jsonObject = + new JsonParser().parse(rawResponse).getAsJsonObject(); + + if (jsonObject.has("created")) { + final String pasteId = jsonObject.get("paste_id").getAsString(); + final String link = + String.format("https://incendo.org/paste/view/%s", pasteId); + player.sendMessage(C.DEBUG_REPORT_CREATED.s().replace("%url%", link)); + } else { + final String responseMessage = jsonObject.get("response").getAsString(); + MainUtil.sendMessage(player, String + .format("&cFailed to create the debug paste: %s", responseMessage)); + } + } catch (final Throwable throwable) { + throwable.printStackTrace(); + MainUtil.sendMessage(player, + "&cFailed to create the debug paste: " + throwable.getMessage()); + } + } catch (IOException e) { + e.printStackTrace(); + } + }); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugRoadRegen.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugRoadRegen.java new file mode 100644 index 000000000..84489e88b --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugRoadRegen.java @@ -0,0 +1,41 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.generator.HybridPlotManager; +import com.github.intellectualsites.plotsquared.plot.generator.HybridPlotWorld; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; + +@CommandDeclaration(command = "debugroadregen", usage = "/plot debugroadregen", + requiredType = RequiredType.NONE, + description = "Regenerate all roads based on the road schematic", + category = CommandCategory.DEBUG, permission = "plots.debugroadregen") +public class DebugRoadRegen extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + Location loc = player.getLocation(); + PlotArea plotArea = loc.getPlotArea(); + if (!(plotArea instanceof HybridPlotWorld)) { + return sendMessage(player, C.NOT_IN_PLOT_WORLD); + } + Plot plot = player.getCurrentPlot(); + if (plot == null) { + C.NOT_IN_PLOT.send(player); + } else if (plot.isMerged()) { + C.REQUIRES_UNMERGED.send(player); + } else { + HybridPlotManager manager = (HybridPlotManager) plotArea.getPlotManager(); + manager.createRoadEast(plotArea, plot); + manager.createRoadSouth(plotArea, plot); + manager.createRoadSouthEast(plotArea, plot); + MainUtil.sendMessage(player, "&6Regenerating plot south/east roads: " + plot.getId() + + "\n&6 - Result: &aSuccess"); + MainUtil.sendMessage(player, "&cTo regenerate all roads: /plot regenallroads"); + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugSaveTest.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugSaveTest.java new file mode 100644 index 000000000..fbbc3267c --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/DebugSaveTest.java @@ -0,0 +1,29 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; + +import java.util.ArrayList; + +@CommandDeclaration(command = "debugsavetest", permission = "plots.debugsavetest", + category = CommandCategory.DEBUG, requiredType = RequiredType.CONSOLE, + usage = "/plot debugsavetest", + description = "This command will force the recreation of all plots in the DB") +public class DebugSaveTest extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + ArrayList plots = new ArrayList(); + plots.addAll(PlotSquared.get().getPlots()); + MainUtil.sendMessage(player, "&6Starting `DEBUGSAVETEST`"); + DBFunc.createPlotsAndData(plots, new Runnable() { + @Override public void run() { + MainUtil.sendMessage(player, "&6Database sync finished!"); + } + }); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Delete.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Delete.java new file mode 100644 index 000000000..b399f5752 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Delete.java @@ -0,0 +1,71 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.*; + + +@CommandDeclaration(command = "delete", permission = "plots.delete", + description = "Delete the plot you stand on", usage = "/plot delete", + aliases = {"dispose", "del"}, category = CommandCategory.CLAIMING, + requiredType = RequiredType.NONE, confirmation = true) public class Delete extends SubCommand { + + // Note: To delete a specific plot use /plot delete + // The syntax also works with any command: /plot + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + Location loc = player.getLocation(); + final Plot plot = loc.getPlotAbs(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + return !sendMessage(player, C.PLOT_UNOWNED); + } + if (!plot.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_DELETE)) { + return !sendMessage(player, C.NO_PLOT_PERMS); + } + final PlotArea plotArea = plot.getArea(); + final java.util.Set plots = plot.getConnectedPlots(); + final int currentPlots = + Settings.Limit.GLOBAL ? player.getPlotCount() : player.getPlotCount(loc.getWorld()); + Runnable run = new Runnable() { + @Override public void run() { + if (plot.getRunning() > 0) { + MainUtil.sendMessage(player, C.WAIT_FOR_TIMER); + return; + } + final long start = System.currentTimeMillis(); + boolean result = plot.deletePlot(new Runnable() { + @Override public void run() { + plot.removeRunning(); + if ((EconHandler.manager != null) && plotArea.USE_ECONOMY) { + Expression valueExr = plotArea.PRICES.get("sell"); + double value = plots.size() * valueExr.evaluate((double) currentPlots); + if (value > 0d) { + EconHandler.manager.depositMoney(player, value); + sendMessage(player, C.ADDED_BALANCE, String.valueOf(value)); + } + } + MainUtil.sendMessage(player, C.DELETING_DONE, + System.currentTimeMillis() - start); + } + }); + if (result) { + plot.addRunning(); + } else { + MainUtil.sendMessage(player, C.WAIT_FOR_TIMER); + } + } + }; + if (hasConfirmation(player)) { + CmdConfirm.addPending(player, getCommandString() + ' ' + plot.getId(), run); + } else { + TaskManager.runTask(run); + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Deny.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Deny.java new file mode 100644 index 000000000..e586f0656 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Deny.java @@ -0,0 +1,114 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Argument; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.*; + +import java.util.Iterator; +import java.util.Set; +import java.util.UUID; + +@CommandDeclaration(command = "deny", aliases = {"d", "ban"}, + description = "Deny a user from a plot", usage = "/plot deny ", + category = CommandCategory.SETTINGS, requiredType = RequiredType.NONE) public class Deny + extends SubCommand { + + public Deny() { + super(Argument.PlayerName); + } + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + + Location location = player.getLocation(); + Plot plot = location.getPlotAbs(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + MainUtil.sendMessage(player, C.PLOT_UNOWNED); + return false; + } + if (!plot.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_DENY)) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return true; + } + Set uuids = MainUtil.getUUIDsFromString(args[0]); + if (uuids.isEmpty()) { + MainUtil.sendMessage(player, C.INVALID_PLAYER, args[0]); + return false; + } + Iterator iter = uuids.iterator(); + while (iter.hasNext()) { + UUID uuid = iter.next(); + if (uuid == DBFunc.EVERYONE && !( + Permissions.hasPermission(player, C.PERMISSION_DENY_EVERYONE) || Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_DENY))) { + MainUtil.sendMessage(player, C.INVALID_PLAYER, MainUtil.getName(uuid)); + continue; + } + if (plot.isOwner(uuid)) { + MainUtil.sendMessage(player, C.ALREADY_OWNER, MainUtil.getName(uuid)); + return false; + } + + if (plot.getDenied().contains(uuid)) { + MainUtil.sendMessage(player, C.ALREADY_ADDED, MainUtil.getName(uuid)); + return false; + } + if (uuid != DBFunc.EVERYONE) { + plot.removeMember(uuid); + plot.removeTrusted(uuid); + } + plot.addDenied(uuid); + EventUtil.manager.callDenied(player, plot, uuid, true); + if (!uuid.equals(DBFunc.EVERYONE)) { + handleKick(UUIDHandler.getPlayer(uuid), plot); + } else { + for (PlotPlayer plotPlayer : plot.getPlayersInPlot()) { + handleKick(plotPlayer, plot); + } + } + } + if (!uuids.isEmpty()) { + MainUtil.sendMessage(player, C.DENIED_ADDED); + } + return true; + } + + private void handleKick(PlotPlayer player, Plot plot) { + if (player == null) { + return; + } + if (!plot.equals(player.getCurrentPlot())) { + return; + } + if (player.hasPermission("plots.admin.entry.denied")) { + return; + } + if (player.getGameMode() == PlotGameMode.SPECTATOR) { + player.stopSpectating(); + } + Location loc = player.getLocation(); + Location spawn = WorldUtil.IMP.getSpawn(loc.getWorld()); + MainUtil.sendMessage(player, C.YOU_GOT_DENIED); + if (plot.equals(spawn.getPlot())) { + Location newSpawn = + WorldUtil.IMP.getSpawn(PlotSquared.get().getPlotAreaManager().getAllWorlds()[0]); + if (plot.equals(newSpawn.getPlot())) { + // Kick from server if you can't be teleported to spawn + player.kick(C.YOU_GOT_DENIED.s()); + } else { + player.teleport(newSpawn); + } + } else { + player.teleport(spawn); + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Desc.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Desc.java new file mode 100644 index 000000000..687eef002 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Desc.java @@ -0,0 +1,30 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.flag.FlagManager; +import com.github.intellectualsites.plotsquared.plot.flag.Flags; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; + +@CommandDeclaration(command = "setdescription", permission = "plots.set.desc", + description = "Set the plot description", usage = "/plot desc ", + aliases = {"desc", "setdesc", "setd", "description"}, category = CommandCategory.SETTINGS, + requiredType = RequiredType.NONE) public class Desc extends SetCommand { + + @Override public boolean set(PlotPlayer player, Plot plot, String desc) { + if (desc.isEmpty()) { + plot.removeFlag(Flags.DESCRIPTION); + MainUtil.sendMessage(player, C.DESC_UNSET); + return true; + } + boolean result = FlagManager.addPlotFlag(plot, Flags.DESCRIPTION, desc); + if (!result) { + MainUtil.sendMessage(player, C.FLAG_NOT_ADDED); + return false; + } + MainUtil.sendMessage(player, C.DESC_SET); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Done.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Done.java new file mode 100644 index 000000000..a37c187cc --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Done.java @@ -0,0 +1,68 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.flag.Flags; +import com.github.intellectualsites.plotsquared.plot.generator.HybridUtils; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; +import com.github.intellectualsites.plotsquared.plot.util.expiry.ExpireManager; +import com.github.intellectualsites.plotsquared.plot.util.expiry.PlotAnalysis; + +@CommandDeclaration(command = "done", aliases = {"submit"}, description = "Mark a plot as done", + permission = "plots.done", category = CommandCategory.SETTINGS, + requiredType = RequiredType.NONE) public class Done extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + Location loc = player.getLocation(); + final Plot plot = loc.getPlotAbs(); + if ((plot == null) || !plot.hasOwner()) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_DONE)) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + if (plot.hasFlag(Flags.DONE)) { + MainUtil.sendMessage(player, C.DONE_ALREADY_DONE); + return false; + } + if (plot.getRunning() > 0) { + MainUtil.sendMessage(player, C.WAIT_FOR_TIMER); + return false; + } + plot.addRunning(); + MainUtil.sendMessage(player, C.GENERATING_LINK); + final Settings.Auto_Clear doneRequirements = Settings.AUTO_CLEAR.get("done"); + if (ExpireManager.IMP == null || doneRequirements == null) { + finish(plot, player, true); + plot.removeRunning(); + } else { + HybridUtils.manager.analyzePlot(plot, new RunnableVal() { + @Override public void run(PlotAnalysis value) { + plot.removeRunning(); + boolean result = + value.getComplexity(doneRequirements) <= doneRequirements.THRESHOLD; + finish(plot, player, result); + } + }); + } + return true; + } + + private void finish(Plot plot, PlotPlayer pp, boolean success) { + if (success) { + long flagValue = System.currentTimeMillis() / 1000; + plot.setFlag(Flags.DONE, flagValue); + MainUtil.sendMessage(pp, C.DONE_SUCCESS); + } else { + MainUtil.sendMessage(pp, C.DONE_INSUFFICIENT_COMPLEXITY); + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Download.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Download.java new file mode 100644 index 000000000..7dd7b7acd --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Download.java @@ -0,0 +1,95 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.flag.Flags; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal; +import com.github.intellectualsites.plotsquared.plot.util.*; +import com.sk89q.jnbt.CompoundTag; + +import java.net.URL; + +@CommandDeclaration(usage = "/plot download [schematic|world]", command = "download", + aliases = {"dl"}, category = CommandCategory.SCHEMATIC, requiredType = RequiredType.NONE, + description = "Download your plot", permission = "plots.download") public class Download + extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + String world = player.getLocation().getWorld(); + if (!PlotSquared.get().hasPlotArea(world)) { + return !sendMessage(player, C.NOT_IN_PLOT_WORLD); + } + final Plot plot = player.getCurrentPlot(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + MainUtil.sendMessage(player, C.PLOT_UNOWNED); + return false; + } + if ((Settings.Done.REQUIRED_FOR_DOWNLOAD && (!plot.getFlag(Flags.DONE).isPresent())) + && !Permissions.hasPermission(player, C.PERMISSION_ADMIN_COMMAND_DOWNLOAD)) { + MainUtil.sendMessage(player, C.DONE_NOT_DONE); + return false; + } + if ((!plot.isOwner(player.getUUID())) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN.s())) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + if (plot.getRunning() > 0) { + MainUtil.sendMessage(player, C.WAIT_FOR_TIMER); + return false; + } + if (args.length == 0 || (args.length == 1 && StringMan + .isEqualIgnoreCaseToAny(args[0], "sch", "schem", "schematic"))) { + if (plot.getVolume() > Integer.MAX_VALUE) { + C.SCHEMATIC_TOO_LARGE.send(player); + return false; + } + plot.addRunning(); + SchematicHandler.manager.getCompoundTag(plot, new RunnableVal() { + @Override public void run(CompoundTag value) { + plot.removeRunning(); + SchematicHandler.manager.upload(value, null, null, new RunnableVal() { + @Override public void run(URL url) { + if (url == null) { + MainUtil.sendMessage(player, C.GENERATING_LINK_FAILED); + return; + } + MainUtil.sendMessage(player, url.toString()); + } + }); + } + }); + } else if (args.length == 1 && StringMan + .isEqualIgnoreCaseToAny(args[0], "mcr", "world", "mca")) { + if (!Permissions.hasPermission(player, C.PERMISSION_DOWNLOAD_WORLD)) { + C.NO_PERMISSION.send(player, C.PERMISSION_DOWNLOAD_WORLD); + return false; + } + MainUtil.sendMessage(player, "&cNote: The `.mca` files are 512x512"); + plot.addRunning(); + WorldUtil.IMP.saveWorld(world); + WorldUtil.IMP.upload(plot, null, null, new RunnableVal() { + @Override public void run(URL url) { + plot.removeRunning(); + if (url == null) { + MainUtil.sendMessage(player, C.GENERATING_LINK_FAILED); + return; + } + MainUtil.sendMessage(player, url.toString()); + } + }); + } else { + C.COMMAND_SYNTAX.send(player, getUsage()); + return false; + } + MainUtil.sendMessage(player, C.GENERATING_LINK); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java new file mode 100644 index 000000000..9d0435c07 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/FlagCmd.java @@ -0,0 +1,299 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.flag.*; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotBlock; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.*; + +import java.util.*; + +@CommandDeclaration(command = "setflag", aliases = {"f", "flag", "setf", "setflag"}, + usage = "/plot flag ", description = "Set plot flags", + category = CommandCategory.SETTINGS, requiredType = RequiredType.NONE, + permission = "plots.flag") public class FlagCmd extends SubCommand { + + private boolean checkPermValue(PlotPlayer player, Flag flag, String key, String value) { + key = key.toLowerCase(); + value = value.toLowerCase(); + String perm = C.PERMISSION_SET_FLAG_KEY_VALUE.f(key.toLowerCase(), value.toLowerCase()); + if (flag instanceof IntegerFlag && MathMan.isInteger(value)) { + try { + int numeric = Integer.parseInt(value); + perm = perm.substring(0, perm.length() - value.length() - 1); + if (numeric > 0) { + int checkRange = PlotSquared.get().getPlatform().equalsIgnoreCase("bukkit") ? + numeric : + Settings.Limit.MAX_PLOTS; + final boolean result = player.hasPermissionRange(perm, checkRange) >= numeric; + if (!result) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_SET_FLAG_KEY_VALUE + .f(key.toLowerCase(), value.toLowerCase())); + } + return result; + } + + } catch (NumberFormatException ignore) { + } + } else if (flag instanceof PlotBlockListFlag) { + final PlotBlockListFlag blockListFlag = (PlotBlockListFlag) flag; + final HashSet parsedBlocks = blockListFlag.parseValue(value); + for (final PlotBlock block : parsedBlocks) { + final String permission = C.PERMISSION_SET_FLAG_KEY_VALUE + .f(key.toLowerCase(), block.getRawId().toString().toLowerCase()); + final boolean result = Permissions.hasPermission(player, permission); + if (!result) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_SET_FLAG_KEY_VALUE.f(key.toLowerCase(), value.toLowerCase())); + return false; + } + } + return true; + } + final boolean result = Permissions.hasPermission(player, perm); + if (!result) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_SET_FLAG_KEY_VALUE.f(key.toLowerCase(), value.toLowerCase())); + } + return result; + } + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + + /* + * plot flag set fly true + * plot flag remove fly + * plot flag remove use 1,3 + * plot flag add use 2,4 + * plot flag list + */ + if (args.length == 0) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot flag "); + return false; + } + Location loc = player.getLocation(); + Plot plot = loc.getPlotAbs(); + if (plot == null) { + MainUtil.sendMessage(player, C.NOT_IN_PLOT); + return false; + } + if (!plot.hasOwner()) { + sendMessage(player, C.PLOT_NOT_CLAIMED); + return false; + } + if (!plot.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_SET_FLAG_OTHER)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_SET_FLAG_OTHER); + return false; + } + Flag flag = null; + if (args.length > 1) { + flag = FlagManager.getFlag(args[1]); + if (flag == null || flag.isReserved()) { + boolean suggested = false; + try { + StringComparison> stringComparison = + new StringComparison<>(args[1], Flags.getFlags()); + String best = stringComparison.getBestMatch(); + if (best != null) { + MainUtil.sendMessage(player, C.NOT_VALID_FLAG_SUGGESTED, best); + suggested = true; + } + } catch (final Exception ignored) { /* Happens sometimes because of mean code */ } + if (!suggested) { + MainUtil.sendMessage(player, C.NOT_VALID_FLAG); + } + return false; + } + } + switch (args[0].toLowerCase()) { + case "info": { + if (!Permissions.hasPermission(player, C.PERMISSION_SET_FLAG)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, "plots.flag.info"); + return false; + } + if (args.length != 2) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot flag info "); + return false; + } + // flag key + MainUtil.sendMessage(player, C.FLAG_KEY, flag.getName()); + // flag type + MainUtil.sendMessage(player, C.FLAG_TYPE, flag.getClass().getSimpleName()); + // Flag type description + MainUtil.sendMessage(player, C.FLAG_DESC, flag.getValueDescription()); + return true; + } + case "set": { + if (!Permissions.hasPermission(player, C.PERMISSION_SET_FLAG)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_SET_FLAG); + return false; + } + if (args.length < 3) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot flag set "); + return false; + } + String value = StringMan.join(Arrays.copyOfRange(args, 2, args.length), " "); + if (!checkPermValue(player, flag, args[1], value)) { + return false; + } + Object parsed = flag.parseValue(value); + if (parsed == null) { + MainUtil.sendMessage(player, "&c" + flag.getValueDescription()); + return false; + } + boolean result = plot.setFlag(flag, parsed); + if (!result) { + MainUtil.sendMessage(player, C.FLAG_NOT_ADDED); + return false; + } + MainUtil.sendMessage(player, C.FLAG_ADDED); + return true; + } + case "remove": { + if (!Permissions.hasPermission(player, C.PERMISSION_FLAG_REMOVE)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_FLAG_REMOVE); + return false; + } + if (args.length != 2 && args.length != 3) { + MainUtil + .sendMessage(player, C.COMMAND_SYNTAX, "/plot flag remove [values]"); + return false; + } + if (!Permissions + .hasPermission(player, C.PERMISSION_SET_FLAG_KEY.f(args[1].toLowerCase()))) { + if (args.length != 3) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_SET_FLAG_KEY.f(args[1].toLowerCase())); + return false; + } + for (String entry : args[2].split(",")) { + if (!checkPermValue(player, flag, args[1], entry)) { + return false; + } + } + } + if (args.length == 3 && flag instanceof ListFlag) { + String value = StringMan.join(Arrays.copyOfRange(args, 2, args.length), " "); + Optional flag1 = + plot.getFlag((Flag>) flag); + if (flag1.isPresent()) { + boolean o = flag1.get().removeAll((Collection) flag.parseValue(value)); + if (o) { + if (flag1.get().isEmpty()) { + final boolean result = plot.removeFlag(flag); + if (result) { + MainUtil.sendMessage(player, C.FLAG_REMOVED); + } else { + MainUtil.sendMessage(player, C.FLAG_NOT_REMOVED); + } + return true; + } else { + MainUtil.sendMessage(player, C.FLAG_REMOVED); + } + } else { + MainUtil.sendMessage(player, C.FLAG_NOT_REMOVED); + return false; + } + } + DBFunc.setFlags(plot, plot.getFlags()); + return true; + } else { + boolean result = plot.removeFlag(flag); + if (!result) { + MainUtil.sendMessage(player, C.FLAG_NOT_REMOVED); + return false; + } + } + if (flag == Flags.TIME) { + player.setTime(Long.MAX_VALUE); + } else if (flag == Flags.WEATHER) { + player.setWeather(PlotWeather.RESET); + } + MainUtil.sendMessage(player, C.FLAG_REMOVED); + return true; + } + case "add": + if (!Permissions.hasPermission(player, C.PERMISSION_FLAG_ADD)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_FLAG_ADD); + return false; + } + if (args.length < 3) { + MainUtil + .sendMessage(player, C.COMMAND_SYNTAX, "/plot flag add "); + return false; + } + for (String entry : args[2].split(",")) { + if (!checkPermValue(player, flag, args[1], entry)) { + return false; + } + } + String value = StringMan.join(Arrays.copyOfRange(args, 2, args.length), " "); + Object parsed = flag.parseValue(value); + if (parsed == null) { + MainUtil.sendMessage(player, "&c" + flag.getValueDescription()); + return false; + } + Object val = parsed; + if (flag instanceof ListFlag) { + Optional flag1 = + plot.getFlag((Flag>) flag); + if (flag1.isPresent()) { + boolean o = flag1.get().addAll((Collection) parsed); + if (o) { + MainUtil.sendMessage(player, C.FLAG_ADDED); + val = flag1.get(); + } else { + MainUtil.sendMessage(player, C.FLAG_NOT_ADDED); + return false; + } + } + } + boolean result = plot.setFlag(flag, val); + if (!result) { + MainUtil.sendMessage(player, C.FLAG_NOT_ADDED); + return false; + } + MainUtil.sendMessage(player, C.FLAG_ADDED); + return true; + case "list": + if (!Permissions.hasPermission(player, C.PERMISSION_FLAG_LIST)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_FLAG_LIST); + return false; + } + if (args.length > 1) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot flag list"); + return false; + } + HashMap> flags = new HashMap<>(); + for (Flag flag1 : Flags.getFlags()) { + String type = flag1.getClass().getSimpleName(); + if (!flags.containsKey(type)) { + flags.put(type, new ArrayList<>()); + } + flags.get(type).add(flag1.getName()); + } + StringBuilder message = new StringBuilder(); + String prefix = ""; + for (Map.Entry> entry : flags.entrySet()) { + String category = entry.getKey(); + List flagNames = entry.getValue(); + Collections.sort(flagNames); + message.append(prefix).append("&6").append(category).append(": &7") + .append(StringMan.join(flagNames, ", ")); + prefix = "\n"; + } + MainUtil.sendMessage(player, message.toString()); + return true; + } + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot flag "); + return false; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/GenerateDocs.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/GenerateDocs.java new file mode 100644 index 000000000..5a69479b5 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/GenerateDocs.java @@ -0,0 +1,221 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.util.StringMan; + +import java.io.File; +import java.io.IOException; +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.regex.Matcher; +import java.util.regex.Pattern; + +public class GenerateDocs { + + public static void main(String[] args) { + new WE_Anywhere(); + List commands = MainCommand.getInstance().getCommands(); + GenerateDocs.log("### Want to document some commands?"); + GenerateDocs.log(" - This page is automatically generated"); + GenerateDocs + .log(" - Fork the project and add a javadoc comment to one of the command classes"); + GenerateDocs.log(" - Then do a pull request and it will be added to this page"); + GenerateDocs.log(""); + GenerateDocs.log("# Contents"); + for (CommandCategory category : CommandCategory.values()) { + GenerateDocs.log("###### " + category.name()); + for (Command command : MainCommand.getInstance().getCommands(category, null)) { + GenerateDocs.log(" - [/plot " + command.getId() + + "](https://github.com/IntellectualSites/PlotSquared/wiki/Commands#" + command + .getId() + ") "); + } + GenerateDocs.log(""); + } + GenerateDocs.log("# Commands"); + for (Command command : commands) { + GenerateDocs.printCommand(command); + } + } + + public static void printCommand(Command command) { + try { + String clazz = command.getClass().getSimpleName(); + String name = command.getId(); + + // Header + String source = + "https://github.com/IntellectualSites/PlotSquared/tree/master/Core/src/main/java/com/intellectualcrafters/plot/commands/" + + clazz + ".java"; + GenerateDocs.log("## [" + name.toUpperCase() + "](" + source + ") "); + + File file = new File( + "Core/src/main/java/com/intellectualcrafters/plot/commands/" + clazz + ".java"); + List lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8); + List perms = GenerateDocs.getPerms(name, lines); + List usages = GenerateDocs.getUsage(name, lines); + String comment = GenerateDocs.getComments(lines); + + GenerateDocs.log("#### Description"); + GenerateDocs.log('`' + command.getDescription() + '`'); + if (!comment.isEmpty()) { + GenerateDocs.log("##### Comments"); + GenerateDocs.log("``` java"); + GenerateDocs.log(comment); + GenerateDocs.log("```"); + } + + GenerateDocs.log("#### Usage "); + String mainUsage = command.getUsage().replaceAll("\\{label\\}", "plot"); + if (!usages.isEmpty() && !usages.get(0).equalsIgnoreCase(mainUsage)) { + GenerateDocs.log("##### Primary "); + GenerateDocs.log(" - `" + mainUsage + "` "); + GenerateDocs.log(""); + GenerateDocs.log("##### Other "); + GenerateDocs.log(" - `" + StringMan.join(usages, "`\n - `") + "` "); + GenerateDocs.log(""); + } else { + GenerateDocs.log('`' + mainUsage + "` "); + } + + if (command.getRequiredType() != RequiredType.NONE) { + GenerateDocs.log("#### Required callers"); + GenerateDocs.log('`' + command.getRequiredType().name() + '`'); + } + + List aliases = command.getAliases(); + if (!aliases.isEmpty()) { + GenerateDocs.log("#### Aliases"); + GenerateDocs.log('`' + StringMan.getString(command.getAliases()) + '`'); + } + + GenerateDocs.log("#### Permissions"); + if (!perms.isEmpty()) { + GenerateDocs.log("##### Primary"); + GenerateDocs.log(" - `" + command.getPermission() + "` "); + GenerateDocs.log(""); + GenerateDocs.log("##### Other"); + GenerateDocs.log(" - `" + StringMan.join(perms, "`\n - `") + '`'); + GenerateDocs.log(""); + } else { + GenerateDocs.log('`' + command.getPermission() + "` "); + } + GenerateDocs.log("***"); + GenerateDocs.log(""); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static List getUsage(String cmd, List lines) { + Pattern p = Pattern.compile("\"([^\"]*)\""); + HashSet usages = new HashSet<>(); + for (String line : lines) { + if (line.contains("COMMAND_SYNTAX") && !line.contains("getUsage()")) { + Matcher m = p.matcher(line); + String prefix = ""; + StringBuilder usage = new StringBuilder(); + while (m.find()) { + String match = m.group(1); + usage.append(prefix).append(match); + prefix = " "; + } + if (usage.length() != 0) { + usages.add(usage.toString().trim().replaceAll(" ", " ") + .replaceAll("\\{label\\}", "plot")); + } + } + } + return new ArrayList<>(usages); + } + + public static List getPerms(String cmd, List lines) { + HashSet perms = new HashSet<>(); + Pattern p = Pattern.compile("\"([^\"]*)\""); + Pattern p2 = Pattern.compile("C.PERMISSION_\\s*(\\w+)"); + String last = null; + for (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.equalsIgnoreCase(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); + } + Matcher m = p.matcher(line); + while (m.find()) { + String perm = m.group(1); + if (perm.endsWith(".")) { + perm += ""; + } + if (perm.startsWith(".")) { + 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.equalsIgnoreCase(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.<#>"); + break; + } + return new ArrayList<>(perms); + } + + public static String getComments(List lines) { + StringBuilder result = new StringBuilder(); + for (String line : lines) { + line = line.trim(); + if (line.startsWith("/** ") || line.startsWith("*/ ") || line.startsWith("* ")) { + line = + line.replaceAll("/[*][*] ", "").replaceAll("[*]/ ", "").replaceAll("[*] ", "") + .trim(); + result.append(line + '\n'); + } + } + return result.toString().trim(); + } + + public static void log(String s) { + System.out.println(s); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Grant.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Grant.java new file mode 100644 index 000000000..d29bd76bb --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Grant.java @@ -0,0 +1,71 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3; +import com.github.intellectualsites.plotsquared.plot.util.ByteArrayUtilities; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; +import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; + +import java.util.UUID; + +@CommandDeclaration(command = "grant", category = CommandCategory.CLAIMING, + usage = "/plot grant [player]", permission = "plots.grant", + requiredType = RequiredType.NONE) public class Grant extends Command { + + public Grant() { + super(MainCommand.getInstance(), true); + } + + @Override public void execute(final PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) throws CommandException { + checkTrue(args.length >= 1 && args.length <= 2, C.COMMAND_SYNTAX, getUsage()); + final String arg0 = args[0].toLowerCase(); + switch (arg0) { + case "add": + case "check": + if (!Permissions.hasPermission(player, C.PERMISSION_GRANT.f(arg0))) { + C.NO_PERMISSION.send(player, C.PERMISSION_GRANT.f(arg0)); + return; + } + if (args.length > 2) { + break; + } + final UUID uuid = + args.length == 2 ? UUIDHandler.getUUIDFromString(args[1]) : player.getUUID(); + if (uuid == null) { + C.INVALID_PLAYER.send(player, args[1]); + return; + } + MainUtil.getPersistentMeta(uuid, "grantedPlots", new RunnableVal() { + @Override public void run(byte[] array) { + if (arg0.equals("check")) { // check + int granted = + array == null ? 0 : ByteArrayUtilities.bytesToInteger(array); + C.GRANTED_PLOTS.send(player, granted); + } else { // add + int amount = + 1 + (array == null ? 0 : ByteArrayUtilities.bytesToInteger(array)); + boolean replace = array != null; + String key = "grantedPlots"; + byte[] rawData = ByteArrayUtilities.integerToBytes(amount); + PlotPlayer online = UUIDHandler.getPlayer(uuid); + if (online != null) { + online.setPersistentMeta(key, rawData); + } else { + DBFunc.addPersistentMeta(uuid, key, rawData, replace); + } + } + } + }); + } + C.COMMAND_SYNTAX.send(player, getUsage()); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Help.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Help.java new file mode 100644 index 000000000..ff697953c --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Help.java @@ -0,0 +1,91 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.MathMan; +import com.github.intellectualsites.plotsquared.plot.util.StringMan; +import com.github.intellectualsites.plotsquared.plot.util.helpmenu.HelpMenu; + +@CommandDeclaration(command = "help", description = "Get this help menu", aliases = {"he", "?"}, + category = CommandCategory.INFO, usage = "help [category|#]", permission = "plots.use") +public class Help extends Command { + public Help(Command parent) { + super(parent, true); + } + + @Override public boolean canExecute(PlotPlayer player, boolean message) { + return true; + } + + @Override public void execute(PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) { + switch (args.length) { + case 0: + displayHelp(player, null, 0); + return; + case 1: + if (MathMan.isInteger(args[0])) { + try { + displayHelp(player, null, Integer.parseInt(args[0])); + } catch (NumberFormatException ignored) { + displayHelp(player, null, 1); + } + } else { + displayHelp(player, args[0], 1); + } + return; + case 2: + if (MathMan.isInteger(args[1])) { + try { + displayHelp(player, args[0], Integer.parseInt(args[1])); + } catch (NumberFormatException ignored) { + displayHelp(player, args[0], 1); + } + } + return; + default: + C.COMMAND_SYNTAX.send(player, getUsage()); + } + } + + public void displayHelp(PlotPlayer player, String cat, int page) { + CommandCategory catEnum = null; + if (cat != null) { + if (!StringMan.isEqualIgnoreCase(cat, "all")) { + for (CommandCategory c : CommandCategory.values()) { + if (StringMan.isEqualIgnoreCaseToAny(cat, c.name(), c.toString())) { + catEnum = c; + cat = c.name(); + break; + } + } + if (catEnum == null) { + cat = null; + } + } + } + if (cat == null && page == 0) { + StringBuilder builder = new StringBuilder(); + builder.append(C.HELP_HEADER.s()); + for (CommandCategory c : CommandCategory.values()) { + builder.append("\n" + StringMan + .replaceAll(C.HELP_INFO_ITEM.s(), "%category%", c.toString().toLowerCase(), + "%category_desc%", c.toString())); + } + builder.append("\n").append(C.HELP_INFO_ITEM.s().replaceAll("%category%", "all") + .replaceAll("%category_desc%", "Display all commands")); + builder.append("\n" + C.HELP_FOOTER.s()); + MainUtil.sendMessage(player, builder.toString(), false); + return; + } + page--; + new HelpMenu(player).setCategory(catEnum).getCommands().generateMaxPages() + .generatePage(page, getParent().toString()).render(); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Inbox.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Inbox.java new file mode 100644 index 000000000..908e35afc --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Inbox.java @@ -0,0 +1,198 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal; +import com.github.intellectualsites.plotsquared.plot.object.comment.CommentInbox; +import com.github.intellectualsites.plotsquared.plot.object.comment.PlotComment; +import com.github.intellectualsites.plotsquared.plot.util.CommentManager; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.StringMan; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@CommandDeclaration(command = "inbox", description = "Review the comments for a plot", + usage = "/plot inbox [inbox] [delete |clear|page]", permission = "plots.inbox", + category = CommandCategory.CHAT, requiredType = RequiredType.NONE) public class Inbox + extends SubCommand { + + public void displayComments(PlotPlayer player, List oldComments, int page) { + if (oldComments == null || oldComments.isEmpty()) { + MainUtil.sendMessage(player, C.INBOX_EMPTY); + return; + } + PlotComment[] comments = oldComments.toArray(new PlotComment[oldComments.size()]); + if (page < 0) { + page = 0; + } + // Get the total pages + // int totalPages = ((int) Math.ceil(12 * + int totalPages = (int) Math.ceil(comments.length / 12); + if (page > totalPages) { + page = totalPages; + } + // Only display 12 per page + int max = page * 12 + 12; + if (max > comments.length) { + max = comments.length; + } + StringBuilder string = new StringBuilder(); + string.append(StringMan + .replaceAll(C.COMMENT_LIST_HEADER_PAGED.s(), "%amount%", comments.length, "%cur", + page + 1, "%max", totalPages + 1, "%word", "all") + '\n'); + + // This might work xD + for (int x = page * 12; x < max; x++) { + PlotComment comment = comments[x]; + String color; + if (player.getName().equals(comment.senderName)) { + color = "&a"; + } else { + color = "&7"; + } + string.append("&8[&7#").append(x + 1).append("&8][&7").append(comment.world).append(';') + .append(comment.id).append("&8][&6").append(comment.senderName).append("&8]") + .append(color).append(comment.comment).append('\n'); + } + MainUtil.sendMessage(player, string.toString()); + } + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + final Plot plot = player.getCurrentPlot(); + if (plot == null) { + sendMessage(player, C.NOT_IN_PLOT); + return false; + } + if (!plot.hasOwner()) { + sendMessage(player, C.PLOT_UNOWNED); + return false; + } + if (args.length == 0) { + sendMessage(player, C.COMMAND_SYNTAX, + "/plot inbox [inbox] [delete |clear|page]"); + for (final CommentInbox inbox : CommentManager.inboxes.values()) { + if (inbox.canRead(plot, player)) { + if (!inbox.getComments(plot, new RunnableVal>() { + @Override public void run(List value) { + if (value != null) { + int total = 0; + int unread = 0; + for (PlotComment comment : value) { + total++; + if (comment.timestamp > CommentManager + .getTimestamp(player, inbox.toString())) { + unread++; + } + } + if (total != 0) { + String color; + if (unread > 0) { + color = "&c"; + } else { + color = ""; + } + sendMessage(player, C.INBOX_ITEM, + color + inbox.toString() + " (" + total + '/' + unread + + ')'); + return; + } + } + sendMessage(player, C.INBOX_ITEM, inbox.toString()); + } + })) { + sendMessage(player, C.INBOX_ITEM, inbox.toString()); + } + } + } + return false; + } + final CommentInbox inbox = CommentManager.inboxes.get(args[0].toLowerCase()); + if (inbox == null) { + sendMessage(player, C.INVALID_INBOX, + StringMan.join(CommentManager.inboxes.keySet(), ", ")); + return false; + } + player.setMeta("inbox:" + inbox.toString(), System.currentTimeMillis()); + final int page; + if (args.length > 1) { + switch (args[1].toLowerCase()) { + case "delete": + if (!inbox.canModify(plot, player)) { + sendMessage(player, C.NO_PERM_INBOX_MODIFY); + return false; + } + if (args.length != 3) { + sendMessage(player, C.COMMAND_SYNTAX, + "/plot inbox " + inbox.toString() + " delete "); + } + final int index; + try { + index = Integer.parseInt(args[2]); + if (index < 1) { + sendMessage(player, C.NOT_VALID_INBOX_INDEX, index + ""); + return false; + } + } catch (NumberFormatException ignored) { + sendMessage(player, C.COMMAND_SYNTAX, + "/plot inbox " + inbox.toString() + " delete "); + return false; + } + + if (!inbox.getComments(plot, new RunnableVal>() { + @Override public void run(List value) { + if (index > value.size()) { + sendMessage(player, C.NOT_VALID_INBOX_INDEX, index + ""); + return; + } + PlotComment comment = value.get(index - 1); + inbox.removeComment(plot, comment); + plot.getSettings().removeComment(comment); + MainUtil.sendMessage(player, C.COMMENT_REMOVED, comment.comment); + } + })) { + sendMessage(player, C.NOT_IN_PLOT); + return false; + } + return true; + case "clear": + if (!inbox.canModify(plot, player)) { + sendMessage(player, C.NO_PERM_INBOX_MODIFY); + } + inbox.clearInbox(plot); + Optional> comments = + plot.getSettings().getComments(inbox.toString()); + comments + .ifPresent(plotComments -> plot.getSettings().removeComments(plotComments)); + MainUtil.sendMessage(player, C.COMMENT_REMOVED, "*"); + return true; + default: + try { + page = Integer.parseInt(args[1]); + } catch (NumberFormatException ignored) { + sendMessage(player, C.COMMAND_SYNTAX, + "/plot inbox [inbox] [delete |clear|page]"); + return false; + } + } + } else { + page = 1; + } + if (!inbox.canRead(plot, player)) { + sendMessage(player, C.NO_PERM_INBOX); + return false; + } + if (!inbox.getComments(plot, new RunnableVal>() { + @Override public void run(List value) { + displayComments(player, value, page); + } + })) { + sendMessage(player, C.PLOT_UNOWNED); + return false; + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Info.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Info.java new file mode 100644 index 000000000..6241e1d51 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Info.java @@ -0,0 +1,155 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.expiry.ExpireManager; + +import java.util.UUID; + +@CommandDeclaration(command = "info", aliases = "i", description = "Display plot info", + usage = "/plot info ", category = CommandCategory.INFO) public class Info + extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + Plot plot; + String arg; + if (args.length > 0) { + arg = args[0]; + switch (arg) { + case "trusted": + case "alias": + case "inv": + case "biome": + case "denied": + case "flags": + case "id": + case "size": + case "members": + case "seen": + case "owner": + case "rating": + plot = MainUtil.getPlotFromString(player, null, false); + break; + default: + plot = MainUtil.getPlotFromString(player, arg, false); + if (args.length == 2) { + arg = args[1]; + } else { + arg = null; + } + break; + } + if (plot == null) { + plot = player.getCurrentPlot(); + } + } else { + arg = null; + plot = player.getCurrentPlot(); + } + if (plot == null) { + MainUtil.sendMessage(player, C.NOT_IN_PLOT.s()); + return false; + } + if (arg != null) { + if (args.length == 1) { + args = new String[0]; + } else { + args = new String[] {args[1]}; + } + } + if (args.length == 1 && args[0].equalsIgnoreCase("inv")) { + PlotInventory inv = new PlotInventory(player) { + @Override public boolean onClick(int index) { + // TODO InfoInventory not implemented yet!!!!!!!! + // See plot rating or musicsubcommand on examples + return false; + } + }; + UUID uuid = player.getUUID(); + String name = MainUtil.getName(plot.owner); + inv.setItem(1, new PlotItemStack(388, (short) 0, 1, "&cPlot Info", + "&cID: &6" + plot.getId().toString(), "&cOwner: &6" + name, + "&cAlias: &6" + plot.getAlias(), + "&cBiome: &6" + plot.getBiome().replaceAll("_", "").toLowerCase(), + "&cCan Build: &6" + plot.isAdded(uuid), + "&cSeen: &6" + MainUtil.secToTime((int) (ExpireManager.IMP.getAge(plot) / 1000)), + "&cIs Denied: &6" + plot.isDenied(uuid))); + inv.setItem(1, new PlotItemStack(388, (short) 0, 1, "&cTrusted", + "&cAmount: &6" + plot.getTrusted().size(), + "&8Click to view a list of the trusted users")); + inv.setItem(1, new PlotItemStack(388, (short) 0, 1, "&cMembers", + "&cAmount: &6" + plot.getMembers().size(), + "&8Click to view a list of plot members")); + inv.setItem(1, new PlotItemStack(388, (short) 0, 1, "&cDenied", "&cDenied", + "&cAmount: &6" + plot.getDenied().size(), + "&8Click to view a list of denied players")); + inv.setItem(1, new PlotItemStack(388, (short) 0, 1, "&cFlags", "&cFlags", + "&cAmount: &6" + plot.getFlags().size(), "&8Click to view a list of plot flags")); + inv.openInventory(); + return true; + } + boolean hasOwner = plot.hasOwner(); + // Wildcard player {added} + boolean containsEveryone = plot.getTrusted().contains(DBFunc.EVERYONE); + boolean trustedEveryone = plot.getMembers().contains(DBFunc.EVERYONE); + // Unclaimed? + if (!hasOwner && !containsEveryone && !trustedEveryone) { + MainUtil + .sendMessage(player, C.PLOT_INFO_UNCLAIMED, plot.getId().x + ";" + plot.getId().y); + return true; + } + String info = C.PLOT_INFO.s(); + boolean full; + if (arg != null) { + info = getCaption(arg); + if (info == null) { + MainUtil.sendMessage(player, + "&6Categories&7: &amembers&7, &aalias&7, &abiome&7, &aseen&7, &adenied&7, &aflags&7, &aid&7, &asize&7, &atrusted&7, " + + "&aowner&7, &arating"); + return false; + } + full = true; + } else { + full = false; + } + MainUtil.format(info, plot, player, full, new RunnableVal() { + @Override public void run(String value) { + MainUtil.sendMessage(player, + C.PLOT_INFO_HEADER.s() + '\n' + value + '\n' + C.PLOT_INFO_FOOTER.s(), false); + } + }); + return true; + } + + private String getCaption(String string) { + switch (string) { + case "trusted": + return C.PLOT_INFO_TRUSTED.s(); + case "alias": + return C.PLOT_INFO_ALIAS.s(); + case "biome": + return C.PLOT_INFO_BIOME.s(); + case "denied": + return C.PLOT_INFO_DENIED.s(); + case "flags": + return C.PLOT_INFO_FLAGS.s(); + case "id": + return C.PLOT_INFO_ID.s(); + case "size": + return C.PLOT_INFO_SIZE.s(); + case "members": + return C.PLOT_INFO_MEMBERS.s(); + case "owner": + return C.PLOT_INFO_OWNER.s(); + case "rating": + return C.PLOT_INFO_RATING.s(); + case "seen": + return C.PLOT_INFO_SEEN.s(); + default: + return null; + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Kick.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Kick.java new file mode 100644 index 000000000..fc16db715 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Kick.java @@ -0,0 +1,92 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Argument; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; +import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; +import com.github.intellectualsites.plotsquared.plot.util.WorldUtil; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +@CommandDeclaration(command = "kick", aliases = {"k"}, description = "Kick a player from your plot", + permission = "plots.kick", usage = "/plot kick ", category = CommandCategory.TELEPORT, + requiredType = RequiredType.NONE) public class Kick extends SubCommand { + + public Kick() { + super(Argument.PlayerName); + } + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + Location location = player.getLocation(); + Plot plot = location.getPlot(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if ((!plot.hasOwner() || !plot.isOwner(player.getUUID())) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_KICK)) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + Set uuids = MainUtil.getUUIDsFromString(args[0]); + if (uuids.isEmpty()) { + MainUtil.sendMessage(player, C.INVALID_PLAYER, args[0]); + return false; + } + Set players = new HashSet<>(); + for (UUID uuid : uuids) { + if (uuid == DBFunc.EVERYONE) { + for (PlotPlayer pp : plot.getPlayersInPlot()) { + if (pp == player || Permissions + .hasPermission(pp, C.PERMISSION_ADMIN_ENTRY_DENIED)) { + continue; + } + players.add(pp); + } + continue; + } + PlotPlayer pp = UUIDHandler.getPlayer(uuid); + if (pp != null) { + players.add(pp); + } + } + players.remove(player); // Don't ever kick the calling player + if (players.isEmpty()) { + MainUtil.sendMessage(player, C.INVALID_PLAYER, args[0]); + return false; + } + for (PlotPlayer player2 : players) { + if (!plot.equals(player2.getCurrentPlot())) { + MainUtil.sendMessage(player, C.INVALID_PLAYER, args[0]); + return false; + } + if (Permissions.hasPermission(player2, C.PERMISSION_ADMIN_ENTRY_DENIED)) { + C.CANNOT_KICK_PLAYER.send(player, player2.getName()); + return false; + } + Location spawn = WorldUtil.IMP.getSpawn(location.getWorld()); + C.YOU_GOT_KICKED.send(player2); + if (plot.equals(spawn.getPlot())) { + Location newSpawn = WorldUtil.IMP + .getSpawn(PlotSquared.get().getPlotAreaManager().getAllWorlds()[0]); + if (plot.equals(newSpawn.getPlot())) { + // Kick from server if you can't be teleported to spawn + player2.kick(C.YOU_GOT_KICKED.s()); + } else { + player2.plotkick(newSpawn); + } + } else { + player2.plotkick(spawn); + } + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Leave.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Leave.java new file mode 100644 index 000000000..5504ce777 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Leave.java @@ -0,0 +1,48 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3; +import com.github.intellectualsites.plotsquared.plot.util.EventUtil; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; + +import java.util.UUID; + +@CommandDeclaration(command = "leave", + description = "Removes self from being trusted or a member of the plot", + permission = "plots.leave", category = CommandCategory.CLAIMING, + requiredType = RequiredType.NONE) public class Leave extends Command { + public Leave() { + super(MainCommand.getInstance(), true); + } + + @Override public void execute(PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) throws CommandException { + final Plot plot = check(player.getCurrentPlot(), C.NOT_IN_PLOT); + checkTrue(plot.hasOwner(), C.PLOT_UNOWNED); + checkTrue(plot.isAdded(player.getUUID()), C.NO_PLOT_PERMS); + checkTrue(args.length == 0, C.COMMAND_SYNTAX, getUsage()); + if (plot.isOwner(player.getUUID())) { + checkTrue(plot.hasOwner(), C.ALREADY_OWNER); + // TODO setowner, other + } else { + UUID uuid = player.getUUID(); + if (plot.isAdded(uuid)) { + if (plot.removeTrusted(uuid)) { + EventUtil.manager.callTrusted(player, plot, uuid, false); + } + if (plot.removeMember(uuid)) { + EventUtil.manager.callMember(player, plot, uuid, false); + } + MainUtil.sendMessage(player, C.INVALID_PLAYER, args[0]); + } else { + MainUtil.sendMessage(player, C.REMOVED_PLAYERS, 1); + } + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/ListCmd.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/ListCmd.java new file mode 100644 index 000000000..9df74d30b --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/ListCmd.java @@ -0,0 +1,397 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.PlotSquared.SortType; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.flag.Flags; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.*; +import com.github.intellectualsites.plotsquared.plot.util.expiry.ExpireManager; + +import java.util.*; +import java.util.Map.Entry; + +@CommandDeclaration(command = "list", aliases = {"l", "find", "search"}, description = "List plots", + permission = "plots.list", category = CommandCategory.INFO, + usage = "/plot list > [#]") +public class ListCmd extends SubCommand { + + private String[] getArgumentList(PlotPlayer player) { + List args = new ArrayList<>(); + if (EconHandler.manager != null && Permissions + .hasPermission(player, C.PERMISSION_LIST_FORSALE)) { + args.add("forsale"); + } + if (Permissions.hasPermission(player, C.PERMISSION_LIST_MINE)) { + args.add("mine"); + } + if (Permissions.hasPermission(player, C.PERMISSION_LIST_SHARED)) { + args.add("shared"); + } + if (Permissions.hasPermission(player, C.PERMISSION_LIST_WORLD)) { + args.add("world"); + } + if (Permissions.hasPermission(player, C.PERMISSION_LIST_TOP)) { + args.add("top"); + } + if (Permissions.hasPermission(player, C.PERMISSION_LIST_ALL)) { + args.add("all"); + } + if (Permissions.hasPermission(player, C.PERMISSION_LIST_UNOWNED)) { + args.add("unowned"); + } + if (Permissions.hasPermission(player, C.PERMISSION_LIST_UNKNOWN)) { + args.add("unknown"); + } + if (Permissions.hasPermission(player, C.PERMISSION_LIST_PLAYER)) { + args.add(""); + } + if (Permissions.hasPermission(player, C.PERMISSION_LIST_WORLD)) { + args.add(""); + } + if (Permissions.hasPermission(player, C.PERMISSION_LIST_DONE)) { + args.add("done"); + } + if (Permissions.hasPermission(player, C.PERMISSION_LIST_EXPIRED)) { + args.add("expired"); + } + if (Permissions.hasPermission(player, C.PERMISSION_LIST_FUZZY)) { + args.add("fuzzy "); + } + return args.toArray(new String[args.size()]); + } + + public void noArgs(PlotPlayer player) { + MainUtil.sendMessage(player, + C.SUBCOMMAND_SET_OPTIONS_HEADER.s() + Arrays.toString(getArgumentList(player))); + } + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + if (args.length < 1) { + noArgs(player); + return false; + } + int page = 0; + if (args.length > 1) { + try { + page = Integer.parseInt(args[args.length - 1]); + --page; + if (page < 0) { + page = 0; + } + } catch (NumberFormatException ignored) { + page = -1; + } + } + + List plots = null; + + String world = player.getLocation().getWorld(); + PlotArea area = player.getApplicablePlotArea(); + String arg = args[0].toLowerCase(); + boolean sort = true; + switch (arg) { + case "mine": + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_MINE)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_MINE); + return false; + } + sort = false; + plots = PlotSquared.get().sortPlotsByTemp(PlotSquared.get().getBasePlots(player)); + break; + case "shared": + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_SHARED)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_SHARED); + return false; + } + plots = new ArrayList<>(); + for (Plot plot : PlotSquared.get().getPlots()) { + if (plot.getTrusted().contains(player.getUUID()) || plot.getMembers() + .contains(player.getUUID())) { + plots.add(plot); + } + } + break; + case "world": + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_WORLD)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_WORLD); + return false; + } + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_WORLD_NAME.f(world))) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_LIST_WORLD_NAME.f(world)); + return false; + } + plots = new ArrayList<>(PlotSquared.get().getPlots(world)); + break; + case "expired": + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_EXPIRED)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_EXPIRED); + return false; + } + plots = ExpireManager.IMP == null ? + new ArrayList() : + new ArrayList<>(ExpireManager.IMP.getPendingExpired()); + break; + case "area": + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_AREA)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_AREA); + return false; + } + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_WORLD_NAME.f(world))) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_LIST_WORLD_NAME.f(world)); + return false; + } + plots = area == null ? new ArrayList() : new ArrayList<>(area.getPlots()); + break; + case "all": + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_ALL)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_ALL); + return false; + } + plots = new ArrayList<>(PlotSquared.get().getPlots()); + break; + case "done": + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_DONE)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_DONE); + return false; + } + plots = new ArrayList<>(); + for (Plot plot : PlotSquared.get().getPlots()) { + Optional flag = plot.getFlag(Flags.DONE); + if (flag.isPresent()) { + plots.add(plot); + } + } + Collections.sort(plots, new Comparator() { + @Override public int compare(Plot a, Plot b) { + String va = "" + a.getFlags().get(Flags.DONE); + String vb = "" + b.getFlags().get(Flags.DONE); + if (MathMan.isInteger(va)) { + if (MathMan.isInteger(vb)) { + return Integer.parseInt(vb) - Integer.parseInt(va); + } + return -1; + } + return 1; + } + }); + sort = false; + break; + case "top": + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_TOP)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_TOP); + return false; + } + plots = new ArrayList<>(PlotSquared.get().getPlots()); + Collections.sort(plots, new Comparator() { + @Override public int compare(Plot p1, Plot p2) { + double v1 = 0; + int p1s = p1.getSettings().getRatings().size(); + int p2s = p2.getRatings().size(); + if (!p1.getSettings().getRatings().isEmpty()) { + for (Entry entry : p1.getRatings().entrySet()) { + double av = entry.getValue().getAverageRating(); + v1 += av * av; + } + v1 /= p1s; + v1 += p1s; + } + double v2 = 0; + if (!p2.getSettings().getRatings().isEmpty()) { + for (Entry entry : p2.getRatings().entrySet()) { + double av = entry.getValue().getAverageRating(); + v2 += av * av; + } + v2 /= p2s; + v2 += p2s; + } + if (v2 == v1 && v2 != 0) { + return p2s - p1s; + } + return (int) Math.signum(v2 - v1); + } + }); + sort = false; + break; + case "forsale": + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_FORSALE)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_FORSALE); + return false; + } + if (EconHandler.manager == null) { + break; + } + plots = new ArrayList<>(); + for (Plot plot : PlotSquared.get().getPlots()) { + Optional price = plot.getFlag(Flags.PRICE); + if (price.isPresent()) { + plots.add(plot); + } + } + break; + case "unowned": + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_UNOWNED)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_UNOWNED); + return false; + } + plots = new ArrayList<>(); + for (Plot plot : PlotSquared.get().getPlots()) { + if (plot.owner == null) { + plots.add(plot); + } + } + break; + case "unknown": + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_UNKNOWN)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_UNKNOWN); + return false; + } + plots = new ArrayList<>(); + for (Plot plot : PlotSquared.get().getPlots()) { + if (plot.owner == null) { + continue; + } + if (UUIDHandler.getName(plot.owner) == null) { + plots.add(plot); + } + } + break; + case "fuzzy": + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_FUZZY)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_FUZZY); + return false; + } + if (args.length < (page == -1 ? 2 : 3)) { + C.COMMAND_SYNTAX.send(player, "/plot list fuzzy [#]"); + return false; + } + String term; + if (MathMan.isInteger(args[args.length - 1])) { + term = StringMan.join(Arrays.copyOfRange(args, 1, args.length - 1), " "); + } else { + term = StringMan.join(Arrays.copyOfRange(args, 1, args.length), " "); + } + plots = MainUtil.getPlotsBySearch(term); + sort = false; + break; + default: + if (PlotSquared.get().hasPlotArea(args[0])) { + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_WORLD)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_WORLD); + return false; + } + if (!Permissions + .hasPermission(player, C.PERMISSION_LIST_WORLD_NAME.f(args[0]))) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_LIST_WORLD_NAME.f(args[0])); + return false; + } + plots = new ArrayList<>(PlotSquared.get().getPlots(args[0])); + break; + } + UUID uuid = UUIDHandler.getUUID(args[0], null); + if (uuid == null) { + try { + uuid = UUID.fromString(args[0]); + } catch (Exception ignored) { + } + } + if (uuid != null) { + if (!Permissions.hasPermission(player, C.PERMISSION_LIST_PLAYER)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_LIST_PLAYER); + return false; + } + sort = false; + plots = PlotSquared.get().sortPlotsByTemp(PlotSquared.get().getPlots(uuid)); + break; + } + } + + if (plots == null) { + sendMessage(player, C.DID_YOU_MEAN, + new StringComparison<>(args[0], new String[] {"mine", "shared", "world", "all"}) + .getBestMatch()); + return false; + } + + if (plots.isEmpty()) { + MainUtil.sendMessage(player, C.FOUND_NO_PLOTS); + return false; + } + displayPlots(player, plots, 12, page, area, args, sort); + return true; + } + + public void displayPlots(final PlotPlayer player, List plots, int pageSize, int page, + PlotArea area, String[] args, boolean sort) { + // Header + Iterator iterator = plots.iterator(); + while (iterator.hasNext()) { + if (!iterator.next().isBasePlot()) { + iterator.remove(); + } + } + if (sort) { + plots = PlotSquared.get().sortPlots(plots, SortType.CREATION_DATE, area); + } + this.paginate(player, plots, pageSize, page, + new RunnableVal3() { + @Override public void run(Integer i, Plot plot, PlotMessage message) { + String color; + if (plot.owner == null) { + color = "$3"; + } else if (plot.isOwner(player.getUUID())) { + color = "$1"; + } else if (plot.isAdded(player.getUUID())) { + color = "$4"; + } else if (plot.isDenied(player.getUUID())) { + color = "$2"; + } else { + color = "$1"; + } + PlotMessage trusted = new PlotMessage().text(C.color(C.PLOT_INFO_TRUSTED.s() + .replaceAll("%trusted%", MainUtil.getPlayerList(plot.getTrusted())))) + .color("$1"); + PlotMessage members = new PlotMessage().text(C.color(C.PLOT_INFO_MEMBERS.s() + .replaceAll("%members%", MainUtil.getPlayerList(plot.getMembers())))) + .color("$1"); + String strFlags = StringMan.join(plot.getFlags().values(), ","); + if (strFlags.isEmpty()) { + strFlags = C.NONE.s(); + } + PlotMessage flags = new PlotMessage() + .text(C.color(C.PLOT_INFO_FLAGS.s().replaceAll("%flags%", strFlags))) + .color("$1"); + message.text("[").color("$3").text(i + "") + .command("/plot visit " + plot.getArea() + ";" + plot.getId()) + .tooltip("/plot visit " + plot.getArea() + ";" + plot.getId()).color("$1") + .text("]").color("$3").text(" " + plot.toString()) + .tooltip(trusted, members, flags) + .command("/plot info " + plot.getArea() + ";" + plot.getId()).color(color) + .text(" - ").color("$2"); + String prefix = ""; + for (UUID uuid : plot.getOwners()) { + String name = UUIDHandler.getName(uuid); + if (name == null) { + message = message.text(prefix).color("$4").text("unknown").color("$2") + .tooltip(uuid.toString()).suggest(uuid.toString()); + } else { + PlotPlayer pp = UUIDHandler.getPlayer(uuid); + if (pp != null) { + message = message.text(prefix).color("$4").text(name).color("$1") + .tooltip(new PlotMessage("Online").color("$4")); + } else { + message = message.text(prefix).color("$4").text(name).color("$1") + .tooltip(new PlotMessage("Offline").color("$3")); + } + } + prefix = ", "; + } + } + }, "/plot list " + args[0], C.PLOT_LIST_HEADER_PAGED.s()); + } + +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Load.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Load.java new file mode 100644 index 000000000..cc9106d28 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Load.java @@ -0,0 +1,179 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.object.schematic.Schematic; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; +import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler; +import com.github.intellectualsites.plotsquared.plot.util.TaskManager; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; + +@CommandDeclaration(command = "load", aliases = {"restore"}, category = CommandCategory.SCHEMATIC, + requiredType = RequiredType.NONE, description = "Load your plot", permission = "plots.load", + usage = "/plot load") public class Load extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + String world = player.getLocation().getWorld(); + if (!PlotSquared.get().hasPlotArea(world)) { + return !sendMessage(player, C.NOT_IN_PLOT_WORLD); + } + final Plot plot = player.getCurrentPlot(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + MainUtil.sendMessage(player, C.PLOT_UNOWNED); + return false; + } + if (!plot.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_LOAD)) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + if (plot.getRunning() > 0) { + MainUtil.sendMessage(player, C.WAIT_FOR_TIMER); + return false; + } + + if (args.length != 0) { + if (args.length == 1) { + List schematics = player.getMeta("plot_schematics"); + if (schematics == null) { + // No schematics found: + MainUtil.sendMessage(player, C.LOAD_NULL); + return false; + } + String schem; + try { + schem = schematics.get(Integer.parseInt(args[0]) - 1); + } catch (Exception ignored) { + // use /plot load + MainUtil + .sendMessage(player, C.NOT_VALID_NUMBER, "(1, " + schematics.size() + ')'); + return false; + } + final URL url; + try { + url = new URL(Settings.Web.URL + "saves/" + player.getUUID() + '/' + schem); + } catch (MalformedURLException e) { + e.printStackTrace(); + MainUtil.sendMessage(player, C.LOAD_FAILED); + return false; + } + plot.addRunning(); + MainUtil.sendMessage(player, C.GENERATING_COMPONENT); + TaskManager.runTaskAsync(() -> { + Schematic schematic = SchematicHandler.manager.getSchematic(url); + if (schematic == null) { + plot.removeRunning(); + sendMessage(player, C.SCHEMATIC_INVALID, + "non-existent or not in gzip format"); + return; + } + PlotArea area = plot.getArea(); + SchematicHandler.manager + .paste(schematic, plot, 0, area.MIN_BUILD_HEIGHT, 0, false, + new RunnableVal() { + @Override public void run(Boolean value) { + plot.removeRunning(); + if (value) { + sendMessage(player, C.SCHEMATIC_PASTE_SUCCESS); + } else { + sendMessage(player, C.SCHEMATIC_PASTE_FAILED); + } + } + }); + }); + return true; + } + plot.removeRunning(); + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot load "); + return false; + } + + // list schematics + + List schematics = player.getMeta("plot_schematics"); + if (schematics == null) { + plot.addRunning(); + TaskManager.runTaskAsync(() -> { + List schematics1 = SchematicHandler.manager.getSaves(player.getUUID()); + plot.removeRunning(); + if ((schematics1 == null) || schematics1.isEmpty()) { + MainUtil.sendMessage(player, C.LOAD_FAILED); + return; + } + player.setMeta("plot_schematics", schematics1); + displaySaves(player); + }); + } else { + displaySaves(player); + } + return true; + } + + public void displaySaves(PlotPlayer player) { + List schematics = player.getMeta("plot_schematics"); + for (int i = 0; i < Math.min(schematics.size(), 32); i++) { + try { + String schematic = schematics.get(i).split("\\.")[0]; + String[] split = schematic.split("_"); + if (split.length < 5) { + continue; + } + String time = + secToTime((System.currentTimeMillis() / 1000) - Long.parseLong(split[0])); + String world = split[1]; + PlotId id = PlotId.fromString(split[2] + ';' + split[3]); + String size = split[4]; + String color = "$4"; + MainUtil.sendMessage(player, + "$3[$2" + (i + 1) + "$3] " + color + time + "$3 | " + color + world + ';' + id + + "$3 | " + color + size + 'x' + size); + } catch (Exception e) { + e.printStackTrace(); + } + } + MainUtil.sendMessage(player, C.LOAD_LIST); + } + + public String secToTime(long time) { + StringBuilder toreturn = new StringBuilder(); + if (time >= 33868800) { + int years = (int) (time / 33868800); + time -= years * 33868800; + toreturn.append(years).append("y "); + } + if (time >= 604800) { + int weeks = (int) (time / 604800); + time -= weeks * 604800; + toreturn.append(weeks).append("w "); + } + if (time >= 86400) { + int days = (int) (time / 86400); + time -= days * 86400; + toreturn.append(days).append("d "); + } + if (time >= 3600) { + int hours = (int) (time / 3600); + time -= hours * 3600; + toreturn.append(hours).append("h "); + } + if (time >= 60) { + int minutes = (int) (time / 60); + time -= minutes * 60; + toreturn.append(minutes).append("m "); + } + if (toreturn.length() == 0 || (time > 0)) { + toreturn.append(time).append("s "); + } + return toreturn.toString().trim(); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/MainCommand.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/MainCommand.java new file mode 100644 index 000000000..0e1630e76 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/MainCommand.java @@ -0,0 +1,286 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.CmdConfirm; +import com.github.intellectualsites.plotsquared.plot.util.EconHandler; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; + +import java.util.Arrays; + +/** + * PlotSquared command class. + */ +@CommandDeclaration(command = "plot", + aliases = {"plots", "p", "plotsquared", "plot2", "p2", "ps", "2", "plotme", "plotz", "ap"}) +public class MainCommand extends Command { + + private static MainCommand instance; + public Help help; + public Toggle toggle; + + private MainCommand() { + super(null, true); + instance = this; + } + + public static MainCommand getInstance() { + if (instance == null) { + instance = new MainCommand(); + new Buy(); + new Save(); + new Load(); + new Confirm(); + new Template(); + new Download(); + new Template(); + new Setup(); + new Area(); + new DebugSaveTest(); + new DebugLoadTest(); + new CreateRoadSchematic(); + new DebugAllowUnsafe(); + new RegenAllRoads(); + new Claim(); + new Auto(); + new Visit(); + new Set(); + new Clear(); + new Delete(); + new Trust(); + new Add(); + new Leave(); + new Deny(); + new Remove(); + new Info(); + new Near(); + new ListCmd(); + new Debug(); + new SchematicCmd(); + new PluginCmd(); + new Purge(); + new Reload(); + new Relight(); + new Merge(); + new DebugPaste(); + new Unlink(); + new Kick(); + new Rate(); + new DebugClaimTest(); + new Inbox(); + new Comment(); + new Database(); + new Swap(); + new Music(); + new DebugRoadRegen(); + new Trust(); + new DebugExec(); + new FlagCmd(); + new Target(); + new DebugFixFlags(); + new Move(); + new Condense(); + new Copy(); + new Chat(); + new Trim(); + new Done(); + new Continue(); + new Middle(); + new Grant(); + // Set commands + new Owner(); + new Desc(); + new Biome(); + new Alias(); + new SetHome(); + new Cluster(); + new DebugImportWorlds(); + // Referenced commands + instance.toggle = new Toggle(); + instance.help = new Help(instance); + } + return instance; + } + + public static boolean onCommand(final PlotPlayer player, String... args) { + if (args.length >= 1 && args[0].contains(":")) { + String[] split2 = args[0].split(":"); + if (split2.length == 2) { + // Ref: c:v, this will push value to the last spot in the array + // ex. /p h:2 SomeUsername + // > /p h SomeUsername 2 + String[] tmp = new String[args.length + 1]; + tmp[0] = split2[0]; + tmp[args.length] = split2[1]; + if (args.length >= 2) { + System.arraycopy(args, 1, tmp, 1, args.length - 1); + } + args = tmp; + } + } + try { + getInstance().execute(player, args, new RunnableVal3() { + @Override + public void run(final Command cmd, final Runnable success, final Runnable failure) { + if (cmd.hasConfirmation(player)) { + CmdConfirm.addPending(player, cmd.getUsage(), new Runnable() { + @Override public void run() { + if (EconHandler.manager != null) { + PlotArea area = player.getApplicablePlotArea(); + if (area != null) { + Expression priceEval = + area.PRICES.get(cmd.getFullId()); + Double price = + priceEval != null ? priceEval.evaluate(0d) : 0d; + if (price != null + && EconHandler.manager.getMoney(player) < price) { + if (failure != null) { + failure.run(); + } + return; + } + } + } + if (success != null) { + success.run(); + } + } + }); + return; + } + if (EconHandler.manager != null) { + PlotArea area = player.getApplicablePlotArea(); + if (area != null) { + Expression priceEval = area.PRICES.get(cmd.getFullId()); + Double price = priceEval != null ? priceEval.evaluate(0d) : 0d; + if (price != 0d && EconHandler.manager.getMoney(player) < price) { + if (failure != null) { + failure.run(); + } + return; + } + } + } + if (success != null) { + success.run(); + } + } + }, new RunnableVal2() { + @Override public void run(Command cmd, CommandResult result) { + // Post command stuff!? + } + }); + } catch (CommandException e) { + e.perform(player); + } + // Always true + return true; + } + + @Deprecated + /** + * @Deprecated legacy + */ public void addCommand(SubCommand command) { + PlotSquared.debug("Command registration is now done during instantiation"); + } + + @Override public void execute(final PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) { + // Clear perm caching // + player.deleteMeta("perm"); + // Optional command scope // + Location loc = null; + Plot plot = null; + boolean tp = false; + if (args.length >= 2) { + PlotArea area = player.getApplicablePlotArea(); + Plot newPlot = Plot.fromString(area, args[0]); + if (newPlot != null && (player instanceof ConsolePlayer || newPlot.getArea() + .equals(area) || Permissions.hasPermission(player, C.PERMISSION_ADMIN)) && !newPlot + .isDenied(player.getUUID())) { + Location newLoc = newPlot.getCenter(); + if (player.canTeleport(newLoc)) { + // Save meta + loc = player.getMeta(PlotPlayer.META_LOCATION); + plot = player.getMeta(PlotPlayer.META_LAST_PLOT); + tp = true; + // Set loc + player.setMeta(PlotPlayer.META_LOCATION, newLoc); + player.setMeta(PlotPlayer.META_LAST_PLOT, newPlot); + } else { + C.BORDER.send(player); + } + // Trim command + args = Arrays.copyOfRange(args, 1, args.length); + } + if (args.length >= 2 && !args[0].isEmpty() && args[0].charAt(0) == '-') { + switch (args[0].substring(1)) { + case "f": + confirm = new RunnableVal3() { + @Override + public void run(Command cmd, Runnable success, Runnable failure) { + if (EconHandler.manager != null) { + PlotArea area = player.getApplicablePlotArea(); + if (area != null) { + Expression priceEval = + area.PRICES.get(cmd.getFullId()); + Double price = + priceEval != null ? priceEval.evaluate(0d) : 0d; + if (price != 0d + && EconHandler.manager.getMoney(player) < price) { + if (failure != null) { + failure.run(); + } + return; + } + } + } + if (success != null) { + success.run(); + } + } + }; + args = Arrays.copyOfRange(args, 1, args.length); + break; + default: + C.INVALID_COMMAND_FLAG.send(player); + return; + } + } + } + try { + super.execute(player, args, confirm, whenDone); + } catch (CommandException e) { + throw e; + } catch (Throwable e) { + e.printStackTrace(); + String message = e.getLocalizedMessage(); + if (message != null) { + C.ERROR.send(player, message); + } else { + C.ERROR.send(player); + } + } + // Reset command scope // + if (tp && !(player instanceof ConsolePlayer)) { + if (loc == null) { + player.deleteMeta(PlotPlayer.META_LOCATION); + } else { + player.setMeta(PlotPlayer.META_LOCATION, loc); + } + if (plot == null) { + player.deleteMeta(PlotPlayer.META_LAST_PLOT); + } else { + player.setMeta(PlotPlayer.META_LAST_PLOT, plot); + } + } + } + + @Override public boolean canExecute(PlotPlayer player, boolean message) { + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Merge.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Merge.java new file mode 100644 index 000000000..94152175e --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Merge.java @@ -0,0 +1,198 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.*; + +import java.util.UUID; + +@CommandDeclaration(command = "merge", aliases = "m", + description = "Merge the plot you are standing on, with another plot", + permission = "plots.merge", usage = "/plot merge [removeroads]", + category = CommandCategory.SETTINGS, requiredType = RequiredType.NONE, confirmation = true) +public class Merge extends SubCommand { + + public static final String[] values = new String[] {"north", "east", "south", "west", "auto"}; + public static final String[] aliases = new String[] {"n", "e", "s", "w", "all"}; + + public static String direction(float yaw) { + yaw = yaw / 90; + int i = Math.round(yaw); + switch (i) { + case -4: + case 0: + case 4: + return "SOUTH"; + case -1: + case 3: + return "EAST"; + case -2: + case 2: + return "NORTH"; + case -3: + case 1: + return "WEST"; + default: + return ""; + } + } + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + Location loc = player.getLocationFull(); + final Plot plot = loc.getPlotAbs(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + MainUtil.sendMessage(player, C.PLOT_UNOWNED); + return false; + } + UUID uuid = player.getUUID(); + if (!plot.isOwner(uuid)) { + if (!Permissions.hasPermission(player, C.PERMISSION_ADMIN_COMMAND_MERGE)) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } else { + uuid = plot.guessOwner(); + } + } + final PlotArea plotArea = plot.getArea(); + Expression priceExr = + plotArea.PRICES.getOrDefault("merge", Expression.constant(0d)); + final int size = plot.getConnectedPlots().size(); + final double price = priceExr.evaluate((double) size); + if (EconHandler.manager != null && plotArea.USE_ECONOMY && price > 0d + && EconHandler.manager.getMoney(player) < price) { + sendMessage(player, C.CANNOT_AFFORD_MERGE, String.valueOf(price)); + return false; + } + final int maxSize = + Permissions.hasPermissionRange(player, "plots.merge", Settings.Limit.MAX_PLOTS); + if (size - 1 > maxSize) { + MainUtil.sendMessage(player, C.NO_PERMISSION, "plots.merge." + (size + 1)); + return false; + } + int direction = -1; + if (args.length == 0) { + switch (direction(player.getLocationFull().getYaw())) { + case "NORTH": + direction = 0; + break; + case "EAST": + direction = 1; + break; + case "SOUTH": + direction = 2; + break; + case "WEST": + direction = 3; + break; + } + } else { + if ("all".equalsIgnoreCase(args[0]) || "auto".equalsIgnoreCase(args[0])) { + boolean terrain = true; + if (args.length == 2) { + terrain = "true".equalsIgnoreCase(args[1]); + } + if (!terrain && !Permissions.hasPermission(player, C.PERMISSION_MERGE_KEEPROAD)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_MERGE_KEEPROAD.s()); + return true; + } + if (plot.autoMerge(-1, maxSize, uuid, terrain)) { + if (EconHandler.manager != null && plotArea.USE_ECONOMY && price > 0d) { + EconHandler.manager.withdrawMoney(player, price); + sendMessage(player, C.REMOVED_BALANCE, String.valueOf(price)); + } + MainUtil.sendMessage(player, C.SUCCESS_MERGE); + return true; + } + MainUtil.sendMessage(player, C.NO_AVAILABLE_AUTOMERGE); + return false; + + } + for (int i = 0; i < values.length; i++) { + if (args[0].equalsIgnoreCase(values[i]) || args[0].equalsIgnoreCase(aliases[i])) { + direction = i; + break; + } + } + } + if (direction == -1) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, + "/plot merge <" + StringMan.join(values, "|") + "> [removeroads]"); + MainUtil + .sendMessage(player, C.DIRECTION.s().replaceAll("%dir%", direction(loc.getYaw()))); + return false; + } + final boolean terrain; + if (args.length == 2) { + terrain = "true".equalsIgnoreCase(args[1]); + } else { + terrain = true; + } + if (!terrain && !Permissions.hasPermission(player, C.PERMISSION_MERGE_KEEPROAD)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_MERGE_KEEPROAD.s()); + return true; + } + if (plot.autoMerge(direction, maxSize - size, uuid, terrain)) { + if (EconHandler.manager != null && plotArea.USE_ECONOMY && price > 0d) { + EconHandler.manager.withdrawMoney(player, price); + sendMessage(player, C.REMOVED_BALANCE, String.valueOf(price)); + } + MainUtil.sendMessage(player, C.SUCCESS_MERGE); + return true; + } + Plot adjacent = plot.getRelative(direction); + if (adjacent == null || !adjacent.hasOwner() || adjacent.getMerged((direction + 2) % 4) + || adjacent.isOwner(uuid)) { + MainUtil.sendMessage(player, C.NO_AVAILABLE_AUTOMERGE); + return false; + } + if (!Permissions.hasPermission(player, C.PERMISSION_MERGE_OTHER)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_MERGE_OTHER); + return false; + } + java.util.Set uuids = adjacent.getOwners(); + boolean isOnline = false; + for (final UUID owner : uuids) { + final PlotPlayer accepter = UUIDHandler.getPlayer(owner); + if (accepter == null) { + continue; + } + isOnline = true; + final int dir = direction; + Runnable run = () -> { + MainUtil.sendMessage(accepter, C.MERGE_ACCEPTED); + plot.autoMerge(dir, maxSize - size, owner, terrain); + PlotPlayer plotPlayer = UUIDHandler.getPlayer(player.getUUID()); + if (plotPlayer == null) { + sendMessage(accepter, C.MERGE_NOT_VALID); + return; + } + if (EconHandler.manager != null && plotArea.USE_ECONOMY && price > 0d) { + if (EconHandler.manager.getMoney(player) < price) { + sendMessage(player, C.CANNOT_AFFORD_MERGE, String.valueOf(price)); + return; + } + EconHandler.manager.withdrawMoney(player, price); + sendMessage(player, C.REMOVED_BALANCE, String.valueOf(price)); + } + MainUtil.sendMessage(player, C.SUCCESS_MERGE); + }; + if (hasConfirmation(player)) { + CmdConfirm.addPending(accepter, + C.MERGE_REQUEST_CONFIRM.s().replaceAll("%s", player.getName()), run); + } else { + run.run(); + } + } + if (!isOnline) { + MainUtil.sendMessage(player, C.NO_AVAILABLE_AUTOMERGE); + return false; + } + MainUtil.sendMessage(player, C.MERGE_REQUESTED); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Middle.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Middle.java new file mode 100644 index 000000000..f4f184cc1 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Middle.java @@ -0,0 +1,29 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; + +/** + * @author manuelgu, altered by Citymonstret + */ +@CommandDeclaration(command = "middle", aliases = {"center", "centre"}, + description = "Teleports you to the center of the plot", usage = "/plot middle", + category = CommandCategory.TELEPORT, requiredType = RequiredType.NONE) public class Middle + extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] arguments) { + Location location = player.getLocation(); + Plot plot = location.getPlot(); + if (plot == null) { + return sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + return sendMessage(player, C.PLOT_UNOWNED); + } + player.teleport(plot.getCenter()); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Move.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Move.java new file mode 100644 index 000000000..289a3c4a6 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Move.java @@ -0,0 +1,65 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; + +@CommandDeclaration(usage = "/plot move ", command = "move", description = "Move a plot", + aliases = {"debugmove"}, permission = "plots.move", category = CommandCategory.CLAIMING, + requiredType = RequiredType.NONE) public class Move extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + Location loc = player.getLocation(); + Plot plot1 = loc.getPlotAbs(); + if (plot1 == null) { + return !MainUtil.sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot1.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN.s())) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + boolean override = false; + if (args.length == 2 && args[1].equalsIgnoreCase("-f")) { + args = new String[] {args[0]}; + override = true; + } + if (args.length != 1) { + C.COMMAND_SYNTAX.send(player, getUsage()); + return false; + } + PlotArea area = PlotSquared.get().getPlotAreaByString(args[0]); + Plot plot2; + if (area == null) { + plot2 = MainUtil.getPlotFromString(player, args[0], true); + if (plot2 == null) { + return false; + } + } else { + plot2 = area.getPlotAbs(plot1.getId()); + } + if (plot1.equals(plot2)) { + MainUtil.sendMessage(player, C.NOT_VALID_PLOT_ID); + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot copy "); + return false; + } + if (!plot1.getArea().isCompatible(plot2.getArea()) && (!override || !Permissions + .hasPermission(player, C.PERMISSION_ADMIN.s()))) { + C.PLOTWORLD_INCOMPATIBLE.send(player); + return false; + } + if (plot1.move(plot2, () -> MainUtil.sendMessage(player, C.MOVE_SUCCESS), false)) { + return true; + } else { + MainUtil.sendMessage(player, C.REQUIRES_UNOWNED); + return false; + } + } + +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Music.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Music.java new file mode 100644 index 000000000..b2e5170e5 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Music.java @@ -0,0 +1,69 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.flag.Flags; +import com.github.intellectualsites.plotsquared.plot.object.*; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Locale; + +@CommandDeclaration(command = "music", permission = "plots.music", + description = "Play music in your plot", usage = "/plot music", + category = CommandCategory.APPEARANCE, requiredType = RequiredType.PLAYER) public class Music + extends SubCommand { + + private static final Collection DISCS = Arrays + .asList("music_disc_13", "music_disc_cat", "music_disc_blocks", "music_disc_chirp", + "music_disc_far", "music_disc_mall", "music_disc_mellohi", "music_disc_stal", + "music_disc_strad", "music_disc_ward", "music_disc_11", "music_disc_wait"); + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + Location loc = player.getLocation(); + final Plot plot = loc.getPlotAbs(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.isAdded(player.getUUID())) { + sendMessage(player, C.NO_PLOT_PERMS); + return true; + } + PlotInventory inv = new PlotInventory(player, 2, "Plot Jukebox") { + @Override public boolean onClick(int index) { + PlotItemStack item = getItem(index); + if (item == null) { + return true; + } + if (item.getPlotBlock().equalsAny(7, "bedrock")) { + plot.removeFlag(Flags.MUSIC); + C.FLAG_REMOVED.send(player); + } else if (item.name.toLowerCase(Locale.ENGLISH).contains("disc")) { + plot.setFlag(Flags.MUSIC, item.getPlotBlock().getRawId()); + C.FLAG_ADDED.send(player); + } else { + C.FLAG_NOT_ADDED.send(player); + } + return false; + } + }; + int index = 0; + + for (final String disc : DISCS) { + final String name = String.format("&r&6%s", disc); + final String[] lore = {"&r&aClick to play!"}; + final PlotItemStack item = new PlotItemStack(disc, 1, name, lore); + inv.setItem(index++, item); + } + + // Always add the cancel button + // if (player.getMeta("music") != null) { + String name = "&r&6Cancel music"; + String[] lore = {"&r&cClick to cancel!"}; + inv.setItem(index, new PlotItemStack("bedrock", 1, name, lore)); + // } + + inv.openInventory(); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Near.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Near.java new file mode 100644 index 000000000..c3e9c5f9e --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Near.java @@ -0,0 +1,24 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3; +import com.github.intellectualsites.plotsquared.plot.util.StringMan; + +@CommandDeclaration(command = "near", aliases = "n", description = "Display nearby players", + usage = "/plot near", category = CommandCategory.INFO) public class Near extends Command { + public Near() { + super(MainCommand.getInstance(), true); + } + + @Override public void execute(PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) throws CommandException { + final Plot plot = check(player.getCurrentPlot(), C.NOT_IN_PLOT); + C.PLOT_NEAR.send(player, StringMan.join(plot.getPlayersInPlot(), ", ")); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Owner.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Owner.java new file mode 100644 index 000000000..4095c15c9 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Owner.java @@ -0,0 +1,96 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.*; + +import java.util.Set; +import java.util.UUID; + +@CommandDeclaration(command = "setowner", permission = "plots.set.owner", + description = "Set the plot owner", usage = "/plot setowner ", + aliases = {"owner", "so", "seto"}, category = CommandCategory.CLAIMING, + requiredType = RequiredType.NONE, confirmation = true) public class Owner extends SetCommand { + + @Override public boolean set(final PlotPlayer player, final Plot plot, String value) { + Set plots = plot.getConnectedPlots(); + UUID uuid = null; + String name = null; + if (value.length() == 36) { + try { + uuid = UUID.fromString(value); + name = MainUtil.getName(uuid); + } catch (Exception ignored) { + } + } else { + uuid = UUIDHandler.getUUID(value, null); + name = UUIDHandler.getName(uuid); + name = name == null ? value : name; + } + if (uuid == null || value.equalsIgnoreCase("-")) { + if (value.equalsIgnoreCase("none") || value.equalsIgnoreCase("null") || value + .equalsIgnoreCase("-")) { + if (!Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_SETOWNER.s(), true)) { + return false; + } + Set connected = plot.getConnectedPlots(); + plot.unlinkPlot(false, false); + for (Plot current : connected) { + current.unclaim(); + current.removeSign(); + } + MainUtil.sendMessage(player, C.SET_OWNER); + return true; + } + C.INVALID_PLAYER.send(player, value); + return false; + } + final PlotPlayer other = UUIDHandler.getPlayer(uuid); + if (plot.isOwner(uuid)) { + C.ALREADY_OWNER.send(player, MainUtil.getName(uuid)); + return false; + } + if (!Permissions.hasPermission(player, C.PERMISSION_ADMIN_COMMAND_SETOWNER)) { + if (other == null) { + C.INVALID_PLAYER_OFFLINE.send(player, value); + return false; + } + int size = plots.size(); + int currentPlots = (Settings.Limit.GLOBAL ? + other.getPlotCount() : + other.getPlotCount(plot.getWorldName())) + size; + if (currentPlots > other.getAllowedPlots()) { + sendMessage(player, C.CANT_TRANSFER_MORE_PLOTS); + return false; + } + } + final String finalName = name; + final UUID finalUUID = uuid; + final boolean removeDenied = plot.isDenied(finalUUID); + Runnable run = new Runnable() { + @Override public void run() { + if (plot.setOwner(finalUUID, player)) { + if (removeDenied) + plot.removeDenied(finalUUID); + plot.setSign(finalName); + MainUtil.sendMessage(player, C.SET_OWNER); + if (other != null) { + MainUtil + .sendMessage(other, C.NOW_OWNER, plot.getArea() + ";" + plot.getId()); + } + } else + MainUtil.sendMessage(player, C.SET_OWNER_CANCELLED); + } + }; + if (hasConfirmation(player)) { + CmdConfirm.addPending(player, "/plot set owner " + value, run); + } else { + TaskManager.runTask(run); + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/PluginCmd.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/PluginCmd.java new file mode 100644 index 000000000..81047ec9b --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/PluginCmd.java @@ -0,0 +1,38 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.json.JSONObject; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.HttpUtil; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.TaskManager; + +@CommandDeclaration(command = "plugin", permission = "plots.use", + description = "Show plugin information", usage = "/plot plugin", aliases = "version", + category = CommandCategory.INFO) public class PluginCmd extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + TaskManager.IMP.taskAsync(new Runnable() { + @Override public void run() { + MainUtil.sendMessage(player, String.format( + "$2>> $1&l" + PlotSquared.imp().getPluginName() + " $2($1Version$2: $1%s$2)", + PlotSquared.get().getVersion())); + MainUtil.sendMessage(player, + "$2>> $1&lAuthors$2: $1Citymonstret $2& $1Empire92 $2& $1MattBDev $2& $1dordsor21"); + MainUtil.sendMessage(player, + "$2>> $1&lWiki$2: $1https://github.com/IntellectualCrafters/PlotSquared/wiki"); + MainUtil.sendMessage(player, + "$2>> $1&lNewest Version$2: $1" + getNewestVersionString()); + } + }); + return true; + } + + public String getNewestVersionString() { + String str = HttpUtil + .readUrl("https://api.github.com/repos/IntellectualSites/PlotSquared/releases/latest"); + JSONObject release = new JSONObject(str); + return release.getString("name"); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Purge.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Purge.java new file mode 100644 index 000000000..8cd4d9e56 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Purge.java @@ -0,0 +1,167 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.listener.PlotListener; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; +import com.github.intellectualsites.plotsquared.plot.object.PlotId; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.CmdConfirm; +import com.github.intellectualsites.plotsquared.plot.util.StringMan; +import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.UUID; + +@CommandDeclaration( + usage = "/plot purge world: area: id: owner: shared: unknown:[true|false]", + command = "purge", permission = "plots.admin", description = "Purge all plots for a world", + category = CommandCategory.ADMINISTRATION, requiredType = RequiredType.CONSOLE, + confirmation = true) public class Purge extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + if (args.length == 0) { + return false; + } + + String world = null; + PlotArea area = null; + PlotId id = null; + UUID owner = null; + UUID added = null; + boolean unknown = false; + for (String arg : args) { + String[] split = arg.split(":"); + if (split.length != 2) { + C.COMMAND_SYNTAX.send(player, getUsage()); + return false; + } + switch (split[0].toLowerCase()) { + case "world": + case "w": + world = split[1]; + break; + case "area": + case "a": + area = PlotSquared.get().getPlotAreaByString(split[1]); + if (area == null) { + C.NOT_VALID_PLOT_WORLD.send(player, split[1]); + return false; + } + break; + case "plotid": + case "id": + id = PlotId.fromString(split[1]); + if (id == null) { + C.NOT_VALID_PLOT_ID.send(player, split[1]); + return false; + } + break; + case "owner": + case "o": + owner = UUIDHandler.getUUID(split[1], null); + if (owner == null) { + C.INVALID_PLAYER.send(player, split[1]); + return false; + } + break; + case "shared": + case "s": + added = UUIDHandler.getUUID(split[1], null); + if (added == null) { + C.INVALID_PLAYER.send(player, split[1]); + return false; + } + break; + case "unknown": + case "?": + case "u": + unknown = Boolean.parseBoolean(split[1]); + break; + default: + C.COMMAND_SYNTAX.send(player, getUsage()); + return false; + } + } + final HashSet toDelete = new HashSet<>(); + for (Plot plot : PlotSquared.get().getBasePlots()) { + if (world != null && !plot.getWorldName().equalsIgnoreCase(world)) { + continue; + } + if (area != null && !plot.getArea().equals(area)) { + continue; + } + if (id != null && !plot.getId().equals(id)) { + continue; + } + if (owner != null && !plot.isOwner(owner)) { + continue; + } + if (added != null && !plot.isAdded(added)) { + continue; + } + if (unknown && UUIDHandler.getName(plot.owner) != null) { + continue; + } + toDelete.addAll(plot.getConnectedPlots()); + } + if (PlotSquared.get().plots_tmp != null) { + for (Entry> entry : PlotSquared.get().plots_tmp + .entrySet()) { + String worldName = entry.getKey(); + if (world != null && !world.equalsIgnoreCase(worldName)) { + continue; + } + for (Entry entry2 : entry.getValue().entrySet()) { + Plot plot = entry2.getValue(); + if (id != null && !plot.getId().equals(id)) { + continue; + } + if (owner != null && !plot.isOwner(owner)) { + continue; + } + if (added != null && !plot.isAdded(added)) { + continue; + } + if (unknown && UUIDHandler.getName(plot.owner) != null) { + continue; + } + toDelete.add(plot); + } + } + } + if (toDelete.isEmpty()) { + C.FOUND_NO_PLOTS.send(player); + return false; + } + String cmd = + "/plot purge " + StringMan.join(args, " ") + " (" + toDelete.size() + " plots)"; + Runnable run = () -> { + PlotSquared.debug("Calculating plots to purge, please wait..."); + HashSet ids = new HashSet<>(); + for (Plot plot : toDelete) { + if (plot.temp != Integer.MAX_VALUE) { + ids.add(plot.temp); + plot.getArea().removePlot(plot.getId()); + for (PlotPlayer pp : plot.getPlayersInPlot()) { + PlotListener.plotEntry(pp, plot); + } + plot.removeSign(); + } + } + DBFunc.purgeIds(ids); + C.PURGE_SUCCESS.send(player, ids.size() + "/" + toDelete.size()); + }; + if (hasConfirmation(player)) { + CmdConfirm.addPending(player, cmd, run); + } else { + run.run(); + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Rate.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Rate.java new file mode 100644 index 000000000..d8103e5b8 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Rate.java @@ -0,0 +1,217 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.flag.Flags; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map.Entry; +import java.util.UUID; + +@CommandDeclaration(command = "rate", permission = "plots.rate", description = "Rate the plot", + usage = "/plot rate [#|next|purge]", aliases = "rt", category = CommandCategory.INFO, + requiredType = RequiredType.NONE) public class Rate extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + if (args.length == 1) { + switch (args[0].toLowerCase()) { + case "next": { + ArrayList plots = new ArrayList<>(PlotSquared.get().getBasePlots()); + plots.sort((p1, p2) -> { + double v1 = 0; + if (!p1.getRatings().isEmpty()) { + for (Entry entry : p1.getRatings().entrySet()) { + v1 -= 11 - entry.getValue().getAverageRating(); + } + } + double v2 = 0; + if (!p2.getRatings().isEmpty()) { + for (Entry entry : p2.getRatings().entrySet()) { + v2 -= 11 - entry.getValue().getAverageRating(); + } + } + if (v1 == v2) { + return -0; + } + return v2 > v1 ? 1 : -1; + }); + UUID uuid = player.getUUID(); + for (Plot p : plots) { + if ((!Settings.Done.REQUIRED_FOR_RATINGS || p.hasFlag(Flags.DONE)) && p + .isBasePlot() && (!p.getRatings().containsKey(uuid)) && !p + .isAdded(uuid)) { + p.teleportPlayer(player); + MainUtil.sendMessage(player, C.RATE_THIS); + return true; + } + } + MainUtil.sendMessage(player, C.FOUND_NO_PLOTS); + return false; + } + case "purge": { + final Plot plot = player.getCurrentPlot(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!Permissions.hasPermission(player, C.PERMISSION_ADMIN_COMMAND_RATE, true)) { + return false; + } + plot.clearRatings(); + C.RATINGS_PURGED.send(player); + return true; + } + } + } + final Plot plot = player.getCurrentPlot(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + sendMessage(player, C.RATING_NOT_OWNED); + return false; + } + if (plot.isOwner(player.getUUID())) { + sendMessage(player, C.RATING_NOT_YOUR_OWN); + return false; + } + if (Settings.Done.REQUIRED_FOR_RATINGS && !plot.hasFlag(Flags.DONE)) { + sendMessage(player, C.RATING_NOT_DONE); + return false; + } + if (Settings.Ratings.CATEGORIES != null && !Settings.Ratings.CATEGORIES.isEmpty()) { + final Runnable run = new Runnable() { + @Override public void run() { + if (plot.getRatings().containsKey(player.getUUID())) { + sendMessage(player, C.RATING_ALREADY_EXISTS, plot.getId().toString()); + return; + } + final MutableInt index = new MutableInt(0); + final MutableInt rating = new MutableInt(0); + String title = Settings.Ratings.CATEGORIES.get(0); + PlotInventory inventory = new PlotInventory(player, 1, title) { + @Override public boolean onClick(int i) { + rating.add((i + 1) * Math.pow(10, index.getValue())); + index.increment(); + if (index.getValue() >= Settings.Ratings.CATEGORIES.size()) { + int rV = rating.getValue(); + Rating result = + EventUtil.manager.callRating(this.player, plot, new Rating(rV)); + if (result != null) { + plot.addRating(this.player.getUUID(), result); + sendMessage(this.player, C.RATING_APPLIED, + plot.getId().toString()); + if (Permissions + .hasPermission(this.player, C.PERMISSION_COMMENT)) { + Command command = + MainCommand.getInstance().getCommand(Comment.class); + if (command != null) { + MainUtil.sendMessage(this.player, C.COMMENT_THIS, + command.getUsage()); + } + } + } + return false; + } + setTitle(Settings.Ratings.CATEGORIES.get(index.getValue())); + return true; + } + }; + inventory.setItem(0, new PlotItemStack("minecraft:brown_wool", 0, "0/8")); + inventory.setItem(1, new PlotItemStack(35, (short) 14, 1, "1/8")); + inventory.setItem(2, new PlotItemStack(35, (short) 1, 2, "2/8")); + inventory.setItem(3, new PlotItemStack(35, (short) 4, 3, "3/8")); + inventory.setItem(4, new PlotItemStack(35, (short) 5, 4, "4/8")); + inventory.setItem(5, new PlotItemStack(35, (short) 9, 5, "5/8")); + inventory.setItem(6, new PlotItemStack(35, (short) 11, 6, "6/8")); + inventory.setItem(7, new PlotItemStack(35, (short) 10, 7, "7/8")); + inventory.setItem(8, new PlotItemStack(35, (short) 2, 8, "8/8")); + inventory.openInventory(); + } + }; + if (plot.getSettings().ratings == null) { + if (!Settings.Enabled_Components.RATING_CACHE) { + TaskManager.runTaskAsync(() -> { + plot.getSettings().ratings = DBFunc.getRatings(plot); + run.run(); + }); + return true; + } + plot.getSettings().ratings = new HashMap<>(); + } + run.run(); + return true; + } + if (args.length < 1) { + sendMessage(player, C.RATING_NOT_VALID); + return true; + } + String arg = args[0]; + final int rating; + if (MathMan.isInteger(arg) && arg.length() < 3 && !arg.isEmpty()) { + rating = Integer.parseInt(arg); + if (rating > 10 || rating < 1) { + sendMessage(player, C.RATING_NOT_VALID); + return false; + } + } else { + sendMessage(player, C.RATING_NOT_VALID); + return false; + } + final UUID uuid = player.getUUID(); + final Runnable run = () -> { + if (plot.getRatings().containsKey(uuid)) { + sendMessage(player, C.RATING_ALREADY_EXISTS, plot.getId().toString()); + return; + } + Rating result = EventUtil.manager.callRating(player, plot, new Rating(rating)); + if (result != null) { + plot.addRating(uuid, result); + sendMessage(player, C.RATING_APPLIED, plot.getId().toString()); + } + }; + if (plot.getSettings().ratings == null) { + if (!Settings.Enabled_Components.RATING_CACHE) { + TaskManager.runTaskAsync(() -> { + plot.getSettings().ratings = DBFunc.getRatings(plot); + run.run(); + }); + return true; + } + plot.getSettings().ratings = new HashMap<>(); + } + run.run(); + return true; + } + + private class MutableInt { + + private int value; + + MutableInt(int i) { + this.value = i; + } + + void increment() { + this.value++; + } + + void decrement() { + this.value--; + } + + int getValue() { + return this.value; + } + + void add(Number v) { + this.value += v.intValue(); + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/RegenAllRoads.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/RegenAllRoads.java new file mode 100644 index 000000000..9edf20a62 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/RegenAllRoads.java @@ -0,0 +1,60 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.generator.HybridPlotManager; +import com.github.intellectualsites.plotsquared.plot.generator.HybridUtils; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; +import com.github.intellectualsites.plotsquared.plot.object.PlotManager; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; + +@CommandDeclaration(command = "regenallroads", + description = "Regenerate all roads in the map using the set road schematic", + aliases = {"rgar"}, usage = "/plot regenallroads [height]", + category = CommandCategory.ADMINISTRATION, requiredType = RequiredType.CONSOLE, + permission = "plots.regenallroads") public class RegenAllRoads extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + int height = 0; + if (args.length == 2) { + try { + height = Integer.parseInt(args[1]); + } catch (NumberFormatException ignored) { + MainUtil.sendMessage(player, C.NOT_VALID_NUMBER, "(0, 256)"); + MainUtil + .sendMessage(player, C.COMMAND_SYNTAX, "/plot regenallroads [height]"); + return false; + } + } else if (args.length != 1) { + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot regenallroads [height]"); + return false; + } + PlotArea area = PlotSquared.get().getPlotAreaByString(args[0]); + if (area == null) { + C.NOT_VALID_PLOT_WORLD.send(player, args[0]); + return false; + } + String name = args[0]; + PlotManager manager = area.getPlotManager(); + if (!(manager instanceof HybridPlotManager)) { + MainUtil.sendMessage(player, C.NOT_VALID_PLOT_WORLD); + return false; + } + //Set chunks = ChunkManager.manager.getChunkChunks(name); + MainUtil + .sendMessage(player, "&cIf no schematic is set, the following will not do anything"); + MainUtil.sendMessage(player, + "&7 - To set a schematic, stand in a plot and use &c/plot createroadschematic"); + //MainUtil.sendMessage(player, "&6Potential chunks to update: &7" + (chunks.size() * 1024)); + //MainUtil.sendMessage(player, "&6Estimated time: &7" + chunks.size() + " seconds"); + boolean result = HybridUtils.manager.scheduleRoadUpdate(area, height); + if (!result) { + MainUtil.sendMessage(player, + "&cCannot schedule mass schematic update! (Is one already in progress?)"); + return false; + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Relight.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Relight.java new file mode 100644 index 000000000..79a87b887 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Relight.java @@ -0,0 +1,39 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.ChunkManager; +import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue; + +import java.util.HashSet; + +@CommandDeclaration(command = "relight", description = "Relight your plot", usage = "/plot relight", + category = CommandCategory.DEBUG) public class Relight extends Command { + public Relight() { + super(MainCommand.getInstance(), true); + } + + @Override public void execute(final PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) { + final Plot plot = player.getCurrentPlot(); + if (plot == null) { + C.NOT_IN_PLOT.send(player); + return; + } + HashSet regions = plot.getRegions(); + final LocalBlockQueue queue = plot.getArea().getQueue(false); + ChunkManager.chunkTask(plot, new RunnableVal() { + @Override public void run(int[] value) { + queue.fixChunkLighting(value[0], value[1]); + } + }, new Runnable() { + @Override public void run() { + plot.refreshChunks(); + C.SET_BLOCK_ACTION_FINISHED.send(player); + } + }, 5); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Reload.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Reload.java new file mode 100644 index 000000000..71ee2e840 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Reload.java @@ -0,0 +1,84 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.configuration.ConfigurationSection; +import com.github.intellectualsites.plotsquared.configuration.MemorySection; +import com.github.intellectualsites.plotsquared.configuration.file.YamlConfiguration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.PlotArea; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; + +import java.io.IOException; +import java.util.Objects; + +@CommandDeclaration(command = "reload", aliases = "rl", permission = "plots.admin.command.reload", + description = "Reload translations and world settings", usage = "/plot reload", + category = CommandCategory.ADMINISTRATION) public class Reload extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + try { + // The following won't affect world generation, as that has to be + // loaded during startup unfortunately. + PlotSquared.get().setupConfigs(); + C.load(PlotSquared.get().translationFile); + PlotSquared.get().foreachPlotArea(new RunnableVal() { + @Override public void run(PlotArea area) { + ConfigurationSection worldSection = PlotSquared.get().worlds + .getConfigurationSection("worlds." + area.worldname); + if (worldSection == null) { + return; + } + if (area.TYPE != 2 || !worldSection.contains("areas")) { + area.saveConfiguration(worldSection); + area.loadDefaultConfiguration(worldSection); + } else { + ConfigurationSection areaSection = worldSection.getConfigurationSection( + "areas." + area.id + "-" + area.getMin() + "-" + area.getMax()); + YamlConfiguration clone = new YamlConfiguration(); + for (String key : areaSection.getKeys(true)) { + if (areaSection.get(key) instanceof MemorySection) { + continue; + } + if (!clone.contains(key)) { + clone.set(key, areaSection.get(key)); + } + } + for (String key : worldSection.getKeys(true)) { + if (worldSection.get(key) instanceof MemorySection) { + continue; + } + if (!key.startsWith("areas") && !clone.contains(key)) { + clone.set(key, worldSection.get(key)); + } + } + area.saveConfiguration(clone); + // netSections is the combination of + for (String key : clone.getKeys(true)) { + if (clone.get(key) instanceof MemorySection) { + continue; + } + if (!worldSection.contains(key)) { + worldSection.set(key, clone.get(key)); + } else { + Object value = worldSection.get(key); + if (Objects.equals(value, clone.get(key))) { + areaSection.set(key, clone.get(key)); + } + } + } + area.loadDefaultConfiguration(clone); + } + } + }); + PlotSquared.get().worlds.save(PlotSquared.get().worldsFile); + MainUtil.sendMessage(player, C.RELOADED_CONFIGS); + } catch (IOException e) { + e.printStackTrace(); + MainUtil.sendMessage(player, C.RELOAD_FAILED); + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Remove.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Remove.java new file mode 100644 index 000000000..bf027f20d --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Remove.java @@ -0,0 +1,108 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Argument; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.database.DBFunc; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.EventUtil; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; +import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +@CommandDeclaration(command = "remove", aliases = {"r", "untrust", "ut", "undeny", "unban", "ud"}, + description = "Remove a player from a plot", usage = "/plot remove ", + category = CommandCategory.SETTINGS, requiredType = RequiredType.NONE, + permission = "plots.remove") public class Remove extends SubCommand { + + public Remove() { + super(Argument.PlayerName); + } + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + Location location = player.getLocation(); + Plot plot = location.getPlotAbs(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + MainUtil.sendMessage(player, C.PLOT_UNOWNED); + return false; + } + if (!plot.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_REMOVE)) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return true; + } + int count = 0; + switch (args[0]) { + case "unknown": { + ArrayList toRemove = new ArrayList<>(); + HashSet all = new HashSet<>(); + all.addAll(plot.getMembers()); + all.addAll(plot.getTrusted()); + all.addAll(plot.getDenied()); + for (UUID uuid : all) { + if (UUIDHandler.getName(uuid) == null) { + toRemove.add(uuid); + count++; + } + } + for (UUID uuid : toRemove) { + plot.removeDenied(uuid); + plot.removeTrusted(uuid); + plot.removeMember(uuid); + } + break; + } + default: + Set uuids = MainUtil.getUUIDsFromString(args[0]); + if (!uuids.isEmpty()) { + for (UUID uuid : uuids) { + if (uuid == DBFunc.EVERYONE) { + if (plot.removeTrusted(uuid)) { + EventUtil.manager.callTrusted(player, plot, uuid, false); + count++; + } else if (plot.removeMember(uuid)) { + EventUtil.manager.callMember(player, plot, uuid, false); + count++; + } else if (plot.removeDenied(uuid)) { + EventUtil.manager.callDenied(player, plot, uuid, false); + count++; + } + } else if (plot.getTrusted().contains(uuid)) { + if (plot.removeTrusted(uuid)) { + EventUtil.manager.callTrusted(player, plot, uuid, false); + count++; + } + } else if (plot.getMembers().contains(uuid)) { + if (plot.removeMember(uuid)) { + EventUtil.manager.callMember(player, plot, uuid, false); + count++; + } + } else if (plot.getDenied().contains(uuid)) { + if (plot.removeDenied(uuid)) { + EventUtil.manager.callDenied(player, plot, uuid, false); + count++; + } + } + } + } + break; + } + if (count == 0) { + MainUtil.sendMessage(player, C.INVALID_PLAYER, args[0]); + return false; + } else { + MainUtil.sendMessage(player, C.REMOVED_PLAYERS, count + ""); + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/RequiredType.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/RequiredType.java new file mode 100644 index 000000000..3f13368de --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/RequiredType.java @@ -0,0 +1,16 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandCaller; + +public enum RequiredType { + CONSOLE, PLAYER, NONE; + + public boolean allows(CommandCaller player) { + switch (this) { + case NONE: + return true; + default: + return this == player.getSuperCaller(); + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Save.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Save.java new file mode 100644 index 000000000..aec9543ed --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Save.java @@ -0,0 +1,76 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; +import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler; +import com.github.intellectualsites.plotsquared.plot.util.TaskManager; +import com.sk89q.jnbt.CompoundTag; + +import java.net.URL; +import java.util.List; +import java.util.UUID; + +@CommandDeclaration(command = "save", aliases = {"backup"}, description = "Save your plot", + category = CommandCategory.SCHEMATIC, requiredType = RequiredType.NONE, + permission = "plots.save") public class Save extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + String world = player.getLocation().getWorld(); + if (!PlotSquared.get().hasPlotArea(world)) { + return !sendMessage(player, C.NOT_IN_PLOT_WORLD); + } + final Plot plot = player.getCurrentPlot(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + MainUtil.sendMessage(player, C.PLOT_UNOWNED); + return false; + } + if (!plot.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_SAVE)) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + if (plot.getRunning() > 0) { + MainUtil.sendMessage(player, C.WAIT_FOR_TIMER); + return false; + } + plot.addRunning(); + SchematicHandler.manager.getCompoundTag(plot, new RunnableVal() { + @Override public void run(final CompoundTag value) { + TaskManager.runTaskAsync(() -> { + String time = (System.currentTimeMillis() / 1000) + ""; + Location[] corners = plot.getCorners(); + corners[0].setY(0); + corners[1].setY(255); + int size = (corners[1].getX() - corners[0].getX()) + 1; + PlotId id = plot.getId(); + String world1 = plot.getArea().toString().replaceAll(";", "-") + .replaceAll("[^A-Za-z0-9]", ""); + final String file = time + '_' + world1 + '_' + id.x + '_' + id.y + '_' + size; + UUID uuid = player.getUUID(); + SchematicHandler.manager.upload(value, uuid, file, new RunnableVal() { + @Override public void run(URL url) { + plot.removeRunning(); + if (url == null) { + MainUtil.sendMessage(player, C.SAVE_FAILED); + return; + } + MainUtil.sendMessage(player, C.SAVE_SUCCESS); + List schematics = player.getMeta("plot_schematics"); + if (schematics != null) { + schematics.add(file + ".schematic"); + } + } + }); + }); + } + }); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SchematicCmd.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SchematicCmd.java new file mode 100644 index 000000000..110992543 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SchematicCmd.java @@ -0,0 +1,222 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.object.schematic.Schematic; +import com.github.intellectualsites.plotsquared.plot.util.*; + +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.UUID; + +@CommandDeclaration(command = "schematic", permission = "plots.schematic", + description = "Schematic command", aliases = {"sch", "schem"}, + category = CommandCategory.SCHEMATIC, usage = "/plot schematic ") +public class SchematicCmd extends SubCommand { + + private boolean running = false; + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + if (args.length < 1) { + sendMessage(player, C.SCHEMATIC_MISSING_ARG); + return true; + } + String arg = args[0].toLowerCase(); + switch (arg) { + case "paste": { + if (!Permissions.hasPermission(player, C.PERMISSION_SCHEMATIC_PASTE)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_SCHEMATIC_PASTE); + return false; + } + if (args.length < 2) { + sendMessage(player, C.SCHEMATIC_MISSING_ARG); + break; + } + Location loc = player.getLocation(); + final Plot plot = loc.getPlotAbs(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + MainUtil.sendMessage(player, C.PLOT_UNOWNED); + return false; + } + if (!plot.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_SCHEMATIC_PASTE)) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + if (this.running) { + MainUtil.sendMessage(player, "&cTask is already running."); + return false; + } + final String location = args[1]; + this.running = true; + TaskManager.runTaskAsync(() -> { + Schematic schematic = null; + if (location.startsWith("url:")) { + try { + UUID uuid = UUID.fromString(location.substring(4)); + URL base = new URL(Settings.Web.URL); + URL url = new URL(base, "uploads/" + uuid + ".schematic"); + schematic = SchematicHandler.manager.getSchematic(url); + } catch (Exception e) { + e.printStackTrace(); + sendMessage(player, C.SCHEMATIC_INVALID, + "non-existent url: " + location); + SchematicCmd.this.running = false; + return; + } + } else { + try { + schematic = SchematicHandler.manager.getSchematic(location); + } catch (SchematicHandler.UnsupportedFormatException e) { + e.printStackTrace(); + } + } + if (schematic == null) { + SchematicCmd.this.running = false; + sendMessage(player, C.SCHEMATIC_INVALID, + "non-existent or not in gzip format"); + return; + } + SchematicHandler.manager + .paste(schematic, plot, 0, 1, 0, false, new RunnableVal() { + @Override public void run(Boolean value) { + SchematicCmd.this.running = false; + if (value) { + sendMessage(player, C.SCHEMATIC_PASTE_SUCCESS); + } else { + sendMessage(player, C.SCHEMATIC_PASTE_FAILED); + } + } + }); + }); + break; + } + // TODO test + // case "test": { + // if (!Permissions.hasPermission(plr, "plots.schematic.test")) { + // MainUtil.sendMessage(plr, C.NO_PERMISSION, "plots.schematic.test"); + // return false; + // } + // if (args.length < 2) { + // sendMessage(plr, C.SCHEMATIC_MISSING_ARG); + // return false; + // } + // final Location loc = plr.getLocation(); + // final Plot plot = MainUtil.getPlot(loc); + // if (plot == null) { + // sendMessage(plr, C.NOT_IN_PLOT); + // return false; + // } + // file = args[1]; + // schematic = SchematicHandler.manager.getSchematic(file); + // if (schematic == null) { + // sendMessage(plr, C.SCHEMATIC_INVALID, "non-existent"); + // return false; + // } + // final int l1 = schematic.getSchematicDimension().getX(); + // final int l2 = schematic.getSchematicDimension().getZ(); + // final int length = MainUtil.getPlotWidth(loc.getWorld(), plot.id); + // if ((l1 < length) || (l2 < length)) { + // sendMessage(plr, C.SCHEMATIC_INVALID, String.format("Wrong size (x: %s, z: %d) vs %d ", l1, l2, length)); + // break; + // } + // sendMessage(plr, C.SCHEMATIC_VALID); + // break; + // } + case "saveall": + case "exportall": { + if (!(player instanceof ConsolePlayer)) { + MainUtil.sendMessage(player, C.NOT_CONSOLE); + return false; + } + if (args.length != 2) { + MainUtil.sendMessage(player, + "&cNeed world argument. Use &7/plot sch exportall "); + return false; + } + PlotArea area = PlotSquared.get().getPlotAreaByString(args[1]); + if (area == null) { + C.NOT_VALID_PLOT_WORLD.send(player, args[1]); + return false; + } + Collection plots = area.getPlots(); + if (plots.isEmpty()) { + MainUtil + .sendMessage(player, "&cInvalid world. Use &7/plot sch exportall "); + return false; + } + boolean result = SchematicHandler.manager.exportAll(plots, null, null, + () -> MainUtil.sendMessage(player, "&aFinished mass export")); + if (!result) { + MainUtil.sendMessage(player, "&cTask is already running."); + return false; + } else { + MainUtil.sendMessage(player, + "&3Plot&8->&3Schematic&8: &7Mass export has started. This may take a while."); + MainUtil.sendMessage(player, + "&3Plot&8->&3Schematic&8: &7Found &c" + plots.size() + "&7 plots..."); + } + break; + } + case "export": + case "save": + if (!Permissions.hasPermission(player, C.PERMISSION_SCHEMATIC_SAVE)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_SCHEMATIC_SAVE); + return false; + } + if (this.running) { + MainUtil.sendMessage(player, "&cTask is already running."); + return false; + } + Location location = player.getLocation(); + Plot plot = location.getPlotAbs(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + MainUtil.sendMessage(player, C.PLOT_UNOWNED); + return false; + } + if (!plot.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN_COMMAND_SCHEMATIC_SAVE)) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + location.getWorld(); + Collection plots = new ArrayList<>(); + plots.add(plot); + boolean result = SchematicHandler.manager.exportAll(plots, null, null, () -> { + MainUtil.sendMessage(player, "&aFinished export"); + SchematicCmd.this.running = false; + }); + if (!result) { + MainUtil.sendMessage(player, "&cTask is already running."); + return false; + } else { + MainUtil.sendMessage(player, "&7Starting export..."); + } + break; + case "list": { + if (!Permissions.hasPermission(player, C.PERMISSION_SCHEMATIC_LIST)) { + MainUtil.sendMessage(player, C.NO_PERMISSION, C.PERMISSION_SCHEMATIC_LIST); + return false; + } + final String string = + StringMan.join(SchematicHandler.manager.getShematicNames(), "$2, $1"); + C.SCHEMATIC_LIST.send(player, string); + } + break; + default: + sendMessage(player, C.SCHEMATIC_MISSING_ARG); + break; + } + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Set.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Set.java new file mode 100644 index 000000000..95166aa4a --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Set.java @@ -0,0 +1,167 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Configuration; +import com.github.intellectualsites.plotsquared.plot.config.Configuration.UnknownBlockException; +import com.github.intellectualsites.plotsquared.plot.flag.Flag; +import com.github.intellectualsites.plotsquared.plot.flag.FlagManager; +import com.github.intellectualsites.plotsquared.plot.flag.Flags; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.*; +import com.github.intellectualsites.plotsquared.plot.util.block.GlobalBlockQueue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; + +@CommandDeclaration(command = "set", description = "Set a plot value", aliases = {"s"}, + usage = "/plot set ", permission = "plots.set", + category = CommandCategory.APPEARANCE, requiredType = RequiredType.NONE) public class Set + extends SubCommand { + + public static final String[] values = new String[] {"biome", "alias", "home", "flag"}; + public static final String[] aliases = new String[] {"b", "w", "wf", "f", "a", "h", "fl"}; + + private final SetCommand component; + + public Set() { + this.component = new SetCommand() { + + @Override public String getId() { + return "set.component"; + } + + @Override public boolean set(PlotPlayer player, final Plot plot, String value) { + PlotArea plotArea = player.getLocation().getPlotArea(); + PlotManager manager = player.getLocation().getPlotManager(); + String[] components = manager.getPlotComponents(plotArea, plot.getId()); + boolean allowUnsafe = DebugAllowUnsafe.unsafeAllowed.contains(player.getUUID()); + + String[] args = value.split(" "); + String material = + StringMan.join(Arrays.copyOfRange(args, 1, args.length), ",").trim(); + + for (String component : components) { + if (component.equalsIgnoreCase(args[0])) { + if (!Permissions + .hasPermission(player, C.PERMISSION_SET_COMPONENT.f(component))) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_SET_COMPONENT.f(component)); + return false; + } + // PlotBlock[] blocks; + BlockBucket bucket; + try { + if (args.length < 2) { + MainUtil.sendMessage(player, C.NEED_BLOCK); + return true; + } + String[] split = material.split(","); + // blocks = Configuration.BLOCKLIST.parseString(material); + + try { + bucket = Configuration.BLOCK_BUCKET.parseString(material); + } catch (final UnknownBlockException unknownBlockException) { + final String unknownBlock = unknownBlockException.getUnknownValue(); + C.NOT_VALID_BLOCK.send(player, unknownBlock); + StringComparison.ComparisonResult match = + WorldUtil.IMP.getClosestBlock(unknownBlock); + if (match != null) { + final String found = + WorldUtil.IMP.getClosestMatchingName(match.best); + if (found != null) { + MainUtil.sendMessage(player, C.DID_YOU_MEAN, + found.toLowerCase()); + } + } + return false; + } + + if (!allowUnsafe) { + for (final PlotBlock block : bucket.getBlocks()) { + if (!block.isAir() && !WorldUtil.IMP.isBlockSolid(block)) { + C.NOT_ALLOWED_BLOCK.send(player, block.toString()); + return false; + } + } + } + } catch (Exception ignored) { + MainUtil.sendMessage(player, C.NOT_VALID_BLOCK, material); + return false; + } + if (plot.getRunning() > 0) { + MainUtil.sendMessage(player, C.WAIT_FOR_TIMER); + return false; + } + plot.addRunning(); + for (Plot current : plot.getConnectedPlots()) { + current.setComponent(component, bucket); + } + MainUtil.sendMessage(player, C.GENERATING_COMPONENT); + GlobalBlockQueue.IMP.addTask(new Runnable() { + @Override public void run() { + plot.removeRunning(); + } + }); + return true; + } + } + return false; + } + }; + } + + public boolean noArgs(PlotPlayer player) { + ArrayList newValues = new ArrayList<>(); + newValues.addAll(Arrays.asList("biome", "alias", "home", "flag")); + Plot plot = player.getCurrentPlot(); + if (plot != null) { + newValues.addAll( + Arrays.asList(plot.getManager().getPlotComponents(plot.getArea(), plot.getId()))); + } + MainUtil.sendMessage(player, C.SUBCOMMAND_SET_OPTIONS_HEADER.s() + StringMan + .join(newValues, C.BLOCK_LIST_SEPARATER.formatted())); + return false; + } + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + if (args.length == 0) { + return noArgs(player); + } + Command cmd = MainCommand.getInstance().getCommand("set" + args[0]); + if (cmd != null) { + if (!Permissions.hasPermission(player, cmd.getPermission(), true)) { + return false; + } + cmd.execute(player, Arrays.copyOfRange(args, 1, args.length), null, null); + return true; + } + // Additional checks + Plot plot = player.getCurrentPlot(); + if (plot == null) { + MainUtil.sendMessage(player, C.NOT_IN_PLOT); + return false; + } + // components + HashSet components = new HashSet<>( + Arrays.asList(plot.getManager().getPlotComponents(plot.getArea(), plot.getId()))); + if (components.contains(args[0].toLowerCase())) { + return this.component.onCommand(player, Arrays.copyOfRange(args, 0, args.length)); + } + // flag + Flag flag = FlagManager.getFlag(args[0].toLowerCase()); + if (Flags.getFlags().contains(flag)) { + StringBuilder a = new StringBuilder(); + if (args.length > 1) { + for (int x = 1; x < args.length; x++) { + a.append(" ").append(args[x]); + } + } + MainCommand.onCommand(player, ("flag set " + args[0] + a.toString()).split(" ")); + return true; + } + return noArgs(player); + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SetCommand.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SetCommand.java new file mode 100644 index 000000000..aaa1adfa2 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SetCommand.java @@ -0,0 +1,43 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; +import com.github.intellectualsites.plotsquared.plot.util.StringMan; + +public abstract class SetCommand extends SubCommand { + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + Location loc = player.getLocation(); + Plot plot = loc.getPlotAbs(); + if (plot == null) { + return !sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot.hasOwner()) { + if (!Permissions.hasPermission(player, C.PERMISSION_ADMIN_COMMAND.f(getFullId()))) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_ADMIN_COMMAND.f(getFullId())); + MainUtil.sendMessage(player, C.PLOT_NOT_CLAIMED); + return false; + } + } + if (!plot.isOwner(player.getUUID())) { + if (!Permissions.hasPermission(player, C.PERMISSION_ADMIN_COMMAND.f(getFullId()))) { + MainUtil.sendMessage(player, C.NO_PERMISSION, + C.PERMISSION_ADMIN_COMMAND.f(getFullId())); + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + } + if (args.length == 0) { + return set(player, plot, ""); + } + return set(player, plot, StringMan.join(args, " ")); + } + + public abstract boolean set(PlotPlayer player, Plot plot, String value); + +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SetHome.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SetHome.java new file mode 100644 index 000000000..fc92cc550 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SetHome.java @@ -0,0 +1,40 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.BlockLoc; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; + +@CommandDeclaration(command = "sethome", permission = "plots.set.home", + description = "Set the plot home to your current position", usage = "/plot sethome [none]", + aliases = {"sh", "seth"}, category = CommandCategory.SETTINGS, requiredType = RequiredType.NONE) +public class SetHome extends SetCommand { + + @Override public boolean set(PlotPlayer player, Plot plot, String value) { + switch (value.toLowerCase()) { + case "unset": + case "reset": + case "remove": + case "none": { + Plot base = plot.getBasePlot(false); + base.setHome(null); + return MainUtil.sendMessage(player, C.POSITION_UNSET); + } + case "": + Plot base = plot.getBasePlot(false); + Location bot = base.getBottomAbs(); + Location loc = player.getLocationFull(); + BlockLoc rel = + new BlockLoc(loc.getX() - bot.getX(), loc.getY(), loc.getZ() - bot.getZ(), + loc.getYaw(), loc.getPitch()); + base.setHome(rel); + return MainUtil.sendMessage(player, C.POSITION_SET); + default: + MainUtil.sendMessage(player, C.HOME_ARGUMENT); + return false; + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Setup.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Setup.java new file mode 100644 index 000000000..facea4952 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Setup.java @@ -0,0 +1,434 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.Configuration; +import com.github.intellectualsites.plotsquared.plot.config.ConfigurationNode; +import com.github.intellectualsites.plotsquared.plot.generator.GeneratorWrapper; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.SetupUtils; +import com.github.intellectualsites.plotsquared.plot.util.StringMan; +import com.github.intellectualsites.plotsquared.plot.util.WorldUtil; +import lombok.*; + +import javax.annotation.Nullable; +import java.util.*; +import java.util.Map.Entry; + +@CommandDeclaration(command = "setup", permission = "plots.admin.command.setup", + description = "Setup wizard for plot worlds", usage = "/plot setup", aliases = {"create"}, + category = CommandCategory.ADMINISTRATION) public class Setup extends SubCommand { + + public void displayGenerators(PlotPlayer player) { + StringBuilder message = new StringBuilder(); + message.append("&6What generator do you want?"); + for (Entry> entry : SetupUtils.generators.entrySet()) { + if (entry.getKey().equals(PlotSquared.imp().getPluginName())) { + message.append("\n&8 - &2").append(entry.getKey()).append(" (Default Generator)"); + } else if (entry.getValue().isFull()) { + message.append("\n&8 - &7").append(entry.getKey()).append(" (Plot Generator)"); + } else { + message.append("\n&8 - &7").append(entry.getKey()).append(" (Unknown structure)"); + } + } + MainUtil.sendMessage(player, message.toString()); + } + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + // going through setup + SetupObject object = player.getMeta("setup"); + if (object == null) { + object = new SetupObject(); + player.setMeta("setup", object); + SetupUtils.manager.updateGenerators(); + sendMessage(player, C.SETUP_INIT); + displayGenerators(player); + return false; + } + if (args.length == 1) { + if (args[0].equalsIgnoreCase("cancel")) { + player.deleteMeta("setup"); + MainUtil.sendMessage(player, "&aCancelled setup"); + return false; + } + if (args[0].equalsIgnoreCase("back")) { + if (object.setup_index > 0) { + object.setup_index--; + ConfigurationNode node = object.step[object.setup_index]; + sendMessage(player, C.SETUP_STEP, object.setup_index + 1, node.getDescription(), + node.getType().getType(), String.valueOf(node.getDefaultValue())); + return false; + } else if (object.current > 0) { + object.current--; + } + } + } + int index = object.current; + switch (index) { + case 0: // choose generator + if (args.length != 1 || !SetupUtils.generators.containsKey(args[0])) { + String prefix = "\n&8 - &7"; + MainUtil.sendMessage(player, + "&cYou must choose a generator!" + prefix + StringMan + .join(SetupUtils.generators.keySet(), prefix) + .replaceAll(PlotSquared.imp().getPluginName(), + "&2" + PlotSquared.imp().getPluginName())); + sendMessage(player, C.SETUP_INIT); + return false; + } + object.setupGenerator = args[0]; + object.current++; + String partial = "\n&8 - &7PARTIAL&8 - &7Vanilla with clusters of plots"; + MainUtil.sendMessage(player, + "&6What world type do you want?\n&8 - &2DEFAULT&8 - &7Standard plot generation" + + "\n&8 - &7AUGMENTED&8 - &7Plot generation with terrain" + partial); + break; + case 1: // choose world type + List allTypes = Arrays.asList("default", "augmented", "partial"); + List allDesc = Arrays + .asList("Standard plot generation", "Plot generation with vanilla terrain", + "Vanilla with clusters of plots"); + ArrayList types = new ArrayList<>(); + if (SetupUtils.generators.get(object.setupGenerator).isFull()) { + types.add("default"); + } + types.add("augmented"); + types.add("partial"); + if (args.length != 1 || !types.contains(args[0].toLowerCase())) { + MainUtil.sendMessage(player, "&cYou must choose a world type!"); + for (String type : types) { + int i = allTypes.indexOf(type); + if (type.equals("default")) { + MainUtil + .sendMessage(player, "&8 - &2" + type + " &8-&7 " + allDesc.get(i)); + } else { + MainUtil + .sendMessage(player, "&8 - &7" + type + " &8-&7 " + allDesc.get(i)); + } + } + return false; + } + object.type = allTypes.indexOf(args[0].toLowerCase()); + GeneratorWrapper gen = SetupUtils.generators.get(object.setupGenerator); + if (object.type == 0) { + object.current = 6; + if (object.step == null) { + object.plotManager = object.setupGenerator; + object.step = + SetupUtils.generators.get(object.plotManager).getPlotGenerator() + .getNewPlotArea("CheckingPlotSquaredGenerator", null, null, null) + .getSettingNodes(); + SetupUtils.generators.get(object.plotManager).getPlotGenerator() + .processSetup(object); + } + if (object.step.length == 0) { + MainUtil.sendMessage(player, "&6What do you want your world to be called?"); + object.setup_index = 0; + return true; + } + ConfigurationNode step = object.step[object.setup_index]; + sendMessage(player, C.SETUP_STEP, object.setup_index + 1, step.getDescription(), + step.getType().getType(), String.valueOf(step.getDefaultValue())); + } else { + if (gen.isFull()) { + object.plotManager = object.setupGenerator; + object.setupGenerator = null; + object.step = + SetupUtils.generators.get(object.plotManager).getPlotGenerator() + .getNewPlotArea("CheckingPlotSquaredGenerator", null, null, null) + .getSettingNodes(); + SetupUtils.generators.get(object.plotManager).getPlotGenerator() + .processSetup(object); + } else { + object.plotManager = PlotSquared.imp().getPluginName(); + MainUtil.sendMessage(player, + "&c[WARNING] The specified generator does not identify as BukkitPlotGenerator"); + MainUtil.sendMessage(player, + "&7 - You may need to manually configure the other plugin"); + object.step = + SetupUtils.generators.get(object.plotManager).getPlotGenerator() + .getNewPlotArea("CheckingPlotSquaredGenerator", null, null, null) + .getSettingNodes(); + } + if (object.type == 2) { + MainUtil.sendMessage(player, "What would you like this area called?"); + object.current++; + } else { + MainUtil.sendMessage(player, "&6What terrain would you like in plots?" + + "\n&8 - &2NONE&8 - &7No terrain at all" + + "\n&8 - &7ORE&8 - &7Just some ore veins and trees" + + "\n&8 - &7ROAD&8 - &7Terrain separated by roads" + + "\n&8 - &7ALL&8 - &7Entirely vanilla generation"); + object.current = 5; + } + } + break; + case 2: // area id + if (!StringMan.isAlphanumericUnd(args[0])) { + MainUtil.sendMessage(player, "&cThe area id must be alphanumerical!"); + return false; + } + for (PlotArea area : PlotSquared.get().getPlotAreas()) { + if (area.id != null && area.id.equalsIgnoreCase(args[0])) { + MainUtil.sendMessage(player, + "&cYou must choose an area id that is not in use!"); + return false; + } + } + object.id = args[0]; + object.current++; + MainUtil.sendMessage(player, "&6What should be the minimum Plot Id?"); + break; + case 3: // min + object.min = PlotId.fromString(args[0]); + if (object.min == null) { + MainUtil.sendMessage(player, "&cYou must choose a valid minimum PlotId!"); + return false; + } + object.current++; + MainUtil.sendMessage(player, "&6What should be the maximum Plot Id?"); + break; + case 4: + // max + PlotId id = PlotId.fromString(args[0]); + if (id == null) { + MainUtil.sendMessage(player, "&cYou must choose a valid maximum PlotId!"); + return false; + } + if (id.x <= object.min.x || id.y <= object.min.y) { + MainUtil + .sendMessage(player, "&cThe max PlotId must be greater than the minimum!"); + return false; + } + object.max = id; + object.current++; + MainUtil.sendMessage(player, "&6What terrain would you like in plots?" + + "\n&8 - &2NONE&8 - &7No terrain at all" + + "\n&8 - &7ORE&8 - &7Just some ore veins and trees" + + "\n&8 - &7ROAD&8 - &7Terrain separated by roads" + + "\n&8 - &7ALL&8 - &7Entirely vanilla generation"); + break; + case 5: { // Choose terrain + List terrain = Arrays.asList("none", "ore", "road", "all"); + if (args.length != 1 || !terrain.contains(args[0].toLowerCase())) { + MainUtil.sendMessage(player, + "&cYou must choose the terrain!" + "\n&8 - &2NONE&8 - &7No terrain at all" + + "\n&8 - &7ORE&8 - &7Just some ore veins and trees" + + "\n&8 - &7ROAD&8 - &7Terrain separated by roads" + + "\n&8 - &7ALL&8 - &7Entirely vanilla generation"); + return false; + } + object.terrain = terrain.indexOf(args[0].toLowerCase()); + object.current++; + if (object.step == null) { + object.step = SetupUtils.generators.get(object.plotManager).getPlotGenerator() + .getNewPlotArea("CheckingPlotSquaredGenerator", null, null, null) + .getSettingNodes(); + } + ConfigurationNode step = object.step[object.setup_index]; + sendMessage(player, C.SETUP_STEP, object.setup_index + 1, step.getDescription(), + step.getType().getType(), String.valueOf(step.getDefaultValue())); + break; + } + case 6: // world setup + if (object.setup_index == object.step.length) { + MainUtil.sendMessage(player, "&6What do you want your world to be called?"); + object.setup_index = 0; + object.current++; + return true; + } + ConfigurationNode step = object.step[object.setup_index]; + if (args.length < 1) { + sendMessage(player, C.SETUP_STEP, object.setup_index + 1, step.getDescription(), + step.getType().getType(), String.valueOf(step.getDefaultValue())); + return false; + } + + boolean valid = false; + try { + valid = step.isValid(args[0]); + } catch (final Configuration.UnsafeBlockException e) { + C.NOT_ALLOWED_BLOCK.send(player, e.getUnsafeBlock().toString()); + } + if (valid) { + sendMessage(player, C.SETUP_VALID_ARG, step.getConstant(), args[0]); + step.setValue(args[0]); + object.setup_index++; + if (object.setup_index == object.step.length) { + onCommand(player, args); + return false; + } + step = object.step[object.setup_index]; + sendMessage(player, C.SETUP_STEP, object.setup_index + 1, step.getDescription(), + step.getType().getType(), String.valueOf(step.getDefaultValue())); + return false; + } else { + sendMessage(player, C.SETUP_INVALID_ARG, args[0], step.getConstant()); + sendMessage(player, C.SETUP_STEP, object.setup_index + 1, step.getDescription(), + step.getType().getType(), String.valueOf(step.getDefaultValue())); + return false; + } + case 7: + if (args.length != 1) { + MainUtil.sendMessage(player, "&cYou need to choose a world name!"); + return false; + } + if (WorldUtil.IMP.isWorld(args[0])) { + if (PlotSquared.get().hasPlotArea(args[0])) { + MainUtil.sendMessage(player, "&cThat world name is already taken!"); + return false; + } + MainUtil.sendMessage(player, + "&cThe world you specified already exists. After restarting, new terrain will use " + + PlotSquared.imp().getPluginName() + ", however you may need to " + + "reset the world for it to generate correctly!"); + } + object.world = args[0]; + player.deleteMeta("setup"); + String world; + if (object.setupManager == null) { + world = SetupUtils.manager.setupWorld(object); + } else { + world = object.setupManager.setupWorld(object); + } + try { + player.teleport(WorldUtil.IMP.getSpawn(world)); + } catch (Exception e) { + player.sendMessage("&cAn error occurred. See console for more information"); + e.printStackTrace(); + } + sendMessage(player, C.SETUP_FINISHED, object.world); + } + return false; + } + + private static final class StepPickGenerator extends SetupStep { + + @Getter private String generator; + + public StepPickGenerator() { + super("generator"); + } + + @Override public Collection showDescriptionMessage() { + SetupUtils.manager.updateGenerators(); + final List messages = new ArrayList<>(); + messages.add(new PlotMessage("What generator do you want?").color("$6")); + for (Entry> entry : SetupUtils.generators.entrySet()) { + final PlotMessage plotMessage = new PlotMessage(" - ").color("$8"); + if (entry.getKey().equals(PlotSquared.imp().getPluginName())) { + plotMessage.text(entry.getKey()).color("$8").tooltip("Select this generator") + .color("$2").command("/plot setup generator " + entry.getKey()) + .text(" (Default Generator)").color("$7"); + } else if (entry.getValue().isFull()) { + plotMessage.text(entry.getKey()).color("$8").tooltip("Select this generator") + .color("$7").command("/plot setup generator " + entry.getKey()) + .text(" (Plot Generator)").color("$7"); + } else { + plotMessage.text(entry.getKey()).color("$8").tooltip("Select this generator") + .color("$7").command("/plot setup generator " + entry.getKey()) + .text(" (Unknown Structure)").color("$7"); + } + messages.add(plotMessage); + } + return messages; + } + + @Override public boolean parseInut(String input) { + this.generator = input.toLowerCase(); + return true; + } + + @Nullable @Override public String getDefault() { + return null; + } + } + + + private static final class StepWorldType extends SetupStep { + + private static final Map WORLD_TYPES = new HashMap<>(); + + static { + WORLD_TYPES.put("default", "Standard plot generation"); + WORLD_TYPES.put("augmented", "Plot generation with vanilla terrain"); + WORLD_TYPES.put("partial", "Vanilla clusters of plots"); + } + + @Getter private String worldType; + + public StepWorldType() { + super("type"); + } + + @Override public Collection showDescriptionMessage() { + final List messages = new ArrayList<>(); + messages.add(new PlotMessage("What world type do you want?").color("$6")); + for (final Map.Entry worldType : WORLD_TYPES.entrySet()) { + messages.add(new PlotMessage(" - ").color("$8").text(worldType.getKey()) + .color(worldType.getKey().equals(getDefault()) ? "$2" : "$7") + .tooltip("Select this world type") + .command("/plot setup type " + worldType.getKey()) + .text(" (" + worldType.getValue() + ")").color("$7")); + } + return messages; + } + + @Override public boolean parseInut(String input) { + if (!WORLD_TYPES.keySet().contains(input.toLowerCase())) { + return false; + } + this.worldType = input.toLowerCase(); + return true; + } + + @Override public String getDefault() { + return "default"; + } + } + + + @ToString @EqualsAndHashCode(of = "uuid") @AllArgsConstructor + private static class SetupContext { + + private final UUID uuid; + + @Getter private String step; + + } + + + @RequiredArgsConstructor(access = AccessLevel.PROTECTED) + private abstract static class SetupStep { + + private final String stepName; + + public abstract Collection showDescriptionMessage(); + + public abstract boolean parseInut(String input); + + public final PlotMessage getUsage() { + return new PlotMessage("Usage: ").color("$1") + .text("/plot setup " + this.stepName + " ").color("$2").suggest( + "/plot setup " + this.stepName + (this.getDefault() != null ? + this.getDefault() : + "")); + } + + @Nullable public abstract String getDefault(); + + public void sendToPlayer(@NonNull final PlotPlayer plotPlayer) { + new PlotMessage("Setup Step: ").color("$6").text(this.stepName).color("$7") + .send(plotPlayer); + this.getUsage().send(plotPlayer); + this.showDescriptionMessage().forEach(plotMessage -> plotMessage.send(plotPlayer)); + if (this.getDefault() != null) { + new PlotMessage("Default: ").color("$6").text(this.getDefault()).color("$7"); + } + } + + } + +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SubCommand.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SubCommand.java new file mode 100644 index 000000000..396185e29 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/SubCommand.java @@ -0,0 +1,39 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Argument; +import com.github.intellectualsites.plotsquared.commands.Command; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2; +import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3; + +/** + * SubCommand class + * + * @Deprecated In favor of normal Command class + * @see Command(Command, boolean) + */ +public abstract class SubCommand extends Command { + public SubCommand() { + super(MainCommand.getInstance(), true); + } + + public SubCommand(Argument... arguments) { + this(); + setRequiredArguments(arguments); + } + + @Override public void execute(PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) { + onCommand(player, args); + } + + + public abstract boolean onCommand(PlotPlayer player, String[] args); + + public boolean sendMessage(PlotPlayer player, C message, Object... args) { + message.send(player, args); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Swap.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Swap.java new file mode 100644 index 000000000..80a96dfb6 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Swap.java @@ -0,0 +1,54 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.Permissions; + +@CommandDeclaration(usage = "/plot swap ", command = "swap", description = "Swap two plots", + aliases = {"switch"}, category = CommandCategory.CLAIMING, requiredType = RequiredType.NONE) +public class Swap extends SubCommand { + + @Override public boolean onCommand(final PlotPlayer player, String[] args) { + Location loc = player.getLocation(); + Plot plot1 = loc.getPlotAbs(); + if (plot1 == null) { + return !MainUtil.sendMessage(player, C.NOT_IN_PLOT); + } + if (!plot1.isOwner(player.getUUID()) && !Permissions + .hasPermission(player, C.PERMISSION_ADMIN.s())) { + MainUtil.sendMessage(player, C.NO_PLOT_PERMS); + return false; + } + if (args.length != 1) { + C.COMMAND_SYNTAX.send(player, getUsage()); + return false; + } + Plot plot2 = MainUtil.getPlotFromString(player, args[0], true); + if (plot2 == null) { + return false; + } + if (plot1.equals(plot2)) { + MainUtil.sendMessage(player, C.NOT_VALID_PLOT_ID); + MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot copy "); + return false; + } + if (!plot1.getArea().isCompatible(plot2.getArea())) { + C.PLOTWORLD_INCOMPATIBLE.send(player); + return false; + } + if (plot1.move(plot2, new Runnable() { + @Override public void run() { + MainUtil.sendMessage(player, C.SWAP_SUCCESS); + } + }, true)) { + return true; + } else { + MainUtil.sendMessage(player, C.SWAP_OVERLAP); + return false; + } + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Target.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Target.java new file mode 100644 index 000000000..03879463a --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Target.java @@ -0,0 +1,49 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.Argument; +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.object.Location; +import com.github.intellectualsites.plotsquared.plot.object.Plot; +import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.StringMan; + +@CommandDeclaration(command = "target", usage = "/plot target <|nearest>", + description = "Target a plot with your compass", permission = "plots.target", + requiredType = RequiredType.PLAYER, category = CommandCategory.INFO) public class Target + extends SubCommand { + + public Target() { + super(Argument.PlotID); + } + + @Override public boolean onCommand(PlotPlayer player, String[] args) { + Location location = player.getLocation(); + if (!location.isPlotArea()) { + MainUtil.sendMessage(player, C.NOT_IN_PLOT_WORLD); + return false; + } + Plot target = null; + if (StringMan.isEqualIgnoreCaseToAny(args[0], "near", "nearest")) { + int distance = Integer.MAX_VALUE; + for (Plot plot : PlotSquared.get().getPlots(location.getWorld())) { + double current = plot.getCenter().getEuclideanDistanceSquared(location); + if (current < distance) { + distance = (int) current; + target = plot; + } + } + if (target == null) { + MainUtil.sendMessage(player, C.FOUND_NO_PLOTS); + return false; + } + } else if ((target = MainUtil.getPlotFromString(player, args[0], true)) == null) { + return false; + } + player.setCompassTarget(target.getCenter()); + MainUtil.sendMessage(player, C.COMPASS_TARGET); + return true; + } +} diff --git a/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Template.java b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Template.java new file mode 100644 index 000000000..aed9c5ca6 --- /dev/null +++ b/Bukkit/src/main/java/com/github/intellectualsites/plotsquared/plot/commands/Template.java @@ -0,0 +1,201 @@ +package com.github.intellectualsites.plotsquared.plot.commands; + +import com.github.intellectualsites.plotsquared.commands.CommandDeclaration; +import com.github.intellectualsites.plotsquared.configuration.ConfigurationSection; +import com.github.intellectualsites.plotsquared.configuration.InvalidConfigurationException; +import com.github.intellectualsites.plotsquared.configuration.file.YamlConfiguration; +import com.github.intellectualsites.plotsquared.plot.PlotSquared; +import com.github.intellectualsites.plotsquared.plot.config.C; +import com.github.intellectualsites.plotsquared.plot.config.ConfigurationNode; +import com.github.intellectualsites.plotsquared.plot.config.Settings; +import com.github.intellectualsites.plotsquared.plot.object.*; +import com.github.intellectualsites.plotsquared.plot.util.MainUtil; +import com.github.intellectualsites.plotsquared.plot.util.SetupUtils; +import com.github.intellectualsites.plotsquared.plot.util.TaskManager; +import com.github.intellectualsites.plotsquared.plot.util.WorldUtil; +import com.github.intellectualsites.plotsquared.plot.util.block.GlobalBlockQueue; + +import java.io.*; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +@CommandDeclaration(command = "template", permission = "plots.admin", + description = "Create or use a world template", + usage = "/plot template [import|export]