diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java
index 3a6d64f38..94ea558a0 100644
--- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java
+++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java
@@ -361,7 +361,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain
if (!PS.get().setupPlotWorld(world, id, result)) {
return null;
}
- return (ChunkGenerator) result.specify();
+ return (ChunkGenerator) result.specify(world);
}
@Override
@@ -665,7 +665,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain
}
@Override
- public GeneratorWrapper> wrapPlotGenerator(IndependentPlotGenerator generator) {
+ public GeneratorWrapper> wrapPlotGenerator(String world, IndependentPlotGenerator generator) {
return new BukkitPlotGenerator(generator);
}
diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/GenChunk.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/GenChunk.java
index 21c03f6d1..90d235fc4 100644
--- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/GenChunk.java
+++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/block/GenChunk.java
@@ -168,8 +168,6 @@ public class GenChunk extends ScopedLocalBlockQueue {
return new Location(getWorld(), getX() << 4, 0, getZ() << 4);
}
-
-
public GenChunk clone() {
GenChunk toReturn = new GenChunk(chunk, new ChunkWrapper(getWorld(), chunk.getX(), chunk.getZ()));
if (this.result != null) {
diff --git a/Core/src/main/java/com/intellectualcrafters/plot/IPlotMain.java b/Core/src/main/java/com/intellectualcrafters/plot/IPlotMain.java
index 6c644b38b..bb5948d41 100644
--- a/Core/src/main/java/com/intellectualcrafters/plot/IPlotMain.java
+++ b/Core/src/main/java/com/intellectualcrafters/plot/IPlotMain.java
@@ -222,7 +222,7 @@ public interface IPlotMain extends ILogger {
*/
GeneratorWrapper> getGenerator(String world, String name);
- GeneratorWrapper> wrapPlotGenerator(IndependentPlotGenerator generator);
+ GeneratorWrapper> wrapPlotGenerator(String world, IndependentPlotGenerator generator);
/**
* Register the chunk processor which will clean out chunks that have too
diff --git a/Core/src/main/java/com/intellectualcrafters/plot/commands/Leave.java b/Core/src/main/java/com/intellectualcrafters/plot/commands/Leave.java
new file mode 100644
index 000000000..abc3d26ba
--- /dev/null
+++ b/Core/src/main/java/com/intellectualcrafters/plot/commands/Leave.java
@@ -0,0 +1,35 @@
+package com.intellectualcrafters.plot.commands;
+
+import com.intellectualcrafters.plot.config.C;
+import com.intellectualcrafters.plot.object.Plot;
+import com.intellectualcrafters.plot.object.PlotPlayer;
+import com.intellectualcrafters.plot.object.RunnableVal2;
+import com.intellectualcrafters.plot.object.RunnableVal3;
+import com.plotsquared.general.commands.Command;
+import com.plotsquared.general.commands.CommandDeclaration;
+import java.util.*;
+import java.util.Set;
+
+@CommandDeclaration(command = "leave",
+ description = "Leave a plot",
+ permission = "plots.leave",
+ category = CommandCategory.CLAIMING,
+ requiredType = RequiredType.NONE)
+public class Leave extends Command {
+ public Leave(Command parent, boolean isStatic) {
+ 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())) {
+ Set owners = plot.getOwners();
+ } else {
+
+ }
+ }
+}
diff --git a/Core/src/main/java/com/intellectualcrafters/plot/generator/ClassicPlotManager.java b/Core/src/main/java/com/intellectualcrafters/plot/generator/ClassicPlotManager.java
index f558bab1a..ace2a8a90 100644
--- a/Core/src/main/java/com/intellectualcrafters/plot/generator/ClassicPlotManager.java
+++ b/Core/src/main/java/com/intellectualcrafters/plot/generator/ClassicPlotManager.java
@@ -81,7 +81,7 @@ public class ClassicPlotManager extends SquarePlotManager {
LocalBlockQueue queue = plotArea.getQueue(false);
for (RegionWrapper region : plot.getRegions()) {
Location pos1 = new Location(plotArea.worldname, region.minX, 1, region.minZ);
- Location pos2 = new Location(plotArea.worldname, region.maxX, 255, region.maxZ);
+ Location pos2 = new Location(plotArea.worldname, region.maxX, Math.min(plotArea.MAX_BUILD_HEIGHT, 255), region.maxZ);
queue.setCuboid(pos1, pos2, blocks);
}
queue.enqueue();
@@ -97,7 +97,7 @@ public class ClassicPlotManager extends SquarePlotManager {
LocalBlockQueue queue = plotArea.getQueue(false);
for (RegionWrapper region : plot.getRegions()) {
Location pos1 = new Location(plotArea.worldname, region.minX, dpw.PLOT_HEIGHT + 1, region.minZ);
- Location pos2 = new Location(plotArea.worldname, region.maxX, 255, region.maxZ);
+ Location pos2 = new Location(plotArea.worldname, region.maxX, Math.min(plotArea.MAX_BUILD_HEIGHT, 255), region.maxZ);
queue.setCuboid(pos1, pos2, blocks);
}
queue.enqueue();
@@ -147,7 +147,7 @@ public class ClassicPlotManager extends SquarePlotManager {
if (!plot.getMerged(0)) {
int z = bottom.getZ();
for (int x = bottom.getX(); x <= top.getX(); x++) {
- for (int y = dpw.PLOT_HEIGHT; y <= 255; y++) {
+ for (int y = dpw.PLOT_HEIGHT; y <= Math.min(plotArea.MAX_BUILD_HEIGHT, 255); y++) {
queue.setBlock(x, y, z, blocks[random.random(blocks.length)]);
}
}
@@ -155,7 +155,7 @@ public class ClassicPlotManager extends SquarePlotManager {
if (!plot.getMerged(3)) {
int x = bottom.getX();
for (int z = bottom.getZ(); z <= top.getZ(); z++) {
- for (int y = dpw.PLOT_HEIGHT; y <= 255; y++) {
+ for (int y = dpw.PLOT_HEIGHT; y <= Math.min(plotArea.MAX_BUILD_HEIGHT, 255); y++) {
queue.setBlock(x, y, z, blocks[random.random(blocks.length)]);
}
}
@@ -164,7 +164,7 @@ public class ClassicPlotManager extends SquarePlotManager {
if (!plot.getMerged(2)) {
int z = top.getZ();
for (int x = bottom.getX(); x <= top.getX(); x++) {
- for (int y = dpw.PLOT_HEIGHT; y <= 255; y++) {
+ for (int y = dpw.PLOT_HEIGHT; y <= Math.min(plotArea.MAX_BUILD_HEIGHT, 255); y++) {
queue.setBlock(x, y, z, blocks[random.random(blocks.length)]);
}
}
@@ -172,15 +172,15 @@ public class ClassicPlotManager extends SquarePlotManager {
if (!plot.getMerged(1)) {
int x = top.getX();
for (int z = bottom.getZ(); z <= top.getZ(); z++) {
- for (int y = dpw.PLOT_HEIGHT; y <= 255; y++) {
+ for (int y = dpw.PLOT_HEIGHT; y <= Math.min(plotArea.MAX_BUILD_HEIGHT, 255); y++) {
queue.setBlock(x, y, z, blocks[random.random(blocks.length)]);
}
}
}
if (plot.isBasePlot()) {
for (RegionWrapper region : plot.getRegions()) {
- Location pos1 = new Location(plotArea.worldname, region.minX, 255, region.minZ);
- Location pos2 = new Location(plotArea.worldname, region.maxX, 255, region.maxZ);
+ Location pos1 = new Location(plotArea.worldname, region.minX, Math.min(plotArea.MAX_BUILD_HEIGHT, 255), region.minZ);
+ Location pos2 = new Location(plotArea.worldname, region.maxX, Math.min(plotArea.MAX_BUILD_HEIGHT, 255), region.maxZ);
queue.setCuboid(pos1, pos2, blocks);
}
}
@@ -288,7 +288,7 @@ public class ClassicPlotManager extends SquarePlotManager {
LocalBlockQueue queue = plotArea.getQueue(false);
queue.setCuboid(
new Location(plotArea.worldname, sx, Math.min(dpw.WALL_HEIGHT, dpw.ROAD_HEIGHT) + 1, sz + 1),
- new Location(plotArea.worldname, ex, 255, ez - 1), PlotBlock.get((short) 0, (byte) 0));
+ new Location(plotArea.worldname, ex, Math.min(plotArea.MAX_BUILD_HEIGHT, 255), ez - 1), PlotBlock.get((short) 0, (byte) 0));
queue.setCuboid(new Location(plotArea.worldname, sx, 0, sz + 1),
new Location(plotArea.worldname, ex, 0, ez - 1), PlotBlock.get((short) 7,
(byte) 0));
@@ -320,7 +320,7 @@ public class ClassicPlotManager extends SquarePlotManager {
LocalBlockQueue queue = plotArea.getQueue(false);
queue.setCuboid(
new Location(plotArea.worldname, sx + 1, Math.min(dpw.WALL_HEIGHT, dpw.ROAD_HEIGHT) + 1, sz),
- new Location(plotArea.worldname, ex - 1, 255, ez), PlotBlock.get((short) 0, (byte) 0));
+ new Location(plotArea.worldname, ex - 1, Math.min(plotArea.MAX_BUILD_HEIGHT, 255), ez), PlotBlock.get((short) 0, (byte) 0));
queue.setCuboid(new Location(plotArea.worldname, sx + 1, 0, sz),
new Location(plotArea.worldname, ex - 1, 0, ez), PlotBlock.get((short) 7, (byte) 0));
queue.setCuboid(new Location(plotArea.worldname, sx + 1, 1, sz),
@@ -370,7 +370,7 @@ public class ClassicPlotManager extends SquarePlotManager {
int ez = pos2.getZ() + 1;
LocalBlockQueue queue = plotArea.getQueue(false);
queue.setCuboid(new Location(plotArea.worldname, sx, Math.min(dpw.PLOT_HEIGHT, dpw.ROAD_HEIGHT) + 1, sz),
- new Location(plotArea.worldname, ex, 255, ez), PlotBlock.get((short) 0, (byte) 0));
+ new Location(plotArea.worldname, ex, Math.min(plotArea.MAX_BUILD_HEIGHT, 255), ez), PlotBlock.get((short) 0, (byte) 0));
queue.setCuboid(new Location(plotArea.worldname, sx, 1, sz + 1),
new Location(plotArea.worldname, ex, dpw.PLOT_HEIGHT - 1, ez - 1), dpw.MAIN_BLOCK);
queue.setCuboid(new Location(plotArea.worldname, sx, dpw.PLOT_HEIGHT, sz + 1),
@@ -390,7 +390,7 @@ public class ClassicPlotManager extends SquarePlotManager {
int ex = pos2.getX() + 1;
LocalBlockQueue queue = plotArea.getQueue(false);
queue.setCuboid(new Location(plotArea.worldname, sx, Math.min(dpw.PLOT_HEIGHT, dpw.ROAD_HEIGHT) + 1, sz),
- new Location(plotArea.worldname, ex, 255, ez), PlotBlock.get((short) 0, (byte) 0));
+ new Location(plotArea.worldname, ex, Math.min(plotArea.MAX_BUILD_HEIGHT, 255), ez), PlotBlock.get((short) 0, (byte) 0));
queue.setCuboid(new Location(plotArea.worldname, sx + 1, 1, sz),
new Location(plotArea.worldname, ex - 1, dpw.PLOT_HEIGHT - 1, ez), dpw.MAIN_BLOCK);
queue.setCuboid(new Location(plotArea.worldname, sx + 1, dpw.PLOT_HEIGHT, sz),
diff --git a/Core/src/main/java/com/intellectualcrafters/plot/generator/HybridGen.java b/Core/src/main/java/com/intellectualcrafters/plot/generator/HybridGen.java
index 3b2ac579f..ffa6801b9 100644
--- a/Core/src/main/java/com/intellectualcrafters/plot/generator/HybridGen.java
+++ b/Core/src/main/java/com/intellectualcrafters/plot/generator/HybridGen.java
@@ -26,11 +26,7 @@ public class HybridGen extends IndependentPlotGenerator {
public void generateChunk(ScopedLocalBlockQueue result, PlotArea settings, PseudoRandom random) {
HybridPlotWorld hpw = (HybridPlotWorld) settings;
// Biome
- for (short x = 0; x < 16; x++) {
- for (short z = 0; z < 16; z++) {
- result.fillBiome(hpw.PLOT_BIOME);
- }
- }
+ result.fillBiome(hpw.PLOT_BIOME);
// Bedrock
if (hpw.PLOT_BEDROCK) {
for (short x = 0; x < 16; x++) {
diff --git a/Core/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotManager.java b/Core/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotManager.java
index f6dd0deec..b17b0e9cc 100644
--- a/Core/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotManager.java
+++ b/Core/src/main/java/com/intellectualcrafters/plot/generator/HybridPlotManager.java
@@ -61,7 +61,7 @@ public class HybridPlotManager extends ClassicPlotManager {
Location bot = getPlotBottomLocAbs(hpw, id2);
Location top = getPlotTopLocAbs(hpw, id);
Location pos1 = new Location(plotArea.worldname, top.getX() + 1, 0, bot.getZ() - 1);
- Location pos2 = new Location(plotArea.worldname, bot.getX(), 255, top.getZ() + 1);
+ Location pos2 = new Location(plotArea.worldname, bot.getX(), Math.min(plotArea.MAX_BUILD_HEIGHT, 255), top.getZ() + 1);
MainUtil.resetBiome(plotArea, pos1, pos2);
if (!hpw.ROAD_SCHEMATIC_ENABLED) {
return true;
@@ -108,7 +108,7 @@ public class HybridPlotManager extends ClassicPlotManager {
Location bot = getPlotBottomLocAbs(hpw, id2);
Location top = getPlotTopLocAbs(hpw, id);
Location pos1 = new Location(plotArea.worldname, bot.getX() - 1, 0, top.getZ() + 1);
- Location pos2 = new Location(plotArea.worldname, top.getX() + 1, 255, bot.getZ());
+ Location pos2 = new Location(plotArea.worldname, top.getX() + 1, Math.min(plotArea.MAX_BUILD_HEIGHT, 255), bot.getZ());
MainUtil.resetBiome(plotArea, pos1, pos2);
if (!hpw.ROAD_SCHEMATIC_ENABLED) {
return true;
@@ -128,7 +128,7 @@ public class HybridPlotManager extends ClassicPlotManager {
Location pos1 = getPlotTopLocAbs(hpw, id).add(1, 0, 1);
Location pos2 = getPlotBottomLocAbs(hpw, id2);
pos1.setY(0);
- pos2.setY(256);
+ pos2.setY(Math.min(plotArea.MAX_BUILD_HEIGHT, 255));
LocalBlockQueue queue = hpw.getQueue(false);
createSchemAbs(hpw, queue, pos1, pos2, true);
if (hpw.ROAD_SCHEMATIC_ENABLED) {
@@ -145,7 +145,7 @@ public class HybridPlotManager extends ClassicPlotManager {
* to have 512x512 sized plots.
*/
@Override
- public boolean clearPlot(PlotArea plotArea, Plot plot, final Runnable whenDone) {
+ public boolean clearPlot(final PlotArea plotArea, Plot plot, final Runnable whenDone) {
final String world = plotArea.worldname;
final HybridPlotWorld dpw = (HybridPlotWorld) plotArea;
Location pos1 = plot.getBottomAbs();
@@ -189,7 +189,7 @@ public class HybridPlotManager extends ClassicPlotManager {
top.setY(dpw.PLOT_HEIGHT + 1);
queue.setCuboid(bot, top, plotfloor);
bot.setY(dpw.PLOT_HEIGHT + 1);
- top.setY(256);
+ top.setY(plotArea.MAX_BUILD_HEIGHT);
queue.setCuboid(bot, top, air);
// And finally set the schematic, the y value is unimportant for this function
pastePlotSchematic(dpw, queue, bot, top);
diff --git a/Core/src/main/java/com/intellectualcrafters/plot/generator/IndependentPlotGenerator.java b/Core/src/main/java/com/intellectualcrafters/plot/generator/IndependentPlotGenerator.java
index 7cdbc7613..4602106a0 100644
--- a/Core/src/main/java/com/intellectualcrafters/plot/generator/IndependentPlotGenerator.java
+++ b/Core/src/main/java/com/intellectualcrafters/plot/generator/IndependentPlotGenerator.java
@@ -70,8 +70,8 @@ public abstract class IndependentPlotGenerator {
* @param
* @return
*/
- public GeneratorWrapper specify() {
- return (GeneratorWrapper) PS.get().IMP.wrapPlotGenerator(this);
+ public GeneratorWrapper specify(String world) {
+ return (GeneratorWrapper) PS.get().IMP.wrapPlotGenerator(world, this);
}
@Override
diff --git a/Nukkit/build.gradle b/Nukkit/build.gradle
new file mode 100644
index 000000000..52e56f3e4
--- /dev/null
+++ b/Nukkit/build.gradle
@@ -0,0 +1,51 @@
+repositories {
+ maven {url "https://hub.spigotmc.org/nexus/content/groups/public/"}
+ maven { url = "https://oss.sonatype.org/content/repositories/snapshots/"}
+ maven {url "http://nexus.hc.to/content/repositories/pub_releases"}
+}
+
+dependencies {
+ compile project(':Core')
+ compile 'cn.nukkit:nukkit:1.0-SNAPSHOT'
+ compile 'com.google.guava:guava:17.0'
+}
+
+configurations.all {
+ resolutionStrategy {
+ force 'com.google.guava:guava:17.0'
+ }
+}
+
+sourceCompatibility = 1.7
+targetCompatibility = 1.7
+
+processResources {
+ from('src/main/resources') {
+ include 'plugin.yml'
+ expand(
+ name: project.parent.name,
+ version: project.parent.version
+ )
+ }
+}
+// We only want the shadow jar produced
+jar.enabled = false
+
+shadowJar {
+ dependencies {
+ include(dependency(':Core'))
+ }
+ archiveName = "${parent.name}-${project.name}-${parent.version}.jar"
+ destinationDir = file '../target'
+
+ relocate('com.google.gson', 'com.sk89q.worldedit.internal.gson')
+ relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml'
+ relocate 'com.google.common', 'com.sk89q.worldedit.internal.common'
+}
+
+shadowJar.doLast {
+ task ->
+ ant.checksum file: task.archivePath
+}
+
+build.dependsOn(shadowJar);
diff --git a/Nukkit/build/resources/main/plugin.yml b/Nukkit/build/resources/main/plugin.yml
new file mode 100644
index 000000000..0afd5358d
--- /dev/null
+++ b/Nukkit/build/resources/main/plugin.yml
@@ -0,0 +1,6 @@
+name: "PlotSquared"
+version: "3.4.6-SNAPSHOT-0557671"
+author: Empire92
+api: ["1.0.0"]
+main: com.plotsquared.nukkit.NukkitMain
+load: STARTUP
\ No newline at end of file
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/NukkitMain.java b/Nukkit/src/main/java/com/plotsquared/nukkit/NukkitMain.java
new file mode 100644
index 000000000..c56cc5129
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/NukkitMain.java
@@ -0,0 +1,410 @@
+package com.plotsquared.nukkit;
+
+import cn.nukkit.Nukkit;
+import cn.nukkit.OfflinePlayer;
+import cn.nukkit.Player;
+import cn.nukkit.entity.Entity;
+import cn.nukkit.event.Listener;
+import cn.nukkit.level.Level;
+import cn.nukkit.level.generator.Generator;
+import cn.nukkit.metadata.MetadataValue;
+import cn.nukkit.plugin.Plugin;
+import cn.nukkit.plugin.PluginBase;
+import com.intellectualcrafters.plot.IPlotMain;
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.config.C;
+import com.intellectualcrafters.plot.config.Settings;
+import com.intellectualcrafters.plot.generator.GeneratorWrapper;
+import com.intellectualcrafters.plot.generator.HybridUtils;
+import com.intellectualcrafters.plot.generator.IndependentPlotGenerator;
+import com.intellectualcrafters.plot.object.Plot;
+import com.intellectualcrafters.plot.object.PlotArea;
+import com.intellectualcrafters.plot.object.PlotPlayer;
+import com.intellectualcrafters.plot.object.RunnableVal;
+import com.intellectualcrafters.plot.object.chat.PlainChatManager;
+import com.intellectualcrafters.plot.util.AbstractTitle;
+import com.intellectualcrafters.plot.util.ChatManager;
+import com.intellectualcrafters.plot.util.ChunkManager;
+import com.intellectualcrafters.plot.util.ConsoleColors;
+import com.intellectualcrafters.plot.util.EconHandler;
+import com.intellectualcrafters.plot.util.EventUtil;
+import com.intellectualcrafters.plot.util.InventoryUtil;
+import com.intellectualcrafters.plot.util.SchematicHandler;
+import com.intellectualcrafters.plot.util.SetupUtils;
+import com.intellectualcrafters.plot.util.TaskManager;
+import com.intellectualcrafters.plot.util.UUIDHandler;
+import com.intellectualcrafters.plot.util.UUIDHandlerImplementation;
+import com.intellectualcrafters.plot.util.WorldUtil;
+import com.intellectualcrafters.plot.util.block.QueueProvider;
+import com.plotsquared.nukkit.generator.NukkitPlotGenerator;
+import com.plotsquared.nukkit.listeners.PlayerEvents;
+import com.plotsquared.nukkit.listeners.WorldEvents;
+import com.plotsquared.nukkit.util.Metrics;
+import com.plotsquared.nukkit.util.NukkitChunkManager;
+import com.plotsquared.nukkit.util.NukkitCommand;
+import com.plotsquared.nukkit.util.NukkitEventUtil;
+import com.plotsquared.nukkit.util.NukkitHybridUtils;
+import com.plotsquared.nukkit.util.NukkitInventoryUtil;
+import com.plotsquared.nukkit.util.NukkitSchematicHandler;
+import com.plotsquared.nukkit.util.NukkitSetupUtils;
+import com.plotsquared.nukkit.util.NukkitTaskManager;
+import com.plotsquared.nukkit.util.NukkitUtil;
+import com.plotsquared.nukkit.util.block.NukkitHybridGen;
+import com.plotsquared.nukkit.util.block.NukkitLocalQueue;
+import com.plotsquared.nukkit.uuid.FileUUIDHandler;
+import com.plotsquared.nukkit.uuid.LowerOfflineUUIDWrapper;
+import com.sk89q.worldedit.WorldEdit;
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public final class NukkitMain extends PluginBase implements Listener, IPlotMain {
+
+ public static WorldEdit worldEdit;
+
+ private int[] version;
+
+ @Override
+ public int[] getServerVersion() {
+ if (this.version == null) {
+ try {
+ this.version = new int[3];
+ String[] split = Nukkit.API_VERSION.split("\\.");
+ this.version[0] = Integer.parseInt(split[0]);
+ this.version[1] = Integer.parseInt(split[1]);
+ if (split.length == 3) {
+ this.version[2] = Integer.parseInt(split[2]);
+ }
+ } catch (NumberFormatException e) {
+ return new int[]{1, 0, 0};
+ }
+ }
+ return this.version;
+ }
+
+ @Override
+ public void onEnable() {
+ try {
+ getServer().getName();
+ new PS(this, "Nukkit");
+ if (Settings.Enabled_Components.METRICS) {
+ new Metrics(this).start();
+ PS.log(C.PREFIX + "&6Metrics enabled.");
+ } else {
+ PS.log(C.CONSOLE_PLEASE_ENABLE_METRICS);
+ }
+ Generator.addGenerator(NukkitHybridGen.class, "PlotSquared", 1);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onDisable() {
+ PS.get().disable();
+ getServer().getScheduler().cancelAllTasks();
+ }
+
+ @Override
+ public void log(String message) {
+ try {
+ message = C.color(message);
+ if (!Settings.Chat.CONSOLE_COLOR) {
+ message = message.replaceAll('\u00A7' + "[0-9]", "");
+ }
+ this.getServer().getConsoleSender().sendMessage(message);
+ } catch (Throwable ignored) {
+ System.out.println(ConsoleColors.fromString(message));
+ }
+ }
+
+ @Override
+ public void disable() {
+ onDisable();
+ }
+
+ @Override
+ public int[] getPluginVersion() {
+ String ver = getDescription().getVersion();
+ if (ver.contains("-")) {
+ ver = ver.split("-")[0];
+ }
+ String[] split = ver.split("\\.");
+ return new int[]{Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2])};
+ }
+
+ @Override public String getPluginVersionString() {
+ return getDescription().getVersion();
+ }
+
+ @Override
+ public void registerCommands() {
+ NukkitCommand bukkitCommand = new NukkitCommand("plot", new String[] {"p","plot","ps","plotsquared","p2","2"});
+ getServer().getCommandMap().register("plot", bukkitCommand);
+ }
+
+ @Override
+ public File getDirectory() {
+ return getDataFolder();
+ }
+
+ @Override
+ public File getWorldContainer() {
+ return new File("worlds");
+ }
+
+ @Override
+ public TaskManager getTaskManager() {
+ return new NukkitTaskManager(this);
+ }
+
+ @Override
+ public void runEntityTask() {
+ PS.log(C.PREFIX + "KillAllEntities started.");
+ TaskManager.runTaskRepeat(new Runnable() {
+ @Override
+ public void run() {
+ PS.get().foreachPlotArea(new RunnableVal() {
+ @Override
+ public void run(PlotArea plotArea) {
+ Level world = getServer().getLevelByName(plotArea.worldname);
+ try {
+ if (world == null) {
+ return;
+ }
+ Entity[] entities = world.getEntities();
+ for (Entity entity : entities) {
+ if (entity instanceof Player) {
+ continue;
+ }
+ com.intellectualcrafters.plot.object.Location location = NukkitUtil.getLocation(entity.getLocation());
+ Plot plot = location.getPlot();
+ if (plot == null) {
+ if (location.isPlotArea()) {
+ entity.kill();
+ }
+ continue;
+ }
+ List meta = entity.getMetadata("plot");
+ if (meta.isEmpty()) {
+ continue;
+ }
+ Plot origin = (Plot) meta.get(0).value();
+ if (!plot.equals(origin.getBasePlot(false))) {
+ entity.kill();
+ }
+ continue;
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ }
+ }, 20);
+ }
+
+ @Override
+ public void registerPlayerEvents() {
+ getServer().getPluginManager().registerEvents(new PlayerEvents(), this);
+ }
+
+ @Override
+ public void registerInventoryEvents() {
+ PS.debug("Not implemented: registerPlotPlusEvents");
+ }
+
+ @Override
+ public void registerPlotPlusEvents() {
+ PS.debug("Not implemented: registerPlotPlusEvents");
+ }
+
+ @Override
+ public void registerForceFieldEvents() {
+ PS.debug("Not implemented: registerPlotPlusEvents");
+ }
+
+ @Override
+ public boolean initWorldEdit() {
+ if (getServer().getPluginManager().getPlugin("WorldEdit") != null) {
+ worldEdit = WorldEdit.getInstance();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public EconHandler getEconomyHandler() {
+ return null;
+ }
+
+ @Override
+ public QueueProvider initBlockQueue() {
+ return QueueProvider.of(NukkitLocalQueue.class, null);
+ }
+
+ @Override
+ public WorldUtil initWorldUtil() {
+ return new NukkitUtil(this);
+ }
+
+ @Override
+ public boolean initPlotMeConverter() {
+ return false; // No PlotMe for MCPE
+ }
+
+ @Override
+ public GeneratorWrapper> getGenerator(String world, String name) {
+ if (name == null) {
+ return null;
+ }
+ HashMap map = new HashMap();
+ map.put("world", world);
+ try {
+ Class extends Generator> gen = Generator.getGenerator(name);
+ if (gen != null) {
+ Generator instance = gen.getConstructor(Map.class).newInstance(map);
+ if (GeneratorWrapper.class.isAssignableFrom(gen.getClass())) {
+ return (GeneratorWrapper>) instance;
+ }
+ map.put("generator", instance);
+ return new NukkitPlotGenerator(map);
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ return new NukkitHybridGen(map);
+ }
+
+ @Override
+ public HybridUtils initHybridUtils() {
+ return new NukkitHybridUtils();
+ }
+
+ @Override
+ public SetupUtils initSetupUtils() {
+ return new NukkitSetupUtils(this);
+ }
+
+ @Override
+ public UUIDHandlerImplementation initUUIDHandler() {
+ Settings.UUID.FORCE_LOWERCASE = true;
+ Settings.UUID.OFFLINE = true;
+ LowerOfflineUUIDWrapper wrapper = new LowerOfflineUUIDWrapper();
+ return new FileUUIDHandler(wrapper);
+ }
+
+ @Override
+ public ChunkManager initChunkManager() {
+ return new NukkitChunkManager();
+ }
+
+ @Override
+ public EventUtil initEventUtil() {
+ return new NukkitEventUtil(this);
+ }
+
+ @Override
+ public void unregister(PlotPlayer player) {
+ NukkitUtil.removePlayer(player.getName());
+ }
+
+ @Override
+ public void registerChunkProcessor() {
+ PS.debug("Not implemented: registerChunkProcessor");
+ }
+
+ @Override
+ public void registerWorldEvents() {
+ getServer().getPluginManager().registerEvents(new WorldEvents(), this);
+ }
+
+ @Override
+ public InventoryUtil initInventoryUtil() {
+ return new NukkitInventoryUtil();
+ }
+
+ @Override
+ public void startMetrics() {
+ new Metrics(this).start();
+ PS.log(C.PREFIX + "&6Metrics enabled.");
+ }
+
+ @Override
+ public void setGenerator(String worldName) {
+ throw new UnsupportedOperationException("Not implemented: setGenerator");
+ }
+
+ private void setGenerator(Level level, Generator generator) {
+ try {
+ Field fieldClass = Level.class.getDeclaredField("generator");
+ Field fieldInstance = Level.class.getDeclaredField("generatorInstance");
+ fieldClass.setAccessible(true);
+ fieldInstance.setAccessible(true);
+ fieldClass.set(level, generator.getClass());
+ fieldInstance.set(level, generator);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public SchematicHandler initSchematicHandler() {
+ return new NukkitSchematicHandler(this);
+ }
+
+ @Override
+ public AbstractTitle initTitleManager() {
+ // Already initialized in UUID handler
+ return AbstractTitle.TITLE_CLASS;
+ }
+
+ @Override
+ public PlotPlayer wrapPlayer(Object player) {
+ if (player instanceof Player) {
+ return NukkitUtil.getPlayer((Player) player);
+ }
+ if (player instanceof OfflinePlayer) {
+ return NukkitUtil.getPlayer((OfflinePlayer) player);
+ }
+ if (player instanceof String) {
+ return UUIDHandler.getPlayer((String) player);
+ }
+ if (player instanceof UUID) {
+ return UUIDHandler.getPlayer((UUID) player);
+ }
+ return null;
+ }
+
+ @Override
+ public String getNMSPackage() {
+ return "";
+ }
+
+ @Override
+ public ChatManager> initChatManager() {
+ return new PlainChatManager();
+ }
+
+ @Override
+ public GeneratorWrapper> wrapPlotGenerator(String world, IndependentPlotGenerator generator) {
+ HashMap settings = new HashMap<>();
+ settings.put("world", world);
+ settings.put("plot-generator", generator);
+ return new NukkitPlotGenerator(settings);
+ }
+
+ @Override
+ public List getPluginIds() {
+ ArrayList names = new ArrayList<>();
+ for (Map.Entry entry : getServer().getPluginManager().getPlugins().entrySet()) {
+ Plugin plugin = entry.getValue();
+ names.add(entry.getKey() + ';' + plugin.getDescription().getVersion() + ':' + plugin.isEnabled());
+ }
+ return names;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/ClusterFlagRemoveEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/ClusterFlagRemoveEvent.java
new file mode 100644
index 000000000..42ed22303
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/ClusterFlagRemoveEvent.java
@@ -0,0 +1,61 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.event.Cancellable;
+import cn.nukkit.event.Event;
+import cn.nukkit.event.HandlerList;
+import com.intellectualcrafters.plot.flag.Flag;
+import com.intellectualcrafters.plot.object.PlotCluster;
+
+/**
+ * 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 getHandlers() {
+ 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 boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean b) {
+ this.cancelled = b;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerClaimPlotEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerClaimPlotEvent.java
new file mode 100644
index 000000000..fccb184d1
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerClaimPlotEvent.java
@@ -0,0 +1,57 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.Player;
+import cn.nukkit.event.Cancellable;
+import cn.nukkit.event.HandlerList;
+import cn.nukkit.event.player.PlayerEvent;
+import com.intellectualcrafters.plot.object.Plot;
+
+public class PlayerClaimPlotEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final Plot plot;
+ private final boolean auto;
+ private boolean cancelled;
+
+ /**
+ * PlayerClaimPlotEvent: Called when a plot is claimed.
+ *
+ * @param player Player that claimed the plot
+ * @param plot Plot that was claimed
+ */
+ public PlayerClaimPlotEvent(Player player, Plot plot, boolean auto) {
+ this.player = player;
+ this.plot = plot;
+ this.auto = auto;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * Get the plot involved
+ *
+ * @return Plot
+ */
+ public Plot getPlot() {
+ return this.plot;
+ }
+
+ /**
+ * @return true if it was an automated claim, else false
+ */
+ public boolean wasAuto() {
+ return this.auto;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean b) {
+ this.cancelled = b;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerEnterPlotEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerEnterPlotEvent.java
new file mode 100644
index 000000000..8ac37ac9e
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerEnterPlotEvent.java
@@ -0,0 +1,37 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.Player;
+import cn.nukkit.event.HandlerList;
+import cn.nukkit.event.player.PlayerEvent;
+import com.intellectualcrafters.plot.object.Plot;
+
+public class PlayerEnterPlotEvent extends PlayerEvent {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final Plot plot;
+ private final Player player;
+
+ /**
+ * Called when a player leaves a plot.
+ *
+ * @param player Player that entered the plot
+ * @param plot Plot that was entered
+ */
+ public PlayerEnterPlotEvent(Player player, Plot plot) {
+ this.player = player;
+ this.plot = plot;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * Get the plot involved.
+ *
+ * @return Plot
+ */
+ public Plot getPlot() {
+ return this.plot;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerLeavePlotEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerLeavePlotEvent.java
new file mode 100644
index 000000000..0937e7aea
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerLeavePlotEvent.java
@@ -0,0 +1,41 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.Player;
+import cn.nukkit.event.HandlerList;
+import cn.nukkit.event.player.PlayerEvent;
+import com.intellectualcrafters.plot.object.Plot;
+
+/**
+
+
+ */
+public class PlayerLeavePlotEvent extends PlayerEvent {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final Plot plot;
+
+ /**
+ * PlayerLeavePlotEvent: Called when a player leaves a plot
+ *
+ * @param player Player that left the plot
+ * @param plot Plot that was left
+ */
+ public PlayerLeavePlotEvent(Player player, Plot plot) {
+ this.player = player;
+ this.plot = plot;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * Get the plot involved
+ *
+ * @return Plot
+ */
+ public Plot getPlot() {
+ return this.plot;
+ }
+
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerPlotDeniedEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerPlotDeniedEvent.java
new file mode 100644
index 000000000..f17e07c2b
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerPlotDeniedEvent.java
@@ -0,0 +1,61 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.Player;
+import cn.nukkit.event.HandlerList;
+import com.intellectualcrafters.plot.object.Plot;
+import java.util.UUID;
+
+public class PlayerPlotDeniedEvent extends PlotEvent {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final Player initiator;
+ private final boolean added;
+ private final UUID player;
+
+ /**
+ * PlayerPlotDeniedEvent: Called when the denied UUID list is modified for a plot.
+ *
+ * @param initiator Player that initiated the event
+ * @param plot Plot in which the event occurred
+ * @param player Player that was denied/un-denied
+ * @param added true of add to deny list, false if removed
+ */
+ public PlayerPlotDeniedEvent(Player initiator, Plot plot, UUID player, boolean added) {
+ super(plot);
+ this.initiator = initiator;
+ this.added = added;
+ this.player = player;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * If a user was added.
+ *
+ * @return boolean
+ */
+ public boolean wasAdded() {
+ return this.added;
+ }
+
+ /**
+ * The player added/removed.
+ *
+ * @return UUID
+ */
+ public UUID getPlayer() {
+ return this.player;
+ }
+
+ /**
+ * The player initiating the action.
+ *
+ * @return Player
+ */
+ public Player getInitiator() {
+ return this.initiator;
+ }
+
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerPlotHelperEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerPlotHelperEvent.java
new file mode 100644
index 000000000..ffc94e915
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerPlotHelperEvent.java
@@ -0,0 +1,64 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.Player;
+import cn.nukkit.event.HandlerList;
+import com.intellectualcrafters.plot.object.Plot;
+import java.util.UUID;
+
+/**
+
+
+ */
+public class PlayerPlotHelperEvent extends PlotEvent {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final Player initiator;
+ private final boolean added;
+ private final UUID player;
+
+ /**
+ * PlayerPlotHelperEvent: Called when a plot helper is added/removed
+ *
+ * @param initiator Player that initiated the event
+ * @param plot Plot in which the event occurred
+ * @param player Player that was added/removed from the helper list
+ * @param added true of the player was added, false if the player was removed
+ */
+ public PlayerPlotHelperEvent(Player initiator, Plot plot, UUID player, boolean added) {
+ super(plot);
+ this.initiator = initiator;
+ this.added = added;
+ this.player = player;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * If a player was added
+ *
+ * @return boolean
+ */
+ public boolean wasAdded() {
+ return this.added;
+ }
+
+ /**
+ * The UUID added/removed
+ *
+ * @return UUID
+ */
+ public UUID getPlayer() {
+ return this.player;
+ }
+
+ /**
+ * The player initiating the action
+ *
+ * @return Player
+ */
+ public Player getInitiator() {
+ return this.initiator;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerPlotTrustedEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerPlotTrustedEvent.java
new file mode 100644
index 000000000..bd1c20a6d
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerPlotTrustedEvent.java
@@ -0,0 +1,64 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.Player;
+import cn.nukkit.event.HandlerList;
+import com.intellectualcrafters.plot.object.Plot;
+import java.util.UUID;
+
+/**
+
+
+ */
+public class PlayerPlotTrustedEvent extends PlotEvent {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final Player initiator;
+ private final boolean added;
+ private final UUID player;
+
+ /**
+ * PlayerPlotTrustedEvent: Called when a plot trusted user is added/removed
+ *
+ * @param initiator Player that initiated the event
+ * @param plot Plot in which the event occurred
+ * @param player Player that was added/removed from the trusted list
+ * @param added true of the player was added, false if the player was removed
+ */
+ public PlayerPlotTrustedEvent(Player initiator, Plot plot, UUID player, boolean added) {
+ super(plot);
+ this.initiator = initiator;
+ this.added = added;
+ this.player = player;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * If a player was added
+ *
+ * @return boolean
+ */
+ public boolean wasAdded() {
+ return this.added;
+ }
+
+ /**
+ * The UUID added/removed
+ *
+ * @return UUID
+ */
+ public UUID getPlayer() {
+ return this.player;
+ }
+
+ /**
+ * The player initiating the action
+ *
+ * @return Player
+ */
+ public Player getInitiator() {
+ return this.initiator;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerTeleportToPlotEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerTeleportToPlotEvent.java
new file mode 100644
index 000000000..089bb3ffb
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlayerTeleportToPlotEvent.java
@@ -0,0 +1,63 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.Player;
+import cn.nukkit.event.Cancellable;
+import cn.nukkit.event.HandlerList;
+import cn.nukkit.event.player.PlayerEvent;
+import com.intellectualcrafters.plot.object.Location;
+import com.intellectualcrafters.plot.object.Plot;
+
+/**
+ * Called when a player teleports to a plot
+ *
+
+
+ */
+public class PlayerTeleportToPlotEvent extends PlayerEvent implements Cancellable {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final Location from;
+ private final Plot plot;
+ private boolean cancelled;
+
+ /**
+ * PlayerTeleportToPlotEvent: Called when a player teleports to a plot
+ *
+ * @param player That was teleported
+ * @param from Start location
+ * @param plot Plot to which the player was teleported
+ */
+ public PlayerTeleportToPlotEvent(Player player, Location from, Plot plot) {
+ this.player = player;
+ this.from = from;
+ this.plot = plot;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+
+ /**
+ * Get the from location
+ *
+ * @return Location
+ */
+ public Location getFrom() {
+ return this.from;
+ }
+
+ /**
+ * Get the plot involved
+ *
+ * @return Plot
+ */
+ public Plot getPlot() {
+ return this.plot;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotClearEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotClearEvent.java
new file mode 100644
index 000000000..47e5ddcf8
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotClearEvent.java
@@ -0,0 +1,52 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.event.Cancellable;
+import cn.nukkit.event.HandlerList;
+import com.intellectualcrafters.plot.object.Plot;
+import com.intellectualcrafters.plot.object.PlotId;
+
+/**
+ * Called when a plot is cleared
+ *
+ */
+public class PlotClearEvent extends PlotEvent implements Cancellable {
+
+ private static final HandlerList handlers = new HandlerList();
+ private boolean cancelled;
+ public PlotClearEvent(Plot plot) {
+ super(plot);
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * Get the PlotId.
+ *
+ * @return PlotId
+ */
+ public PlotId getPlotId() {
+ return getPlot().getId();
+ }
+
+ /**
+ * Get the world name.
+ *
+ * @return String
+ */
+ public String getWorld() {
+ return getPlot().getArea().worldname;
+ }
+
+
+ @Override
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean b) {
+ this.cancelled = b;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotComponentSetEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotComponentSetEvent.java
new file mode 100644
index 000000000..5a3515342
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotComponentSetEvent.java
@@ -0,0 +1,52 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.event.HandlerList;
+import com.intellectualcrafters.plot.object.Plot;
+import com.intellectualcrafters.plot.object.PlotId;
+
+/**
+ * Called when a plot component is set
+ *
+ */
+public class PlotComponentSetEvent extends PlotEvent {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final String component;
+
+ public PlotComponentSetEvent(Plot plot, String component) {
+ super(plot);
+ this.component = component;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * Get the PlotId
+ *
+ * @return PlotId
+ */
+ public PlotId getPlotId() {
+ return getPlot().getId();
+ }
+
+ /**
+ * Get the world name
+ *
+ * @return String
+ */
+ public String getWorld() {
+ return getPlot().getArea().worldname;
+ }
+
+ /**
+ * Get the component which was set
+ *
+ * @return Component name
+ */
+ public String getComponent() {
+ return this.component;
+ }
+
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotDeleteEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotDeleteEvent.java
new file mode 100644
index 000000000..223eb5251
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotDeleteEvent.java
@@ -0,0 +1,41 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.event.HandlerList;
+import com.intellectualcrafters.plot.object.Plot;
+import com.intellectualcrafters.plot.object.PlotId;
+
+/**
+ * Called when a plot is deleted
+ *
+ */
+public class PlotDeleteEvent extends PlotEvent {
+
+ private static final HandlerList handlers = new HandlerList();
+
+ public PlotDeleteEvent(Plot plot) {
+ super(plot);
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * Get the PlotId
+ *
+ * @return PlotId
+ */
+ public PlotId getPlotId() {
+ return getPlot().getId();
+ }
+
+ /**
+ * Get the world name
+ *
+ * @return String
+ */
+ public String getWorld() {
+ return getPlot().getArea().worldname;
+ }
+
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotEvent.java
new file mode 100644
index 000000000..21f90f3bf
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotEvent.java
@@ -0,0 +1,18 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.event.Event;
+import com.intellectualcrafters.plot.object.Plot;
+
+public abstract class PlotEvent extends Event {
+
+ private final Plot plot;
+
+ public PlotEvent(Plot plot) {
+ this.plot = plot;
+ }
+
+ public final Plot getPlot() {
+ return this.plot;
+ }
+
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotFlagAddEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotFlagAddEvent.java
new file mode 100644
index 000000000..540f1dad9
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotFlagAddEvent.java
@@ -0,0 +1,51 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.event.Cancellable;
+import cn.nukkit.event.HandlerList;
+import com.intellectualcrafters.plot.flag.Flag;
+import com.intellectualcrafters.plot.object.Plot;
+
+/**
+ * Called when a Flag is added to a plot.
+ *
+ */
+public class PlotFlagAddEvent extends PlotEvent implements Cancellable {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final Flag flag;
+ private boolean cancelled;
+
+ /**
+ * PlotFlagAddEvent: Called when a Flag is added to a plot.
+ *
+ * @param flag Flag that was added
+ * @param plot Plot to which the flag was added
+ */
+ public PlotFlagAddEvent(Flag flag, Plot plot) {
+ super(plot);
+ this.flag = flag;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * Get the flag involved.
+ *
+ * @return Flag
+ */
+ public Flag getFlag() {
+ return this.flag;
+ }
+
+ @Override
+ public final boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ @Override
+ public final void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotFlagRemoveEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotFlagRemoveEvent.java
new file mode 100644
index 000000000..3baa8b462
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotFlagRemoveEvent.java
@@ -0,0 +1,51 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.event.Cancellable;
+import cn.nukkit.event.HandlerList;
+import com.intellectualcrafters.plot.flag.Flag;
+import com.intellectualcrafters.plot.object.Plot;
+
+/**
+ * Called when a flag is removed from a plot
+ *
+ */
+public class PlotFlagRemoveEvent extends PlotEvent implements Cancellable {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final Flag flag;
+ private boolean cancelled;
+
+ /**
+ * PlotFlagRemoveEvent: Called when a flag is removed from a plot
+ *
+ * @param flag Flag that was removed
+ * @param plot Plot from which the flag was removed
+ */
+ public PlotFlagRemoveEvent(Flag flag, Plot plot) {
+ super(plot);
+ this.flag = flag;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * Get the flag involved
+ *
+ * @return Flag
+ */
+ public Flag getFlag() {
+ return this.flag;
+ }
+
+ @Override
+ public final boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ @Override
+ public final void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotMergeEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotMergeEvent.java
new file mode 100644
index 000000000..960eb4c03
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotMergeEvent.java
@@ -0,0 +1,56 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.event.Cancellable;
+import cn.nukkit.event.HandlerList;
+import cn.nukkit.level.Level;
+import com.intellectualcrafters.plot.object.Plot;
+import com.intellectualcrafters.plot.object.PlotId;
+import java.util.ArrayList;
+
+public class PlotMergeEvent extends PlotEvent implements Cancellable {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final ArrayList plots;
+ private final Level world;
+ private boolean cancelled;
+
+ /**
+ * PlotMergeEvent: Called when plots are merged
+ *
+ * @param world World in which the event occurred
+ * @param plot Plot that was merged
+ * @param plots A list of plots involved in the event
+ */
+ public PlotMergeEvent(Level world, Plot plot, ArrayList plots) {
+ super(plot);
+ this.world = world;
+ this.plots = plots;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * Get the plots being added.
+ *
+ * @return Plot
+ */
+ public ArrayList getPlots() {
+ return this.plots;
+ }
+
+ public Level getLevel() {
+ return this.world;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean b) {
+ this.cancelled = b;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotRateEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotRateEvent.java
new file mode 100644
index 000000000..de9a9f0b5
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotRateEvent.java
@@ -0,0 +1,36 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.event.HandlerList;
+import com.intellectualcrafters.plot.object.Plot;
+import com.intellectualcrafters.plot.object.PlotPlayer;
+import com.intellectualcrafters.plot.object.Rating;
+
+public class PlotRateEvent extends PlotEvent {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final PlotPlayer rater;
+ private Rating rating;
+
+ public PlotRateEvent(PlotPlayer rater, Rating rating, Plot plot) {
+ super(plot);
+ this.rater = rater;
+ this.rating = rating;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ public PlotPlayer getRater() {
+ return this.rater;
+ }
+
+ public Rating getRating() {
+ return this.rating;
+ }
+
+ public void setRating(Rating rating) {
+ this.rating = rating;
+ }
+
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotUnlinkEvent.java b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotUnlinkEvent.java
new file mode 100644
index 000000000..4ddc2e6ee
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/events/PlotUnlinkEvent.java
@@ -0,0 +1,61 @@
+package com.plotsquared.nukkit.events;
+
+import cn.nukkit.event.Cancellable;
+import cn.nukkit.event.Event;
+import cn.nukkit.event.HandlerList;
+import cn.nukkit.level.Level;
+import com.intellectualcrafters.plot.object.PlotArea;
+import com.intellectualcrafters.plot.object.PlotId;
+import java.util.ArrayList;
+
+public class PlotUnlinkEvent extends Event implements Cancellable {
+
+ private static final HandlerList handlers = new HandlerList();
+ private final ArrayList plots;
+ private final Level world;
+ private final PlotArea area;
+ private boolean cancelled;
+
+ /**
+ * Called when a mega-plot is unlinked.
+ *
+ * @param world World in which the event occurred
+ * @param plots Plots that are involved in the event
+ */
+ public PlotUnlinkEvent(Level world, PlotArea area, ArrayList plots) {
+ this.plots = plots;
+ this.world = world;
+ this.area = area;
+ }
+
+ public static HandlerList getHandlers() {
+ return handlers;
+ }
+
+ /**
+ * Get the plots involved.
+ *
+ * @return The {@link PlotId}'s of the plots involved
+ */
+ public ArrayList getPlots() {
+ return this.plots;
+ }
+
+ public Level getLevel() {
+ return this.world;
+ }
+
+ public PlotArea getArea() {
+ return this.area;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return this.cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean b) {
+ this.cancelled = b;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/generator/NukkitAugmentedGenerator.java b/Nukkit/src/main/java/com/plotsquared/nukkit/generator/NukkitAugmentedGenerator.java
new file mode 100644
index 000000000..5ba60b4f6
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/generator/NukkitAugmentedGenerator.java
@@ -0,0 +1,47 @@
+package com.plotsquared.nukkit.generator;
+
+import cn.nukkit.event.EventHandler;
+import cn.nukkit.event.Listener;
+import cn.nukkit.event.level.ChunkLoadEvent;
+import cn.nukkit.level.Level;
+import cn.nukkit.level.format.FullChunk;
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.generator.AugmentedUtils;
+import com.plotsquared.nukkit.NukkitMain;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class NukkitAugmentedGenerator implements Listener {
+
+ private static NukkitAugmentedGenerator generator;
+ private static ConcurrentHashMap generators = new ConcurrentHashMap<>();
+
+ private NukkitAugmentedGenerator(NukkitMain plugin) {
+ plugin.getServer().getPluginManager().registerEvents(this, plugin);
+ }
+
+ public static NukkitAugmentedGenerator get(Level level) {
+ NukkitAugmentedGenerator current = generators.get(level.getName());
+ if (current != null) {
+ return current;
+ }
+ if (generator == null) {
+ NukkitMain plugin = ((NukkitMain) PS.get().IMP);
+ generator = new NukkitAugmentedGenerator(plugin);
+ }
+ generators.put(level.getName(), generator);
+ return generator;
+ }
+
+ @EventHandler
+ private void onChunkLoad(ChunkLoadEvent event) {
+ Level level = event.getLevel();
+ generator = generators.get(level.getName());
+ if (generator != null) {
+ generator.populate(level, event.getChunk());
+ }
+ }
+
+ private void populate(Level world, FullChunk chunk) {
+ AugmentedUtils.generate(world.getName(), chunk.getX(), chunk.getZ(), null);
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/generator/NukkitPlotGenerator.java b/Nukkit/src/main/java/com/plotsquared/nukkit/generator/NukkitPlotGenerator.java
new file mode 100644
index 000000000..d37609549
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/generator/NukkitPlotGenerator.java
@@ -0,0 +1,203 @@
+package com.plotsquared.nukkit.generator;
+
+import cn.nukkit.level.format.generic.BaseFullChunk;
+import cn.nukkit.level.generator.Generator;
+import cn.nukkit.math.NukkitRandom;
+import cn.nukkit.math.Vector3;
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.generator.GeneratorWrapper;
+import com.intellectualcrafters.plot.generator.HybridGen;
+import com.intellectualcrafters.plot.generator.IndependentPlotGenerator;
+import com.intellectualcrafters.plot.object.Location;
+import com.intellectualcrafters.plot.object.PlotArea;
+import com.intellectualcrafters.plot.object.PlotId;
+import com.intellectualcrafters.plot.object.PlotManager;
+import com.intellectualcrafters.plot.object.PseudoRandom;
+import com.intellectualcrafters.plot.object.SetupObject;
+import com.intellectualcrafters.plot.util.ChunkManager;
+import com.intellectualcrafters.plot.util.MainUtil;
+import com.intellectualcrafters.plot.util.block.ScopedLocalBlockQueue;
+import com.plotsquared.nukkit.util.NukkitUtil;
+import com.plotsquared.nukkit.util.block.NukkitWrappedChunk;
+import java.util.Map;
+
+public class NukkitPlotGenerator extends Generator implements GeneratorWrapper {
+
+ private final PseudoRandom random = new PseudoRandom();
+ private final IndependentPlotGenerator plotGenerator;
+ private final Generator platformGenerator;
+ private final boolean full;
+ private final String world;
+ private final Map settings;
+ private boolean loaded = false;
+ private cn.nukkit.level.ChunkManager chunkManager;
+ private final NukkitWrappedChunk chunkSetter;
+
+ public NukkitPlotGenerator(Map map) {
+ if (map == null) {
+ throw new IllegalArgumentException("options may not be null!");
+ }
+ this.settings = map;
+ MainUtil.initCache();
+ this.world = map.get("world").toString();
+ if (map.containsKey("generator")) {
+ final Generator cg = (Generator) map.get("generator");
+ if (cg instanceof NukkitPlotGenerator) {
+ throw new IllegalArgumentException("Generator: " + cg.getClass().getName() + " is already a BukkitPlotGenerator!");
+ }
+ this.full = false;
+ PS.debug("BukkitPlotGenerator does not fully support: " + cg);
+ this.platformGenerator = cg;
+ this.plotGenerator = new IndependentPlotGenerator() {
+ @Override
+ public void processSetup(SetupObject setup) {}
+
+ @Override
+ public void initialize(PlotArea area) {}
+
+ @Override
+ public PlotManager getNewPlotManager() {
+ return new HybridGen().getNewPlotManager();
+ }
+
+ @Override
+ public String getName() {
+ return cg.getClass().getName();
+ }
+
+ @Override
+ public PlotArea getNewPlotArea(String world, String id, PlotId min, PlotId max) {
+ return new HybridGen().getNewPlotArea(world, id, min, max);
+ }
+
+ @Override
+ public void generateChunk(final ScopedLocalBlockQueue result, PlotArea settings, PseudoRandom random) {
+ Location min = result.getMin();
+ int cx = min.getX() >> 4;
+ int cz = min.getZ() >> 4;
+ cg.generateChunk(cx, cz);
+ cg.populateChunk(cx, cz);
+ }
+ };
+ chunkSetter = new NukkitWrappedChunk(world, null);
+ MainUtil.initCache();
+ } else {
+ this.plotGenerator = (IndependentPlotGenerator) map.get("plot-generator");
+ this.platformGenerator = this;
+ this.full = true;
+ chunkSetter = new NukkitWrappedChunk(world, null);
+ }
+ PS.get().loadWorld(world, this);
+ }
+
+ @Override
+ public void augment(PlotArea area) {
+ NukkitAugmentedGenerator.get(NukkitUtil.getWorld(area.worldname));
+ }
+
+ @Override
+ public boolean isFull() {
+ return this.full;
+ }
+
+ @Override
+ public IndependentPlotGenerator getPlotGenerator() {
+ return this.plotGenerator;
+ }
+
+ @Override
+ public Generator getPlatformGenerator() {
+ return this.platformGenerator;
+ }
+
+ @Override
+ public String toString() {
+ if (this.platformGenerator == this) {
+ return this.plotGenerator.getName();
+ }
+ if (this.platformGenerator == null) {
+ return "null";
+ } else {
+ return this.platformGenerator.getClass().getName();
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ return toString().equals(obj.toString()) || toString().equals(obj.getClass().getName());
+ }
+
+ @Override
+ public int getId() {
+ return 1;
+ }
+
+ @Override
+ public void init(cn.nukkit.level.ChunkManager chunkManager, NukkitRandom nukkitRandom) {
+ this.chunkManager = chunkManager;
+ if (getPlatformGenerator() != this) {
+ getPlatformGenerator().init(chunkManager, nukkitRandom);
+ }
+ }
+
+ @Override
+ public void generateChunk(int cx, int cz) {
+ if (getPlatformGenerator() != this) {
+ getPlatformGenerator().generateChunk(cx, cz);
+ } else {
+ BaseFullChunk chunk = this.chunkManager.getChunk(cx, cz);
+ // Load if improperly loaded
+ if (!this.loaded) {
+ PS.get().loadWorld(world, this);
+ this.loaded = true;
+ }
+ chunkSetter.init(chunk);
+ // Set random seed
+ this.random.state = cx << 16 | cz & 0xFFFF;
+ // Process the chunk
+ if (ChunkManager.preProcessChunk(chunkSetter)) {
+ return;
+ }
+ PlotArea area = PS.get().getPlotArea(world, null);
+ try {
+ this.plotGenerator.generateChunk(this.chunkSetter, area, this.random);
+ } catch (Throwable e) {
+ // Recover from generator error
+ e.printStackTrace();
+ }
+ ChunkManager.postProcessChunk(chunkSetter);
+ }
+ }
+
+ @Override
+ public void populateChunk(int x, int z) {
+ if (getPlatformGenerator() != this) {
+ getPlatformGenerator().populateChunk(x, z);
+ } else {
+ // No populating
+ }
+ }
+
+ @Override
+ public Map getSettings() {
+ return settings;
+ }
+
+ @Override
+ public String getName() {
+ return plotGenerator.getName();
+ }
+
+ @Override
+ public Vector3 getSpawn() {
+ return new Vector3(0, 61, 0);
+ }
+
+ @Override
+ public cn.nukkit.level.ChunkManager getChunkManager() {
+ return chunkManager;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/listeners/PlayerEvents.java b/Nukkit/src/main/java/com/plotsquared/nukkit/listeners/PlayerEvents.java
new file mode 100644
index 000000000..1736d610a
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/listeners/PlayerEvents.java
@@ -0,0 +1,1321 @@
+package com.plotsquared.nukkit.listeners;
+
+import cn.nukkit.Player;
+import cn.nukkit.block.Block;
+import cn.nukkit.command.CommandSender;
+import cn.nukkit.entity.Entity;
+import cn.nukkit.entity.EntityCreature;
+import cn.nukkit.entity.EntityHanging;
+import cn.nukkit.entity.EntityHuman;
+import cn.nukkit.entity.EntityLiving;
+import cn.nukkit.entity.item.EntityPotion;
+import cn.nukkit.entity.item.EntityVehicle;
+import cn.nukkit.entity.mob.EntityMob;
+import cn.nukkit.entity.passive.EntityAnimal;
+import cn.nukkit.entity.passive.EntityWaterAnimal;
+import cn.nukkit.entity.projectile.EntityProjectile;
+import cn.nukkit.event.Cancellable;
+import cn.nukkit.event.Event;
+import cn.nukkit.event.EventHandler;
+import cn.nukkit.event.EventPriority;
+import cn.nukkit.event.Listener;
+import cn.nukkit.event.block.BlockBreakEvent;
+import cn.nukkit.event.block.BlockBurnEvent;
+import cn.nukkit.event.block.BlockFormEvent;
+import cn.nukkit.event.block.BlockGrowEvent;
+import cn.nukkit.event.block.BlockPlaceEvent;
+import cn.nukkit.event.block.BlockSpreadEvent;
+import cn.nukkit.event.block.BlockUpdateEvent;
+import cn.nukkit.event.entity.EntityBlockChangeEvent;
+import cn.nukkit.event.entity.EntityCombustByEntityEvent;
+import cn.nukkit.event.entity.EntityDamageByEntityEvent;
+import cn.nukkit.event.entity.EntityDamageEvent;
+import cn.nukkit.event.entity.EntityExplodeEvent;
+import cn.nukkit.event.entity.EntitySpawnEvent;
+import cn.nukkit.event.entity.ExplosionPrimeEvent;
+import cn.nukkit.event.entity.ProjectileHitEvent;
+import cn.nukkit.event.entity.ProjectileLaunchEvent;
+import cn.nukkit.event.inventory.InventoryCloseEvent;
+import cn.nukkit.event.player.PlayerBucketEmptyEvent;
+import cn.nukkit.event.player.PlayerBucketFillEvent;
+import cn.nukkit.event.player.PlayerChatEvent;
+import cn.nukkit.event.player.PlayerCommandPreprocessEvent;
+import cn.nukkit.event.player.PlayerInteractEvent;
+import cn.nukkit.event.player.PlayerJoinEvent;
+import cn.nukkit.event.player.PlayerMoveEvent;
+import cn.nukkit.event.player.PlayerQuitEvent;
+import cn.nukkit.event.player.PlayerRespawnEvent;
+import cn.nukkit.event.player.PlayerTeleportEvent;
+import cn.nukkit.event.potion.PotionCollideEvent;
+import cn.nukkit.event.redstone.RedstoneUpdateEvent;
+import cn.nukkit.metadata.MetadataValue;
+import cn.nukkit.plugin.Plugin;
+import com.google.common.base.Optional;
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.config.C;
+import com.intellectualcrafters.plot.config.Settings;
+import com.intellectualcrafters.plot.flag.Flags;
+import com.intellectualcrafters.plot.flag.IntegerFlag;
+import com.intellectualcrafters.plot.object.Location;
+import com.intellectualcrafters.plot.object.Plot;
+import com.intellectualcrafters.plot.object.PlotArea;
+import com.intellectualcrafters.plot.object.PlotBlock;
+import com.intellectualcrafters.plot.object.PlotId;
+import com.intellectualcrafters.plot.object.PlotPlayer;
+import com.intellectualcrafters.plot.object.StringWrapper;
+import com.intellectualcrafters.plot.util.EventUtil;
+import com.intellectualcrafters.plot.util.MainUtil;
+import com.intellectualcrafters.plot.util.MathMan;
+import com.intellectualcrafters.plot.util.Permissions;
+import com.intellectualcrafters.plot.util.RegExUtil;
+import com.intellectualcrafters.plot.util.TaskManager;
+import com.intellectualcrafters.plot.util.UUIDHandler;
+import com.plotsquared.listener.PlotListener;
+import com.plotsquared.nukkit.object.NukkitPlayer;
+import com.plotsquared.nukkit.util.NukkitUtil;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+public class PlayerEvents extends PlotListener implements Listener {
+
+ private boolean pistonBlocks = true;
+ // To prevent recursion
+ private boolean tmpTeleport = true;
+
+ // TODO fix this
+ @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
+ public void onPhysicsEvent(BlockUpdateEvent event) {
+ if (event instanceof RedstoneUpdateEvent) {
+ Block block = event.getBlock();
+ Location loc = NukkitUtil.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;
+ }
+ if (Settings.Redstone.DISABLE_OFFLINE) {
+ if (UUIDHandler.getPlayer(plot.owner) == null) {
+ boolean disable = true;
+ for (UUID trusted : plot.getTrusted()) {
+ if (UUIDHandler.getPlayer(trusted) != null) {
+ disable = false;
+ break;
+ }
+ }
+ if (disable) {
+ event.setCancelled(true);
+ return;
+ }
+ }
+ }
+ if (Settings.Redstone.DISABLE_UNOCCUPIED) {
+ for (Map.Entry entry : UUIDHandler.getPlayers().entrySet()) {
+ if (plot.equals(entry.getValue().getCurrentPlot())) {
+ return;
+ }
+ }
+ event.setCancelled(true);
+ }
+ } else {
+ Block block = event.getBlock();
+ Location loc = NukkitUtil.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);
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onEntityCombustByEntity(EntityCombustByEntityEvent event) {
+ EntityDamageByEntityEvent eventChange = new EntityDamageByEntityEvent(event.getCombuster(), event.getEntity(), EntityDamageEvent.CAUSE_FIRE_TICK, event.getDuration());
+ onEntityDamageByEntityEvent(eventChange);
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onEntityDamageByEntityEvent(EntityDamageEvent event) {
+ if (event instanceof EntityDamageByEntityEvent) {
+ EntityDamageByEntityEvent specific = (EntityDamageByEntityEvent) event;
+ Entity damager = specific.getDamager();
+ Location l = NukkitUtil.getLocation(damager);
+ if (!PS.get().hasPlotArea(l.getWorld())) {
+ return;
+ }
+ Entity victim = event.getEntity();
+ if (!entityDamage(damager, victim)) {
+ event.setCancelled(true);
+ }
+ }
+ }
+
+ @EventHandler
+ public void onProjectileLaunch(ProjectileLaunchEvent event) {
+ EntityProjectile entity = event.getEntity();
+ if (!(entity instanceof EntityPotion)) {
+ return;
+ }
+ Entity shooter = entity.shootingEntity;
+ if (!(shooter instanceof Player)) {
+ return;
+ }
+ Location l = NukkitUtil.getLocation(entity);
+ if (!PS.get().hasPlotArea(l.getWorld())) {
+ return;
+ }
+ PlotPlayer pp = NukkitUtil.getPlayer((Player) shooter);
+ Plot plot = l.getOwnedPlot();
+ if (plot != null && !plot.isAdded(pp.getUUID())) {
+ kill(entity, event);
+ }
+ }
+
+ @EventHandler
+ public boolean onProjectileHit(ProjectileHitEvent event) {
+ EntityProjectile entity = (EntityProjectile) event.getEntity();
+ Location loc = NukkitUtil.getLocation(entity);
+ if (!PS.get().hasPlotArea(loc.getWorld())) {
+ return true;
+ }
+ PlotArea area = loc.getPlotArea();
+ if (area == null) {
+ return true;
+ }
+ Plot plot = area.getPlotAbs(loc);
+ Entity shooter = entity.shootingEntity;
+ if (shooter instanceof Player) {
+ PlotPlayer pp = NukkitUtil.getPlayer((Player) shooter);
+ if (plot == null) {
+ if (!Permissions.hasPermission(pp, C.PERMISSION_PROJECTILE_UNOWNED)) {
+ kill(entity, event);
+ return false;
+ }
+ return true;
+ }
+ if (plot.isAdded(pp.getUUID()) || Permissions.hasPermission(pp, C.PERMISSION_PROJECTILE_OTHER)) {
+ return true;
+ }
+ kill(entity, event);
+ return false;
+ }
+ if (shooter == null) {
+ kill(entity, event);
+ 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()) {
+ return;
+ }
+ String[] split = msg.split(" ");
+ Player player = event.getPlayer();
+ PlotPlayer pp = NukkitUtil.getPlayer(player);
+ Plot plot = pp.getCurrentPlot();
+ 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();
+ 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.MONITOR, ignoreCancelled = true)
+ public void onConnect(PlayerJoinEvent event) {
+ final Player player = event.getPlayer();
+ NukkitUtil.getPlayer(event.getPlayer()).unregister();
+ final PlotPlayer pp = NukkitUtil.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(new Runnable() {
+ @Override
+ public void run() {
+ if (!player.hasPlayedBefore() && player.isOnline()) {
+ player.save();
+ }
+ EventUtil.manager.doJoinTask(pp);
+ }
+ }, 20);
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void playerRespawn(PlayerRespawnEvent event) {
+ Player player = event.getPlayer();
+ PlotPlayer pp = NukkitUtil.getPlayer(player);
+ EventUtil.manager.doRespawnTask(pp);
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void onTeleport(PlayerTeleportEvent event) {
+ if (event.getTo() == null || event.getFrom() == null) {
+ NukkitUtil.getPlayer(event.getPlayer()).deleteMeta("location");
+ NukkitUtil.getPlayer(event.getPlayer()).deleteMeta("lastplot");
+ return;
+ }
+ cn.nukkit.level.Location from = event.getFrom();
+ cn.nukkit.level.Location to = event.getTo();
+ int x2;
+ if (MathMan.roundInt(from.getX()) != (x2 = MathMan.roundInt(to.getX()))) {
+ Player player = event.getPlayer();
+ PlotPlayer pp = NukkitUtil.getPlayer(player);
+ // Cancel teleport
+ TaskManager.TELEPORT_QUEUE.remove(pp.getName());
+ // Set last location
+ Location loc = NukkitUtil.getLocation(to);
+ pp.setMeta("location", loc);
+ PlotArea area = loc.getPlotArea();
+ if (area == null) {
+ pp.deleteMeta("lastplot");
+ return;
+ }
+ Plot now = area.getPlot(loc);
+ Plot lastPlot = pp.getMeta("lastplot");
+ if (now == null) {
+ if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport) {
+ MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_EXIT_DENIED);
+ this.tmpTeleport = false;
+ if (lastPlot.equals(NukkitUtil.getLocation(from).getPlot())) {
+ player.teleport(from);
+ } else {
+ player.teleport(player.getLevel().getSpawnLocation());
+ }
+ this.tmpTeleport = true;
+ event.setCancelled(true);
+ return;
+ }
+ } else if (now.equals(lastPlot)) {
+ return;
+ } else if (!plotEntry(pp, now) && this.tmpTeleport) {
+ MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_ENTRY_DENIED);
+ this.tmpTeleport = false;
+ to.setComponents(from.getX(), from.getY(), from.getZ());
+ player.teleport(event.getTo());
+ this.tmpTeleport = true;
+ return;
+ }
+ Integer border = area.getBorder();
+ if (x2 > border) {
+ to.setComponents(border - 4, to.getY(), to.getZ());
+ this.tmpTeleport = false;
+ player.teleport(event.getTo());
+ this.tmpTeleport = true;
+ MainUtil.sendMessage(pp, C.BORDER);
+ return;
+ }
+ if (x2 < -border) {
+ to.setComponents(-border + 4, to.getY(), to.getZ());
+ 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 = NukkitUtil.getPlayer(player);
+ // Cancel teleport
+ TaskManager.TELEPORT_QUEUE.remove(pp.getName());
+ // Set last location
+ Location loc = NukkitUtil.getLocation(to);
+ pp.setMeta("location", loc);
+ PlotArea area = loc.getPlotArea();
+ if (area == null) {
+ pp.deleteMeta("lastplot");
+ return;
+ }
+ Plot now = area.getPlot(loc);
+ Plot lastPlot = pp.getMeta("lastplot");
+ if (now == null) {
+ if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport) {
+ MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_EXIT_DENIED);
+ this.tmpTeleport = false;
+ if (lastPlot.equals(NukkitUtil.getLocation(from).getPlot())) {
+ player.teleport(from);
+ } else {
+ player.teleport(player.getLevel().getSpawnLocation());
+ }
+ this.tmpTeleport = true;
+ event.setCancelled(true);
+ return;
+ }
+ } else if (now.equals(lastPlot)) {
+ 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.setComponents(from.getX(), from.getY(), from.getZ());
+ player.teleport(event.getTo());
+ this.tmpTeleport = true;
+ return;
+ }
+ Integer border = area.getBorder();
+ if (z2 > border) {
+ to.setComponents(to.getX(), to.getY(), border - 4);
+ this.tmpTeleport = false;
+ player.teleport(event.getTo());
+ this.tmpTeleport = true;
+ MainUtil.sendMessage(pp, C.BORDER);
+ } else if (z2 < -border) {
+ to.setComponents(to.getX(), to.getY(), -border + 4);
+ this.tmpTeleport = false;
+ player.teleport(event.getTo());
+ this.tmpTeleport = true;
+ MainUtil.sendMessage(pp, C.BORDER);
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void playerMove(PlayerMoveEvent event) {
+ cn.nukkit.level.Location from = event.getFrom();
+ cn.nukkit.level.Location to = event.getTo();
+ int x2;
+ if (MathMan.roundInt(from.getX()) != (x2 = MathMan.roundInt(to.getX()))) {
+ Player player = event.getPlayer();
+ PlotPlayer pp = NukkitUtil.getPlayer(player);
+ // Cancel teleport
+ TaskManager.TELEPORT_QUEUE.remove(pp.getName());
+ // Set last location
+ Location loc = NukkitUtil.getLocation(to);
+ pp.setMeta("location", loc);
+ PlotArea area = loc.getPlotArea();
+ if (area == null) {
+ pp.deleteMeta("lastplot");
+ return;
+ }
+ Plot now = area.getPlot(loc);
+ Plot lastPlot = pp.getMeta("lastplot");
+ if (now == null) {
+ if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport) {
+ MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_EXIT_DENIED);
+ this.tmpTeleport = false;
+ if (lastPlot.equals(NukkitUtil.getLocation(from).getPlot())) {
+ player.teleport(from);
+ } else {
+ player.teleport(player.getLevel().getSpawnLocation());
+ }
+ this.tmpTeleport = true;
+ event.setCancelled(true);
+ return;
+ }
+ } else if (now.equals(lastPlot)) {
+ return;
+ } else if (!plotEntry(pp, now) && this.tmpTeleport) {
+ MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_ENTRY_DENIED);
+ this.tmpTeleport = false;
+ to.setComponents(from.getX(), from.getY(), from.getZ());
+ player.teleport(event.getTo());
+ this.tmpTeleport = true;
+ return;
+ }
+ Integer border = area.getBorder();
+ if (x2 > border) {
+ to.setComponents(border - 4, to.getY(), to.getZ());
+ this.tmpTeleport = false;
+ player.teleport(event.getTo());
+ this.tmpTeleport = true;
+ MainUtil.sendMessage(pp, C.BORDER);
+ return;
+ }
+ if (x2 < -border) {
+ to.setComponents(-border + 4, to.getY(), to.getZ());
+ 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 = NukkitUtil.getPlayer(player);
+ // Cancel teleport
+ TaskManager.TELEPORT_QUEUE.remove(pp.getName());
+ // Set last location
+ Location loc = NukkitUtil.getLocation(to);
+ pp.setMeta("location", loc);
+ PlotArea area = loc.getPlotArea();
+ if (area == null) {
+ pp.deleteMeta("lastplot");
+ return;
+ }
+ Plot now = area.getPlot(loc);
+ Plot lastPlot = pp.getMeta("lastplot");
+ if (now == null) {
+ if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport) {
+ MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_EXIT_DENIED);
+ this.tmpTeleport = false;
+ if (lastPlot.equals(NukkitUtil.getLocation(from).getPlot())) {
+ player.teleport(from);
+ } else {
+ player.teleport(player.getLevel().getSpawnLocation());
+ }
+ this.tmpTeleport = true;
+ event.setCancelled(true);
+ return;
+ }
+ } else if (now.equals(lastPlot)) {
+ 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.setComponents(from.getX(), from.getY(), from.getZ());
+ player.teleport(event.getTo());
+ this.tmpTeleport = true;
+ return;
+ }
+ Integer border = area.getBorder();
+ if (z2 > border) {
+ to.setComponents(to.getX(), to.getY(), border - 4);
+ this.tmpTeleport = false;
+ player.teleport(event.getTo());
+ this.tmpTeleport = true;
+ MainUtil.sendMessage(pp, C.BORDER);
+ } else if (z2 < -border) {
+ to.setComponents(to.getX(), to.getY(), -border + 4);
+ this.tmpTeleport = false;
+ player.teleport(event.getTo());
+ this.tmpTeleport = true;
+ MainUtil.sendMessage(pp, C.BORDER);
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
+ public void onChat(PlayerChatEvent event) {
+ PlotPlayer plotPlayer = NukkitUtil.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();
+ recipients.clear();
+ for (Entry entry : UUIDHandler.getPlayers().entrySet()) {
+ PlotPlayer pp = entry.getValue();
+ if (pp.getAttribute("chatspy")) {
+ String spy = event.getFormat();
+ spy = String.format(spy, sender, message);
+ pp.sendMessage(spy);
+ } else {
+ Plot current = pp.getCurrentPlot();
+ if (current != null && current.getBasePlot(false).equals(plot)) {
+ recipients.add(((NukkitPlayer) pp).player);
+ }
+ }
+ }
+ String partial = C.color(format.replace("%plot_id%", id.x + ";" + id.y).replace("%sender%", sender));
+ String full = partial.replace("%msg%", message);
+ for (CommandSender receiver : recipients) {
+ receiver.sendMessage(full);
+ }
+ }
+
+@EventHandler(priority = EventPriority.LOWEST)
+public void blockDestroy(BlockBreakEvent event) {
+ Player player = event.getPlayer();
+ Location location = NukkitUtil.getLocation(event.getBlock().getLocation());
+ PlotArea area = location.getPlotArea();
+ if (area == null) {
+ return;
+ }
+ Plot plot = area.getPlotAbs(location);
+ if (plot != null) {
+ PlotPlayer plotPlayer = NukkitUtil.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;
+ }
+ }
+ 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((short) block.getId(), block.getDamage()))) {
+ 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 = NukkitUtil.getPlayer(player);
+ if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_DESTROY_ROAD)) {
+ return;
+ }
+ if (PS.get().worldedit != null && pp.getAttribute("worldedit")) {
+ if (player.getInventory().getItemInHand().getId() == PS.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(ExplosionPrimeEvent event) {
+ Entity entity = event.getEntity();
+ Location location = NukkitUtil.getLocation(entity);
+ PlotArea area = location.getPlotArea();
+ if (area == null) {
+ return;
+ }
+ final Plot finalPlot = area.getOwnedPlot(location);
+ if (!entity.hasMetadata("plot")) {
+ entity.setMetadata("plot", new MetadataValue((Plugin) PS.get().IMP) {
+ private Plot plot = finalPlot;
+ @Override
+ public Object value() {
+ return plot;
+ }
+ @Override
+ public void invalidate() {
+ plot = null;
+ }
+ });
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void onBigBoom(EntityExplodeEvent event) {
+ Location location = NukkitUtil.getLocation(event.getPosition());
+ PlotArea area = location.getPlotArea();
+ if (area == null) {
+ if (!PS.get().hasPlotArea(location.getWorld())) {
+ return;
+ }
+ Iterator iterator = event.getBlockList().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();
+ }
+ Iterator iterator = event.getBlockList().iterator();
+ while (iterator.hasNext()) {
+ Block block = iterator.next();
+ location = NukkitUtil.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 onEntityBlockForm(BlockFormEvent event) {
+ String world = event.getBlock().getLevel().getName();
+ if (!PS.get().hasPlotArea(world)) {
+ return;
+ }
+ if (NukkitUtil.getLocation(event.getBlock().getLocation()).getPlotArea() != null) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void onBlockSpread(BlockSpreadEvent event) {
+ Block block = event.getBlock();
+ Location location = NukkitUtil.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;
+ }
+ Block source = event.getSource();
+ switch (source.getId()) {
+ case 2:
+ if (Flags.GRASS_GROW.isFalse(plot)) {
+ event.setCancelled(true);
+ }
+ break;
+ case 110:
+ if (Flags.MYCEL_GROW.isFalse(plot)) {
+ event.setCancelled(true);
+ }
+ break;
+ case 106:
+ if (Flags.VINE_GROW.isFalse(plot)) {
+ event.setCancelled(true);
+ }
+ break;
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void onGrow(BlockGrowEvent event) {
+ Block b = event.getBlock();
+ Location location = NukkitUtil.getLocation(b.getLocation());
+ if (location.isUnownedPlotArea()) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
+ public void onInteract(PlayerInteractEvent event) {
+ Player player = event.getPlayer();
+ PlotPlayer pp = NukkitUtil.getPlayer(player);
+ PlotArea area = pp.getPlotAreaAbs();
+ if (area == null) {
+ return;
+ }
+ switch (event.getAction()) {
+ case PlayerInteractEvent.RIGHT_CLICK_BLOCK:
+ case PlayerInteractEvent.LEFT_CLICK_BLOCK:
+ case PlayerInteractEvent.PHYSICAL: {
+ Plot plot = pp.getCurrentPlot();
+ if (plot == null || !plot.isAdded(pp.getUUID())) {
+ Block block = event.getBlock();
+ if (block != null) {
+ if (plot != null && Flags.USE.contains(plot, PlotBlock.get(block.getId(), block.getDamage()))) {
+ return;
+ }
+ }
+ if (plot == null) {
+ if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_ROAD.s(), true)) {
+ return;
+ }
+ } else if (!plot.hasOwner()) {
+ if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_UNOWNED.s(), true)) {
+ return;
+ }
+ } else if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_OTHER.s(), true)) {
+ return;
+ }
+ event.setCancelled(true);
+ return;
+ }
+ return;
+ }
+ case PlayerInteractEvent.LEFT_CLICK_AIR:
+ case PlayerInteractEvent.RIGHT_CLICK_AIR: {
+ Plot plot = pp.getCurrentPlot();
+ if (plot == null || !plot.isAdded(pp.getUUID())) {
+ if (plot == null) {
+ if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_ROAD.s(), true)) {
+ return;
+ }
+ } else if (!plot.hasOwner()) {
+ if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_UNOWNED.s(), true)) {
+ return;
+ }
+ } else if (Permissions.hasPermission(pp, C.PERMISSION_ADMIN_INTERACT_OTHER.s(), true)) {
+ return;
+ }
+ event.setCancelled(true);
+ return;
+ }
+ return;
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void creatureSpawnEvent(EntitySpawnEvent event) {
+ Entity entity = event.getEntity();
+ Location location = NukkitUtil.getLocation(entity.getLocation());
+ PlotArea area = location.getPlotArea();
+ if (area == null) {
+ return;
+ }
+ Plot plot = area.getOwnedPlotAbs(location);
+ if (plot == null) {
+ if (!area.MOB_SPAWNING) {
+ kill(entity, event);
+ }
+ return;
+ }
+ if (checkEntity(entity, plot)) {
+ kill(entity, event);
+ }
+ }
+
+ private void kill(Entity entity, Event event) {
+ if (event instanceof Cancellable) {
+ event.setCancelled(true);
+ }
+ entity.kill();
+ }
+
+ @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
+ public void onEntityFall(EntityBlockChangeEvent event) {
+ Entity entity = event.getEntity();
+ Location location = NukkitUtil.getLocation(entity);
+ if (!PS.get().hasPlotArea(location.getWorld())) {
+ return;
+ }
+ PlotArea area = location.getPlotArea();
+ if (area == null) {
+ return;
+ }
+ Block from = event.getFrom();
+ Block to = event.getTo();
+ final Plot finalPlot = area.getOwnedPlotAbs(location);
+ boolean toBlock = from == null || from.getId() == 0;
+ if (toBlock) {
+ List meta = entity.getMetadata("plot");
+ if (meta.isEmpty()) {
+ return;
+ }
+ Plot origin = (Plot) meta.get(0).value();
+ if (origin != null && !origin.equals(finalPlot)) {
+ kill(entity, event);
+ }
+ } else {
+ entity.setMetadata("plot", new MetadataValue((Plugin) PS.get().IMP) {
+ private Plot plot = finalPlot;
+ @Override
+ public Object value() {
+ return plot;
+ }
+ @Override
+ public void invalidate() {
+ plot = null;
+ }
+ });
+ }
+ }
+
+ public static boolean checkEntity(Plot plot, IntegerFlag... flags) {
+ if (Settings.Done.RESTRICT_BUILDING && Flags.DONE.isSet(plot)) {
+ return true;
+ }
+ int[] mobs = null;
+ for (IntegerFlag flag : flags) {
+ int i;
+ switch (flag.getName()) {
+ case "entity-cap":
+ i = 0;
+ break;
+ case "mob-cap":
+ i = 3;
+ break;
+ case "hostile-cap":
+ i = 2;
+ break;
+ case "animal-cap":
+ i = 1;
+ break;
+ case "vehicle-cap":
+ i = 4;
+ break;
+ case "misc-cap":
+ i = 5;
+ break;
+ default:
+ i = 0;
+ }
+ int cap = plot.getFlag(flag, Integer.MAX_VALUE);
+ if (cap == Integer.MAX_VALUE) {
+ continue;
+ }
+ if (cap == 0) {
+ return true;
+ }
+ if (mobs == null) {
+ mobs = plot.countEntities();
+ }
+ if (mobs[i] >= cap) {
+ plot.setMeta("EntityCount", mobs);
+ plot.setMeta("EntityCountTime", System.currentTimeMillis());
+ return true;
+ }
+ }
+ if (mobs != null) {
+ for (IntegerFlag flag : flags) {
+ int i;
+ switch (flag.getName()) {
+ case "entity-cap":
+ i = 0;
+ break;
+ case "mob-cap":
+ i = 3;
+ break;
+ case "hostile-cap":
+ i = 2;
+ break;
+ case "animal-cap":
+ i = 1;
+ break;
+ case "vehicle-cap":
+ i = 4;
+ break;
+ case "misc-cap":
+ i = 5;
+ break;
+ default:
+ i = 0;
+ }
+ mobs[i]++;
+ }
+ plot.setMeta("EntityCount", mobs);
+ plot.setMeta("EntityCountTime", System.currentTimeMillis());
+ }
+ return false;
+ }
+
+ public static boolean checkEntity(Entity entity, Plot plot) {
+ if (plot == null || !plot.hasOwner() || plot.getFlags().isEmpty() && plot.getArea().DEFAULT_FLAGS.isEmpty()) {
+ return false;
+ }
+ if (entity instanceof EntityLiving) {
+ if (entity instanceof EntityCreature) {
+ if (entity instanceof EntityAnimal || entity instanceof EntityWaterAnimal) {
+ return checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP, Flags.ANIMAL_CAP);
+ } else if (entity instanceof EntityMob) {
+ return checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP, Flags.HOSTILE_CAP);
+ } else if (entity instanceof EntityHuman){
+ return false;
+ } else {
+ return checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP, Flags.MOB_CAP);
+ }
+ } else {
+ return checkEntity(plot, Flags.ENTITY_CAP, Flags.MOB_CAP);
+ }
+ } else if (entity instanceof EntityVehicle) {
+ return checkEntity(plot, Flags.ENTITY_CAP, Flags.VEHICLE_CAP);
+ } else if (entity instanceof EntityHanging){
+ return checkEntity(plot, Flags.ENTITY_CAP, Flags.MISC_CAP);
+ } else {
+ return checkEntity(plot, Flags.ENTITY_CAP);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void onBlockBurn(BlockBurnEvent event) {
+ Block b = event.getBlock();
+ Location location = NukkitUtil.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) {
+ Block block = event.getBlockClicked();
+ Block b = block.getSide(event.getBlockFace());
+ Location location = NukkitUtil.getLocation(b.getLocation());
+ PlotArea area = location.getPlotArea();
+ if (area == null) {
+ return;
+ }
+ PlotPlayer pp = NukkitUtil.getPlayer(event.getPlayer());
+ Plot plot = area.getPlotAbs(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);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onInventoryClose(InventoryCloseEvent event) {
+ Player closer = event.getPlayer();
+ Player player = (Player) closer;
+ NukkitUtil.getPlayer(player).deleteMeta("inventory");
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onLeave(PlayerQuitEvent event) {
+ if (TaskManager.TELEPORT_QUEUE.contains(event.getPlayer().getName())) {
+ TaskManager.TELEPORT_QUEUE.remove(event.getPlayer().getName());
+ }
+ PlotPlayer pp = NukkitUtil.getPlayer(event.getPlayer());
+ pp.unregister();
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void onBucketFill(PlayerBucketFillEvent event) {
+ Block b = event.getBlockClicked();
+ Location location = NukkitUtil.getLocation(b.getLocation());
+ PlotArea area = location.getPlotArea();
+ if (area == null) {
+ return;
+ }
+ Player player = event.getPlayer();
+ PlotPlayer plotPlayer = NukkitUtil.getPlayer(player);
+ Plot plot = area.getPlotAbs(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.getId(), block.getDamage()))) {
+ 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);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void onPotionSplash(PotionCollideEvent event) {
+ EntityPotion entity = event.getThrownPotion();
+ Location l = NukkitUtil.getLocation(entity);
+ if (!PS.get().hasPlotArea(l.getWorld())) {
+ return;
+ }
+ Entity shooter = entity.shootingEntity;
+ if (shooter instanceof Player) {
+ PlotPlayer pp = NukkitUtil.getPlayer((Player) shooter);
+ Plot plot = l.getOwnedPlotAbs();
+ if (plot == null) {
+ if (!Permissions.hasPermission(pp, C.PERMISSION_PROJECTILE_UNOWNED)) {
+ kill(entity, event);
+ return;
+ }
+ return;
+ }
+ if (plot.isAdded(pp.getUUID()) || Permissions.hasPermission(pp, C.PERMISSION_PROJECTILE_OTHER)) {
+ return;
+ }
+ kill(entity, event);
+ return;
+ }
+ if (shooter == null) {
+ kill(entity, event);
+ return;
+ }
+ }
+
+ public boolean entityDamage(Entity damager, Entity victim) {
+ Location dloc = NukkitUtil.getLocation(damager);
+ Location vloc = NukkitUtil.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.ticksLived > damager.ticksLived) {
+ 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 EntityProjectile) {
+ EntityProjectile projectile = (EntityProjectile) damager;
+ Entity shooter = projectile.shootingEntity;
+ if (shooter instanceof Player) { // shooter is player
+ player = (Player) shooter;
+ } else { // shooter is not player
+ player = null;
+ }
+ } else { // Attacker is not player
+ player = null;
+ }
+ if (player != null) {
+ PlotPlayer plotPlayer = NukkitUtil.getPlayer(player);
+ if (victim instanceof EntityHanging) { // 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 (false) { // TODO armor stand
+ 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 EntityMob) { // 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 (false) { // TODO 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 EntityCreature) { // 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 EntityVehicle) { // 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;
+ }
+ // player is null
+ return !(damager instanceof EntityProjectile && !(victim instanceof EntityCreature));
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void blockCreate(BlockPlaceEvent event) {
+ Location location = NukkitUtil.getLocation(event.getBlock().getLocation());
+ PlotArea area = location.getPlotArea();
+ if (area == null) {
+ return;
+ }
+ Player player = event.getPlayer();
+ PlotPlayer pp = NukkitUtil.getPlayer(player);
+ Plot plot = area.getPlotAbs(location);
+ if (plot != null) {
+ 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((short) block.getId(), block.getDamage()))) {
+ 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 (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)));
+ }
+ } else if (!Permissions.hasPermission(pp, C.PERMISSION_ADMIN_BUILD_OTHER)) {
+ MainUtil.sendMessage(pp, C.NO_PERMISSION_EVENT, C.PERMISSION_ADMIN_BUILD_ROAD);
+ event.setCancelled(true);
+ }
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/listeners/WorldEvents.java b/Nukkit/src/main/java/com/plotsquared/nukkit/listeners/WorldEvents.java
new file mode 100644
index 000000000..36586b4cf
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/listeners/WorldEvents.java
@@ -0,0 +1,59 @@
+package com.plotsquared.nukkit.listeners;
+
+import cn.nukkit.event.EventHandler;
+import cn.nukkit.event.EventPriority;
+import cn.nukkit.event.Listener;
+import cn.nukkit.event.level.LevelInitEvent;
+import cn.nukkit.event.level.LevelLoadEvent;
+import cn.nukkit.level.Level;
+import cn.nukkit.level.generator.Generator;
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.generator.GeneratorWrapper;
+import com.intellectualcrafters.plot.object.PlotArea;
+import com.plotsquared.nukkit.generator.NukkitPlotGenerator;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+
+public class WorldEvents implements Listener {
+
+ private final Field instance;
+
+ public WorldEvents() {
+ try {
+ this.instance = Level.class.getDeclaredField("generatorInstance");
+ this.instance.setAccessible(true);
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void onWorldLoad(LevelLoadEvent event) {
+ handle(event.getLevel());
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void onWorldInit(LevelInitEvent event) {
+ handle(event.getLevel());
+ }
+
+ private void handle(Level level) {
+ String name = level.getName();
+ try {
+ Generator gen = (Generator) instance.get(level);
+ if (gen instanceof GeneratorWrapper) {
+ PS.get().loadWorld(name, (GeneratorWrapper>) gen);
+ } else {
+ HashMap settings = new HashMap<>();
+ settings.put("world", level.getName());
+ settings.put("generator", gen);
+ PS.get().loadWorld(name, new NukkitPlotGenerator(settings));
+ for (PlotArea area : PS.get().getPlotAreas(name)) {
+ area.MAX_BUILD_HEIGHT = Math.min(128, area.MAX_BUILD_HEIGHT);
+ }
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/object/NukkitPlayer.java b/Nukkit/src/main/java/com/plotsquared/nukkit/object/NukkitPlayer.java
new file mode 100644
index 000000000..db55bb322
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/object/NukkitPlayer.java
@@ -0,0 +1,215 @@
+package com.plotsquared.nukkit.object;
+
+import cn.nukkit.Player;
+import cn.nukkit.event.player.PlayerTeleportEvent;
+import cn.nukkit.plugin.RegisteredListener;
+import cn.nukkit.utils.EventException;
+import com.intellectualcrafters.plot.object.Location;
+import com.intellectualcrafters.plot.object.PlotPlayer;
+import com.intellectualcrafters.plot.util.EconHandler;
+import com.intellectualcrafters.plot.util.PlotGameMode;
+import com.intellectualcrafters.plot.util.PlotWeather;
+import com.intellectualcrafters.plot.util.StringMan;
+import com.intellectualcrafters.plot.util.UUIDHandler;
+import com.plotsquared.nukkit.util.NukkitUtil;
+import java.util.UUID;
+
+public class NukkitPlayer extends PlotPlayer {
+
+ public final Player player;
+ public boolean offline;
+ private UUID uuid;
+ private String name;
+
+ /**
+ * Please do not use this method. Instead use
+ * NukkitUtil.getPlayer(Player), as it caches player objects.
+ * @param player
+ */
+ public NukkitPlayer(Player player) {
+ this.player = player;
+ super.populatePersistentMetaMap();
+ }
+
+ public NukkitPlayer(Player player, boolean offline) {
+ this.player = player;
+ this.offline = offline;
+ super.populatePersistentMetaMap();
+ }
+
+ @Override
+ public Location getLocation() {
+ Location location = super.getLocation();
+ return location == null ? NukkitUtil.getLocation(this.player) : location;
+ }
+
+ @Override
+ public UUID getUUID() {
+ if (this.uuid == null) {
+ this.uuid = UUIDHandler.getUUID(this);
+ }
+ return this.uuid;
+ }
+
+ @Override public long getLastPlayed() {
+ return this.player.getLastPlayed();
+ }
+
+ @Override
+ public boolean canTeleport(Location loc) {
+ cn.nukkit.level.Location to = NukkitUtil.getLocation(loc);
+ cn.nukkit.level.Location from = player.getLocation();
+ PlayerTeleportEvent event = new PlayerTeleportEvent(player, from, to, PlayerTeleportEvent.TeleportCause.PLUGIN);
+ RegisteredListener[] listeners = event.getHandlers().getRegisteredListeners();
+ for (RegisteredListener listener : listeners) {
+ if (listener.getPlugin().getName().equals("PlotSquared")) {
+ continue;
+ }
+ try {
+ listener.callEvent(event);
+ } catch (EventException e) {
+ e.printStackTrace();
+ }
+ }
+ if (event.isCancelled() || !event.getTo().equals(to)) {
+ return false;
+ }
+ event = new PlayerTeleportEvent(player, to, from, PlayerTeleportEvent.TeleportCause.PLUGIN);
+ for (RegisteredListener listener : listeners) {
+ if (listener.getPlugin().getName().equals("PlotSquared")) {
+ continue;
+ }
+ try {
+ listener.callEvent(event);
+ } catch (EventException e) {
+ e.printStackTrace();
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean hasPermission(String permission) {
+ if (this.offline && EconHandler.manager != null) {
+ return EconHandler.manager.hasPermission(getName(), permission);
+ }
+ return this.player.hasPermission(permission);
+ }
+
+ @Override
+ public void sendMessage(String message) {
+ if (!StringMan.isEqual(this.getMeta("lastMessage"), message) || (System.currentTimeMillis() - this.getMeta("lastMessageTime") > 5000)) {
+ setMeta("lastMessage", message);
+ setMeta("lastMessageTime", System.currentTimeMillis());
+ this.player.sendMessage(message);
+ }
+ }
+
+ @Override
+ public void teleport(Location to) {
+ if (Math.abs(to.getX()) >= 30000000 || Math.abs(to.getZ()) >= 30000000) {
+ return;
+ }
+ cn.nukkit.level.Location loc = new cn.nukkit.level.Location(to.getX() + 0.5, to.getY(), to.getZ() + 0.5, to.getYaw(), to.getPitch(), NukkitUtil.getWorld(to.getWorld()));
+ this.player.teleport(loc);
+ }
+
+ @Override
+ public String getName() {
+ if (this.name == null) {
+ this.name = this.player.getName();
+ }
+ return this.name;
+ }
+
+ @Override
+ public boolean isOnline() {
+ return !this.offline && this.player.isOnline();
+ }
+
+ @Override
+ public void setCompassTarget(Location location) {
+ throw new UnsupportedOperationException("Not implemented yet: setCompassTarget");
+ }
+
+ @Override
+ public Location getLocationFull() {
+ return NukkitUtil.getLocationFull(this.player);
+ }
+
+ @Override
+ public void setWeather(PlotWeather weather) {
+ throw new UnsupportedOperationException("Not implemented yet: setWeather");
+ }
+
+ @Override
+ public PlotGameMode getGameMode() {
+ switch (this.player.getGamemode()) {
+ case 0:
+ return PlotGameMode.SURVIVAL;
+ case 1:
+ return PlotGameMode.CREATIVE;
+ case 2:
+ return PlotGameMode.ADVENTURE;
+ case 3:
+ return PlotGameMode.SPECTATOR;
+ default:
+ return PlotGameMode.NOT_SET;
+ }
+ }
+
+ @Override
+ public void setGameMode(PlotGameMode gameMode) {
+ switch (gameMode) {
+ case ADVENTURE:
+ this.player.setGamemode(2);
+ break;
+ case CREATIVE:
+ this.player.setGamemode(1);
+ break;
+ case SPECTATOR:
+ this.player.setGamemode(3);
+ break;
+ case SURVIVAL:
+ this.player.setGamemode(0);
+ break;
+ default:
+ this.player.setGamemode(0);
+ break;
+ }
+ }
+
+ @Override
+ public void setTime(long time) {
+ throw new UnsupportedOperationException("Not implemented yet: setTIme");
+ }
+
+ @Override
+ public void setFlight(boolean fly) {
+ this.player.setAllowFlight(fly);
+ }
+
+ @Override
+ public boolean getFlight() {
+ return player.getAllowFlight();
+ }
+
+ @Override
+ public void playMusic(Location location, int id) {
+ throw new UnsupportedOperationException("Not implemented yet: playMusic");
+ }
+
+ @Override
+ public void kick(String message) {
+ player.kick(message);
+ }
+
+ @Override public void stopSpectating() {
+ // Do nothing
+ }
+
+ @Override
+ public boolean isBanned() {
+ return this.player.isBanned();
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/Metrics.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/Metrics.java
new file mode 100644
index 000000000..eb88fa3d1
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/Metrics.java
@@ -0,0 +1,579 @@
+package com.plotsquared.nukkit.util;
+
+import cn.nukkit.plugin.Plugin;
+import cn.nukkit.plugin.PluginDescription;
+import cn.nukkit.utils.LogLevel;
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.util.TaskManager;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.Proxy;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLEncoder;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.UUID;
+import java.util.zip.GZIPOutputStream;
+
+public class Metrics {
+
+ /**
+ * The current revision number.
+ */
+ private static final int REVISION = 7;
+ /**
+ * The base url of the metrics domain.
+ */
+ private static final String BASE_URL = "http://report.mcstats.org";
+ /**
+ * The url used to report a server's status.
+ */
+ private static final String REPORT_URL = "/plugin/%s";
+ /**
+ * Interval of time to ping (in minutes).
+ */
+ private static final int PING_INTERVAL = 15;
+ /**
+ * The plugin this metrics submits for.
+ */
+ private final Plugin plugin;
+ /**
+ * All of the custom graphs to submit to metrics.
+ */
+ private final Set graphs = Collections.synchronizedSet(new HashSet());
+ /**
+ * Unique server id.
+ */
+ private final String guid;
+ /**
+ * Debug mode.
+ */
+ private final boolean debug;
+ /**
+ * The scheduled task.
+ */
+ private volatile int taskId = -1;
+
+ public Metrics(Plugin plugin) {
+ if (plugin == null) {
+ throw new IllegalArgumentException("Plugin cannot be null");
+ }
+ this.plugin = plugin;
+ this.guid = UUID.randomUUID().toString();
+ this.debug = false;
+ }
+
+ /**
+ * GZip compress a string of bytes.
+ *
+ * @param input
+ *
+ * @return byte[] the file as a byte array
+ */
+ public static byte[] gzip(String input) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ GZIPOutputStream gzos = null;
+ try {
+ gzos = new GZIPOutputStream(baos);
+ gzos.write(input.getBytes("UTF-8"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (gzos != null) {
+ try {
+ gzos.close();
+ } catch (IOException ignore) {
+ }
+ }
+ }
+ return baos.toByteArray();
+ }
+
+ /**
+ * Appends a json encoded key/value pair to the given string builder.
+ *
+ * @param json
+ * @param key
+ * @param value
+ *
+ */
+ private static void appendJSONPair(StringBuilder json, String key, String value) {
+ boolean isValueNumeric = false;
+ try {
+ if (value.equals("0") || !value.endsWith("0")) {
+ Double.parseDouble(value);
+ isValueNumeric = true;
+ }
+ } catch (NumberFormatException e) {
+ isValueNumeric = false;
+ }
+ if (json.charAt(json.length() - 1) != '{') {
+ json.append(',');
+ }
+ json.append(escapeJSON(key));
+ json.append(':');
+ if (isValueNumeric) {
+ json.append(value);
+ } else {
+ json.append(escapeJSON(value));
+ }
+ }
+
+ /**
+ * Escape a string to create a valid JSON string
+ *
+ * @param text
+ *
+ * @return String
+ */
+ private static String escapeJSON(String text) {
+ StringBuilder builder = new StringBuilder();
+ builder.append('"');
+ for (int index = 0; index < text.length(); index++) {
+ char chr = text.charAt(index);
+ switch (chr) {
+ case '"':
+ case '\\':
+ builder.append('\\');
+ builder.append(chr);
+ break;
+ case '\b':
+ builder.append("\\b");
+ break;
+ case '\t':
+ builder.append("\\t");
+ break;
+ case '\n':
+ builder.append("\\n");
+ break;
+ case '\r':
+ builder.append("\\r");
+ break;
+ default:
+ if (chr < ' ') {
+ String t = "000" + Integer.toHexString(chr);
+ builder.append("\\u" + t.substring(t.length() - 4));
+ } else {
+ builder.append(chr);
+ }
+ break;
+ }
+ }
+ builder.append('"');
+ return builder.toString();
+ }
+
+ /**
+ * Encode text as UTF-8
+ *
+ * @param text the text to encode
+ *
+ * @return the encoded text, as UTF-8
+ */
+ private static String urlEncode(String text) throws UnsupportedEncodingException {
+ return URLEncoder.encode(text, "UTF-8");
+ }
+
+ /**
+ * Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics
+ * website. Plotters can be added to the graph object returned.
+ *
+ * @param name The name of the graph
+ *
+ * @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given
+ */
+ public Graph createGraph(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("Graph name cannot be null");
+ }
+ // Construct the graph object
+ Graph graph = new Graph(name);
+ // Now we can add our graph
+ this.graphs.add(graph);
+ // and return back
+ return graph;
+ }
+
+ /**
+ * Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend
+ *
+ * @param graph The name of the graph
+ */
+ public void addGraph(Graph graph) {
+ if (graph == null) {
+ throw new IllegalArgumentException("Graph cannot be null");
+ }
+ this.graphs.add(graph);
+ }
+
+ /**
+ * Start measuring statistics. This will immediately create an async repeating task as the plugin and send the
+ * initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200
+ * ticks.
+ *
+ * @return True if statistics measuring is running, otherwise false.
+ */
+ public boolean start() {
+ // Is metrics already running?
+ if (this.taskId != -1) {
+ return true;
+ }
+ // Begin hitting the server with glorious data
+ this.taskId = TaskManager.IMP.taskRepeatAsync(new Runnable() {
+ private boolean firstPost = true;
+ @Override
+ public void run() {
+ try {
+ postPlugin(!this.firstPost);
+ // After the first post we set firstPost to
+ // false
+ // Each post thereafter will be a ping
+ this.firstPost = false;
+ } catch (IOException e) {
+ e.printStackTrace();
+ if (Metrics.this.debug) {
+ plugin.getLogger().log(LogLevel.INFO, "[Metrics] " + e.getMessage());
+ }
+ }
+ }
+ }, PING_INTERVAL * 1200);
+ return true;
+ }
+
+ /**
+ * Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
+ *
+ * @throws java.io.IOException
+ */
+ public void enable() {
+ // Enable Task, if it is not running
+ if (this.taskId == -1) {
+ start();
+ }
+ }
+
+ /**
+ * Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
+ *
+ */
+ public void disable() {
+ // Disable Task, if it is running
+ if (this.taskId != -1) {
+ TaskManager.IMP.cancelTask(this.taskId);
+ this.taskId = -1;
+ }
+ }
+
+ /**
+ * Gets the File object of the config file that should be used to store
+ * data such as the GUID and opt-out status.
+ *
+ * @return the File object for the config file
+ */
+ public File getConfigFile() {
+ // I believe the easiest way to get the base folder (e.g craftbukkit set
+ // via -P) for plugins to use
+ // is to abuse the plugin object we already have
+ // plugin.getDataFolder() => base/plugins/PluginA/
+ // pluginsFolder => base/plugins/
+ // The base is not necessarily relative to the startup directory.
+ File pluginsFolder = this.plugin.getDataFolder().getParentFile();
+ // return => base/plugins/PluginMetrics/config.yml
+ return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml");
+ }
+
+ /**
+ * Generic method that posts a plugin to the metrics website.
+ */
+ private void postPlugin(boolean isPing) throws IOException {
+ // Server software specific section
+ PluginDescription description = this.plugin.getDescription();
+ String pluginName = description.getName();
+ boolean onlineMode = false;
+ String pluginVersion = description.getVersion();
+ String serverVersion = plugin.getServer().getNukkitVersion();
+ int playersOnline = plugin.getServer().getOnlinePlayers().size();
+ // END server software specific section -- all code below does not use
+ // any code outside of this class / Java
+ // Construct the post data
+ StringBuilder json = new StringBuilder(1024);
+ json.append('{');
+ // The plugin's description file containing all of the plugin data such as name, version, author, etc
+ appendJSONPair(json, "guid", this.guid);
+ appendJSONPair(json, "plugin_version", pluginVersion);
+ appendJSONPair(json, "server_version", serverVersion);
+ appendJSONPair(json, "players_online", Integer.toString(playersOnline));
+ // New data as of R6
+ String osname = System.getProperty("os.name");
+ String osarch = System.getProperty("os.arch");
+ String osversion = System.getProperty("os.version");
+ String java_version = System.getProperty("java.version");
+ int coreCount = Runtime.getRuntime().availableProcessors();
+ // normalize os arch .. amd64 -> x86_64
+ if (osarch.equals("amd64")) {
+ osarch = "x86_64";
+ }
+ appendJSONPair(json, "osname", osname);
+ appendJSONPair(json, "osarch", osarch);
+ appendJSONPair(json, "osversion", osversion);
+ appendJSONPair(json, "cores", Integer.toString(coreCount));
+ appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
+ appendJSONPair(json, "java_version", java_version);
+ // If we're pinging, append it
+ if (isPing) {
+ appendJSONPair(json, "ping", "1");
+ }
+ if (!this.graphs.isEmpty()) {
+ synchronized (this.graphs) {
+ json.append(',');
+ json.append('"');
+ json.append("graphs");
+ json.append('"');
+ json.append(':');
+ json.append('{');
+ boolean firstGraph = true;
+ for (Graph graph : this.graphs) {
+ StringBuilder graphJson = new StringBuilder();
+ graphJson.append('{');
+ for (Plotter plotter : graph.getPlotters()) {
+ appendJSONPair(graphJson, plotter.getColumnName(), Integer.toString(plotter.getValue()));
+ }
+ graphJson.append('}');
+ if (!firstGraph) {
+ json.append(',');
+ }
+ json.append(escapeJSON(graph.getName()));
+ json.append(':');
+ json.append(graphJson);
+ firstGraph = false;
+ }
+ json.append('}');
+ }
+ }
+ // close json
+ json.append('}');
+ // Create the url
+ URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
+ // Connect to the website
+ URLConnection connection;
+ // Mineshafter creates a socks proxy, so we can safely bypass it
+ // It does not reroute POST requests so we need to go around it
+ if (isMineshafterPresent()) {
+ connection = url.openConnection(Proxy.NO_PROXY);
+ } else {
+ connection = url.openConnection();
+ }
+ byte[] uncompressed = json.toString().getBytes();
+ byte[] compressed = gzip(json.toString());
+ // Headers
+ connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
+ connection.addRequestProperty("Content-Type", "application/json");
+ connection.addRequestProperty("Content-Encoding", "gzip");
+ connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
+ connection.addRequestProperty("Accept", "application/json");
+ connection.addRequestProperty("Connection", "close");
+ connection.setDoOutput(true);
+ if (this.debug) {
+ PS.debug("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length);
+ }
+ try {
+ try (OutputStream os = connection.getOutputStream()) {
+ os.write(compressed);
+ os.flush();
+ }
+ String response;
+ try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
+ response = reader.readLine();
+ if (this.debug) {
+ PS.debug("[Metrics] Response for " + pluginName + ": " + response);
+ }
+ }
+ if (response == null || response.startsWith("ERR") || response.startsWith("7")) {
+ if (response == null) {
+ response = "null";
+ } else if (response.startsWith("7")) {
+ response = response.substring(response.startsWith("7,") ? 2 : 1);
+ }
+ throw new IOException(response);
+ } else {
+ // Is this the first update this hour?
+ if ("1".equals(response) || response.contains("This is your first update this hour")) {
+ synchronized (this.graphs) {
+ for (Graph graph : this.graphs) {
+ for (Plotter plotter : graph.getPlotters()) {
+ plotter.reset();
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ if (this.debug) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Check if mineshafter is present. If it is, we need to bypass it to send POST requests
+ *
+ * @return true if mineshafter is installed on the server
+ */
+ private boolean isMineshafterPresent() {
+ try {
+ Class.forName("mineshafter.MineServer");
+ return true;
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Represents a custom graph on the website
+ */
+ public static class Graph {
+
+ /**
+ * The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is
+ * rejected
+ */
+ private final String name;
+ /**
+ * The set of plotters that are contained within this graph
+ */
+ private final Set plotters = new LinkedHashSet<>();
+
+ private Graph(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Gets the graph's name
+ *
+ * @return the Graph's name
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Add a plotter to the graph, which will be used to plot entries
+ *
+ * @param plotter the plotter to add to the graph
+ */
+ public void addPlotter(Plotter plotter) {
+ this.plotters.add(plotter);
+ }
+
+ /**
+ * Remove a plotter from the graph
+ *
+ * @param plotter the plotter to remove from the graph
+ */
+ public void removePlotter(Plotter plotter) {
+ this.plotters.remove(plotter);
+ }
+
+ /**
+ * Gets an unmodifiable set of the plotter objects in the graph
+ *
+ * @return an unmodifiable {@link java.util.Set} of the plotter objects
+ */
+ public Set getPlotters() {
+ return Collections.unmodifiableSet(this.plotters);
+ }
+
+ @Override
+ public int hashCode() {
+ return this.name.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof Graph)) {
+ return false;
+ }
+ Graph graph = (Graph) object;
+ return graph.name.equals(this.name);
+ }
+
+ /**
+ * Called when the server owner decides to opt-out of BukkitMetrics while the server is running.
+ */
+ protected void onOptOut() {
+ }
+ }
+
+ /**
+ * Interface used to collect custom data for a plugin
+ */
+ public abstract static class Plotter {
+
+ /**
+ * The plot's name
+ */
+ private final String name;
+
+ /**
+ * Construct a plotter with the default plot name
+ */
+ public Plotter() {
+ this("Default");
+ }
+
+ /**
+ * Construct a plotter with a specific plot name
+ *
+ * @param name the name of the plotter to use, which will show up on the website
+ */
+ public Plotter(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Get the current value for the plotted point. Since this function defers to an external function it may or may
+ * not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called
+ * from any thread so care should be taken when accessing resources that need to be synchronized.
+ *
+ * @return the current value for the point to be plotted.
+ */
+ public abstract int getValue();
+
+ /**
+ * Get the column name for the plotted point
+ *
+ * @return the plotted point's column name
+ */
+ public String getColumnName() {
+ return this.name;
+ }
+
+ /**
+ * Called after the website graphs have been updated
+ */
+ public void reset() {
+ }
+
+ @Override
+ public int hashCode() {
+ return getColumnName().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof Plotter)) {
+ return false;
+ }
+ Plotter plotter = (Plotter) object;
+ return plotter.name.equals(this.name) && plotter.getValue() == getValue();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitChunkManager.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitChunkManager.java
new file mode 100644
index 000000000..295b62697
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitChunkManager.java
@@ -0,0 +1,49 @@
+package com.plotsquared.nukkit.util;
+
+
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.object.ChunkLoc;
+import com.intellectualcrafters.plot.object.Location;
+import com.intellectualcrafters.plot.object.Plot;
+import com.intellectualcrafters.plot.util.ChunkManager;
+
+public class NukkitChunkManager extends ChunkManager {
+ public NukkitChunkManager() {
+ PS.debug("Not implemented: NukkitChunkManager");
+ }
+
+ @Override
+ public int[] countEntities(Plot plot) {
+ return new int[0];
+ }
+
+ @Override
+ public boolean loadChunk(String world, ChunkLoc loc, boolean force) {
+ return false;
+ }
+
+ @Override
+ public void unloadChunk(String world, ChunkLoc loc, boolean save, boolean safe) {
+
+ }
+
+ @Override
+ public boolean copyRegion(Location pos1, Location pos2, Location newPos, Runnable whenDone) {
+ return false;
+ }
+
+ @Override
+ public boolean regenerateRegion(Location pos1, Location pos2, boolean ignoreAugment, Runnable whenDone) {
+ return false;
+ }
+
+ @Override
+ public void clearAllEntities(Location pos1, Location pos2) {
+
+ }
+
+ @Override
+ public void swap(Location bot1, Location top1, Location bot2, Location top2, Runnable whenDone) {
+ whenDone.run();
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitCommand.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitCommand.java
new file mode 100644
index 000000000..5805daf6a
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitCommand.java
@@ -0,0 +1,28 @@
+package com.plotsquared.nukkit.util;
+
+import cn.nukkit.Player;
+import cn.nukkit.command.Command;
+import cn.nukkit.command.CommandSender;
+import cn.nukkit.command.ConsoleCommandSender;
+import cn.nukkit.command.RemoteConsoleCommandSender;
+import com.intellectualcrafters.plot.commands.MainCommand;
+import com.intellectualcrafters.plot.object.ConsolePlayer;
+
+public class NukkitCommand extends Command {
+
+ public NukkitCommand(String cmd, String[] aliases) {
+ super(cmd, "PlotSquared command", "/plot", aliases);
+ }
+
+
+ @Override
+ public boolean execute(CommandSender commandSender, String commandLabel, String[] args) {
+ if (commandSender instanceof Player) {
+ return MainCommand.onCommand(NukkitUtil.getPlayer((Player) commandSender), args);
+ }
+ if (commandSender instanceof ConsoleCommandSender || commandSender instanceof RemoteConsoleCommandSender) {
+ return MainCommand.onCommand(ConsolePlayer.getConsole(), args);
+ }
+ return false;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitEventUtil.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitEventUtil.java
new file mode 100644
index 000000000..24b1bbd5a
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitEventUtil.java
@@ -0,0 +1,138 @@
+package com.plotsquared.nukkit.util;
+
+import cn.nukkit.Player;
+import cn.nukkit.event.Cancellable;
+import cn.nukkit.event.Event;
+import com.intellectualcrafters.plot.flag.Flag;
+import com.intellectualcrafters.plot.object.Location;
+import com.intellectualcrafters.plot.object.Plot;
+import com.intellectualcrafters.plot.object.PlotArea;
+import com.intellectualcrafters.plot.object.PlotCluster;
+import com.intellectualcrafters.plot.object.PlotId;
+import com.intellectualcrafters.plot.object.PlotPlayer;
+import com.intellectualcrafters.plot.object.Rating;
+import com.intellectualcrafters.plot.util.EventUtil;
+import com.plotsquared.nukkit.NukkitMain;
+import com.plotsquared.nukkit.events.ClusterFlagRemoveEvent;
+import com.plotsquared.nukkit.events.PlayerClaimPlotEvent;
+import com.plotsquared.nukkit.events.PlayerEnterPlotEvent;
+import com.plotsquared.nukkit.events.PlayerLeavePlotEvent;
+import com.plotsquared.nukkit.events.PlayerPlotDeniedEvent;
+import com.plotsquared.nukkit.events.PlayerPlotHelperEvent;
+import com.plotsquared.nukkit.events.PlayerPlotTrustedEvent;
+import com.plotsquared.nukkit.events.PlayerTeleportToPlotEvent;
+import com.plotsquared.nukkit.events.PlotClearEvent;
+import com.plotsquared.nukkit.events.PlotComponentSetEvent;
+import com.plotsquared.nukkit.events.PlotDeleteEvent;
+import com.plotsquared.nukkit.events.PlotFlagAddEvent;
+import com.plotsquared.nukkit.events.PlotFlagRemoveEvent;
+import com.plotsquared.nukkit.events.PlotMergeEvent;
+import com.plotsquared.nukkit.events.PlotRateEvent;
+import com.plotsquared.nukkit.events.PlotUnlinkEvent;
+import com.plotsquared.nukkit.object.NukkitPlayer;
+import java.util.ArrayList;
+import java.util.UUID;
+
+public class NukkitEventUtil extends EventUtil {
+
+ private final NukkitMain plugin;
+
+ public NukkitEventUtil(NukkitMain plugin) {
+ this.plugin = plugin;
+ }
+
+ public Player getPlayer(PlotPlayer player) {
+ if (player instanceof NukkitPlayer) {
+ return ((NukkitPlayer) player).player;
+ }
+ return null;
+ }
+
+ public boolean callEvent(Event event) {
+ plugin.getServer().getPluginManager().callEvent(event);
+ return !(event instanceof Cancellable) || !((Cancellable) event).isCancelled();
+ }
+
+ @Override
+ public boolean callClaim(PlotPlayer player, Plot plot, boolean auto) {
+ return callEvent(new PlayerClaimPlotEvent(getPlayer(player), plot, auto));
+ }
+
+ @Override
+ public boolean callTeleport(PlotPlayer player, Location from, Plot plot) {
+ return callEvent(new PlayerTeleportToPlotEvent(getPlayer(player), from, plot));
+ }
+
+ @Override
+ public boolean callComponentSet(Plot plot, String component) {
+ return callEvent(new PlotComponentSetEvent(plot, component));
+ }
+
+ @Override
+ public boolean callClear(Plot plot) {
+ return callEvent(new PlotClearEvent(plot));
+ }
+
+ @Override
+ public void callDelete(Plot plot) {
+ callEvent(new PlotDeleteEvent(plot));
+ }
+
+ @Override
+ public boolean callFlagAdd(Flag flag, Plot plot) {
+ return callEvent(new PlotFlagAddEvent(flag, plot));
+ }
+
+ @Override
+ public boolean callFlagRemove(Flag> flag, Plot plot, Object value) {
+ return callEvent(new PlotFlagRemoveEvent(flag, plot));
+ }
+
+ @Override
+ public boolean callMerge(Plot plot, ArrayList plots) {
+ return callEvent(new PlotMergeEvent(NukkitUtil.getWorld(plot.getArea().worldname), plot, plots));
+ }
+
+ @Override
+ public boolean callUnlink(PlotArea area, ArrayList plots) {
+ return callEvent(new PlotUnlinkEvent(NukkitUtil.getWorld(area.worldname), area, plots));
+ }
+
+ @Override
+ public void callEntry(PlotPlayer player, Plot plot) {
+ callEvent(new PlayerEnterPlotEvent(getPlayer(player), plot));
+ }
+
+ @Override
+ public void callLeave(PlotPlayer player, Plot plot) {
+ callEvent(new PlayerLeavePlotEvent(getPlayer(player), plot));
+ }
+
+ @Override
+ public void callDenied(PlotPlayer initiator, Plot plot, UUID player, boolean added) {
+ callEvent(new PlayerPlotDeniedEvent(getPlayer(initiator), plot, player, added));
+ }
+
+ @Override
+ public void callTrusted(PlotPlayer initiator, Plot plot, UUID player, boolean added) {
+ callEvent(new PlayerPlotTrustedEvent(getPlayer(initiator), plot, player, added));
+ }
+
+ @Override
+ public void callMember(PlotPlayer initiator, Plot plot, UUID player, boolean added) {
+ callEvent(new PlayerPlotHelperEvent(getPlayer(initiator), plot, player, added));
+ }
+
+ @Override
+ public boolean callFlagRemove(Flag flag, Object object, PlotCluster cluster) {
+ return callEvent(new ClusterFlagRemoveEvent(flag, cluster));
+ }
+
+ @Override
+ public Rating callRating(PlotPlayer player, Plot plot, Rating rating) {
+ PlotRateEvent event = new PlotRateEvent(player, rating, plot);
+ plugin.getServer().getPluginManager().callEvent(event);
+ return event.getRating();
+ }
+
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitHybridUtils.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitHybridUtils.java
new file mode 100644
index 000000000..2436b67d7
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitHybridUtils.java
@@ -0,0 +1,19 @@
+package com.plotsquared.nukkit.util;
+
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.generator.HybridUtils;
+import com.intellectualcrafters.plot.object.RegionWrapper;
+import com.intellectualcrafters.plot.object.RunnableVal;
+import com.intellectualcrafters.plot.util.expiry.PlotAnalysis;
+
+public class NukkitHybridUtils extends HybridUtils {
+
+ public NukkitHybridUtils() {
+ PS.debug("Not implemented: NukkitHybridUtils");
+ }
+
+ @Override
+ public void analyzeRegion(final String world, final RegionWrapper region, final RunnableVal whenDone) {
+ throw new UnsupportedOperationException("NOT IMPLEMENTED YET");
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitInventoryUtil.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitInventoryUtil.java
new file mode 100644
index 000000000..741dc2014
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitInventoryUtil.java
@@ -0,0 +1,77 @@
+package com.plotsquared.nukkit.util;
+
+import cn.nukkit.inventory.PlayerInventory;
+import cn.nukkit.item.Item;
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.config.C;
+import com.intellectualcrafters.plot.object.PlotInventory;
+import com.intellectualcrafters.plot.object.PlotItemStack;
+import com.intellectualcrafters.plot.object.PlotPlayer;
+import com.intellectualcrafters.plot.util.InventoryUtil;
+import com.plotsquared.nukkit.object.NukkitPlayer;
+
+public class NukkitInventoryUtil extends InventoryUtil {
+
+ public NukkitInventoryUtil() {
+ PS.debug("Not implemented: NukkitInventoryUtil");
+ }
+
+ public static Item getItem(PlotItemStack item) {
+ if (item == null) {
+ return null;
+ }
+ Item stack = new Item(item.id, item.amount, item.data);
+ if (item.name != null) {
+ stack.setCustomName(C.color(item.name));
+ }
+ if (item.lore != null) {
+ // TODO not implemented
+ }
+ return stack;
+ }
+
+ @Override
+ public void open(PlotInventory inv) {
+ return; // TODO
+ }
+
+ @Override
+ public void close(PlotInventory inv) {
+ return; // TODO
+ }
+
+ @Override
+ public void setItem(PlotInventory inv, int index, PlotItemStack item) {
+ return; // TODO
+ }
+
+ public PlotItemStack getItem(Item item) {
+ if (item == null) {
+ return null;
+ }
+ int id = item.getId();
+ int data = item.getDamage();
+ int amount = item.count;
+ String name = item.getCustomName();
+ if (name.length() == 0) {
+ name = null;
+ }
+ return new PlotItemStack(id, (short) data, amount, name);
+ }
+
+ @Override
+ public PlotItemStack[] getItems(PlotPlayer player) {
+ NukkitPlayer bp = (NukkitPlayer) player;
+ PlayerInventory inv = bp.player.getInventory();
+ PlotItemStack[] items = new PlotItemStack[36];
+ for (int i = 0; i < 36; i++) {
+ items[i] = getItem(inv.getItem(i));
+ }
+ return items;
+ }
+
+ @Override
+ public boolean isOpen(PlotInventory inv) {
+ return false; // TODO
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitSchematicHandler.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitSchematicHandler.java
new file mode 100644
index 000000000..f8b2aec6a
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitSchematicHandler.java
@@ -0,0 +1,186 @@
+package com.plotsquared.nukkit.util;
+
+import cn.nukkit.block.Block;
+import cn.nukkit.level.Level;
+import cn.nukkit.level.format.generic.BaseFullChunk;
+import cn.nukkit.math.Vector3;
+import com.intellectualcrafters.jnbt.ByteArrayTag;
+import com.intellectualcrafters.jnbt.CompoundTag;
+import com.intellectualcrafters.jnbt.IntTag;
+import com.intellectualcrafters.jnbt.ListTag;
+import com.intellectualcrafters.jnbt.ShortTag;
+import com.intellectualcrafters.jnbt.StringTag;
+import com.intellectualcrafters.jnbt.Tag;
+import com.intellectualcrafters.plot.object.ChunkLoc;
+import com.intellectualcrafters.plot.object.Location;
+import com.intellectualcrafters.plot.object.RegionWrapper;
+import com.intellectualcrafters.plot.object.RunnableVal;
+import com.intellectualcrafters.plot.util.MainUtil;
+import com.intellectualcrafters.plot.util.SchematicHandler;
+import com.intellectualcrafters.plot.util.TaskManager;
+import com.intellectualcrafters.plot.util.block.LocalBlockQueue;
+import com.plotsquared.nukkit.NukkitMain;
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Schematic Handler.
+ */
+public class NukkitSchematicHandler extends SchematicHandler {
+
+ private final NukkitMain plugin;
+
+ public NukkitSchematicHandler(NukkitMain plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public void getCompoundTag(final String world, final Set regions, final RunnableVal whenDone) {
+ // async
+ TaskManager.runTaskAsync(new Runnable() {
+ @Override
+ public void run() {
+ // Main positions
+ Location[] corners = MainUtil.getCorners(world, regions);
+ final Location bot = corners[0];
+ Location top = corners[1];
+
+ final int width = top.getX() - bot.getX() + 1;
+ int height = top.getY() - bot.getY() + 1;
+ final int length = top.getZ() - bot.getZ() + 1;
+ // Main Schematic tag
+ final HashMap schematic = new HashMap<>();
+ schematic.put("Width", new ShortTag("Width", (short) width));
+ schematic.put("Length", new ShortTag("Length", (short) length));
+ schematic.put("Height", new ShortTag("Height", (short) height));
+ schematic.put("Materials", new StringTag("Materials", "Alpha"));
+ schematic.put("WEOriginX", new IntTag("WEOriginX", 0));
+ schematic.put("WEOriginY", new IntTag("WEOriginY", 0));
+ schematic.put("WEOriginZ", new IntTag("WEOriginZ", 0));
+ schematic.put("WEOffsetX", new IntTag("WEOffsetX", 0));
+ schematic.put("WEOffsetY", new IntTag("WEOffsetY", 0));
+ schematic.put("WEOffsetZ", new IntTag("WEOffsetZ", 0));
+ // Arrays of data types
+ final List tileEntities = new ArrayList<>();
+ final byte[] blocks = new byte[width * height * length];
+ final byte[] blockData = new byte[width * height * length];
+ // Queue
+ final ArrayDeque queue = new ArrayDeque<>(regions);
+ TaskManager.runTask(new Runnable() {
+ @Override
+ public void run() {
+ if (queue.isEmpty()) {
+ TaskManager.runTaskAsync(new Runnable() {
+ @Override
+ public void run() {
+ schematic.put("Blocks", new ByteArrayTag("Blocks", blocks));
+ schematic.put("Data", new ByteArrayTag("Data", blockData));
+ schematic.put("Entities", new ListTag("Entities", CompoundTag.class, new ArrayList()));
+ schematic.put("TileEntities", new ListTag("TileEntities", CompoundTag.class, tileEntities));
+ whenDone.value = new CompoundTag("Schematic", schematic);
+ TaskManager.runTask(whenDone);
+ System.gc();
+ System.gc();
+ }
+ });
+ return;
+ }
+ final Runnable regionTask = this;
+ RegionWrapper region = queue.poll();
+ Location pos1 = new Location(world, region.minX, region.minY, region.minZ);
+ Location pos2 = new Location(world, region.maxX, region.maxY, region.maxZ);
+ final int bx = bot.getX();
+ final int bz = bot.getZ();
+ final int p1x = pos1.getX();
+ final int p1z = pos1.getZ();
+ final int p2x = pos2.getX();
+ final int p2z = pos2.getZ();
+ final int bcx = p1x >> 4;
+ final int bcz = p1z >> 4;
+ final int tcx = p2x >> 4;
+ final int tcz = p2z >> 4;
+ final int sy = pos1.getY();
+ final int ey = pos2.getY();
+ // Generate list of chunks
+ final ArrayList chunks = new ArrayList<>();
+ for (int x = bcx; x <= tcx; x++) {
+ for (int z = bcz; z <= tcz; z++) {
+ chunks.add(new ChunkLoc(x, z));
+ }
+ }
+ final Level worldObj = plugin.getServer().getLevelByName(world);
+ // Main thread
+ final Vector3 mutable = new Vector3();
+ TaskManager.runTask(new Runnable() {
+ @Override
+ public void run() {
+ long start = System.currentTimeMillis();
+ while (!chunks.isEmpty() && System.currentTimeMillis() - start < 20) {
+ // save schematics
+ ChunkLoc chunk = chunks.remove(0);
+ BaseFullChunk bc = worldObj.getChunk(chunk.x, chunk.z);
+ try {
+ bc.load(false);
+ } catch (IOException e) {
+ continue;
+ }
+ int X = chunk.x;
+ int Z = chunk.z;
+ int xxb = X << 4;
+ int zzb = Z << 4;
+ int xxt = xxb + 15;
+ int zzt = zzb + 15;
+
+ if (X == bcx) {
+ xxb = p1x;
+ }
+ if (X == tcx) {
+ xxt = p2x;
+ }
+ if (Z == bcz) {
+ zzb = p1z;
+ }
+ if (Z == tcz) {
+ zzt = p2z;
+ }
+ for (int y = sy; y <= Math.min(255, ey); y++) {
+ int ry = y - sy;
+ int i1 = ry * width * length;
+ for (int z = zzb; z <= zzt; z++) {
+ int rz = z - bz;
+ int i2 = i1 + rz * width;
+ for (int x = xxb; x <= xxt; x++) {
+ int rx = x - bx;
+ int index = i2 + rx;
+ mutable.x = x;
+ mutable.y = y;
+ mutable.z = z;
+ Block block = worldObj.getBlock(mutable);
+ blocks[index] = (byte) block.getId();
+ blockData[index] = (byte) block.getDamage();
+ }
+ }
+ }
+ }
+ if (!chunks.isEmpty()) {
+ TaskManager.runTaskLater(this, 1);
+ } else {
+ regionTask.run();
+ }
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+
+ @Override
+ public boolean restoreTile(LocalBlockQueue queue, CompoundTag ct, int x, int y, int z) {
+ return false;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitSetupUtils.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitSetupUtils.java
new file mode 100644
index 000000000..4e8e999be
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitSetupUtils.java
@@ -0,0 +1,169 @@
+package com.plotsquared.nukkit.util;
+
+import cn.nukkit.level.Level;
+import cn.nukkit.level.generator.Generator;
+import com.intellectualcrafters.configuration.ConfigurationSection;
+import com.intellectualcrafters.configuration.file.YamlConfiguration;
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.config.ConfigurationNode;
+import com.intellectualcrafters.plot.generator.GeneratorWrapper;
+import com.intellectualcrafters.plot.generator.HybridGen;
+import com.intellectualcrafters.plot.object.PlotArea;
+import com.intellectualcrafters.plot.object.SetupObject;
+import com.intellectualcrafters.plot.util.SetupUtils;
+import com.plotsquared.nukkit.NukkitMain;
+import com.plotsquared.nukkit.generator.NukkitPlotGenerator;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map.Entry;
+import java.util.Objects;
+
+public class NukkitSetupUtils extends SetupUtils {
+
+ private final NukkitMain plugin;
+
+ public NukkitSetupUtils(NukkitMain plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public void updateGenerators() {
+ if (!SetupUtils.generators.isEmpty()) {
+ return;
+ }
+ String testWorld = "CheckingPlotSquaredGenerator";
+ HashMap map = new HashMap();
+ map.put("world", testWorld);
+ map.put("plot-generator", new HybridGen());
+ NukkitPlotGenerator gen = new NukkitPlotGenerator(map);
+ SetupUtils.generators.put("PlotSquared", gen);
+ }
+
+ @Override
+ public String setupWorld(SetupObject object) {
+ SetupUtils.manager.updateGenerators();
+ ConfigurationNode[] steps = object.step == null ? new ConfigurationNode[0] : object.step;
+ String world = object.world;
+ int type = object.type;
+ String worldPath = "worlds." + object.world;
+ if (!PS.get().worlds.contains(worldPath)) {
+ PS.get().worlds.createSection(worldPath);
+ }
+ ConfigurationSection worldSection = PS.get().worlds.getConfigurationSection(worldPath);
+ switch (type) {
+ case 2: {
+ if (object.id != null) {
+ String areaName = object.id + "-" + object.min + "-" + object.max;
+ String areaPath = "areas." + areaName;
+ if (!worldSection.contains(areaPath)) {
+ worldSection.createSection(areaPath);
+ }
+ ConfigurationSection areaSection = worldSection.getConfigurationSection(areaPath);
+ HashMap options = new HashMap<>();
+ for (ConfigurationNode step : steps) {
+ options.put(step.getConstant(), step.getValue());
+ }
+ options.put("generator.type", object.type);
+ options.put("generator.terrain", object.terrain);
+ options.put("generator.plugin", object.plotManager);
+ if (object.setupGenerator != null && !object.setupGenerator.equals(object.plotManager)) {
+ options.put("generator.init", object.setupGenerator);
+ }
+ for (Entry entry : options.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ if (worldSection.contains(key)) {
+ Object current = worldSection.get(key);
+ if (!Objects.equals(value, current)) {
+ areaSection.set(key, value);
+ }
+ } else {
+ worldSection.set(key, value);
+ }
+ }
+ }
+ GeneratorWrapper> gen = SetupUtils.generators.get(object.setupGenerator);
+ if (gen != null && gen.isFull()) {
+ object.setupGenerator = null;
+ }
+ break;
+ }
+ case 1:
+ for (ConfigurationNode step : steps) {
+ worldSection.set(step.getConstant(), step.getValue());
+ }
+ PS.get().worlds.set("worlds." + world + ".generator.type", object.type);
+ PS.get().worlds.set("worlds." + world + ".generator.terrain", object.terrain);
+ PS.get().worlds.set("worlds." + world + ".generator.plugin", object.plotManager);
+ if (object.setupGenerator != null && !object.setupGenerator.equals(object.plotManager)) {
+ PS.get().worlds.set("worlds." + world + ".generator.init", object.setupGenerator);
+ }
+ GeneratorWrapper> gen = SetupUtils.generators.get(object.setupGenerator);
+ if (gen != null && gen.isFull()) {
+ object.setupGenerator = null;
+ }
+ break;
+ case 0:
+ for (ConfigurationNode step : steps) {
+ worldSection.set(step.getConstant(), step.getValue());
+ }
+ break;
+ }
+ try {
+ PS.get().worlds.save(PS.get().worldsFile);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ if (object.setupGenerator != null) {
+ HashMap map = new HashMap();
+ map.put("world", object.world);
+ map.put("plot-generator", new HybridGen());
+ plugin.getServer().generateLevel(object.world, object.world.hashCode(), NukkitPlotGenerator.class, map);
+ } else {
+ plugin.getServer().generateLevel(object.world, object.world.hashCode());
+ }
+ return object.world;
+ }
+
+ public void setGenerator(String world, String generator) {
+ File file = new File("nukkit.yml").getAbsoluteFile();
+ YamlConfiguration yml = YamlConfiguration.loadConfiguration(file);
+ yml.set("worlds." + world + ".generator", generator);
+ try {
+ yml.save(file);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public String getGenerator(PlotArea plotArea) {
+ if (SetupUtils.generators.isEmpty()) {
+ updateGenerators();
+ }
+ Level world = NukkitUtil.getWorld(plotArea.worldname);
+ if (world == null) {
+ return null;
+ }
+ try {
+ Field field = Level.class.getDeclaredField("generatorInstance");
+ field.setAccessible(true);
+ Generator generator = (Generator) field.get(world);
+ if (!(generator instanceof NukkitPlotGenerator)) {
+ return null;
+ }
+ for (Entry> entry : SetupUtils.generators.entrySet()) {
+ GeneratorWrapper> current = entry.getValue();
+ if (current.equals(generator)) {
+ return entry.getKey();
+ }
+ }
+ return "PlotSquared";
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitTaskManager.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitTaskManager.java
new file mode 100644
index 000000000..2fa1a4440
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitTaskManager.java
@@ -0,0 +1,68 @@
+package com.plotsquared.nukkit.util;
+
+import cn.nukkit.scheduler.TaskHandler;
+import com.intellectualcrafters.plot.util.TaskManager;
+import com.plotsquared.nukkit.NukkitMain;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class NukkitTaskManager extends TaskManager {
+
+ private final NukkitMain plugin;
+
+ public NukkitTaskManager(NukkitMain bukkitMain) {
+ this.plugin = bukkitMain;
+ }
+
+ private AtomicInteger index = new AtomicInteger(0);
+ private HashMap tasks = new HashMap<>();
+
+ @Override
+ public int taskRepeat(Runnable r, int interval) {
+ TaskHandler task = this.plugin.getServer().getScheduler().scheduleRepeatingTask(r, interval, false);
+ return task.getTaskId();
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ public int taskRepeatAsync(Runnable r, int interval) {
+ TaskHandler task = this.plugin.getServer().getScheduler().scheduleRepeatingTask(r, interval, true);
+ return task.getTaskId();
+ }
+
+ @Override
+ public void taskAsync(Runnable r) {
+ if (r == null) {
+ return;
+ }
+ this.plugin.getServer().getScheduler().scheduleTask(r, true);
+ }
+
+ @Override
+ public void task(Runnable r) {
+ if (r == null) {
+ return;
+ }
+ this.plugin.getServer().getScheduler().scheduleTask(r, false);
+ }
+
+ @Override
+ public void taskLater(Runnable r, int delay) {
+ if (r == null) {
+ return;
+ }
+ this.plugin.getServer().getScheduler().scheduleDelayedTask(r, delay);
+ }
+
+ @Override
+ public void taskLaterAsync(Runnable r, int delay) {
+ this.plugin.getServer().getScheduler().scheduleDelayedTask(r, delay, true);
+ }
+
+ @Override
+ public void cancelTask(int task) {
+ if (task != -1) {
+ this.plugin.getServer().getScheduler().cancelTask(task);
+ }
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitUtil.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitUtil.java
new file mode 100644
index 000000000..21c635500
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/NukkitUtil.java
@@ -0,0 +1,292 @@
+package com.plotsquared.nukkit.util;
+
+import cn.nukkit.OfflinePlayer;
+import cn.nukkit.Player;
+import cn.nukkit.block.Block;
+import cn.nukkit.block.BlockWallSign;
+import cn.nukkit.blockentity.BlockEntity;
+import cn.nukkit.blockentity.BlockEntitySign;
+import cn.nukkit.entity.Entity;
+import cn.nukkit.item.Item;
+import cn.nukkit.level.Level;
+import cn.nukkit.level.Position;
+import cn.nukkit.level.generator.biome.Biome;
+import cn.nukkit.math.Vector3;
+import com.intellectualcrafters.plot.object.Location;
+import com.intellectualcrafters.plot.object.PlotBlock;
+import com.intellectualcrafters.plot.object.PlotPlayer;
+import com.intellectualcrafters.plot.object.RegionWrapper;
+import com.intellectualcrafters.plot.object.schematic.PlotItem;
+import com.intellectualcrafters.plot.util.MathMan;
+import com.intellectualcrafters.plot.util.StringComparison;
+import com.intellectualcrafters.plot.util.StringMan;
+import com.intellectualcrafters.plot.util.UUIDHandler;
+import com.intellectualcrafters.plot.util.WorldUtil;
+import com.plotsquared.nukkit.NukkitMain;
+import com.plotsquared.nukkit.object.NukkitPlayer;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+
+public class NukkitUtil extends WorldUtil {
+
+ private static String lastString = null;
+ private static Level lastWorld = null;
+
+ private static Player lastPlayer = null;
+ private static PlotPlayer lastPlotPlayer = null;
+ private static NukkitMain plugin;
+
+ public NukkitUtil(NukkitMain plugin) {
+ this.plugin = plugin;
+ }
+
+ public static void removePlayer(String player) {
+ lastPlayer = null;
+ lastPlotPlayer = null;
+ }
+
+ public static PlotPlayer getPlayer(OfflinePlayer op) {
+ if (op.isOnline()) {
+ return getPlayer(op.getPlayer());
+ }
+ return null;
+ }
+
+ public static PlotPlayer getPlayer(Player player) {
+ if (player == lastPlayer) {
+ return lastPlotPlayer;
+ }
+ String name = player.getName();
+ PlotPlayer plotPlayer = UUIDHandler.getPlayer(name);
+ if (plotPlayer != null) {
+ return plotPlayer;
+ }
+ lastPlotPlayer = new NukkitPlayer(player);
+ UUIDHandler.getPlayers().put(name, lastPlotPlayer);
+ lastPlayer = player;
+ return lastPlotPlayer;
+ }
+
+ public static Location getLocation(cn.nukkit.level.Location location) {
+ return new Location(location.getLevel().getName(), MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()),
+ MathMan.roundInt(location.getZ()));
+ }
+
+ public static Location getLocation(cn.nukkit.level.Position location) {
+ return new Location(location.getLevel().getName(), MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()),
+ MathMan.roundInt(location.getZ()));
+ }
+
+ public static cn.nukkit.level.Location getLocation(Location location) {
+ return new cn.nukkit.level.Location(location.getX(), location.getY(), location.getZ(), 0, 0, getWorld(location.getWorld()));
+ }
+
+ public static Level getWorld(String string) {
+ if (StringMan.isEqual(string, lastString)) {
+ if (lastWorld != null) {
+ return lastWorld;
+ }
+ }
+ Level world = plugin.getServer().getLevelByName(string);
+ lastString = string;
+ lastWorld = world;
+ return world;
+ }
+
+ public static String getWorld(Entity entity) {
+ return entity.getLevel().getName();
+ }
+
+ public static Entity[] getEntities(String worldName) {
+ return getWorld(worldName).getEntities();
+ }
+
+ public static Location getLocation(Entity entity) {
+ cn.nukkit.level.Location location = entity.getLocation();
+ String world = location.getLevel().getName();
+ return new Location(world, location.getFloorX(), location.getFloorY(), location.getFloorZ());
+ }
+
+ public static Location getLocationFull(Entity entity) {
+ cn.nukkit.level.Location location = entity.getLocation();
+ return new Location(location.getLevel().getName(), MathMan.roundInt(location.getX()), MathMan.roundInt(location.getY()), MathMan.roundInt(location.getZ()),
+ (float) location.getYaw(), (float) location.getPitch());
+ }
+
+ @Override
+ public boolean isWorld(String worldName) {
+ return getWorld(worldName) != null;
+ }
+
+ @Override
+ public String getBiome(String world, int x, int z) {
+ int id = getWorld(world).getBiomeId(x, z);
+ return Biome.getBiome(id).getName();
+ }
+
+ @Override
+ public void setSign(String worldName, int x, int y, int z, String[] lines) {
+ Level world = getWorld(worldName);
+ BlockWallSign sign = new BlockWallSign(0);
+ Vector3 pos = new Vector3(x, y, z);
+ world.setBlock(pos, sign);
+ BlockEntity tile = world.getBlockEntity(pos);
+ if (tile instanceof BlockEntitySign) {
+ ((BlockEntitySign) tile).setText(lines[0], lines[1], lines[2], lines[3]);
+ tile.scheduleUpdate();
+ }
+ }
+
+ @Override
+ public String[] getSign(Location location) {
+ Level world = getWorld(location.getWorld());
+ Vector3 pos = new Vector3(location.getX(), location.getY(), location.getZ());
+ BlockEntity tile = world.getBlockEntity(pos);
+ if (tile instanceof BlockEntitySign) {
+ return ((BlockEntitySign) tile).getText();
+ }
+ return null;
+ }
+
+ @Override
+ public Location getSpawn(PlotPlayer player) {
+ return getLocation(((NukkitPlayer) player).player.getSpawn());
+ }
+
+ @Override
+ public Location getSpawn(String world) {
+ Position loc = getWorld(world).getSpawnLocation();
+ return new Location(world, loc.getFloorX(), loc.getFloorY(), loc.getFloorZ(), 0, 0);
+ }
+
+ @Override
+ public void setSpawn(Location location) {
+ Level world = getWorld(location.getWorld());
+ if (world != null) {
+ world.setSpawnLocation(new Vector3(location.getX(), location.getY(), location.getZ()));
+ }
+ }
+
+ @Override
+ public void saveWorld(String worldName) {
+ Level world = getWorld(worldName);
+ if (world != null) {
+ world.save();
+ }
+ }
+
+ @Override
+ public int getHighestBlock(String world, int x, int z) {
+ return getWorld(world).getHeightMap(x, z);
+ }
+
+ @Override
+ public int getBiomeFromString(String biomeString) {
+ try {
+ Biome biome = Biome.getBiome(biomeString.toUpperCase());
+ return biome.getId();
+ } catch (Throwable ignored) {
+ return -1;
+ }
+ }
+
+ @Override
+ public String[] getBiomeList() {
+ ArrayList biomes = new ArrayList<>();
+ for (Field field : Biome.class.getDeclaredFields()) {
+ if (field.getName().equals(field.getName().toUpperCase())) {
+ biomes.add(field.getName());
+ }
+ }
+ return biomes.toArray(new String[biomes.size()]);
+ }
+
+ @Override
+ public boolean addItems(String worldName, PlotItem items) {
+ return false;
+ }
+
+ @Override
+ public boolean isBlockSolid(PlotBlock block) {
+ try {
+ Item item = Item.get(block.id, (int) block.data);
+ return (item != null && item.canBePlaced() && !Block.transparent[item.getId()] && Block.solid[item.getId()]);
+ } catch (Exception ignored) {
+ ignored.printStackTrace();
+ return false;
+ }
+ }
+
+ @Override
+ public String getClosestMatchingName(PlotBlock block) {
+ try {
+ return Item.get(block.id, (int) block.data).getName();
+ } catch (Exception ignored) {
+ return null;
+ }
+ }
+
+ @Override
+ public StringComparison.ComparisonResult getClosestBlock(String name) {
+ try {
+ Item item = Item.fromString(name);
+ return new StringComparison().new ComparisonResult(0, PlotBlock.get(item.getId(), item.getDamage()));
+ } catch (IllegalArgumentException ignored) {}
+ try {
+ byte data;
+ String[] split = name.split(":");
+ if (split.length == 2) {
+ data = Byte.parseByte(split[1]);
+ name = split[0];
+ } else {
+ data = 0;
+ }
+ double match;
+ short id;
+ if (MathMan.isInteger(split[0])) {
+ id = Short.parseShort(split[0]);
+ match = 0;
+ } else {
+ StringComparison- .ComparisonResult comparison = new StringComparison<>(name, Item.getCreativeItems()).getBestMatchAdvanced();
+ match = comparison.match;
+ id = (short) comparison.best.getId();
+ }
+ PlotBlock block = PlotBlock.get(id, data);
+ StringComparison outer = new StringComparison<>();
+ return outer.new ComparisonResult(match, block);
+
+ } catch (NumberFormatException ignored) {}
+ return null;
+ }
+
+ @Override
+ public void setBiomes(String worldName, RegionWrapper region, String biomeString) {
+ Level world = getWorld(worldName);
+ try {
+ int biome = (int) Biome.class.getDeclaredField(biomeString.toUpperCase()).get(null);
+ for (int x = region.minX; x <= region.maxX; x++) {
+ for (int z = region.minZ; z <= region.maxZ; z++) {
+ world.setBiomeId(x, z, biome);
+ }
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public PlotBlock getBlock(Location location) {
+ Level world = getWorld(location.getWorld());
+ int id = world.getBlockIdAt(location.getX(), location.getY(), location.getZ());
+ if (id == 0) {
+ return PlotBlock.get(0, 0);
+ }
+ int data = world.getBlockDataAt(location.getX(), location.getY(), location.getZ());
+ return PlotBlock.get(id, data);
+ }
+
+ @Override
+ public String getMainWorld() {
+ return plugin.getServer().getDefaultLevel().getName();
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/block/NukkitHybridGen.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/block/NukkitHybridGen.java
new file mode 100644
index 000000000..ee72b62bb
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/block/NukkitHybridGen.java
@@ -0,0 +1,30 @@
+package com.plotsquared.nukkit.util.block;
+
+import cn.nukkit.level.Level;
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.generator.HybridGen;
+import com.plotsquared.nukkit.NukkitMain;
+import com.plotsquared.nukkit.generator.NukkitPlotGenerator;
+import java.util.Map;
+
+public class NukkitHybridGen extends NukkitPlotGenerator {
+ public NukkitHybridGen(Map settings) {
+ super(defaultSettings(settings));
+ }
+
+ private static Map defaultSettings(Map existing) {
+ if (!existing.containsKey("world")) {
+ Map levels = ((NukkitMain) PS.get().IMP).getServer().getLevels();
+ int max = -1;
+ for (Map.Entry entry : levels.entrySet()) {
+ int id = entry.getKey();
+ if (id > max) {
+ max = id;
+ existing.put("world", entry.getValue().getName());
+ }
+ }
+ }
+ existing.put("plot-generator", new HybridGen());
+ return existing;
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/block/NukkitLocalQueue.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/block/NukkitLocalQueue.java
new file mode 100644
index 000000000..d19e74db8
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/block/NukkitLocalQueue.java
@@ -0,0 +1,125 @@
+package com.plotsquared.nukkit.util.block;
+
+import cn.nukkit.block.Block;
+import cn.nukkit.level.Level;
+import cn.nukkit.level.format.FullChunk;
+import cn.nukkit.level.format.generic.BaseFullChunk;
+import cn.nukkit.level.generator.biome.Biome;
+import cn.nukkit.math.Vector3;
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.object.PlotBlock;
+import com.intellectualcrafters.plot.util.StringMan;
+import com.intellectualcrafters.plot.util.block.BasicLocalBlockQueue;
+import com.plotsquared.nukkit.NukkitMain;
+
+public class NukkitLocalQueue extends BasicLocalBlockQueue {
+
+ private final Level level;
+
+ public NukkitLocalQueue(String world) {
+ super(world);
+ this.level = ((NukkitMain) PS.get().IMP).getServer().getLevelByName(world);
+ }
+
+ @Override
+ public LocalChunk getLocalChunk(int x, int z) {
+ return (LocalChunk) new BasicLocalChunk(this, x, z) {
+ // Custom stuff?
+ };
+ }
+
+ @Override
+ public void optimize() {
+
+ }
+
+ @Override
+ public PlotBlock getBlock(int x, int y, int z) {
+ Block block = level.getBlock(getMut(x, y, z));
+ if (block == null) {
+ return PlotBlock.get(0, 0);
+ }
+ int id = block.getId();
+ if (id == 0) {
+ return PlotBlock.get(0, 0);
+ }
+ return PlotBlock.get(id, block.getDamage());
+ }
+
+ @Override
+ public void refreshChunk(int x, int z) {
+
+ }
+
+ @Override
+ public void fixChunkLighting(int x, int z) {
+ // Do nothing
+ }
+
+ @Override
+ public final void regenChunk(int x, int z) {
+ level.regenerateChunk(x, z);
+ }
+
+ @Override
+ public final void setComponents(LocalChunk lc) {
+ setBlocks(lc);
+ setBiomes(lc);
+ }
+
+ public BaseFullChunk getChunk(int x, int z) {
+ return level.getChunk(x, z);
+ }
+
+ private Vector3 mutable;
+ private Vector3 getMut(int x, int y, int z) {
+ mutable.x = x;
+ mutable.y = y;
+ mutable.z = z;
+ return mutable;
+ }
+
+ public void setBlocks(LocalChunk lc) {
+ FullChunk chunk = level.getChunk(lc.getX(), lc.getZ(), true);
+ for (int layer = 0; layer < lc.blocks.length; layer++) {
+ PlotBlock[] blocksLayer = (PlotBlock[]) lc.blocks[layer];
+ if (blocksLayer != null) {
+ int by = layer << 4;
+ int j = 0;
+ for (int y = by; y < by + 16; y++) {
+ for (int z = 0; z < 16; z++) {
+ for (int x = 0; x < 16; x++, j++) {
+ PlotBlock block = blocksLayer[j];
+ if (block != null) {
+ chunk.setBlock(x, y, z, (int) block.id, (int) block.data);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void setBiomes(LocalChunk lc) {
+ if (lc.biomes != null) {
+ int bx = lc.getX() << 4;
+ int bz = lc.getX() << 4;
+ String last = null;
+ int biome = -1;
+ 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];
+ if (biomeStr != null) {
+ if (last == null || !StringMan.isEqual(last, biomeStr)) {
+ biome = Biome.getBiome(biomeStr.toUpperCase()).getId();
+ }
+ level.setBiomeId(bx + x, bz + y, biome);
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/util/block/NukkitWrappedChunk.java b/Nukkit/src/main/java/com/plotsquared/nukkit/util/block/NukkitWrappedChunk.java
new file mode 100644
index 000000000..6daf07f67
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/util/block/NukkitWrappedChunk.java
@@ -0,0 +1,93 @@
+package com.plotsquared.nukkit.util.block;
+
+import cn.nukkit.level.format.generic.BaseFullChunk;
+import cn.nukkit.level.generator.biome.Biome;
+import com.intellectualcrafters.plot.object.Location;
+import com.intellectualcrafters.plot.object.PlotBlock;
+import com.intellectualcrafters.plot.util.block.ScopedLocalBlockQueue;
+import java.awt.Color;
+
+public class NukkitWrappedChunk extends ScopedLocalBlockQueue {
+ private final String world;
+ private BaseFullChunk chunk;
+
+ public NukkitWrappedChunk(String world, BaseFullChunk chunk) {
+ super(null, new Location(null, 0, 0, 0), new Location(null, 15, 127, 15));
+ this.world = world;
+ init(chunk);
+ }
+
+ public void init(BaseFullChunk chunk) {
+ this.chunk = chunk;
+ }
+
+ @Override
+ public boolean setBlock(int x, int y, int z, int id, int data) {
+ chunk.setBlock(x, y, z, id, data);
+ return true;
+ }
+
+ @Override
+ public PlotBlock getBlock(int x, int y, int z) {
+ int id = chunk.getBlockId(x, y, z);
+ if (id == 0) {
+ return PlotBlock.get(0, 0);
+ }
+ int data = chunk.getBlockData(x, y, z);
+ return PlotBlock.get(id, data);
+ }
+
+ @Override
+ public boolean setBiome(int x, int z, String biome) {
+ Biome b = Biome.getBiome(biome);
+ int id = b.getId();
+ Color color = new Color(b.getColor());
+ chunk.setBiomeId(x, z, id);
+ chunk.setBiomeColor(x, z, color.getRed(), color.getGreen(), color.getBlue());
+ return true;
+ }
+
+ @Override
+ public void fillBiome(String biome) {
+ Biome b = Biome.getBiome(biome);
+ int id = b.getId();
+ Color color = new Color(b.getColor());
+ for (int x = 0; x < 16; x++) {
+ for (int z = 0; z < 16; z++) {
+ chunk.setBiomeId(x, z, id);
+ chunk.setBiomeColor(x, z, color.getRed(), color.getGreen(), color.getBlue());
+ }
+ }
+ }
+
+ @Override
+ public String getWorld() {
+ return world;
+ }
+
+ public int getX() {
+ return chunk.getX();
+ }
+
+ public int getZ() {
+ return chunk.getZ();
+ }
+
+ @Override
+ public Location getMax() {
+ return new Location(getWorld(), 15 + (getX() << 4), 255, 15 + (getZ() << 4));
+ }
+
+ @Override
+ public Location getMin() {
+ return new Location(getWorld(), getX() << 4, 0, getZ() << 4);
+ }
+
+ public NukkitWrappedChunk clone() {
+ return new NukkitWrappedChunk(world, chunk);
+ }
+
+ public NukkitWrappedChunk shallowClone() {
+ return new NukkitWrappedChunk(world, chunk);
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/uuid/DatFileFilter.java b/Nukkit/src/main/java/com/plotsquared/nukkit/uuid/DatFileFilter.java
new file mode 100644
index 000000000..c2bb3b938
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/uuid/DatFileFilter.java
@@ -0,0 +1,12 @@
+package com.plotsquared.nukkit.uuid;
+
+import java.io.File;
+import java.io.FilenameFilter;
+
+public class DatFileFilter implements FilenameFilter {
+
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".dat");
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/uuid/FileUUIDHandler.java b/Nukkit/src/main/java/com/plotsquared/nukkit/uuid/FileUUIDHandler.java
new file mode 100644
index 000000000..5260da4c9
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/uuid/FileUUIDHandler.java
@@ -0,0 +1,63 @@
+package com.plotsquared.nukkit.uuid;
+
+import com.google.common.collect.HashBiMap;
+import com.intellectualcrafters.plot.PS;
+import com.intellectualcrafters.plot.config.C;
+import com.intellectualcrafters.plot.object.RunnableVal;
+import com.intellectualcrafters.plot.object.StringWrapper;
+import com.intellectualcrafters.plot.util.TaskManager;
+import com.intellectualcrafters.plot.util.UUIDHandlerImplementation;
+import com.intellectualcrafters.plot.util.expiry.ExpireManager;
+import com.intellectualcrafters.plot.uuid.UUIDWrapper;
+import java.io.File;
+import java.util.HashMap;
+import java.util.UUID;
+
+public class FileUUIDHandler extends UUIDHandlerImplementation {
+
+ public FileUUIDHandler(UUIDWrapper wrapper) {
+ super(wrapper);
+ }
+
+ @Override
+ public boolean startCaching(Runnable whenDone) {
+ return super.startCaching(whenDone) && cache(whenDone);
+ }
+
+ public boolean cache(final Runnable whenDone) {
+ final File container = new File("players");
+ TaskManager.runTaskAsync(new Runnable() {
+ @Override
+ public void run() {
+ PS.debug(C.PREFIX + "&6Starting player data caching for: " + container);
+ HashBiMap toAdd = HashBiMap.create(new HashMap());
+ for (File file : container.listFiles(new DatFileFilter())) {
+ String fileName = file.getName();
+ String name = fileName.substring(0, fileName.length() - 4);
+ UUID uuid = uuidWrapper.getUUID(name);
+ toAdd.put(new StringWrapper(name), uuid);
+ long last = file.lastModified();
+ 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);
+ }
+ });
+ }
+}
diff --git a/Nukkit/src/main/java/com/plotsquared/nukkit/uuid/LowerOfflineUUIDWrapper.java b/Nukkit/src/main/java/com/plotsquared/nukkit/uuid/LowerOfflineUUIDWrapper.java
new file mode 100644
index 000000000..72b6b05f6
--- /dev/null
+++ b/Nukkit/src/main/java/com/plotsquared/nukkit/uuid/LowerOfflineUUIDWrapper.java
@@ -0,0 +1,41 @@
+package com.plotsquared.nukkit.uuid;
+
+import com.google.common.base.Charsets;
+import com.intellectualcrafters.plot.object.OfflinePlotPlayer;
+import com.intellectualcrafters.plot.object.PlotPlayer;
+import com.intellectualcrafters.plot.uuid.UUIDWrapper;
+import java.util.UUID;
+
+public class LowerOfflineUUIDWrapper extends UUIDWrapper {
+
+ @Override
+ public UUID getUUID(PlotPlayer player) {
+ return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName().toLowerCase()).getBytes(Charsets.UTF_8));
+ }
+
+ @Override
+ public UUID getUUID(OfflinePlotPlayer player) {
+ return UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName().toLowerCase()).getBytes(Charsets.UTF_8));
+ }
+
+ @Override
+ public UUID getUUID(String name) {
+ return UUID.nameUUIDFromBytes(("OfflinePlayer:" + name.toLowerCase()).getBytes(Charsets.UTF_8));
+ }
+
+ @Override
+ public OfflinePlotPlayer getOfflinePlayer(UUID uuid) {
+ return null;
+ }
+
+ @Override
+ public OfflinePlotPlayer getOfflinePlayer(String name) {
+ return null;
+ }
+
+ @Override
+ public OfflinePlotPlayer[] getOfflinePlayers() {
+ return new OfflinePlotPlayer[0];
+ }
+
+}
diff --git a/Nukkit/src/main/resources/plugin.yml b/Nukkit/src/main/resources/plugin.yml
new file mode 100644
index 000000000..e0e4732da
--- /dev/null
+++ b/Nukkit/src/main/resources/plugin.yml
@@ -0,0 +1,6 @@
+name: "${name}"
+version: "${version}"
+author: Empire92
+api: ["1.0.0"]
+main: com.plotsquared.nukkit.NukkitMain
+load: STARTUP
\ No newline at end of file
diff --git a/Sponge/src/main/java/com/plotsquared/sponge/SpongeMain.java b/Sponge/src/main/java/com/plotsquared/sponge/SpongeMain.java
index 90b3cd08d..cfda08219 100644
--- a/Sponge/src/main/java/com/plotsquared/sponge/SpongeMain.java
+++ b/Sponge/src/main/java/com/plotsquared/sponge/SpongeMain.java
@@ -136,7 +136,7 @@ public class SpongeMain implements IPlotMain {
THIS = this;
new PS(this, "Sponge");
this.server = this.game.getServer();
- this.game.getRegistry().register(WorldGeneratorModifier.class, (WorldGeneratorModifier) new HybridGen().specify());
+ this.game.getRegistry().register(WorldGeneratorModifier.class, (WorldGeneratorModifier) new HybridGen().specify(null));
}
@Override
@@ -394,7 +394,7 @@ public class SpongeMain implements IPlotMain {
}
@Override
- public GeneratorWrapper> wrapPlotGenerator(IndependentPlotGenerator generator) {
+ public GeneratorWrapper> wrapPlotGenerator(String world, IndependentPlotGenerator generator) {
return new SpongePlotGenerator(generator);
}
diff --git a/build.gradle b/build.gradle
index 2f02607d9..0ef30476a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -42,6 +42,7 @@ subprojects {
}
repositories {
mavenCentral()
+ maven {url "http://ci.regularbox.com/plugin/repository/everything/"}
maven {url "http://empcraft.com/maven2"}
maven {url "http://repo.mcstats.org/content/repositories/public"}
maven {url "http://maven.sk89q.com/repo/"}
diff --git a/settings.gradle b/settings.gradle
index cc0693084..11ad32b30 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,3 +1,3 @@
rootProject.name = 'PlotSquared'
-include 'Core', 'Bukkit', 'Sponge'
\ No newline at end of file
+include 'Core', 'Bukkit', 'Sponge', 'Nukkit'
\ No newline at end of file