diff --git a/pom.xml b/pom.xml
index 794bd33fa..449ef0176 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
UTF-8
PlotSquared
- 3.1.2
+ 3.1.3
PlotSquared
jar
diff --git a/src/main/java/com/intellectualcrafters/plot/PS.java b/src/main/java/com/intellectualcrafters/plot/PS.java
index 596fc7613..fcbf25add 100644
--- a/src/main/java/com/intellectualcrafters/plot/PS.java
+++ b/src/main/java/com/intellectualcrafters/plot/PS.java
@@ -1743,6 +1743,7 @@ public class PS {
// Protection
options.put("protection.redstone.disable-offline", Settings.REDSTONE_DISABLER);
+ options.put("protection.redstone.disable-unoccupied", Settings.REDSTONE_DISABLER_UNOCCUPIED);
options.put("protection.tnt-listener.enabled", Settings.TNT_LISTENER);
options.put("protection.piston.falling-blocks", Settings.PISTON_FALLING_BLOCK_CHECK);
@@ -1837,6 +1838,7 @@ public class PS {
// Chunk processor
options.put("chunk-processor.enabled", Settings.CHUNK_PROCESSOR);
+ options.put("chunk-processor.random-chunk-unloads", Settings.CHUNK_PROCESSOR_RANDOM_CHUNK_UNLOADS);
options.put("chunk-processor.max-blockstates", Settings.CHUNK_PROCESSOR_MAX_BLOCKSTATES);
options.put("chunk-processor.max-entities", Settings.CHUNK_PROCESSOR_MAX_ENTITIES);
options.put("chunk-processor.disable-physics", Settings.CHUNK_PROCESSOR_DISABLE_PHYSICS);
@@ -1869,6 +1871,8 @@ public class PS {
// Protection
Settings.REDSTONE_DISABLER = config.getBoolean("protection.redstone.disable-offline");
+ Settings.REDSTONE_DISABLER_UNOCCUPIED = config.getBoolean("protection.redstone.disable-unoccupied");
+
Settings.TNT_LISTENER = config.getBoolean("protection.tnt-listener.enabled");
Settings.PISTON_FALLING_BLOCK_CHECK = config.getBoolean("protection.piston.falling-blocks");
@@ -1948,6 +1952,7 @@ public class PS {
// Chunk processor
Settings.CHUNK_PROCESSOR = config.getBoolean("chunk-processor.enabled");
+ Settings.CHUNK_PROCESSOR_RANDOM_CHUNK_UNLOADS = config.getInt("chunk-processor.random-chunk-unloads");
Settings.CHUNK_PROCESSOR_MAX_BLOCKSTATES = config.getInt("chunk-processor.max-blockstates");
Settings.CHUNK_PROCESSOR_MAX_ENTITIES = config.getInt("chunk-processor.max-entities");
Settings.CHUNK_PROCESSOR_DISABLE_PHYSICS = config.getBoolean("chunk-processor.disable-physics");
diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Reload.java b/src/main/java/com/intellectualcrafters/plot/commands/Reload.java
index ea90917b8..9bcf3c49a 100644
--- a/src/main/java/com/intellectualcrafters/plot/commands/Reload.java
+++ b/src/main/java/com/intellectualcrafters/plot/commands/Reload.java
@@ -20,6 +20,7 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
package com.intellectualcrafters.plot.commands;
+import com.intellectualcrafters.configuration.ConfigurationSection;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.object.PlotPlayer;
@@ -46,10 +47,13 @@ public class Reload extends SubCommand {
C.load(PS.get().translationFile);
for (final String pw : PS.get().getPlotWorlds()) {
final PlotWorld plotworld = PS.get().getPlotWorld(pw);
- plotworld.loadDefaultConfiguration(PS.get().config.getConfigurationSection("worlds." + pw));
+ ConfigurationSection section = PS.get().config.getConfigurationSection("worlds." + pw);
+ plotworld.saveConfiguration(section);
+ plotworld.loadDefaultConfiguration(section);
}
MainUtil.sendMessage(plr, C.RELOADED_CONFIGS);
} catch (final Exception e) {
+ e.printStackTrace();
MainUtil.sendMessage(plr, C.RELOAD_FAILED);
}
return true;
diff --git a/src/main/java/com/intellectualcrafters/plot/config/Settings.java b/src/main/java/com/intellectualcrafters/plot/config/Settings.java
index a93f9b8d0..f42c37a9c 100644
--- a/src/main/java/com/intellectualcrafters/plot/config/Settings.java
+++ b/src/main/java/com/intellectualcrafters/plot/config/Settings.java
@@ -69,6 +69,7 @@ public class Settings {
*/
public static boolean CHUNK_PROCESSOR = false;
public static int CHUNK_PROCESSOR_MAX_BLOCKSTATES = 4096;
+ public static int CHUNK_PROCESSOR_RANDOM_CHUNK_UNLOADS = 1;
public static int CHUNK_PROCESSOR_MAX_ENTITIES = 512;
public static boolean CHUNK_PROCESSOR_DISABLE_PHYSICS = false;
/**
@@ -79,6 +80,7 @@ public class Settings {
* Redstone disabler
*/
public static boolean REDSTONE_DISABLER = false;
+ public static boolean REDSTONE_DISABLER_UNOCCUPIED = false;
/**
* Check for falling blocks when pistons extend?
*/
diff --git a/src/main/java/com/plotsquared/bukkit/listeners/ChunkListener.java b/src/main/java/com/plotsquared/bukkit/listeners/ChunkListener.java
index 2f8c2b860..73016a808 100644
--- a/src/main/java/com/plotsquared/bukkit/listeners/ChunkListener.java
+++ b/src/main/java/com/plotsquared/bukkit/listeners/ChunkListener.java
@@ -3,6 +3,7 @@ package com.plotsquared.bukkit.listeners;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
+import org.bukkit.World;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
@@ -19,6 +20,8 @@ import org.bukkit.event.world.ChunkUnloadEvent;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.Settings;
+import com.intellectualcrafters.plot.object.PseudoRandom;
+import com.intellectualcrafters.plot.util.ChunkManager;
import com.intellectualcrafters.plot.util.TaskManager;
public class ChunkListener implements Listener {
@@ -27,6 +30,27 @@ public class ChunkListener implements Listener {
private long last = 0;
private int count = 0;
+ public ChunkListener() {
+ final PseudoRandom r = new PseudoRandom();
+ r.state = System.currentTimeMillis();
+ if (Settings.CHUNK_PROCESSOR_RANDOM_CHUNK_UNLOADS > 0) {
+ TaskManager.runTaskRepeat(new Runnable() {
+ @Override
+ public void run() {
+ for (World world : Bukkit.getWorlds()) {
+ if (!PS.get().isPlotWorld(world.getName())) {
+ continue;
+ }
+ Chunk[] chunks = world.getLoadedChunks();
+ for (int i = 0; i < Math.min(chunks.length, Settings.CHUNK_PROCESSOR_RANDOM_CHUNK_UNLOADS); i++) {
+ chunks[r.random(chunks.length)].unload(true, true);
+ }
+ }
+ }
+ }, 1);
+ }
+ }
+
@EventHandler
public void onChunkUnload(ChunkUnloadEvent event) {
if (processChunk(event.getChunk(), true)) {
diff --git a/src/main/java/com/plotsquared/bukkit/listeners/PlayerEvents.java b/src/main/java/com/plotsquared/bukkit/listeners/PlayerEvents.java
index 4fcdf5c7c..94ae1c756 100644
--- a/src/main/java/com/plotsquared/bukkit/listeners/PlayerEvents.java
+++ b/src/main/java/com/plotsquared/bukkit/listeners/PlayerEvents.java
@@ -64,6 +64,7 @@ import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.hanging.HangingPlaceEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
+import org.bukkit.event.inventory.InventoryPickupItemEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerBucketEmptyEvent;
import org.bukkit.event.player.PlayerBucketFillEvent;
@@ -83,6 +84,7 @@ import org.bukkit.event.vehicle.VehicleDestroyEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.StructureGrowEvent;
import org.bukkit.help.HelpTopic;
+import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.projectiles.BlockProjectileSource;
import org.bukkit.projectiles.ProjectileSource;
@@ -156,11 +158,61 @@ public class PlayerEvents extends com.plotsquared.listener.PlotListener implemen
}, 3);
}
+ @EventHandler
+ public void onInventoryPickup(InventoryPickupItemEvent event) {
+ Inventory inv = event.getInventory();
+ System.out.print(inv.getTitle() + " | " + inv.getHolder() + " | " + inv + " | " + inv.getType());
+ Location loc = BukkitUtil.getLocation(event.getItem().getLocation());
+ if (!PS.get().isPlotWorld(loc.getWorld())) {
+ return;
+ }
+ Plot plot = MainUtil.getPlot(loc);
+ if (plot == null || !plot.hasOwner()) {
+ return;
+ }
+ Flag redstone = FlagManager.getPlotFlag(plot, "redstone");
+ if (redstone != null) {
+ if ((Boolean) redstone.getValue()) {
+ return;
+ }
+ else {
+ event.setCancelled(true);
+ return;
+ }
+ }
+ if (Settings.REDSTONE_DISABLER) {
+ 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_DISABLER_UNOCCUPIED) {
+ for (PlotPlayer pp : UUIDHandler.getPlayers().values()) {
+ if (plot.equals(pp.getCurrentPlot())) {
+ return;
+ }
+ }
+ event.setCancelled(true);
+ return;
+ }
+ }
+
@EventHandler
public void onRedstoneEvent(BlockRedstoneEvent event) {
Block block = event.getBlock();
switch (block.getType()) {
case REDSTONE_LAMP_OFF:
+ case REDSTONE_WIRE:
case REDSTONE_LAMP_ON:
case PISTON_BASE:
case PISTON_STICKY_BASE:
@@ -198,10 +250,16 @@ public class PlayerEvents extends com.plotsquared.listener.PlotListener implemen
return;
}
Flag redstone = FlagManager.getPlotFlag(plot, "redstone");
- if (Settings.REDSTONE_DISABLER) {
- if (redstone != null && (Boolean) redstone.getValue()) {
+ if (redstone != null) {
+ if ((Boolean) redstone.getValue()) {
return;
}
+ else {
+ event.setNewCurrent(0);
+ return;
+ }
+ }
+ if (Settings.REDSTONE_DISABLER) {
if (UUIDHandler.getPlayer(plot.owner) == null) {
boolean disable = true;
for (UUID trusted : plot.getTrusted()) {
@@ -216,10 +274,15 @@ public class PlayerEvents extends com.plotsquared.listener.PlotListener implemen
}
}
}
- if (redstone == null || (Boolean) redstone.getValue()) {
+ if (Settings.REDSTONE_DISABLER_UNOCCUPIED) {
+ for (PlotPlayer pp : UUIDHandler.getPlayers().values()) {
+ if (plot.equals(pp.getCurrentPlot())) {
+ return;
+ }
+ }
+ event.setNewCurrent(0);
return;
}
- event.setNewCurrent(0);
}
}
}
diff --git a/src/main/java/com/plotsquared/bukkit/util/SendChunk.java b/src/main/java/com/plotsquared/bukkit/util/SendChunk.java
index 8487d6d07..160c1fcb2 100644
--- a/src/main/java/com/plotsquared/bukkit/util/SendChunk.java
+++ b/src/main/java/com/plotsquared/bukkit/util/SendChunk.java
@@ -4,19 +4,28 @@ import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
-import org.bukkit.Bukkit;
import org.bukkit.Chunk;
-import org.bukkit.World;
import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.object.ChunkLoc;
-import com.intellectualcrafters.plot.util.TaskManager;
+import com.intellectualcrafters.plot.object.Location;
+import com.intellectualcrafters.plot.object.Plot;
+import com.intellectualcrafters.plot.object.PlotPlayer;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefClass;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefConstructor;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefField;
import com.intellectualcrafters.plot.util.ReflectionUtils.RefMethod;
+import com.intellectualcrafters.plot.util.TaskManager;
+import com.intellectualcrafters.plot.util.UUIDHandler;
+import com.plotsquared.bukkit.object.BukkitPlayer;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
+import org.bukkit.Bukkit;
+
/**
* An utility that can be used to send chunks, rather than using bukkit code to do so (uses heavy NMS)
@@ -25,23 +34,17 @@ import com.intellectualcrafters.plot.util.ReflectionUtils.RefMethod;
*/
public class SendChunk {
- // Ref Class
- private final RefClass classWorld = getRefClass("{nms}.World");
+// // Ref Class
private final RefClass classEntityPlayer = getRefClass("{nms}.EntityPlayer");
- private final RefClass classChunkCoordIntPair = getRefClass("{nms}.ChunkCoordIntPair");
+ private final RefClass classMapChunk = getRefClass("{nms}.PacketPlayOutMapChunk");
+ private final RefClass classConnection = getRefClass("{nms}.EntityPlayer.playerConnection");
private final RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
- private final RefClass classChunk = getRefClass("{nms}.Chunk");
- private boolean v1_7_10 = PS.get().checkVersion(PS.get().IMP.getServerVersion(), 1, 7, 10) && !PS.get().checkVersion(PS.get().IMP.getServerVersion(), 1, 8, 0);
- // Ref Method
- private RefMethod methodGetHandle;
- // Ref Field
- private RefField chunkCoordIntPairQueue;
- private RefField players;
- private RefField locX;
- private RefField locZ;
- private RefField world;
- // Ref Constructor
- private RefConstructor ChunkCoordIntPairCon;
+ private final RefClass classCraftPlayer = getRefClass("{cb}.CraftPlayer");
+ private RefMethod methodGetHandleChunk;
+ private RefMethod methodGetHandlePlayer;
+ private RefConstructor MapChunk;
+ private RefField connection;
+ private RefMethod send;
/**
* Constructor
@@ -49,62 +52,134 @@ public class SendChunk {
* @throws NoSuchMethodException
*/
public SendChunk() throws NoSuchMethodException {
- methodGetHandle = classCraftChunk.getMethod("getHandle");
- chunkCoordIntPairQueue = classEntityPlayer.getField("chunkCoordIntPairQueue");
- players = classWorld.getField("players");
- locX = classEntityPlayer.getField("locX");
- locZ = classEntityPlayer.getField("locZ");
- world = classChunk.getField("world");
- ChunkCoordIntPairCon = classChunkCoordIntPair.getConstructor(int.class, int.class);
+ methodGetHandleChunk = classCraftChunk.getMethod("getHandle");
+ methodGetHandlePlayer = classCraftPlayer.getMethod("getHandle");
+ MapChunk = classMapChunk.getConstructor(Chunk.class, boolean.class, int.class);
+ connection = classCraftPlayer.getField("playerConnection");
+ send = classConnection.getMethod("sendPacket", classMapChunk.getRealClass());
}
- public void sendChunk(final Collection chunks) {
- int diffx, diffz;
- final int view = Bukkit.getServer().getViewDistance() << 4;
- for (final Chunk chunk : chunks) {
- if (!chunk.isLoaded()) {
+ public void sendChunk(final Collection input) {
+ HashSet chunks = new HashSet(input);
+ HashMap> map = new HashMap<>();
+ int view = Bukkit.getServer().getViewDistance();
+ for (Chunk chunk : chunks) {
+ String world = chunk.getWorld().getName();
+ ArrayList list = map.get(world);
+ if (list == null) {
+ list = new ArrayList<>();
+ map.put(world, list);
+ }
+ list.add(chunk);
+ }
+ for (PlotPlayer pp : UUIDHandler.getPlayers().values() ) {
+ Plot plot = pp.getCurrentPlot();
+ Location loc = null;
+ String world;
+ if (plot != null) {
+ world = plot.world;
+ }
+ else {
+ loc = pp.getLocation();
+ world = loc.getWorld();
+ }
+ ArrayList list = map.get(world);
+ if (list == null) {
continue;
}
- boolean unload = true;
- final Object c = methodGetHandle.of(chunk).call();
- final Object w = world.of(c).get();
- final Object p = players.of(w).get();
- for (final Object ep : (List