Redstone, chunk sending, reload fix, chunk unloader,

- Added redstone disabler when no players are in the plot
- Fixed chunk sending leaving ghost blocks
- Fixed reloading not populating new values
- Added chunk unloader to chunk processor (decreases memory usage)
This commit is contained in:
boy0001 2015-08-21 04:54:42 +10:00
parent ae7eed8a5b
commit b063494955
9 changed files with 245 additions and 72 deletions

View File

@ -8,7 +8,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<artifactId>PlotSquared</artifactId>
<version>3.1.2</version>
<version>3.1.3</version>
<name>PlotSquared</name>
<packaging>jar</packaging>
<build>

View File

@ -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");

View File

@ -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;

View File

@ -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?
*/

View File

@ -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)) {

View File

@ -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);
}
}
}

View File

@ -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<Chunk> chunks) {
int diffx, diffz;
final int view = Bukkit.getServer().getViewDistance() << 4;
for (final Chunk chunk : chunks) {
if (!chunk.isLoaded()) {
public void sendChunk(final Collection<Chunk> input) {
HashSet<Chunk> chunks = new HashSet<Chunk>(input);
HashMap<String, ArrayList<Chunk>> map = new HashMap<>();
int view = Bukkit.getServer().getViewDistance();
for (Chunk chunk : chunks) {
String world = chunk.getWorld().getName();
ArrayList<Chunk> 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<Chunk> 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<Object>) 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<Object>) 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<ChunkLoc> locs) {

Binary file not shown.

Binary file not shown.