mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2024-11-22 13:16:45 +01:00
ChunkProcessor auto trim and chunk unloading
- The auto trim drastically reduces the cost of players exploring on speed 10, as it prevents chunks of unowned plots from saving to disk when the chunk is unloaded - It is recommended to disable world auto saving, or also enable the chunk processor GC, as otherwise minecraft will also save chunks as they are loaded.
This commit is contained in:
parent
e228c00d87
commit
79b16b8040
@ -1838,6 +1838,8 @@ public class PS {
|
||||
|
||||
// Chunk processor
|
||||
options.put("chunk-processor.enabled", Settings.CHUNK_PROCESSOR);
|
||||
options.put("chunk-processor.auto-unload", Settings.CHUNK_PROCESSOR_GC);
|
||||
options.put("chunk-processor.auto-trim", Settings.CHUNK_PROCESSOR_TRIM_ON_SAVE);
|
||||
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);
|
||||
@ -1951,6 +1953,10 @@ public class PS {
|
||||
|
||||
// Chunk processor
|
||||
Settings.CHUNK_PROCESSOR = config.getBoolean("chunk-processor.enabled");
|
||||
|
||||
Settings.CHUNK_PROCESSOR_GC = config.getBoolean("chunk-processor.auto-unload");
|
||||
Settings.CHUNK_PROCESSOR_TRIM_ON_SAVE = config.getBoolean("chunk-processor.auto-trim");
|
||||
|
||||
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");
|
||||
|
@ -68,6 +68,8 @@ public class Settings {
|
||||
* Chunk processor
|
||||
*/
|
||||
public static boolean CHUNK_PROCESSOR = false;
|
||||
public static boolean CHUNK_PROCESSOR_TRIM_ON_SAVE = false;
|
||||
public static boolean CHUNK_PROCESSOR_GC = false;
|
||||
public static int CHUNK_PROCESSOR_MAX_BLOCKSTATES = 4096;
|
||||
public static int CHUNK_PROCESSOR_MAX_ENTITIES = 512;
|
||||
public static boolean CHUNK_PROCESSOR_DISABLE_PHYSICS = false;
|
||||
|
@ -1,10 +1,16 @@
|
||||
package com.plotsquared.bukkit.listeners;
|
||||
|
||||
import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.craftbukkit.v1_8_R2.CraftChunk;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
@ -17,21 +23,143 @@ import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.bukkit.event.entity.ItemSpawnEvent;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
import org.bukkit.event.world.WorldSaveEvent;
|
||||
|
||||
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.object.ChunkLoc;
|
||||
import com.intellectualcrafters.plot.object.Location;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.util.MainUtil;
|
||||
import com.intellectualcrafters.plot.util.ReflectionUtils.RefClass;
|
||||
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;
|
||||
|
||||
public class ChunkListener implements Listener {
|
||||
|
||||
private Chunk lastChunk = null;
|
||||
private long last = 0;
|
||||
private int count = 0;
|
||||
|
||||
final RefClass classChunk = getRefClass("{nms}.Chunk");
|
||||
final RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
|
||||
final RefMethod methodGetHandleChunk;
|
||||
final RefField mustSave = classChunk.getField("mustSave");
|
||||
|
||||
public ChunkListener() {
|
||||
RefMethod method;
|
||||
try {
|
||||
method = classCraftChunk.getMethod("getHandle");
|
||||
}
|
||||
catch (Exception e) {
|
||||
method = null;
|
||||
e.printStackTrace();
|
||||
}
|
||||
methodGetHandleChunk = method;
|
||||
|
||||
if (!Settings.CHUNK_PROCESSOR_GC) {
|
||||
return;
|
||||
}
|
||||
TaskManager.runTaskRepeat(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int distance = Bukkit.getViewDistance() + 1;
|
||||
HashMap<String, HashMap<ChunkLoc, Integer>> players = new HashMap<>();
|
||||
for (Entry<String, PlotPlayer> entry : UUIDHandler.getPlayers().entrySet()) {
|
||||
PlotPlayer pp = entry.getValue();
|
||||
Location loc = pp.getLocation();
|
||||
String world = loc.getWorld();
|
||||
HashMap<ChunkLoc, Integer> map = players.get(world);
|
||||
if (map == null) {
|
||||
map = new HashMap<>();
|
||||
players.put(world, map);
|
||||
}
|
||||
ChunkLoc origin = new ChunkLoc(loc.getX() >> 4, loc.getZ() >> 4);
|
||||
Integer val = map.get(origin);
|
||||
int check;
|
||||
if (val != null) {
|
||||
if (val == distance) {
|
||||
continue;
|
||||
}
|
||||
check = distance - val;
|
||||
}
|
||||
else {
|
||||
check = distance;
|
||||
map.put(origin, distance);
|
||||
}
|
||||
for (int x = -distance; x <= distance; x++) {
|
||||
if (x >= check || -x >= check) {
|
||||
continue;
|
||||
}
|
||||
for (int z = -distance; z <= distance; z++) {
|
||||
if (z >= check || -z >= check) {
|
||||
continue;
|
||||
}
|
||||
int weight = distance - Math.max(Math.abs(x), Math.abs(z));
|
||||
ChunkLoc chunk = new ChunkLoc(x + origin.x, z + origin.z);
|
||||
val = map.get(chunk);
|
||||
if (val == null || val < weight) {
|
||||
map.put(chunk, weight);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
String name = world.getName();
|
||||
boolean autosave = world.isAutoSave();
|
||||
boolean plotworld = PS.get().isPlotWorld(name);
|
||||
if (autosave && plotworld) {
|
||||
world.setAutoSave(false);
|
||||
}
|
||||
HashMap<ChunkLoc, Integer> map = players.get(name);
|
||||
if (map == null || map.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
for (Chunk chunk : world.getLoadedChunks()) {
|
||||
int x = chunk.getX();
|
||||
int z = chunk.getZ();
|
||||
if (!map.containsKey(new ChunkLoc(x, z))) {
|
||||
Plot plot = MainUtil.getPlot(new Location(name, x << 4, 1, z << 4));
|
||||
if (Settings.CHUNK_PROCESSOR_TRIM_ON_SAVE && plot == null || plot.owner == null && plotworld) {
|
||||
unloadChunk(chunk);
|
||||
CraftChunk c = null;
|
||||
}
|
||||
else {
|
||||
chunk.unload(true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Settings.CHUNK_PROCESSOR_TRIM_ON_SAVE && autosave && plotworld) {
|
||||
world.setAutoSave(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
public void unloadChunk(Chunk chunk) {
|
||||
Object c = methodGetHandleChunk.of(chunk).call();
|
||||
mustSave.of(c).set(false);
|
||||
chunk.unload(false, false);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChunkUnload(ChunkUnloadEvent event) {
|
||||
if (Settings.CHUNK_PROCESSOR_TRIM_ON_SAVE) {
|
||||
Chunk chunk = event.getChunk();
|
||||
String world = chunk.getWorld().getName();
|
||||
if (PS.get().isPlotWorld(world)) {
|
||||
int x = chunk.getX();
|
||||
int z = chunk.getZ();
|
||||
Plot plot = MainUtil.getPlot(new Location(world, x << 4, 1, z << 4));
|
||||
if (plot == null || plot.owner == null && PS.get().isPlotWorld(world)) {
|
||||
unloadChunk(chunk);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (processChunk(event.getChunk(), true)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user