diff --git a/build.gradle b/build.gradle index eeca2a32a..bcd5a3319 100644 --- a/build.gradle +++ b/build.gradle @@ -37,7 +37,7 @@ registerCustomOutputTask('Coco', 'D://mcsm/plugins') registerCustomOutputTask('Strange', 'D://Servers/1.17 Test Server/plugins') registerCustomOutputTask('Vatuu', 'D://Minecraft/Servers/1.19.4/plugins') registerCustomOutputTask('CrazyDev22', 'C://Users/Julian/Desktop/server/plugins') -registerCustomOutputTask('Pixel', 'C://Users/repix/Iris Dimension Engine/Iris Development/plugins') +registerCustomOutputTask('Pixel', 'C://Users/repix/Iris Dimension Engine/1.20.4 - Iris Development/plugins') // ========================== UNIX ============================== registerCustomOutputTaskUnix('CyberpwnLT', '/Users/danielmills/development/server/plugins') registerCustomOutputTaskUnix('PsychoLT', '/Volumes/PRO-G40/Minecraft/MinecraftDevelopment/Server/plugins') @@ -246,7 +246,7 @@ allprojects { compileOnly 'org.zeroturnaround:zt-zip:1.14' compileOnly 'com.google.code.gson:gson:2.9.0' compileOnly 'org.ow2.asm:asm:9.2' - compileOnly 'com.google.guava:guava:31.1-jre' + compileOnly 'com.google.guava:guava:33.0.0-jre' compileOnly 'bsf:bsf:2.4.0' compileOnly 'rhino:js:1.7R2' compileOnly 'com.github.ben-manes.caffeine:caffeine:3.0.6' diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java index 898b99fca..06c2f15b0 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java @@ -38,9 +38,13 @@ import net.jpountz.lz4.LZ4FrameInputStream; import net.jpountz.lz4.LZ4FrameOutputStream; import org.apache.commons.lang.RandomStringUtils; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.World; import java.io.*; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.zip.GZIPInputStream; @@ -51,33 +55,119 @@ public class CommandDeveloper implements DecreeExecutor { private CommandTurboPregen turboPregen; @Decree(description = "Get Loaded TectonicPlates Count", origin = DecreeOrigin.BOTH, sync = true) - public void EngineStatus( - @Param(description = "World") - World world - ) { - if (!IrisToolbelt.isIrisWorld(world)) { - sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", Bukkit.getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList())); - return; + public void EngineStatus() { + List IrisWorlds = new ArrayList<>(); + int TotalLoadedChunks = 0; + int TotalQueuedTectonicPlates = 0; + int TotalNotQueuedTectonicPlates = 0; + int TotalTectonicPlates = 0; + + long lowestUnloadDuration = 0; + long highestUnloadDuration = 0; + + for (World world : Bukkit.getWorlds()) { + try { + if (IrisToolbelt.access(world).getEngine() != null) { + IrisWorlds.add(world); + } + } catch (Exception e) { + // no + } } - Engine engine = IrisToolbelt.access(world).getEngine(); - if(engine != null) { - long lastUseSize = engine.getMantle().getLastUseMapMemoryUsage(); + for (World world : IrisWorlds) { + Engine engine = IrisToolbelt.access(world).getEngine(); + TotalQueuedTectonicPlates += (int) engine.getMantle().getToUnload(); + TotalNotQueuedTectonicPlates += (int) engine.getMantle().getNotQueuedLoadedRegions(); + TotalTectonicPlates += engine.getMantle().getLoadedRegionCount(); + if (highestUnloadDuration <= (long) engine.getMantle().getTectonicDuration()) { + highestUnloadDuration = (long) engine.getMantle().getTectonicDuration(); + } + if (lowestUnloadDuration >= (long) engine.getMantle().getTectonicDuration()) { + lowestUnloadDuration = (long) engine.getMantle().getTectonicDuration(); + } + for (Chunk chunk : world.getLoadedChunks()) { + if (chunk.isLoaded()) { + TotalLoadedChunks++; + } + } + } + Iris.info("-------------------------"); + Iris.info(C.DARK_PURPLE + "Engine Status"); + Iris.info(C.DARK_PURPLE + "Total Loaded Chunks: " + C.LIGHT_PURPLE + TotalLoadedChunks); + Iris.info(C.DARK_PURPLE + "Tectonic Limit: " + C.LIGHT_PURPLE + IrisEngineSVC.getTectonicLimit()); + Iris.info(C.DARK_PURPLE + "Tectonic Total Plates: " + C.LIGHT_PURPLE + TotalTectonicPlates); + Iris.info(C.DARK_PURPLE + "Tectonic Active Plates: " + C.LIGHT_PURPLE + TotalNotQueuedTectonicPlates); + Iris.info(C.DARK_PURPLE + "Tectonic ToUnload: " + C.LIGHT_PURPLE + TotalQueuedTectonicPlates); + Iris.info(C.DARK_PURPLE + "Lowest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(lowestUnloadDuration)); + Iris.info(C.DARK_PURPLE + "Highest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(highestUnloadDuration)); + Iris.info(C.DARK_PURPLE + "Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize())); + Iris.info("-------------------------"); + } - Iris.info("-------------------------"); - Iris.info(C.DARK_PURPLE + "Engine Status"); - Iris.info(C.DARK_PURPLE + "Tectonic Limit: " + C.LIGHT_PURPLE + IrisEngineSVC.getTectonicLimit()); - Iris.info(C.DARK_PURPLE + "Tectonic Loaded Plates: " + C.LIGHT_PURPLE + engine.getMantle().getLoadedRegionCount()); - Iris.info(C.DARK_PURPLE + "Tectonic Plates: " + C.LIGHT_PURPLE + engine.getMantle().getNotClearedLoadedRegions()); - Iris.info(C.DARK_PURPLE + "Tectonic ToUnload: " + C.LIGHT_PURPLE + engine.getMantle().getToUnload()); - Iris.info(C.DARK_PURPLE + "Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration((long) engine.getMantle().getTectonicDuration())); - Iris.info(C.DARK_PURPLE + "Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize())); - Iris.info(C.DARK_PURPLE + "LastUse Size: " + C.LIGHT_PURPLE + Form.mem(lastUseSize)); - Iris.info("-------------------------"); - } else { - Iris.info(C.RED + "Engine is null!"); + @Decree(description = "Test") + public void benchmarkMantle( + @Param(description = "The world to bench", aliases = {"world"}) + World world + ) throws IOException, ClassNotFoundException { + Engine engine = IrisToolbelt.access(world).getEngine(); + int maxHeight = engine.getTarget().getHeight(); + File folder = new File(Bukkit.getWorldContainer(), world.getName()); + int c = 0; + //MCAUtil.read() + + File tectonicplates = new File(folder, "mantle"); + for (File i : Objects.requireNonNull(tectonicplates.listFiles())) { + TectonicPlate.read(maxHeight, i); + c++; + Iris.info("Loaded count: " + c ); + + } + + } + + @Decree(description = "UnloadChunks for good reasons.") + public void unloadchunks() { + List IrisWorlds = new ArrayList<>(); + int chunksUnloaded = 0; + for (World world : Bukkit.getWorlds()) { + try { + if (IrisToolbelt.access(world).getEngine() != null) { + IrisWorlds.add(world); + } + } catch (Exception e) { + // no + } + } + + for (World world : IrisWorlds) { + for (Chunk chunk : world.getLoadedChunks()) { + if (chunk.isLoaded()) { + chunk.unload(); + chunksUnloaded++; + } + } + } + Iris.info(C.IRIS + "Chunks Unloaded: " + chunksUnloaded); + + } + + @Decree(description = "Test", aliases = {"ip"}) + public void network() { + try { + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + for (NetworkInterface ni : Collections.list(networkInterfaces)) { + Iris.info("Display Name: %s", ni.getDisplayName()); + Enumeration inetAddresses = ni.getInetAddresses(); + for (InetAddress ia : Collections.list(inetAddresses)) { + Iris.info("IP: %s", ia.getHostAddress()); + } + } + } catch (Exception e) { + e.printStackTrace(); } } + @Decree(description = "Test", origin = DecreeOrigin.BOTH) public void test() { Iris.info("Test Developer CMD Executed"); 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 dce8d8db0..471189d9e 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 @@ -24,6 +24,7 @@ import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.tools.IrisBenchmarking; 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.core.safeguard.UtilsSFG; import com.volmit.iris.engine.object.IrisWorld; @@ -52,6 +53,7 @@ import org.bukkit.scheduler.BukkitRunnable; import java.io.Console; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -216,6 +218,44 @@ public class CommandIris implements DecreeExecutor { Iris.service(StudioSVC.class).open(sender(), 1337, "overworld"); } + @Decree(description = "Check if iris has access to that specific world") + public void hasAccess( + @Param(description = "The world to access", aliases = {"world"}) + World world + ) { + Engine engine = IrisToolbelt.access(world).getEngine(); + if (engine != null) { + sender().sendMessage("Access granted successfully."); + } else { + sender().sendMessage(C.RED + "Failed to grant access."); + } + } + + @Decree(description = "All Iris Worlds on the server.", aliases = {"worlds"}) + public void irisworlds() { + List IrisWorlds = new ArrayList<>(); + for (World world : Bukkit.getWorlds()) { + try { + if (IrisToolbelt.access(world).getEngine() != null) { + IrisWorlds.add(world); + } + } catch (Exception e) { + // no + } + } + if (sender().isPlayer()) { + sender.sendMessage(C.IRIS + "Iris Worlds:"); + for (World world : IrisWorlds) { + sender.sendMessage(C.GREEN + "- " + world.getName()); + } + } else { + Iris.info(C.IRIS + "Iris Worlds:"); + for (World world : IrisWorlds) { + sender.sendMessage(C.GREEN + "- " + world.getName()); + } + } + } + @Decree(description = "Remove an Iris world", aliases = {"del", "rm", "delete"}, sync = true) public void remove( @Param(description = "The world to remove") diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandWhat.java b/core/src/main/java/com/volmit/iris/core/commands/CommandWhat.java index 3686ad81a..48d8c726e 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandWhat.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandWhat.java @@ -22,7 +22,9 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.edit.BlockSignal; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.tools.IrisToolbelt; +import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.object.IrisBiome; +import com.volmit.iris.engine.object.IrisRegion; import com.volmit.iris.util.data.B; import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeOrigin; @@ -37,6 +39,7 @@ import org.bukkit.Material; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; +import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; @Decree(name = "what", origin = DecreeOrigin.PLAYER, studio = true, description = "Iris What?") @@ -82,6 +85,19 @@ public class CommandWhat implements DecreeExecutor { } } + @Decree(description = "What region am i in?", origin = DecreeOrigin.PLAYER) + public void region() { + try { + Chunk chunk = world().getChunkAt(player().getLocation().getBlockZ() / 16, player().getLocation().getBlockZ() / 16); + IrisRegion r = engine().getRegion(chunk); + sender().sendMessage("IRegion: " + r.getLoadKey() + " (" + r.getName() + ")"); + + } catch (Throwable e) { + Iris.reportError(e); + sender().sendMessage(C.IRIS + "Iris worlds only."); + } + } + @Decree(description = "What block am i looking at?", origin = DecreeOrigin.PLAYER) public void block() { BlockData bd; @@ -147,7 +163,7 @@ public class CommandWhat implements DecreeExecutor { sender().sendMessage("Found " + v.get() + " Nearby Markers (" + marker + ")"); } else { - sender().sendMessage("Iris worlds only."); + sender().sendMessage(C.IRIS + "Iris worlds only."); } } } diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java b/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java index c23b6c6fd..b693e0034 100644 --- a/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java +++ b/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java @@ -19,9 +19,7 @@ package com.volmit.iris.core.pregenerator; import com.volmit.iris.Iris; -import com.volmit.iris.core.tools.IrisPackBenchmarking; import com.volmit.iris.util.collection.KSet; -import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.math.M; @@ -30,15 +28,12 @@ import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.Looper; -import lombok.Getter; -import lombok.Setter; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; -import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmark; public class IrisPregenerator { private final PregenTask task; @@ -112,11 +107,7 @@ public class IrisPregenerator { if (cl.flip()) { double percentage = ((double) generated.get() / (double) totalChunks.get()) * 100; - if(benchmark) { - Iris.info(C.GREEN +"Benchmark: " + C.WHITE + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (%.0f%%) " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration((double) eta, 2), percentage); - } else { - Iris.info("Pregen: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (%.0f%%) " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration(eta, 2), percentage); - } + Iris.info("Pregen: " + Form.f(generated.get()) + " of " + Form.f(totalChunks.get()) + " (%.0f%%) " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration(eta, 2), percentage); } return 1000; } diff --git a/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java b/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java index 6f3f79535..767e9c166 100644 --- a/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java +++ b/core/src/main/java/com/volmit/iris/core/service/IrisEngineSVC.java @@ -4,32 +4,67 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.platform.PlatformChunkGenerator; +import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; +import com.volmit.iris.util.mantle.TectonicPlate; import com.volmit.iris.util.misc.getHardware; import com.volmit.iris.util.plugin.IrisService; +import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.Looper; +import com.volmit.iris.util.scheduling.PrecisionStopwatch; import org.bukkit.Bukkit; import org.bukkit.World; +import org.bukkit.event.EventHandler; +import org.bukkit.event.world.WorldLoadEvent; +import org.bukkit.event.world.WorldUnloadEvent; +import org.checkerframework.checker.units.qual.A; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Supplier; public class IrisEngineSVC implements IrisService { + public static IrisEngineSVC instance; private static final AtomicInteger tectonicLimit = new AtomicInteger(30); private final ReentrantLock lastUseLock = new ReentrantLock(); private final KMap lastUse = new KMap<>(); + private List IrisWorlds; private Looper cacheTicker; + private Looper freezeTicker; private Looper trimTicker; private Looper unloadTicker; + private Looper updateTicker; + private PrecisionStopwatch trimAlive; + private PrecisionStopwatch unloadAlive; + public PrecisionStopwatch trimActiveAlive; + public PrecisionStopwatch unloadActiveAlive; + private AtomicInteger TotalTectonicPlates; + private AtomicInteger TotalQueuedTectonicPlates; + private AtomicInteger TotalNotQueuedTectonicPlates; + private AtomicBoolean IsUnloadAlive; + private AtomicBoolean IsTrimAlive; + ChronoLatch cl; + public List corruptedIrisWorlds = new ArrayList<>(); @Override public void onEnable() { + this.cl = new ChronoLatch(5000); + IrisWorlds = new ArrayList<>(); + IsUnloadAlive = new AtomicBoolean(true); + IsTrimAlive = new AtomicBoolean(true); + trimActiveAlive = new PrecisionStopwatch(); + unloadActiveAlive = new PrecisionStopwatch(); + trimAlive = new PrecisionStopwatch(); + unloadAlive = new PrecisionStopwatch(); + TotalTectonicPlates = new AtomicInteger(); + TotalQueuedTectonicPlates = new AtomicInteger(); + TotalNotQueuedTectonicPlates = new AtomicInteger(); tectonicLimit.set(2); long t = getHardware.getProcessMemory(); while (t > 200) { @@ -37,15 +72,50 @@ public class IrisEngineSVC implements IrisService { t = t - 200; } this.setup(); + trimAlive.begin(); + unloadAlive.begin(); + trimActiveAlive.begin(); + unloadActiveAlive.begin(); + + updateTicker.start(); cacheTicker.start(); trimTicker.start(); unloadTicker.start(); + freezeTicker.start(); + instance = this; + } public static int getTectonicLimit() { return tectonicLimit.get(); } + public void EngineReport() { + Iris.info(C.RED + "CRITICAL ENGINE FAILURE! The Tectonic Trim subsystem has not responded for: " + Form.duration(trimAlive.getMillis()) + "."); + } + + @EventHandler + public void onWorldUnload(WorldUnloadEvent event) { + updateWorlds(); + } + + @EventHandler + public void onWorldLoad(WorldLoadEvent event) { + updateWorlds(); + } + + public void updateWorlds() { + for (World world : Bukkit.getWorlds()) { + try { + if (IrisToolbelt.access(world).getEngine() != null) { + IrisWorlds.add(world); + } + } catch (Exception e) { + // no + } + } + } + private void setup() { cacheTicker = new Looper() { @Override @@ -57,7 +127,7 @@ public class IrisEngineSVC implements IrisService { Long last = lastUse.get(key); if (last == null) continue; - if (now - last > 60000) { // 1 minute + if (now - last > 60000) { lastUse.remove(key); } } @@ -67,11 +137,81 @@ public class IrisEngineSVC implements IrisService { return 1000; } }; + + updateTicker = new Looper() { + @Override + protected long loop() { + try { + TotalQueuedTectonicPlates.set(0); + TotalNotQueuedTectonicPlates.set(0); + TotalTectonicPlates.set(0); + for (World world : IrisWorlds) { + Engine engine = IrisToolbelt.access(world).getEngine(); + TotalQueuedTectonicPlates.addAndGet((int) engine.getMantle().getToUnload()); + TotalNotQueuedTectonicPlates.addAndGet((int) engine.getMantle().getNotQueuedLoadedRegions()); + TotalTectonicPlates.addAndGet(engine.getMantle().getLoadedRegionCount()); + } + } catch (Exception e) { + return -1; + } + return 1000; + } + }; + + freezeTicker = new Looper() { + @Override + protected long loop() { + if (cl.flip()) { + if (!unloadTicker.isAlive()) { + Iris.debug(C.YELLOW + "UnloadTicker Found dead?"); + } + if (!trimTicker.isAlive()) { + Iris.debug(C.YELLOW + "UnloadTicker Found dead?"); + } + Runtime runtime = Runtime.getRuntime(); + long usedMemory = runtime.totalMemory() - runtime.freeMemory(); + long maxMemory = runtime.maxMemory(); + double memoryUsagePercentage = ((double) usedMemory / (double) maxMemory); + double externalTrim = trimActiveAlive.getMillis(); + double externalUnload = unloadActiveAlive.getMillis(); + double localTrim = trimAlive.getMillis(); + double localUnload = unloadAlive.getMillis(); + if (localTrim > 120000) { + Iris.info(C.YELLOW + "EngineSVC Alert! The Trim subsystem has exceeded its expected response time: " + Form.duration(trimAlive.getMillis()) + "."); + } + if (localUnload > 120000) { + Iris.info(C.YELLOW + "EngineSVC Alert! The Tectonic subsystem has exceeded its expected response time: " + Form.duration(trimAlive.getMillis()) + "."); + } + + if (memoryUsagePercentage > 0.9 && tectonicLimit.get() < TotalTectonicPlates.get()) { + if (localTrim > 30000 && externalTrim > 10000) { + Iris.info(C.RED + "CRITICAL EngineSVC FAILURE! The Tectonic Trim subsystem has not trimmed for: " + Form.duration(trimAlive.getMillis()) + "."); + IsTrimAlive.set(false); + } else { + Iris.info(C.IRIS + "EngineSVC reports activity within the Trim subsystem system!"); + IsTrimAlive.set(true); + } + + if (localUnload > 30000 && externalUnload > 12000 && TotalQueuedTectonicPlates.get() != 0) { + Iris.info(C.RED + "CRITICAL EngineSVC FAILURE! The Tectonic Unload subsystem has not unloaded for: " + Form.duration(trimAlive.getMillis()) + "."); + IsUnloadAlive.set(false); + } else { + Iris.info(C.IRIS + "EngineSVC reports activity within the Unload subsystem system!"); + IsUnloadAlive.set(true); + } + } + } + return 1; + } + + }; + trimTicker = new Looper() { private final Supplier supplier = createSupplier(); @Override protected long loop() { long start = System.currentTimeMillis(); + trimAlive.reset(); try { Engine engine = supplier.get(); if (engine != null) { @@ -79,7 +219,9 @@ public class IrisEngineSVC implements IrisService { } } catch (Throwable e) { Iris.reportError(e); - // return -1; + Iris.info(C.RED + "EngineSVC: Failed to trim. Please contact support!"); + e.printStackTrace(); + return -1; } int size = lastUse.size(); @@ -96,6 +238,7 @@ public class IrisEngineSVC implements IrisService { @Override protected long loop() { long start = System.currentTimeMillis(); + unloadAlive.reset(); try { Engine engine = supplier.get(); if (engine != null) { @@ -107,6 +250,8 @@ public class IrisEngineSVC implements IrisService { } } catch (Throwable e) { Iris.reportError(e); + Iris.info(C.RED + "EngineSVC: Failed to unload. Please contact support!"); + e.printStackTrace(); return -1; } @@ -145,6 +290,8 @@ public class IrisEngineSVC implements IrisService { } } } catch (Throwable e) { + Iris.info(C.RED + "EngineSVC: Failed to create supplier. Please contact support!"); + e.printStackTrace(); Iris.reportError(e); } return null; diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java b/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java index da882f56c..fb4d344eb 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisConverter.java @@ -2,30 +2,26 @@ package com.volmit.iris.core.tools; import com.volmit.iris.Iris; import com.volmit.iris.engine.object.*; -import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; -import com.volmit.iris.util.math.M; -import com.volmit.iris.util.math.RollingSequence; import com.volmit.iris.util.nbt.io.NBTUtil; import com.volmit.iris.util.nbt.io.NamedTag; import com.volmit.iris.util.nbt.tag.*; -import com.volmit.iris.util.plugin.VolmitPlugin; import com.volmit.iris.util.plugin.VolmitSender; +import com.volmit.iris.util.reflect.V; import com.volmit.iris.util.scheduling.J; -import com.volmit.iris.util.scheduling.Looper; import com.volmit.iris.util.scheduling.PrecisionStopwatch; -import javassist.bytecode.ByteArray; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import org.bukkit.Bukkit; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; -import org.bukkit.util.BlockVector; +import org.bukkit.util.Vector; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -33,15 +29,14 @@ import java.util.concurrent.atomic.AtomicInteger; public class IrisConverter { public static void convertSchematics(VolmitSender sender) { - Map blockmap = new HashMap<>(); File folder = Iris.instance.getDataFolder("convert"); FilenameFilter filter = (dir, name) -> name.endsWith(".schem"); File[] fileList = folder.listFiles(filter); + ExecutorService executorService = Executors.newFixedThreadPool(1); + executorService.submit(() -> { for (File schem : fileList) { try { - ExecutorService executorService = Executors.newFixedThreadPool(1); - executorService.submit(() -> { PrecisionStopwatch p = new PrecisionStopwatch(); boolean largeObject = false; NamedTag tag = null; @@ -57,24 +52,26 @@ public class IrisConverter { int objW = ((ShortTag) compound.get("Width")).getValue(); int objH = ((ShortTag) compound.get("Height")).getValue(); int objD = ((ShortTag) compound.get("Length")).getValue(); - IrisObject object = new IrisObject(objW, objH, objD); int mv = objW * objH * objD; AtomicInteger v = new AtomicInteger(0); - if (mv > 100000) { + AtomicInteger fv = new AtomicInteger(0); + if (mv > 500_000) { largeObject = true; Iris.info(C.GRAY + "Converting.. "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob")); Iris.info(C.GRAY + "- It may take a while"); if (sender.isPlayer()) { J.a(() -> { - while (v.get() != mv) { - double pr = ((double) v.get() / (double ) mv); - sender.sendProgress(pr, "Converting"); - J.sleep(16); - } +// while (v.get() != mv) { +// double pr = ((double) v.get() / (double ) mv); +// sender.sendProgress(pr, "Converting"); +// J.sleep(16); +// } }); } } + CompoundTag paletteTag = (CompoundTag) compound.get("Palette"); + Map blockmap = new HashMap<>(paletteTag.size(), 0.9f); for (Map.Entry> entry : paletteTag.getValue().entrySet()) { String blockName = entry.getKey(); BlockData bd = Bukkit.createBlockData(blockName); @@ -84,18 +81,179 @@ public class IrisConverter { } ByteArrayTag byteArray = (ByteArrayTag) compound.get("BlockData"); - byte[] l = byteArray.getValue(); + byte[] originalBlockArray = byteArray.getValue(); + int b = 0; + int a = 0; + Map y = new HashMap<>(); + Map x = new HashMap<>(); + Map z = new HashMap<>(); + + // Height adjustments + for (int h = 0; h < objH; h++) { + if (b == 0) { + y.put(h, (byte) 0); + } + if (b > 0) { + y.put(h, (byte) 1); + } + a = 0; + b = 0; + for (int d = 0; d < objD; d++) { + for (int w = 0; w < objW; w++) { + BlockData db = blockmap.get((int) originalBlockArray[fv.get()]); + if(db.getAsString().contains("minecraft:air")) { + a++; + } else { + b++; + } + fv.getAndAdd(1); + } + } + } + fv.set(0); + + // Width adjustments + for (int w = 0; w < objW; w++) { + if (b == 0) { + x.put(w, (byte) 0); + } + if (b > 0) { + x.put(w, (byte) 1); + } + a = 0; + b = 0; + for (int h = 0; h < objH; h++) { + for (int d = 0; d < objD; d++) { + BlockData db = blockmap.get((int) originalBlockArray[fv.get()]); + if(db.getAsString().contains("minecraft:air")) { + a++; + } else { + b++; + } + fv.getAndAdd(1); + } + } + } + fv.set(0); + + // Depth adjustments + for (int d = 0; d < objD; d++) { + if (b == 0) { + z.put(d, (byte) 0); + } + if (b > 0) { + z.put(d, (byte) 1); + } + a = 0; + b = 0; + for (int h = 0; h < objH; h++) { + for (int w = 0; w < objW; w++) { + BlockData db = blockmap.get((int) originalBlockArray[fv.get()]); + if(db.getAsString().contains("minecraft:air")) { + a++; + } else { + b++; + } + fv.getAndAdd(1); + } + } + } + fv.set(0); + int CorrectObjH = getCorrectY(y, objH); + int CorrectObjW = getCorrectX(x, objW); + int CorrectObjD = getCorrectZ(z, objD); + + //IrisObject object = new IrisObject(CorrectObjW, CorrectObjH, CorrectObjH); + IrisObject object = new IrisObject(objW, objH, objD); + Vector originalVector = new Vector(objW,objH,objD); + + + int[] yc = null; + int[] xc = null; + int[] zc = null; + + + int fo = 0; + int so = 0; + int o = 0; + int c = 0; + for (Integer i : y.keySet()) { + if (y.get(i) == 0) { + o++; + } + if (y.get(i) == 1) { + c++; + if (c == 1) { + fo = o; + } + o = 0; + } + } + so = o; + yc = new int[]{fo, so}; + + fo = 0; + so = 0; + o = 0; + c = 0; + for (Integer i : x.keySet()) { + if (x.get(i) == 0) { + o++; + } + if (x.get(i) == 1) { + c++; + if (c == 1) { + fo = o; + } + o = 0; + } + } + so = o; + xc = new int[]{fo, so}; + + fo = 0; + so = 0; + o = 0; + c = 0; + for (Integer i : z.keySet()) { + if (z.get(i) == 0) { + o++; + } + if (z.get(i) == 1) { + c++; + if (c == 1) { + fo = o; + } + o = 0; + } + } + so = o; + zc = new int[]{fo, so}; + + int h1, h2, w1, w2, v1 = 0, volume = objW * objH * objD; + Map blockLocationMap = new LinkedHashMap<>(); + boolean hasAir = false; + int pos = 0; + for (int i : originalBlockArray) { + blockLocationMap.put(pos, i); + pos++; + } + + for (int h = 0; h < objH; h++) { for (int d = 0; d < objD; d++) { for (int w = 0; w < objW; w++) { - BlockData db = blockmap.get((int) l[v.get()]); - object.setUnsigned(w, h, d, db); + BlockData bd = blockmap.get((int) originalBlockArray[v.get()]); + if (!bd.getMaterial().isAir()) { + object.setUnsigned(w, h, d, bd); + } v.getAndAdd(1); } } } + try { object.write(new File(folder, schem.getName().replace(".schem", ".iob"))); } catch (IOException e) { @@ -103,7 +261,11 @@ public class IrisConverter { throw new RuntimeException(e); } if (sender.isPlayer()) { - + if (largeObject) { + sender.sendMessage(C.IRIS + "Converted "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis())); + } else { + sender.sendMessage(C.IRIS + "Converted " + schem.getName() + " -> " + schem.getName().replace(".schem", ".iob")); + } } if (largeObject) { Iris.info(C.GRAY + "Converted "+ schem.getName() + " -> " + schem.getName().replace(".schem", ".iob") + " in " + Form.duration(p.getMillis())); @@ -112,13 +274,120 @@ public class IrisConverter { } // schem.delete(); } - }); } catch (Exception e) { Iris.info(C.RED + "Failed to convert: " + schem.getName()); + if (sender.isPlayer()) { + sender.sendMessage(C.RED + "Failed to convert: " + schem.getName()); + } e.printStackTrace(); Iris.reportError(e); } } + }); + } + + public static boolean isNewPointFurther(int[] originalPoint, int[] oldPoint, int[] newPoint) { + int oX = oldPoint[1]; + int oY = oldPoint[2]; + int oZ = oldPoint[3]; + + int nX = newPoint[1]; + int nY = newPoint[2]; + int nZ = newPoint[3]; + + int orX = originalPoint[1]; + int orY = originalPoint[2]; + int orZ = originalPoint[3]; + + double oldDistance = Math.sqrt(Math.pow(oX - orX, 2) + Math.pow(oY - orY, 2) + Math.pow(oZ - orZ, 2)); + double newDistance = Math.sqrt(Math.pow(nX - orX, 2) + Math.pow(nY - orY, 2) + Math.pow(nZ - orZ, 2)); + + if (newDistance > oldDistance) { + return true; + } + return false; + } + + public static int[] getCoordinates(int pos, int obX, int obY, int obZ) { + int z = 0; + int[] coords = new int[4]; + for (int h = 0; h < obY; h++) { + for (int d = 0; d < obZ; d++) { + for (int w = 0; w < obX; w++) { + if (z == pos) { + coords[1] = w; + coords[2] = h; + coords[3] = d; + return coords; + } + z++; + } + } + } + return null; + } + + public static int getCorrectY(Map y, int H) { + int fo = 0; + int so = 0; + int o = 0; + int c = 0; + for (Integer i : y.keySet()) { + if (y.get(i) == 0) { + o++; + } + if (y.get(i) == 1) { + c++; + if(c == 1){ + fo = o; + } + o = 0; + } + } + so = o; + return H = H - (fo + so); + } + + public static int getCorrectX(Map x, int W) { + int fo = 0; + int so = 0; + int o = 0; + int c = 0; + for (Integer i : x.keySet()) { + if (x.get(i) == 0) { + o++; + } + if (x.get(i) == 1) { + c++; + if(c == 1){ + fo = o; + } + o = 0; + } + } + so = o; + return W = W - (fo + so); + } + + public static int getCorrectZ(Map z, int D) { + int fo = 0; + int so = 0; + int o = 0; + int c = 0; + for (Integer i : z.keySet()) { + if (z.get(i) == 0) { + o++; + } + if (z.get(i) == 1) { + c++; + if(c == 1){ + fo = o; + } + o = 0; + } + } + so = o; + return D = D - (fo + so); } } diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java index 7e6285d07..3e90aced1 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java @@ -46,10 +46,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmark; import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode; /** @@ -86,6 +82,10 @@ public class IrisCreator { * the world itself. Studio worlds are deleted when they are unloaded. */ private boolean studio = false; + /** + * Benchmark mode + */ + private boolean benchmark = false; public static boolean removeFromBukkitYml(String name) throws IOException { YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML); @@ -110,7 +110,7 @@ public class IrisCreator { * @return the IrisAccess * @throws IrisException shit happens */ - IrisPackBenchmarking PackBench = new IrisPackBenchmarking(); + public World create() throws IrisException { if (unstablemode){ Iris.info(C.RED + "Your server is experiencing an incompatibility with the Iris plugin. Please rectify this problem to avoid further complications."); @@ -193,7 +193,7 @@ public class IrisCreator { done.set(true); - if (sender.isPlayer()) { + if (sender.isPlayer() && !benchmark) { J.s(() -> { sender.player().teleport(new Location(world.get(), 0, world.get().getHighestBlockYAt(0, 0), 0)); }); diff --git a/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java b/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java index 13577cc82..60c9aa76b 100644 --- a/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java +++ b/core/src/main/java/com/volmit/iris/core/tools/IrisPackBenchmarking.java @@ -21,97 +21,28 @@ import static com.volmit.iris.core.commands.CommandIris.BenchDimension; public class IrisPackBenchmarking { - public static boolean loaded = false; - public static boolean benchmark = false; - static boolean cancelled = false; - static boolean pregenInProgress = false; - static long startTime; - static long totalChunks; - static long generatedChunks; - static double elapsedTimeNs; + public static IrisPackBenchmarking instance; + long totalChunks; + long generatedChunks; + double elapsedTimeNs; - public static void runBenchmark() { - // IrisPackBenchmarking IrisPackBenchmarking = new IrisPackBenchmarking(); - benchmark = true; - Iris.info(C.BLUE + "Benchmarking Dimension: " + C.AQUA + BenchDimension); - //progress(); - CompletableFuture future = CompletableFuture.runAsync(() -> { - Iris.info(C.GOLD + "Setting everything up.."); - try { - String BenchmarkFolder = "\\Benchmark"; - File folder = new File(BenchmarkFolder); - if (folder.exists() && folder.isDirectory()) { - FileUtils.deleteDirectory(folder); - Iris.debug("Deleted old Benchmark"); - } else { - Iris.info(C.GOLD + "Old Benchmark not found!"); - if(folder.exists()){ - Iris.info(C.RED + "FAILED To remove old Benchmark!"); - //cancelled = true; - - } - } - } catch (Exception e) { - throw new RuntimeException(); - } - - }).thenRun(() -> { - Iris.info(C.GOLD + "Creating Benchmark Environment"); - createBenchmark(); - - }).thenRun(() -> { - Iris.info( C.BLUE + "Benchmark Started!"); - boolean done = false; - startBenchmarkTimer(); - startBenchmark(); - basicScheduler(); - }).thenRun(() -> { - - }); - // cancelled = future.cancel(true); - try { - future.get(); - } catch (InterruptedException | ExecutionException e) { - e.printStackTrace(); - } - } - - private static void results(){ - double averageCps = calculateAverageCPS(); - Iris.info("Benchmark Dimension: " + BenchDimension); - Iris.info("Speeds"); - Iris.info("- Average CPS: " + roundToTwoDecimalPlaces(averageCps)); - Iris.info("Duration: " + roundToTwoDecimalPlaces(elapsedTimeNs)); + public void runBenchmark() { } - private static void basicScheduler() { - while (true) { - totalChunks = IrisPregenerator.getLongTotalChunks(); - generatedChunks = IrisPregenerator.getLongGeneratedChunks(); - if(totalChunks > 0) { - if (generatedChunks >= totalChunks) { - Iris.info("Benchmark Completed!"); - elapsedTimeNs = stopBenchmarkTimer(); - results(); - break; - } - } - //J.sleep(100); test - } - } - static void createBenchmark(){ + public void createBenchmark(){ try { IrisToolbelt.createWorld() .dimension(BenchDimension) .name("Benchmark") .seed(1337) .studio(false) + .benchmark(true) .create(); } catch (IrisException e) { throw new RuntimeException(e); } } - static void startBenchmark(){ + public void startBenchmark(){ int x = 0; int z = 0; IrisToolbelt.pregenerate(PregenTask @@ -122,49 +53,4 @@ public class IrisPackBenchmarking { .build(), Bukkit.getWorld("Benchmark") ); } - static void startLazyBenchmark(){ - int x = 0; - int z = 0; - LazyPregenerator.LazyPregenJob pregenJob = LazyPregenerator.LazyPregenJob.builder() - //.world("Benchmark") - .healingPosition(0) - .healing(false) - .chunksPerMinute(3200) - .radiusBlocks(5000) - .position(0) - .build(); - - LazyPregenerator pregenerator = new LazyPregenerator(pregenJob, new File("plugins/Iris/lazygen.json")); - pregenerator.start(); - } - public static double calculateAverageCPS() { - double elapsedTimeSec = elapsedTimeNs / 1_000_000_000.0; // Convert to seconds - return generatedChunks / elapsedTimeSec; - } - - private static void startBenchmarkTimer() { - startTime = System.nanoTime(); - } - - private static double stopBenchmarkTimer() { - long endTime = System.nanoTime(); - return (endTime - startTime) / 1_000_000_000.0; - } - - public static void deleteDirectory(File dir) { - File[] files = dir.listFiles(); - if(files != null) { - for(File file: files) { - if(file.isDirectory()) { - deleteDirectory(file); - } else { - file.delete(); - } - } - } - dir.delete(); - } - private static double roundToTwoDecimalPlaces(double value) { - return Double.parseDouble(String.format("%.2f", value)); - } } \ No newline at end of file diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java b/core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java index f61d90531..8e28490d8 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngineMantle.java @@ -19,8 +19,6 @@ package com.volmit.iris.engine; import com.volmit.iris.Iris; -import com.volmit.iris.core.IrisSettings; -import com.volmit.iris.core.tools.IrisPackBenchmarking; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.mantle.EngineMantle; @@ -47,9 +45,6 @@ import java.io.IOException; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmark; -import static com.volmit.iris.core.safeguard.PerformanceSFG.*; - @Data @EqualsAndHashCode(exclude = "engine") @ToString(exclude = "engine") @@ -290,17 +285,10 @@ public class IrisEngineMantle implements EngineMantle { x = Math.max(x, c); x = (Math.max(x, 16) + 16) >> 4; x = x % 2 == 0 ? x + 1 : x; - if (benchmark){ - x = 4; - Iris.info("Mantle Size: " + x + " Chunks " + C.BLUE + "BENCHMARK MODE"); - } else { - Iris.info("Mantle Size: " + x + " Chunks"); - Iris.info(" Object Mantle Size: " + u + " (" + ((Math.max(u, 16) + 16) >> 4) + ")"); - Iris.info(" Jigsaw Mantle Size: " + jig + " (" + ((Math.max(jig, 16) + 16) >> 4) + ")"); - Iris.info(" Carving Mantle Size: " + c + " (" + ((Math.max(c, 16) + 16) >> 4) + ")"); - } - - + Iris.info("Mantle Size: " + x + " Chunks"); + Iris.info(" Object Mantle Size: " + u + " (" + ((Math.max(u, 16) + 16) >> 4) + ")"); + Iris.info(" Jigsaw Mantle Size: " + jig + " (" + ((Math.max(jig, 16) + 16) >> 4) + ")"); + Iris.info(" Carving Mantle Size: " + c + " (" + ((Math.max(c, 16) + 16) >> 4) + ")"); return x; } diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java index 25aca5aed..62e18e0d8 100644 --- a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java +++ b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java @@ -298,7 +298,7 @@ public interface EngineMantle extends IObjectPlacer { default long getToUnload(){ return getMantle().getToUnload().size(); } - default long getNotClearedLoadedRegions(){ + default long getNotQueuedLoadedRegions(){ return getMantle().getLoadedRegions().size() - getMantle().getToUnload().size(); } default double getTectonicDuration(){ diff --git a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java index e71652a28..52982442c 100644 --- a/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java +++ b/core/src/main/java/com/volmit/iris/util/mantle/Mantle.java @@ -21,6 +21,7 @@ package com.volmit.iris.util.mantle; import com.google.common.util.concurrent.AtomicDouble; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; +import com.volmit.iris.core.service.IrisEngineSVC; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.engine.data.cache.Cache; import com.volmit.iris.engine.framework.Engine; @@ -423,7 +424,7 @@ public class Mantle { ioTrim.set(true); unloadLock.lock(); try { - if (lastUse != null) { + if (lastUse != null && IrisEngineSVC.instance != null) { if (!lastUse.isEmpty()) { Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration.get(), 0)); for (Long i : new ArrayList<>(lastUse.keySet())) { @@ -433,7 +434,7 @@ public class Mantle { if (lastUseTime != null && M.ms() - lastUseTime >= finalAdjustedIdleDuration) { toUnload.add(i); Iris.debug("Tectonic Region added to unload"); - //Iris.panic(); + IrisEngineSVC.instance.trimActiveAlive.reset(); } }); } @@ -452,37 +453,41 @@ public class Mantle { AtomicInteger i = new AtomicInteger(); unloadLock.lock(); BurstExecutor burst = null; - try { - KList copy = toUnload.copy(); - burst = MultiBurst.burst.burst(copy.size()); - burst.setMulticore(copy.size() > tectonicLimit); - for (long id : copy) { - burst.queue(() -> - hyperLock.withLong(id, () -> { - TectonicPlate m = loadedRegions.get(id); - if (m != null) { - try { - m.write(fileForRegion(dataFolder, id)); - loadedRegions.remove(id); - lastUse.remove(id); - toUnload.remove(id); - i.incrementAndGet(); - Iris.debug("Unloaded Tectonic Plate " + C.DARK_GREEN + Cache.keyX(id) + " " + Cache.keyZ(id)); - } catch (IOException e) { - Iris.reportError(e); + if (IrisEngineSVC.instance != null) { + try { + KList copy = toUnload.copy(); + burst = MultiBurst.burst.burst(copy.size()); + burst.setMulticore(copy.size() > tectonicLimit); + for (long id : copy) { + burst.queue(() -> + hyperLock.withLong(id, () -> { + TectonicPlate m = loadedRegions.get(id); + if (m != null) { + try { + m.write(fileForRegion(dataFolder, id)); + loadedRegions.remove(id); + lastUse.remove(id); + toUnload.remove(id); + i.incrementAndGet(); + Iris.debug("Unloaded Tectonic Plate " + C.DARK_GREEN + Cache.keyX(id) + " " + Cache.keyZ(id)); + IrisEngineSVC.instance.unloadActiveAlive.reset(); + } catch (IOException e) { + Iris.reportError(e); + } } - } - })); + })); - } - burst.complete(); - } catch (Throwable e) { - e.printStackTrace(); - if (burst != null) + } burst.complete(); - } finally { - unloadLock.unlock(); - ioTectonicUnload.set(true); + } catch (Throwable e) { + e.printStackTrace(); + if (burst != null) + burst.complete(); + } finally { + unloadLock.unlock(); + ioTectonicUnload.set(true); + } + return i.get(); } return i.get(); }