mirror of
				https://github.com/IntellectualSites/PlotSquared.git
				synced 2025-10-30 17:13:43 +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:
		| @@ -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); | ||||
|         } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 boy0001
					boy0001