mirror of
				https://github.com/IntellectualSites/PlotSquared.git
				synced 2025-10-31 09:33: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 |         // Chunk processor | ||||||
|         options.put("chunk-processor.enabled", Settings.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-blockstates", Settings.CHUNK_PROCESSOR_MAX_BLOCKSTATES); | ||||||
|         options.put("chunk-processor.max-entities", Settings.CHUNK_PROCESSOR_MAX_ENTITIES); |         options.put("chunk-processor.max-entities", Settings.CHUNK_PROCESSOR_MAX_ENTITIES); | ||||||
|         options.put("chunk-processor.disable-physics", Settings.CHUNK_PROCESSOR_DISABLE_PHYSICS); |         options.put("chunk-processor.disable-physics", Settings.CHUNK_PROCESSOR_DISABLE_PHYSICS); | ||||||
| @@ -1951,6 +1953,10 @@ public class PS { | |||||||
|          |          | ||||||
|         // Chunk processor |         // Chunk processor | ||||||
|         Settings.CHUNK_PROCESSOR = config.getBoolean("chunk-processor.enabled"); |         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_BLOCKSTATES = config.getInt("chunk-processor.max-blockstates"); | ||||||
|         Settings.CHUNK_PROCESSOR_MAX_ENTITIES = config.getInt("chunk-processor.max-entities"); |         Settings.CHUNK_PROCESSOR_MAX_ENTITIES = config.getInt("chunk-processor.max-entities"); | ||||||
|         Settings.CHUNK_PROCESSOR_DISABLE_PHYSICS = config.getBoolean("chunk-processor.disable-physics"); |         Settings.CHUNK_PROCESSOR_DISABLE_PHYSICS = config.getBoolean("chunk-processor.disable-physics"); | ||||||
|   | |||||||
| @@ -68,6 +68,8 @@ public class Settings { | |||||||
|      * Chunk processor |      * Chunk processor | ||||||
|      */ |      */ | ||||||
|     public static boolean CHUNK_PROCESSOR = false; |     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_BLOCKSTATES = 4096; | ||||||
|     public static int CHUNK_PROCESSOR_MAX_ENTITIES = 512; |     public static int CHUNK_PROCESSOR_MAX_ENTITIES = 512; | ||||||
|     public static boolean CHUNK_PROCESSOR_DISABLE_PHYSICS = false; |     public static boolean CHUNK_PROCESSOR_DISABLE_PHYSICS = false; | ||||||
|   | |||||||
| @@ -1,10 +1,16 @@ | |||||||
| package com.plotsquared.bukkit.listeners; | 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.Bukkit; | ||||||
| import org.bukkit.Chunk; | import org.bukkit.Chunk; | ||||||
| import org.bukkit.Material; | import org.bukkit.Material; | ||||||
| import org.bukkit.World; | import org.bukkit.World; | ||||||
| import org.bukkit.block.BlockState; | import org.bukkit.block.BlockState; | ||||||
|  | import org.bukkit.craftbukkit.v1_8_R2.CraftChunk; | ||||||
| import org.bukkit.entity.Entity; | import org.bukkit.entity.Entity; | ||||||
| import org.bukkit.entity.Item; | import org.bukkit.entity.Item; | ||||||
| import org.bukkit.entity.LivingEntity; | 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.entity.ItemSpawnEvent; | ||||||
| import org.bukkit.event.world.ChunkLoadEvent; | import org.bukkit.event.world.ChunkLoadEvent; | ||||||
| import org.bukkit.event.world.ChunkUnloadEvent; | import org.bukkit.event.world.ChunkUnloadEvent; | ||||||
|  | import org.bukkit.event.world.WorldSaveEvent; | ||||||
|  |  | ||||||
| import com.intellectualcrafters.plot.PS; | import com.intellectualcrafters.plot.PS; | ||||||
| import com.intellectualcrafters.plot.config.Settings; | import com.intellectualcrafters.plot.config.Settings; | ||||||
| import com.intellectualcrafters.plot.object.PseudoRandom; | import com.intellectualcrafters.plot.object.ChunkLoc; | ||||||
| import com.intellectualcrafters.plot.util.ChunkManager; | 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.TaskManager; | ||||||
|  | import com.intellectualcrafters.plot.util.UUIDHandler; | ||||||
|  |  | ||||||
| public class ChunkListener implements Listener { | public class ChunkListener implements Listener { | ||||||
|  |  | ||||||
|     private Chunk lastChunk = null; |     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 |     @EventHandler | ||||||
|     public void onChunkUnload(ChunkUnloadEvent event) { |     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)) { |         if (processChunk(event.getChunk(), true)) { | ||||||
|             event.setCancelled(true); |             event.setCancelled(true); | ||||||
|         } |         } | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
		Reference in New Issue
	
	Block a user
	 boy0001
					boy0001