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) p) { - final int x = ((Double) locX.of(ep).get()).intValue(); - final int z = ((Double) locZ.of(ep).get()).intValue(); - diffx = Math.abs(x - (chunk.getX() << 4)); - diffz = Math.abs(z - (chunk.getZ() << 4)); - if ((diffx <= view) && (diffz <= view)) { - unload = false; - if (v1_7_10) { - chunk.getWorld().refreshChunk(chunk.getX(), chunk.getZ()); - chunk.load(true); + if (loc == null) { + loc = pp.getLocation(); + } + int cx = loc.getX() >> 4; + int cz = loc.getZ() >> 4; + Player player = ((BukkitPlayer) pp).player; + Object entity = methodGetHandlePlayer.of(player).call(); + + for (Chunk chunk : list) { + int dx = Math.abs(cx - chunk.getX()); + int dz = Math.abs(cz - chunk.getZ()); + if (dx > view || dz > view) { + continue; + } + chunks.remove(chunk); + + Object packet = MapChunk.create(chunk, true, 0); + Object con = connection.of(entity).get(); + send.of(con).call(packet); + packet = MapChunk.create(chunk, true, 65565); + send.of(con).call(packet); +// Object packet = MapChunk.create(chunk, true, 0); +// +// PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(chunk, true, 0); +// entity.playerConnection.sendPacket(packet); +// packet = new PacketPlayOutMapChunk(chunk, true, 65565); +// entity.playerConnection.sendPacket(packet); + } + } + for (final Chunk chunk : chunks) { + TaskManager.runTask(new Runnable() { + @Override + public void run() { + try { + chunk.unload(true, true); } - else { - final Object pair = ChunkCoordIntPairCon.create(chunk.getX(), chunk.getZ()); - final Object pq = chunkCoordIntPairQueue.of(ep).get(); - ((List) pq).add(pair); + catch (Exception e) { + String worldname = chunk.getWorld().getName(); + PS.debug("$4Could not save chunk: " + worldname + ";" + chunk.getX() + ";" + chunk.getZ()); + PS.debug("$3 - $4File may be open in another process (e.g. MCEdit)"); + PS.debug("$3 - $4" + worldname + "/level.dat or " + worldname + "level_old.dat may be corrupt (try repairing or removing these)"); } } - } - if (unload) { - TaskManager.runTask(new Runnable() { - @Override - public void run() { - try { - chunk.unload(true, true); - } - catch (Exception e) { - String worldname = chunk.getWorld().getName(); - PS.debug("$4Could not save chunk: " + worldname + ";" + chunk.getX() + ";" + chunk.getZ()); - PS.debug("$3 - $4File may be open in another process (e.g. MCEdit)"); - PS.debug("$3 - $4" + worldname + "/level.dat or " + worldname + "level_old.dat may be corrupt (try repairing or removing these)"); - } - } - }); - } - + }); } +// +// +// int diffx, diffz; +// << 4; +// for (final Chunk chunk : chunks) { +// if (!chunk.isLoaded()) { +// 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) p) { +// final int x = ((Double) locX.of(ep).get()).intValue(); +// final int z = ((Double) locZ.of(ep).get()).intValue(); +// diffx = Math.abs(x - (chunk.getX() << 4)); +// diffz = Math.abs(z - (chunk.getZ() << 4)); +// if ((diffx <= view) && (diffz <= view)) { +// unload = false; +// if (v1_7_10) { +// chunk.getWorld().refreshChunk(chunk.getX(), chunk.getZ()); +// chunk.load(true); +// } +// else { +// final Object pair = ChunkCoordIntPairCon.create(chunk.getX(), chunk.getZ()); +// final Object pq = chunkCoordIntPairQueue.of(ep).get(); +// ((List) pq).add(pair); +// } +// } +// } +// if (unload) { +// TaskManager.runTask(new Runnable() { +// @Override +// public void run() { +// try { +// chunk.unload(true, true); +// } +// catch (Exception e) { +// String worldname = chunk.getWorld().getName(); +// PS.debug("$4Could not save chunk: " + worldname + ";" + chunk.getX() + ";" + chunk.getZ()); +// PS.debug("$3 - $4File may be open in another process (e.g. MCEdit)"); +// PS.debug("$3 - $4" + worldname + "/level.dat or " + worldname + "level_old.dat may be corrupt (try repairing or removing these)"); +// } +// } +// }); +// } +// +// } } public void sendChunk(final String worldname, final List locs) { diff --git a/target/PlotSquared-Bukkit.jar b/target/PlotSquared-Bukkit.jar index 562446b1c..8e5f1ca94 100644 Binary files a/target/PlotSquared-Bukkit.jar and b/target/PlotSquared-Bukkit.jar differ diff --git a/target/PlotSquared-Sponge.jar b/target/PlotSquared-Sponge.jar index cd934dc59..7d45b74e3 100644 Binary files a/target/PlotSquared-Sponge.jar and b/target/PlotSquared-Sponge.jar differ