From 63e61047368861f2b4c59a87841dfac86c860e75 Mon Sep 17 00:00:00 2001 From: RePixelatedMC Date: Thu, 2 Nov 2023 12:24:13 +0100 Subject: [PATCH] EXPERIMENTAL ChunkHandler.java --- core/src/main/java/com/volmit/iris/Iris.java | 4 +- .../com/volmit/iris/core/ChunkHandler.java | 153 ++++++++++++++++++ .../iris/core/commands/CommandIris.java | 9 +- .../iris/engine/safeguard/PerformanceSFG.java | 13 +- 4 files changed, 165 insertions(+), 14 deletions(-) create mode 100644 core/src/main/java/com/volmit/iris/core/ChunkHandler.java diff --git a/core/src/main/java/com/volmit/iris/Iris.java b/core/src/main/java/com/volmit/iris/Iris.java index fccb7e1e3..f1090a210 100644 --- a/core/src/main/java/com/volmit/iris/Iris.java +++ b/core/src/main/java/com/volmit/iris/Iris.java @@ -30,6 +30,7 @@ import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.v1X.NMSBinding1X; import com.volmit.iris.core.pregenerator.LazyPregenerator; +import com.volmit.iris.core.ChunkHandler; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.EnginePanic; @@ -440,7 +441,7 @@ public class Iris extends VolmitPlugin implements Listener { private static void fixShading() { ShadeFix.fix(ComponentSerializer.class); } - + private ChunkHandler chunkHandler; private void enable() { instance = this; services = new KMap<>(); @@ -458,6 +459,7 @@ public class Iris extends VolmitPlugin implements Listener { configWatcher = new FileWatcher(getDataFile("settings.json")); services.values().forEach(IrisService::onEnable); services.values().forEach(this::registerListener); + chunkHandler = new ChunkHandler(this); J.s(() -> { J.a(() -> PaperLib.suggestPaper(this)); J.a(() -> IO.delete(getTemp())); diff --git a/core/src/main/java/com/volmit/iris/core/ChunkHandler.java b/core/src/main/java/com/volmit/iris/core/ChunkHandler.java new file mode 100644 index 000000000..73e01e368 --- /dev/null +++ b/core/src/main/java/com/volmit/iris/core/ChunkHandler.java @@ -0,0 +1,153 @@ +package com.volmit.iris.core; + +import com.volmit.iris.Iris; +import com.volmit.iris.core.tools.IrisToolbelt; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.event.world.ChunkUnloadEvent; +import org.bukkit.event.world.WorldLoadEvent; +import org.bukkit.event.world.WorldUnloadEvent; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +public class ChunkHandler implements Listener { + private final JavaPlugin plugin; + private static BukkitTask task; + private final Map worlds = new ConcurrentHashMap<>(); + + private static final Map> playersInChunk = new ConcurrentHashMap<>(); + + public ChunkHandler(JavaPlugin plugin) { + this.plugin = plugin; + Bukkit.getPluginManager().registerEvents(this, plugin); + + for (World world : Bukkit.getWorlds()) { + if (IrisToolbelt.isIrisWorld(world)) { + worlds.put(world, new ChunkUnloader(plugin, world)); + } + } + + startTask(); + } + + private void startTask() { + if (task == null) { + task = new BukkitRunnable() { + @Override + public void run() { + worlds.values().forEach(ChunkUnloader::update); + } + }.runTaskTimerAsynchronously(plugin, 0L, 1L); + } + } + + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + Player player = event.getPlayer(); + Chunk previousChunk = event.getFrom().getChunk(); + Chunk currentChunk = event.getTo().getChunk(); + + if (!previousChunk.equals(currentChunk)) { + playersInChunk.computeIfAbsent(previousChunk, k -> ConcurrentHashMap.newKeySet()).remove(player); + playersInChunk.computeIfAbsent(currentChunk, k -> ConcurrentHashMap.newKeySet()).add(player); + } + } + + public static void exit() { + if (task != null) { + task.cancel(); + } + } + + @EventHandler + public void onWorldLoad(WorldLoadEvent event) { + World world = event.getWorld(); + if (IrisToolbelt.isIrisWorld(world)) { + worlds.put(world, new ChunkUnloader(plugin, world)); + } + } + + @EventHandler + public void onWorldUnload(WorldUnloadEvent event) { + worlds.remove(event.getWorld()); + } + + @EventHandler + public void onChunkLoad(ChunkLoadEvent event) { + World world = event.getWorld(); + if (worlds.containsKey(world)) { + worlds.get(world).onChunkLoad(event.getChunk()); + } + } + + @EventHandler + public void onChunkUnload(ChunkUnloadEvent event) { + World world = event.getWorld(); + if (worlds.containsKey(world)) { + worlds.get(world).onChunkUnload(event.getChunk()); + } + } + + private static class ChunkUnloader { + private final JavaPlugin plugin; + private final World world; + private final Map chunks = new ConcurrentHashMap<>(); + + private ChunkUnloader(JavaPlugin plugin, World world) { + this.plugin = plugin; + this.world = world; + } + + public void onChunkLoad(Chunk chunk) { + //System.out.printf("%s > Loaded Chunk [x=%s, z=%s]%n", world.getName(), chunk.getX(), chunk.getZ()); + chunks.put(chunk, System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(3)); + } + + public void onChunkUnload(Chunk chunk) { + chunks.remove(chunk); + playersInChunk.remove(chunk); + } + + public void update() { + long currentTime = System.currentTimeMillis(); + Set chunkSet = new HashSet<>(chunks.keySet()); + for (Chunk chunk : chunkSet) { + if (!chunk.isLoaded()) { + continue; + } + + if (isChunkNearby(chunk)) { + chunks.put(chunk, currentTime + TimeUnit.MINUTES.toMillis(3)); + } else if (chunks.get(chunk) <= currentTime) { + unloadChunk(chunk); + } + } + } + + private boolean isChunkNearby(Chunk chunk) { + Set players = playersInChunk.get(chunk); + if (players == null) { + players = ConcurrentHashMap.newKeySet(); + playersInChunk.put(chunk, players); + } + return !players.isEmpty(); + } + + private void unloadChunk(Chunk chunk) { + //System.out.printf("%s > Unloading Chunk [x=%s, z=%s]%n", world.getName(), chunk.getX(), chunk.getZ()); + Bukkit.getScheduler().runTask(plugin, () -> chunk.unload(true)); + } + } +} diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java index 856fac30d..cb0cb9fe7 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandIris.java @@ -19,15 +19,14 @@ package com.volmit.iris.core.commands; import com.volmit.iris.Iris; +import com.volmit.iris.core.ChunkHandler; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisBenchmarking; -import com.volmit.iris.core.tools.IrisPackBenchmarking; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.platform.PlatformChunkGenerator; -import com.volmit.iris.engine.safeguard.ServerBootSFG; import com.volmit.iris.engine.safeguard.UtilsSFG; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.decree.DecreeContext; @@ -47,11 +46,9 @@ import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; -import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; -import java.io.Console; import java.io.File; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -213,6 +210,10 @@ public class CommandIris implements DecreeExecutor { sender().sendMessage(C.GREEN + "" + sender().player().getWorld().getMinHeight() + " to " + sender().player().getWorld().getMaxHeight()); sender().sendMessage(C.GREEN + "Total Height: " + (sender().player().getWorld().getMaxHeight() - sender().player().getWorld().getMinHeight())); } + @Decree(description = "TEST") + public void cpspaper() { + ChunkHandler.exit(); + } @Decree(description = "QOL command to open a overworld studio world.", sync = true) public void so() { diff --git a/core/src/main/java/com/volmit/iris/engine/safeguard/PerformanceSFG.java b/core/src/main/java/com/volmit/iris/engine/safeguard/PerformanceSFG.java index c978ff38c..31e3b0e1c 100644 --- a/core/src/main/java/com/volmit/iris/engine/safeguard/PerformanceSFG.java +++ b/core/src/main/java/com/volmit/iris/engine/safeguard/PerformanceSFG.java @@ -6,18 +6,13 @@ import oshi.hardware.GlobalMemory; import static com.volmit.iris.util.misc.getHardware.*; public class PerformanceSFG { - public static byte CPUPerformanceStage = 3; + public static boolean lowPerformance = false; public void getPerformance(){ - // Performance Stage 3 = Max Performance, 2=Medium, 1=Low - SystemInfo systemInfo = new SystemInfo(); - GlobalMemory globalMemory = systemInfo.getHardware().getMemory(); - long totalMemoryMB = globalMemory.getTotal() / (1024 * 1024); - long availableMemoryMB = globalMemory.getAvailable() / (1024 * 1024); - long totalPageSize = globalMemory.getPageSize() / (1024 * 1024); - long usedMemoryMB = totalMemoryMB - availableMemoryMB; + if (getCPUModel().contains("Xeon")){ + lowPerformance = true; + } // Todo RePixelated: Finish this - } }