mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-07-16 03:44:04 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f42bf07d4e | |||
| 289813b044 | |||
| b209f69bba | |||
| 790fde02a8 | |||
| eddc0c81f2 | |||
| d8c3fd8e6c | |||
| 984d294bab | |||
| 96b0db309a | |||
| b5da0dd33f | |||
| 1ac482ff49 | |||
| fb0bc112e3 |
+7
-28
@@ -1,5 +1,3 @@
|
|||||||
import xyz.jpenilla.runpaper.task.RunServer
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
@@ -32,11 +30,10 @@ plugins {
|
|||||||
id 'java-library'
|
id 'java-library'
|
||||||
id "io.github.goooler.shadow" version "8.1.7"
|
id "io.github.goooler.shadow" version "8.1.7"
|
||||||
id "de.undercouch.download" version "5.0.1"
|
id "de.undercouch.download" version "5.0.1"
|
||||||
id "xyz.jpenilla.run-paper" version "2.3.1"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
version '3.6.6-1.20.1-1.21.4'
|
version '3.6.5-1.20.1-1.21.4'
|
||||||
|
|
||||||
// ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED
|
// ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED
|
||||||
// ======================== WINDOWS =============================
|
// ======================== WINDOWS =============================
|
||||||
@@ -48,7 +45,7 @@ registerCustomOutputTask('Strange', 'D://Servers/1.17 Test Server/plugins')
|
|||||||
registerCustomOutputTask('Vatuu', 'D://Minecraft/Servers/1.19.4/plugins')
|
registerCustomOutputTask('Vatuu', 'D://Minecraft/Servers/1.19.4/plugins')
|
||||||
registerCustomOutputTask('CrazyDev22', 'C://Users/Julian/Desktop/server/plugins')
|
registerCustomOutputTask('CrazyDev22', 'C://Users/Julian/Desktop/server/plugins')
|
||||||
registerCustomOutputTask('PixelFury', 'C://Users/repix/workplace/Iris/1.21.3 - Development-Public-v3/plugins')
|
registerCustomOutputTask('PixelFury', 'C://Users/repix/workplace/Iris/1.21.3 - Development-Public-v3/plugins')
|
||||||
registerCustomOutputTask('PixelFuryDev', 'C://Users/repix/workplace/Iris/1.21 - Development-v3/plugins')
|
registerCustomOutputTask('PixelFuryDev', 'C://Users/repix/workplace/Iris/1.21.4 - Development-v3/plugins')
|
||||||
// ========================== UNIX ==============================
|
// ========================== UNIX ==============================
|
||||||
registerCustomOutputTaskUnix('CyberpwnLT', '/Users/danielmills/development/server/plugins')
|
registerCustomOutputTaskUnix('CyberpwnLT', '/Users/danielmills/development/server/plugins')
|
||||||
registerCustomOutputTaskUnix('PsychoLT', '/Users/brianfopiano/Developer/RemoteGit/Server/plugins')
|
registerCustomOutputTaskUnix('PsychoLT', '/Users/brianfopiano/Developer/RemoteGit/Server/plugins')
|
||||||
@@ -56,11 +53,6 @@ registerCustomOutputTaskUnix('PixelMac', '/Users/test/Desktop/mcserver/plugins')
|
|||||||
registerCustomOutputTaskUnix('CrazyDev22LT', '/home/julian/Desktop/server/plugins')
|
registerCustomOutputTaskUnix('CrazyDev22LT', '/home/julian/Desktop/server/plugins')
|
||||||
// ==============================================================
|
// ==============================================================
|
||||||
|
|
||||||
def MIN_HEAP_SIZE = "2G"
|
|
||||||
def MAX_HEAP_SIZE = "8G"
|
|
||||||
//Valid values are: none, truecolor, indexed256, indexed16, indexed8
|
|
||||||
def COLOR = "truecolor"
|
|
||||||
|
|
||||||
def NMS_BINDINGS = Map.of(
|
def NMS_BINDINGS = Map.of(
|
||||||
"v1_21_R3", "1.21.4-R0.1-SNAPSHOT",
|
"v1_21_R3", "1.21.4-R0.1-SNAPSHOT",
|
||||||
"v1_21_R2", "1.21.3-R0.1-SNAPSHOT",
|
"v1_21_R2", "1.21.3-R0.1-SNAPSHOT",
|
||||||
@@ -70,34 +62,21 @@ def NMS_BINDINGS = Map.of(
|
|||||||
"v1_20_R2", "1.20.2-R0.1-SNAPSHOT",
|
"v1_20_R2", "1.20.2-R0.1-SNAPSHOT",
|
||||||
"v1_20_R1", "1.20.1-R0.1-SNAPSHOT",
|
"v1_20_R1", "1.20.1-R0.1-SNAPSHOT",
|
||||||
)
|
)
|
||||||
def JVM_VERSION = Map.<String, Integer>of()
|
def JVM_VERSION = Map.of()
|
||||||
NMS_BINDINGS.forEach { key, value ->
|
NMS_BINDINGS.each { nms ->
|
||||||
project(":nms:$key") {
|
project(":nms:${nms.key}") {
|
||||||
apply plugin: 'java'
|
apply plugin: 'java'
|
||||||
apply plugin: 'com.volmit.nmstools'
|
apply plugin: 'com.volmit.nmstools'
|
||||||
|
|
||||||
nmsTools {
|
nmsTools {
|
||||||
it.jvm = JVM_VERSION.getOrDefault(key, 21)
|
it.jvm = JVM_VERSION.getOrDefault(nms.key, 21)
|
||||||
it.version = value
|
it.version = nms.value
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":core")
|
implementation project(":core")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register("runServer-$key", RunServer) {
|
|
||||||
group("servers")
|
|
||||||
minecraftVersion(value.split("-")[0])
|
|
||||||
minHeapSize(MIN_HEAP_SIZE)
|
|
||||||
maxHeapSize(MAX_HEAP_SIZE)
|
|
||||||
pluginJars(tasks.shadowJar.archiveFile)
|
|
||||||
javaLauncher = javaToolchains.launcherFor { it.languageVersion = JavaLanguageVersion.of(JVM_VERSION.getOrDefault(key, 21))}
|
|
||||||
runDirectory.convention(layout.buildDirectory.dir("run/$key"))
|
|
||||||
systemProperty("disable.watchdog", "")
|
|
||||||
systemProperty("net.kyori.ansi.colorLevel", COLOR)
|
|
||||||
systemProperty("com.mojang.eula.agree", true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import com.volmit.iris.util.io.IO;
|
|||||||
import com.volmit.iris.util.json.JSONException;
|
import com.volmit.iris.util.json.JSONException;
|
||||||
import com.volmit.iris.util.json.JSONObject;
|
import com.volmit.iris.util.json.JSONObject;
|
||||||
import com.volmit.iris.util.plugin.VolmitSender;
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
@@ -135,6 +134,11 @@ public class IrisSettings {
|
|||||||
@Data
|
@Data
|
||||||
public static class IrisSettingsConcurrency {
|
public static class IrisSettingsConcurrency {
|
||||||
public int parallelism = -1;
|
public int parallelism = -1;
|
||||||
|
public int worldGenParallelism = -1;
|
||||||
|
|
||||||
|
public int getWorldGenThreads() {
|
||||||
|
return getThreadCount(worldGenParallelism);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ import com.volmit.iris.Iris;
|
|||||||
import com.volmit.iris.core.ServerConfigurator;
|
import com.volmit.iris.core.ServerConfigurator;
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
|
import com.volmit.iris.core.service.IrisEngineSVC;
|
||||||
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.engine.object.IrisDimension;
|
import com.volmit.iris.engine.object.IrisDimension;
|
||||||
import com.volmit.iris.engine.service.EngineStatusSVC;
|
|
||||||
import com.volmit.iris.util.decree.DecreeExecutor;
|
import com.volmit.iris.util.decree.DecreeExecutor;
|
||||||
import com.volmit.iris.util.decree.DecreeOrigin;
|
import com.volmit.iris.util.decree.DecreeOrigin;
|
||||||
import com.volmit.iris.util.decree.annotations.Decree;
|
import com.volmit.iris.util.decree.annotations.Decree;
|
||||||
@@ -66,20 +66,53 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
|
|
||||||
@Decree(description = "Get Loaded TectonicPlates Count", origin = DecreeOrigin.BOTH, sync = true)
|
@Decree(description = "Get Loaded TectonicPlates Count", origin = DecreeOrigin.BOTH, sync = true)
|
||||||
public void EngineStatus() {
|
public void EngineStatus() {
|
||||||
var status = EngineStatusSVC.getStatus();
|
List<World> IrisWorlds = new ArrayList<>();
|
||||||
|
int TotalLoadedChunks = 0;
|
||||||
|
int TotalQueuedTectonicPlates = 0;
|
||||||
|
int TotalNotQueuedTectonicPlates = 0;
|
||||||
|
int TotalTectonicPlates = 0;
|
||||||
|
|
||||||
sender().sendMessage("-------------------------");
|
long lowestUnloadDuration = 0;
|
||||||
sender().sendMessage(C.DARK_PURPLE + "Engine Status");
|
long highestUnloadDuration = 0;
|
||||||
sender().sendMessage(C.DARK_PURPLE + "Total Engines: " + C.LIGHT_PURPLE + status.engineCount());
|
|
||||||
sender().sendMessage(C.DARK_PURPLE + "Total Loaded Chunks: " + C.LIGHT_PURPLE + status.loadedChunks());
|
for (World world : Bukkit.getWorlds()) {
|
||||||
sender().sendMessage(C.DARK_PURPLE + "Tectonic Limit: " + C.LIGHT_PURPLE + status.tectonicLimit());
|
try {
|
||||||
sender().sendMessage(C.DARK_PURPLE + "Tectonic Total Plates: " + C.LIGHT_PURPLE + status.tectonicPlates());
|
if (IrisToolbelt.access(world).getEngine() != null) {
|
||||||
sender().sendMessage(C.DARK_PURPLE + "Tectonic Active Plates: " + C.LIGHT_PURPLE + status.activeTectonicPlates());
|
IrisWorlds.add(world);
|
||||||
sender().sendMessage(C.DARK_PURPLE + "Tectonic ToUnload: " + C.LIGHT_PURPLE + status.queuedTectonicPlates());
|
}
|
||||||
sender().sendMessage(C.DARK_PURPLE + "Lowest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(status.minTectonicUnloadDuration()));
|
} catch (Exception e) {
|
||||||
sender().sendMessage(C.DARK_PURPLE + "Highest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(status.maxTectonicUnloadDuration()));
|
// no
|
||||||
sender().sendMessage(C.DARK_PURPLE + "Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize()));
|
}
|
||||||
sender().sendMessage("-------------------------");
|
}
|
||||||
|
|
||||||
|
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("-------------------------");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Decree(description = "Test")
|
@Decree(description = "Test")
|
||||||
|
|||||||
@@ -19,13 +19,17 @@
|
|||||||
package com.volmit.iris.core.commands;
|
package com.volmit.iris.core.commands;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.nms.INMS;
|
||||||
import com.volmit.iris.core.service.StudioSVC;
|
import com.volmit.iris.core.service.StudioSVC;
|
||||||
import com.volmit.iris.engine.object.*;
|
import com.volmit.iris.engine.object.*;
|
||||||
import com.volmit.iris.util.decree.DecreeExecutor;
|
import com.volmit.iris.util.decree.DecreeExecutor;
|
||||||
import com.volmit.iris.util.decree.DecreeOrigin;
|
import com.volmit.iris.util.decree.DecreeOrigin;
|
||||||
import com.volmit.iris.util.decree.annotations.Decree;
|
import com.volmit.iris.util.decree.annotations.Decree;
|
||||||
import com.volmit.iris.util.decree.annotations.Param;
|
import com.volmit.iris.util.decree.annotations.Param;
|
||||||
|
import com.volmit.iris.util.decree.specialhandlers.NullableBiomeHandler;
|
||||||
|
import com.volmit.iris.util.decree.specialhandlers.NullableRegionHandler;
|
||||||
import com.volmit.iris.util.format.C;
|
import com.volmit.iris.util.format.C;
|
||||||
|
import org.bukkit.block.Biome;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
|
||||||
@@ -51,12 +55,31 @@ public class CommandEdit implements DecreeExecutor {
|
|||||||
|
|
||||||
|
|
||||||
@Decree(description = "Edit the biome you specified", aliases = {"b"}, origin = DecreeOrigin.PLAYER)
|
@Decree(description = "Edit the biome you specified", aliases = {"b"}, origin = DecreeOrigin.PLAYER)
|
||||||
public void biome(@Param(contextual = false, description = "The biome to edit") IrisBiome biome) {
|
public void biome(@Param(contextual = false, description = "The biome to edit", defaultValue = "---", customHandler = NullableBiomeHandler.class) IrisBiome biome) {
|
||||||
if (noStudio()) {
|
if (noStudio()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (biome == null) {
|
||||||
|
try {
|
||||||
|
IrisBiome b = engine().getBiome(player().getLocation().getBlockX(), player().getLocation().getBlockY() - player().getWorld().getMinHeight(), player().getLocation().getBlockZ());
|
||||||
|
Desktop.getDesktop().open(b.getLoadFile());
|
||||||
|
sender().sendMessage(C.GREEN + "Opening " + b.getTypeName() + " " + b.getLoadFile().getName().split("\\Q.\\E")[0] + " in VSCode! ");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
sender().sendMessage("Non-Iris Biome: " + player().getLocation().getBlock().getBiome().name());
|
||||||
|
if (player().getLocation().getBlock().getBiome().equals(Biome.CUSTOM)) {
|
||||||
|
try {
|
||||||
|
sender().sendMessage("Data Pack Biome: " + INMS.get().getTrueBiomeBaseKey(player().getLocation()) + " (ID: " + INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(player().getLocation())) + ")");
|
||||||
|
} catch (Throwable ee) {
|
||||||
|
Iris.reportError(ee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (biome == null || biome.getLoadFile() == null) {
|
if (biome.getLoadFile() == null) {
|
||||||
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
|
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -69,10 +92,20 @@ public class CommandEdit implements DecreeExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Decree(description = "Edit the region you specified", aliases = {"r"}, origin = DecreeOrigin.PLAYER)
|
@Decree(description = "Edit the region you specified", aliases = {"r"}, origin = DecreeOrigin.PLAYER)
|
||||||
public void region(@Param(contextual = false, description = "The region to edit") IrisRegion region) {
|
public void region(@Param(contextual = false, description = "The region to edit", defaultValue = "---", customHandler = NullableRegionHandler.class) IrisRegion region) {
|
||||||
if (noStudio()) {
|
if (noStudio()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (region == null) {
|
||||||
|
try {
|
||||||
|
IrisRegion r = engine().getRegion(player().getLocation().getBlockX(), player().getLocation().getBlockZ());
|
||||||
|
Desktop.getDesktop().open(r.getLoadFile());
|
||||||
|
sender().sendMessage(C.GREEN + "Opening " + r.getTypeName() + " " + r.getLoadFile().getName().split("\\Q.\\E")[0] + " in VSCode! ");
|
||||||
|
} catch (Throwable e) {
|
||||||
|
sender().sendMessage(C.RED + "Failed to get region.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
if (region == null || region.getLoadFile() == null) {
|
if (region == null || region.getLoadFile() == null) {
|
||||||
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
|
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.volmit.iris.Iris;
|
|||||||
import com.volmit.iris.core.IrisSettings;
|
import com.volmit.iris.core.IrisSettings;
|
||||||
import com.volmit.iris.core.gui.NoiseExplorerGUI;
|
import com.volmit.iris.core.gui.NoiseExplorerGUI;
|
||||||
import com.volmit.iris.core.gui.VisionGUI;
|
import com.volmit.iris.core.gui.VisionGUI;
|
||||||
|
import com.volmit.iris.core.gui.components.IrisRenderer;
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
import com.volmit.iris.core.project.IrisProject;
|
import com.volmit.iris.core.project.IrisProject;
|
||||||
import com.volmit.iris.core.service.ConversionSVC;
|
import com.volmit.iris.core.service.ConversionSVC;
|
||||||
@@ -65,6 +66,9 @@ import org.bukkit.inventory.Inventory;
|
|||||||
import org.bukkit.util.BlockVector;
|
import org.bukkit.util.BlockVector;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -156,6 +160,37 @@ public class CommandStudio implements DecreeExecutor {
|
|||||||
sender().sendMessage(C.GREEN + "The \"" + dimension.getName() + "\" pack has version: " + dimension.getVersion());
|
sender().sendMessage(C.GREEN + "The \"" + dimension.getName() + "\" pack has version: " + dimension.getVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Decree(description = "Debug image")
|
||||||
|
public void printImageChannel(
|
||||||
|
@Param(name = "image", description = "Image found in the image folder inside the project")
|
||||||
|
String image,
|
||||||
|
@Param(name = "channel", description = "Image channel")
|
||||||
|
IrisImageChannel channel
|
||||||
|
) {
|
||||||
|
if (noStudio()) return;
|
||||||
|
try {
|
||||||
|
File file = new File(access().getEngine().getComplex().getData().getDataFolder(), "images/" + image);
|
||||||
|
if (!file.exists()) {
|
||||||
|
sender().sendMessage(C.RED + "The image \"" + image + "\" does not exist.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BufferedImage buffer = ImageIO.read(file);
|
||||||
|
IrisImage irisImage = new IrisImage(buffer);
|
||||||
|
File at = new File(file.getParentFile(), "debug-see-" + file.getName());
|
||||||
|
BufferedImage b = new BufferedImage(buffer.getWidth(), buffer.getHeight(), BufferedImage.TYPE_INT_RGB);
|
||||||
|
for (int i = 0; i < buffer.getWidth(); i++) {
|
||||||
|
for (int j = 0; j < buffer.getHeight(); j++) {
|
||||||
|
b.setRGB(i, j, Color.getHSBColor(0, 0, (float) irisImage.getValue(channel, i, j)).getRGB());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImageIO.write(b, "png", at);
|
||||||
|
sender().sendMessage(C.IRIS + "Debug image written to ./images for channel " + channel.name());
|
||||||
|
} catch (Exception e) {
|
||||||
|
sender().sendMessage(C.RED + "Something went wrong.. ");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Decree(name = "regen", description = "Regenerate nearby chunks.", aliases = "rg", sync = true, origin = DecreeOrigin.PLAYER)
|
@Decree(name = "regen", description = "Regenerate nearby chunks.", aliases = "rg", sync = true, origin = DecreeOrigin.PLAYER)
|
||||||
public void regen(
|
public void regen(
|
||||||
@Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5")
|
@Param(name = "radius", description = "The radius of nearby cunks", defaultValue = "5")
|
||||||
@@ -404,9 +439,16 @@ public class CommandStudio implements DecreeExecutor {
|
|||||||
@Param(name = "world", description = "The world to open the generator for", contextual = true)
|
@Param(name = "world", description = "The world to open the generator for", contextual = true)
|
||||||
World world
|
World world
|
||||||
) {
|
) {
|
||||||
if (noGUI()) return;
|
if (noGUI()) {
|
||||||
|
sender().sendMessage(C.GOLD + "GUI Support isn't enabled or supported on this server.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!IrisToolbelt.isIrisWorld(world)) {
|
if (world == null) {
|
||||||
|
if (noStudio()) return;
|
||||||
|
world = player().getWorld();
|
||||||
|
}
|
||||||
|
else if (!IrisToolbelt.isIrisWorld(world)) {
|
||||||
sender().sendMessage(C.RED + "You need to be in or specify an Iris-generated world!");
|
sender().sendMessage(C.RED + "You need to be in or specify an Iris-generated world!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -842,7 +884,7 @@ public class CommandStudio implements DecreeExecutor {
|
|||||||
sender().sendMessage(C.RED + "No studio world is open!");
|
sender().sendMessage(C.RED + "No studio world is open!");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!engine().isStudio()) {
|
if (engine() == null || !engine().isStudio()) {
|
||||||
sender().sendMessage(C.RED + "You must be in a studio world!");
|
sender().sendMessage(C.RED + "You must be in a studio world!");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package com.volmit.iris.core.commands;
|
|||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
import com.volmit.iris.core.pregenerator.ChunkUpdater;
|
import com.volmit.iris.core.pregenerator.ChunkUpdater;
|
||||||
|
import com.volmit.iris.core.service.IrisEngineSVC;
|
||||||
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
* Copyright (c) 2024 Arcane Arts (Volmit Software)
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -30,7 +30,6 @@ import com.volmit.iris.engine.object.IrisWorld;
|
|||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.data.registry.Attributes;
|
|
||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
import com.volmit.iris.util.math.BlockPosition;
|
import com.volmit.iris.util.math.BlockPosition;
|
||||||
import com.volmit.iris.util.math.M;
|
import com.volmit.iris.util.math.M;
|
||||||
@@ -57,8 +56,9 @@ import java.util.concurrent.ExecutorService;
|
|||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
import static com.volmit.iris.util.data.registry.Attributes.MAX_HEALTH;
|
//todo
|
||||||
|
// - Misalignment
|
||||||
|
// - Weird snapping?
|
||||||
public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener, MouseMotionListener, MouseInputListener {
|
public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener, MouseMotionListener, MouseInputListener {
|
||||||
private static final long serialVersionUID = 2094606939770332040L;
|
private static final long serialVersionUID = 2094606939770332040L;
|
||||||
private final KList<LivingEntity> lastEntities = new KList<>();
|
private final KList<LivingEntity> lastEntities = new KList<>();
|
||||||
@@ -415,8 +415,8 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
private double getWorldX(double screenX) {
|
private double getWorldX(double screenX) {
|
||||||
//return (mscale * screenX) + ((oxp / scale) * mscale);
|
return (mscale * screenX) + ((oxp / scale) * mscale);
|
||||||
return (mscale * screenX) + ((oxp / scale));
|
// return (mscale * screenX) + ((oxp / scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getWorldZ(double screenZ) {
|
private double getWorldZ(double screenZ) {
|
||||||
@@ -639,7 +639,7 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
|
|||||||
|
|
||||||
k.add("Pos: " + h.getLocation().getBlockX() + ", " + h.getLocation().getBlockY() + ", " + h.getLocation().getBlockZ());
|
k.add("Pos: " + h.getLocation().getBlockX() + ", " + h.getLocation().getBlockY() + ", " + h.getLocation().getBlockZ());
|
||||||
k.add("UUID: " + h.getUniqueId());
|
k.add("UUID: " + h.getUniqueId());
|
||||||
k.add("HP: " + h.getHealth() + " / " + h.getAttribute(MAX_HEALTH).getValue());
|
k.add("HP: " + h.getHealth() + " / " + h.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
|
||||||
|
|
||||||
drawCardTR(g, k);
|
drawCardTR(g, k);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ import lombok.EqualsAndHashCode;
|
|||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
@@ -220,10 +219,6 @@ public class ResourceLoader<T extends IrisRegistrant> implements MeteredCache {
|
|||||||
return s.map(this::load);
|
return s.map(this::load);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream<T> streamAllPossible() {
|
|
||||||
return streamAll(Arrays.stream(getPossibleKeys()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public KList<T> loadAll(KList<String> s) {
|
public KList<T> loadAll(KList<String> s) {
|
||||||
KList<T> m = new KList<>();
|
KList<T> m = new KList<>();
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package com.volmit.iris.core.nms;
|
|||||||
|
|
||||||
import com.volmit.iris.core.nms.container.AutoClosing;
|
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
|
import com.volmit.iris.core.nms.container.Pair;
|
||||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
@@ -93,7 +94,6 @@ public interface INMSBinding {
|
|||||||
throw new IllegalStateException("Missing dimenstion types to create world");
|
throw new IllegalStateException("Missing dimenstion types to create world");
|
||||||
|
|
||||||
try (var ignored = injectLevelStems()) {
|
try (var ignored = injectLevelStems()) {
|
||||||
ignored.storeContext();
|
|
||||||
return c.createWorld();
|
return c.createWorld();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,11 +132,7 @@ public interface INMSBinding {
|
|||||||
|
|
||||||
AutoClosing injectLevelStems();
|
AutoClosing injectLevelStems();
|
||||||
|
|
||||||
default AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end);
|
boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end);
|
||||||
|
|
||||||
void removeCustomDimensions(World world);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.volmit.iris.core.nms.container;
|
package com.volmit.iris.core.nms.container;
|
||||||
|
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.function.NastyRunnable;
|
import com.volmit.iris.util.function.NastyRunnable;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
@@ -8,7 +7,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class AutoClosing implements AutoCloseable {
|
public class AutoClosing implements AutoCloseable {
|
||||||
private static final KMap<Thread, AutoClosing> CONTEXTS = new KMap<>();
|
|
||||||
private final AtomicBoolean closed = new AtomicBoolean();
|
private final AtomicBoolean closed = new AtomicBoolean();
|
||||||
private final NastyRunnable action;
|
private final NastyRunnable action;
|
||||||
|
|
||||||
@@ -16,24 +14,9 @@ public class AutoClosing implements AutoCloseable {
|
|||||||
public void close() {
|
public void close() {
|
||||||
if (closed.getAndSet(true)) return;
|
if (closed.getAndSet(true)) return;
|
||||||
try {
|
try {
|
||||||
removeContext();
|
|
||||||
action.run();
|
action.run();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void storeContext() {
|
|
||||||
CONTEXTS.put(Thread.currentThread(), this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeContext() {
|
|
||||||
CONTEXTS.values().removeIf(c -> c == this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void closeContext() {
|
|
||||||
AutoClosing closing = CONTEXTS.remove(Thread.currentThread());
|
|
||||||
if (closing == null) return;
|
|
||||||
closing.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,8 +126,8 @@ public class NMSBinding1X implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
public Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
return injectLevelStems();
|
return new Pair<>(0, new AutoClosing(() -> {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -135,11 +135,6 @@ public class NMSBinding1X implements INMSBinding {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeCustomDimensions(World world) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag serializeEntity(Entity location) {
|
public CompoundTag serializeEntity(Entity location) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
package com.volmit.iris.core.pregenerator.methods;
|
package com.volmit.iris.core.pregenerator.methods;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.IrisSettings;
|
||||||
import com.volmit.iris.core.pregenerator.PregenListener;
|
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||||
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
@@ -34,8 +35,10 @@ import org.bukkit.World;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
public class AsyncPregenMethod implements PregeneratorMethod {
|
public class AsyncPregenMethod implements PregeneratorMethod {
|
||||||
|
private static final AtomicInteger THREAD_COUNT = new AtomicInteger();
|
||||||
private final World world;
|
private final World world;
|
||||||
private final MultiBurst burst;
|
private final MultiBurst burst;
|
||||||
private final Semaphore semaphore;
|
private final Semaphore semaphore;
|
||||||
@@ -92,6 +95,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
unloadAndSaveAllChunks();
|
unloadAndSaveAllChunks();
|
||||||
|
increaseWorkerThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -104,6 +108,7 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
semaphore.acquireUninterruptibly(256);
|
semaphore.acquireUninterruptibly(256);
|
||||||
unloadAndSaveAllChunks();
|
unloadAndSaveAllChunks();
|
||||||
burst.close();
|
burst.close();
|
||||||
|
resetWorkerThreads();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -140,4 +145,44 @@ public class AsyncPregenMethod implements PregeneratorMethod {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void increaseWorkerThreads() {
|
||||||
|
THREAD_COUNT.updateAndGet(i -> {
|
||||||
|
if (i > 0) return 1;
|
||||||
|
try {
|
||||||
|
var field = Class.forName("ca.spottedleaf.moonrise.common.util.MoonriseCommon").getDeclaredField("WORKER_POOL");
|
||||||
|
var pool = field.get(null);
|
||||||
|
var threads = ((Thread[]) pool.getClass().getDeclaredMethod("getCoreThreads").invoke(pool)).length;
|
||||||
|
var adjusted = IrisSettings.get().getConcurrency().getWorldGenThreads();
|
||||||
|
if (threads >= adjusted) return 0;
|
||||||
|
|
||||||
|
pool.getClass().getDeclaredMethod("adjustThreadCount", int.class).invoke(pool, adjusted);
|
||||||
|
return threads;
|
||||||
|
} catch (ClassNotFoundException ignored) {
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.error("Failed to increase worker threads");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void resetWorkerThreads() {
|
||||||
|
THREAD_COUNT.updateAndGet(i -> {
|
||||||
|
if (i == 0) return 0;
|
||||||
|
try {
|
||||||
|
var field = Class.forName("ca.spottedleaf.moonrise.common.util.MoonriseCommon").getDeclaredField("WORKER_POOL");
|
||||||
|
var pool = field.get(null);
|
||||||
|
var method = pool.getClass().getDeclaredMethod("adjustThreadCount", int.class);
|
||||||
|
method.invoke(pool, i);
|
||||||
|
return 0;
|
||||||
|
} catch (ClassNotFoundException ignored) {
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.error("Failed to reset worker threads");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,317 @@
|
|||||||
|
package com.volmit.iris.core.service;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.IrisSettings;
|
||||||
|
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.server.PluginDisableEvent;
|
||||||
|
import org.bukkit.event.server.ServerLoadEvent;
|
||||||
|
import org.bukkit.event.world.WorldLoadEvent;
|
||||||
|
import org.bukkit.event.world.WorldUnloadEvent;
|
||||||
|
import org.checkerframework.checker.units.qual.A;
|
||||||
|
|
||||||
|
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;
|
||||||
|
public boolean isServerShuttingDown = false;
|
||||||
|
public boolean isServerLoaded = false;
|
||||||
|
private static final AtomicInteger tectonicLimit = new AtomicInteger(30);
|
||||||
|
private ReentrantLock lastUseLock;
|
||||||
|
private KMap<World, Long> lastUse;
|
||||||
|
private List<World> IrisWorlds;
|
||||||
|
private Looper cacheTicker;
|
||||||
|
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<World> corruptedIrisWorlds = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
this.cl = new ChronoLatch(5000);
|
||||||
|
lastUse = new KMap<>();
|
||||||
|
lastUseLock = new ReentrantLock();
|
||||||
|
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) {
|
||||||
|
tectonicLimit.getAndAdd(1);
|
||||||
|
t = t - 200;
|
||||||
|
}
|
||||||
|
this.setup();
|
||||||
|
this.TrimLogic();
|
||||||
|
this.UnloadLogic();
|
||||||
|
|
||||||
|
trimAlive.begin();
|
||||||
|
unloadAlive.begin();
|
||||||
|
trimActiveAlive.begin();
|
||||||
|
unloadActiveAlive.begin();
|
||||||
|
|
||||||
|
updateTicker.start();
|
||||||
|
cacheTicker.start();
|
||||||
|
//trimTicker.start();
|
||||||
|
//unloadTicker.start();
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void engineStatus() {
|
||||||
|
boolean trimAlive = trimTicker.isAlive();
|
||||||
|
boolean unloadAlive = unloadTicker.isAlive();
|
||||||
|
Iris.info("Status:");
|
||||||
|
Iris.info("- Trim: " + trimAlive);
|
||||||
|
Iris.info("- Unload: " + unloadAlive);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getTectonicLimit() {
|
||||||
|
return tectonicLimit.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onWorldUnload(WorldUnloadEvent event) {
|
||||||
|
updateWorlds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onWorldLoad(WorldLoadEvent event) {
|
||||||
|
updateWorlds();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onServerBoot(ServerLoadEvent event) {
|
||||||
|
isServerLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPluginDisable(PluginDisableEvent event) {
|
||||||
|
if (event.getPlugin().equals(Iris.instance)) {
|
||||||
|
isServerShuttingDown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
protected long loop() {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
lastUseLock.lock();
|
||||||
|
try {
|
||||||
|
for (World key : new ArrayList<>(lastUse.keySet())) {
|
||||||
|
Long last = lastUse.get(key);
|
||||||
|
if (last == null)
|
||||||
|
continue;
|
||||||
|
if (now - last > 60000) {
|
||||||
|
lastUse.remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lastUseLock.unlock();
|
||||||
|
}
|
||||||
|
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 = Objects.requireNonNull(IrisToolbelt.access(world)).getEngine();
|
||||||
|
TotalQueuedTectonicPlates.addAndGet((int) engine.getMantle().getToUnload());
|
||||||
|
TotalNotQueuedTectonicPlates.addAndGet((int) engine.getMantle().getNotQueuedLoadedRegions());
|
||||||
|
TotalTectonicPlates.addAndGet(engine.getMantle().getLoadedRegionCount());
|
||||||
|
}
|
||||||
|
if (!isServerShuttingDown && isServerLoaded) {
|
||||||
|
if (!trimTicker.isAlive()) {
|
||||||
|
Iris.info(C.RED + "TrimTicker found dead! Booting it up!");
|
||||||
|
try {
|
||||||
|
TrimLogic();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Iris.error("What happened?");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unloadTicker.isAlive()) {
|
||||||
|
Iris.info(C.RED + "UnloadTicker found dead! Booting it up!");
|
||||||
|
try {
|
||||||
|
UnloadLogic();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Iris.error("What happened?");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public void TrimLogic() {
|
||||||
|
if (trimTicker == null || !trimTicker.isAlive()) {
|
||||||
|
trimTicker = new Looper() {
|
||||||
|
private final Supplier<Engine> supplier = createSupplier();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected long loop() {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
trimAlive.reset();
|
||||||
|
try {
|
||||||
|
Engine engine = supplier.get();
|
||||||
|
if (engine != null) {
|
||||||
|
engine.getMantle().trim(tectonicLimit.get() / lastUse.size());
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
Iris.info(C.RED + "EngineSVC: Failed to trim.");
|
||||||
|
e.printStackTrace();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = lastUse.size();
|
||||||
|
long time = (size > 0 ? 1000 / size : 1000) - (System.currentTimeMillis() - start);
|
||||||
|
if (time <= 0)
|
||||||
|
return 0;
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
trimTicker.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void UnloadLogic() {
|
||||||
|
if (unloadTicker == null || !unloadTicker.isAlive()) {
|
||||||
|
unloadTicker = new Looper() {
|
||||||
|
private final Supplier<Engine> supplier = createSupplier();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected long loop() {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
unloadAlive.reset();
|
||||||
|
try {
|
||||||
|
Engine engine = supplier.get();
|
||||||
|
if (engine != null) {
|
||||||
|
long unloadStart = System.currentTimeMillis();
|
||||||
|
int count = engine.getMantle().unloadTectonicPlate(tectonicLimit.get() / lastUse.size());
|
||||||
|
if (count > 0) {
|
||||||
|
Iris.debug(C.GOLD + "Unloaded " + C.YELLOW + count + " TectonicPlates in " + C.RED + Form.duration(System.currentTimeMillis() - unloadStart, 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
Iris.info(C.RED + "EngineSVC: Failed to unload.");
|
||||||
|
e.printStackTrace();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = lastUse.size();
|
||||||
|
long time = (size > 0 ? 1000 / size : 1000) - (System.currentTimeMillis() - start);
|
||||||
|
if (time <= 0)
|
||||||
|
return 0;
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
unloadTicker.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Supplier<Engine> createSupplier() {
|
||||||
|
AtomicInteger i = new AtomicInteger();
|
||||||
|
return () -> {
|
||||||
|
List<World> worlds = Bukkit.getWorlds();
|
||||||
|
if (i.get() >= worlds.size()) {
|
||||||
|
i.set(0);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
for (int j = 0; j < worlds.size(); j++) {
|
||||||
|
World world = worlds.get(i.getAndIncrement());
|
||||||
|
PlatformChunkGenerator generator = IrisToolbelt.access(world);
|
||||||
|
if (i.get() >= worlds.size()) {
|
||||||
|
i.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generator != null) {
|
||||||
|
Engine engine = generator.getEngine();
|
||||||
|
boolean closed = engine.getMantle().getData().isClosed();
|
||||||
|
if (engine != null && !engine.isStudio() && !closed) {
|
||||||
|
lastUseLock.lock();
|
||||||
|
lastUse.put(world, System.currentTimeMillis());
|
||||||
|
lastUseLock.unlock();
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.info(C.RED + "EngineSVC: Failed to create supplier.");
|
||||||
|
e.printStackTrace();
|
||||||
|
Iris.reportError(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
cacheTicker.interrupt();
|
||||||
|
trimTicker.interrupt();
|
||||||
|
unloadTicker.interrupt();
|
||||||
|
lastUse.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import com.volmit.iris.util.collection.KList;
|
|||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.exceptions.IrisException;
|
import com.volmit.iris.util.exceptions.IrisException;
|
||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
|
import com.volmit.iris.util.io.IO;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -17,11 +18,6 @@ import org.bukkit.Bukkit;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.FileVisitResult;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.SimpleFileVisitor;
|
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
|
||||||
import java.time.Clock;
|
import java.time.Clock;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -50,10 +46,7 @@ public class IrisPackBenchmarking {
|
|||||||
.start(() -> {
|
.start(() -> {
|
||||||
Iris.info("Setting up benchmark environment ");
|
Iris.info("Setting up benchmark environment ");
|
||||||
benchmarkInProgress = true;
|
benchmarkInProgress = true;
|
||||||
File file = new File("benchmark");
|
IO.delete(new File(Bukkit.getWorldContainer(), "benchmark"));
|
||||||
if (file.exists()) {
|
|
||||||
deleteDirectory(file.toPath());
|
|
||||||
}
|
|
||||||
createBenchmark();
|
createBenchmark();
|
||||||
while (!IrisToolbelt.isIrisWorld(Bukkit.getWorld("benchmark"))) {
|
while (!IrisToolbelt.isIrisWorld(Bukkit.getWorld("benchmark"))) {
|
||||||
J.sleep(1000);
|
J.sleep(1000);
|
||||||
@@ -72,7 +65,7 @@ public class IrisPackBenchmarking {
|
|||||||
|
|
||||||
public void finishedBenchmark(KList<Integer> cps) {
|
public void finishedBenchmark(KList<Integer> cps) {
|
||||||
try {
|
try {
|
||||||
String time = Form.duration(stopwatch.getMillis());
|
String time = Form.duration((long) stopwatch.getMilliseconds());
|
||||||
Engine engine = IrisToolbelt.access(Bukkit.getWorld("benchmark")).getEngine();
|
Engine engine = IrisToolbelt.access(Bukkit.getWorld("benchmark")).getEngine();
|
||||||
Iris.info("-----------------");
|
Iris.info("-----------------");
|
||||||
Iris.info("Results:");
|
Iris.info("Results:");
|
||||||
@@ -83,11 +76,7 @@ public class IrisPackBenchmarking {
|
|||||||
Iris.info(" - Lowest CPS: " + findLowest(cps));
|
Iris.info(" - Lowest CPS: " + findLowest(cps));
|
||||||
Iris.info("-----------------");
|
Iris.info("-----------------");
|
||||||
Iris.info("Creating a report..");
|
Iris.info("Creating a report..");
|
||||||
File profilers = new File("plugins" + File.separator + "Iris" + File.separator + "packbenchmarks");
|
File results = Iris.instance.getDataFile("packbenchmarks", dimension.getName() + " " + LocalDateTime.now(Clock.systemDefaultZone()).toString().replace(':', '-') + ".txt");
|
||||||
profilers.mkdir();
|
|
||||||
|
|
||||||
File results = new File(profilers, dimension.getName() + " " + LocalDateTime.now(Clock.systemDefaultZone()).toString().replace(':', '-') + ".txt");
|
|
||||||
results.getParentFile().mkdirs();
|
|
||||||
KMap<String, Double> metrics = engine.getMetrics().pull();
|
KMap<String, Double> metrics = engine.getMetrics().pull();
|
||||||
try (FileWriter writer = new FileWriter(results)) {
|
try (FileWriter writer = new FileWriter(results)) {
|
||||||
writer.write("-----------------\n");
|
writer.write("-----------------\n");
|
||||||
@@ -178,26 +167,4 @@ public class IrisPackBenchmarking {
|
|||||||
private int findHighest(KList<Integer> list) {
|
private int findHighest(KList<Integer> list) {
|
||||||
return Collections.max(list);
|
return Collections.max(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean deleteDirectory(Path dir) {
|
|
||||||
try {
|
|
||||||
Files.walkFileTree(dir, new SimpleFileVisitor<>() {
|
|
||||||
@Override
|
|
||||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
|
||||||
Files.delete(file);
|
|
||||||
return FileVisitResult.CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
|
||||||
Files.delete(dir);
|
|
||||||
return FileVisitResult.CONTINUE;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,6 @@ import com.volmit.iris.util.format.C;
|
|||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
import com.volmit.iris.util.hunk.Hunk;
|
import com.volmit.iris.util.hunk.Hunk;
|
||||||
import com.volmit.iris.util.io.IO;
|
import com.volmit.iris.util.io.IO;
|
||||||
import com.volmit.iris.util.io.JarScanner;
|
|
||||||
import com.volmit.iris.util.mantle.MantleFlag;
|
import com.volmit.iris.util.mantle.MantleFlag;
|
||||||
import com.volmit.iris.util.math.M;
|
import com.volmit.iris.util.math.M;
|
||||||
import com.volmit.iris.util.math.RNG;
|
import com.volmit.iris.util.math.RNG;
|
||||||
@@ -61,11 +60,7 @@ import org.bukkit.command.CommandSender;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
@@ -76,8 +71,6 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||||||
@EqualsAndHashCode(exclude = "context")
|
@EqualsAndHashCode(exclude = "context")
|
||||||
@ToString(exclude = "context")
|
@ToString(exclude = "context")
|
||||||
public class IrisEngine implements Engine {
|
public class IrisEngine implements Engine {
|
||||||
private static final Map<Class<? extends IrisEngineService>, Constructor<? extends IrisEngineService>> SERVICES = scanServices();
|
|
||||||
private final KMap<Class<? extends IrisEngineService>, IrisEngineService> services;
|
|
||||||
private final AtomicInteger bud;
|
private final AtomicInteger bud;
|
||||||
private final AtomicInteger buds;
|
private final AtomicInteger buds;
|
||||||
private final AtomicInteger generated;
|
private final AtomicInteger generated;
|
||||||
@@ -118,7 +111,6 @@ public class IrisEngine implements Engine {
|
|||||||
getEngineData();
|
getEngineData();
|
||||||
verifySeed();
|
verifySeed();
|
||||||
this.seedManager = new SeedManager(target.getWorld().getRawWorldSeed());
|
this.seedManager = new SeedManager(target.getWorld().getRawWorldSeed());
|
||||||
services = new KMap<>();
|
|
||||||
bud = new AtomicInteger(0);
|
bud = new AtomicInteger(0);
|
||||||
buds = new AtomicInteger(0);
|
buds = new AtomicInteger(0);
|
||||||
metrics = new EngineMetrics(32);
|
metrics = new EngineMetrics(32);
|
||||||
@@ -145,26 +137,6 @@ public class IrisEngine implements Engine {
|
|||||||
Iris.debug("Engine Initialized " + getCacheID());
|
Iris.debug("Engine Initialized " + getCacheID());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private static Map<Class<? extends IrisEngineService>, Constructor<? extends IrisEngineService>> scanServices() {
|
|
||||||
JarScanner js = new JarScanner(Iris.instance.getJarFile(), "com.volmit.iris.engine.service");
|
|
||||||
J.attempt(js::scan);
|
|
||||||
KMap<Class<? extends IrisEngineService>, Constructor<? extends IrisEngineService>> map = new KMap<>();
|
|
||||||
js.getClasses()
|
|
||||||
.stream()
|
|
||||||
.filter(IrisEngineService.class::isAssignableFrom)
|
|
||||||
.map(c -> (Class<? extends IrisEngineService>) c)
|
|
||||||
.forEach(c -> {
|
|
||||||
try {
|
|
||||||
map.put(c, c.getConstructor(Engine.class));
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
Iris.warn("Failed to load service " + c.getName() + " due to missing constructor");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Collections.unmodifiableMap(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifySeed() {
|
private void verifySeed() {
|
||||||
if (getEngineData().getSeed() != null && getEngineData().getSeed() != target.getWorld().getRawWorldSeed()) {
|
if (getEngineData().getSeed() != null && getEngineData().getSeed() != target.getWorld().getRawWorldSeed()) {
|
||||||
target.getWorld().setRawWorldSeed(getEngineData().getSeed());
|
target.getWorld().setRawWorldSeed(getEngineData().getSeed());
|
||||||
@@ -189,8 +161,6 @@ public class IrisEngine implements Engine {
|
|||||||
execution.close();
|
execution.close();
|
||||||
effects.close();
|
effects.close();
|
||||||
mode.close();
|
mode.close();
|
||||||
services.values().forEach(s -> s.onDisable(true));
|
|
||||||
services.values().forEach(Iris.instance::unregisterListener);
|
|
||||||
|
|
||||||
J.a(() -> new IrisProject(getData().getDataFolder()).updateWorkspace());
|
J.a(() -> new IrisProject(getData().getDataFolder()).updateWorkspace());
|
||||||
}
|
}
|
||||||
@@ -199,24 +169,6 @@ public class IrisEngine implements Engine {
|
|||||||
try {
|
try {
|
||||||
Iris.debug("Setup Engine " + getCacheID());
|
Iris.debug("Setup Engine " + getCacheID());
|
||||||
cacheId = RNG.r.nextInt();
|
cacheId = RNG.r.nextInt();
|
||||||
boolean hotload = true;
|
|
||||||
if (services.isEmpty()) {
|
|
||||||
SERVICES.forEach((s, c) -> {
|
|
||||||
try {
|
|
||||||
services.put(s, c.newInstance(this));
|
|
||||||
} catch (InstantiationException | IllegalAccessException |
|
|
||||||
InvocationTargetException e) {
|
|
||||||
Iris.error("Failed to create service " + s.getName());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
hotload = false;
|
|
||||||
}
|
|
||||||
for (var service : services.values()) {
|
|
||||||
service.onEnable(hotload);
|
|
||||||
Iris.instance.registerListener(service);
|
|
||||||
}
|
|
||||||
|
|
||||||
worldManager = new IrisWorldManager(this);
|
worldManager = new IrisWorldManager(this);
|
||||||
complex = new IrisComplex(this);
|
complex = new IrisComplex(this);
|
||||||
execution = new IrisExecutionEnvironment(this);
|
execution = new IrisExecutionEnvironment(this);
|
||||||
@@ -466,7 +418,6 @@ public class IrisEngine implements Engine {
|
|||||||
PregeneratorJob.shutdownInstance();
|
PregeneratorJob.shutdownInstance();
|
||||||
closed = true;
|
closed = true;
|
||||||
J.car(art);
|
J.car(art);
|
||||||
services.values().forEach(s -> s.onDisable(false));
|
|
||||||
getWorldManager().close();
|
getWorldManager().close();
|
||||||
getTarget().close();
|
getTarget().close();
|
||||||
saveEngineData();
|
saveEngineData();
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import com.volmit.iris.engine.object.*;
|
|||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
|
import com.volmit.iris.util.format.Form;
|
||||||
import com.volmit.iris.util.mantle.Mantle;
|
import com.volmit.iris.util.mantle.Mantle;
|
||||||
import com.volmit.iris.util.mantle.MantleFlag;
|
import com.volmit.iris.util.mantle.MantleFlag;
|
||||||
import com.volmit.iris.util.math.M;
|
import com.volmit.iris.util.math.M;
|
||||||
@@ -71,6 +72,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
private final Looper looper;
|
private final Looper looper;
|
||||||
private final int id;
|
private final int id;
|
||||||
private final KList<Runnable> updateQueue = new KList<>();
|
private final KList<Runnable> updateQueue = new KList<>();
|
||||||
|
private final ChronoLatch cl;
|
||||||
private final ChronoLatch clw;
|
private final ChronoLatch clw;
|
||||||
private final ChronoLatch ecl;
|
private final ChronoLatch ecl;
|
||||||
private final ChronoLatch cln;
|
private final ChronoLatch cln;
|
||||||
@@ -81,10 +83,12 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
private long charge = 0;
|
private long charge = 0;
|
||||||
private int actuallySpawned = 0;
|
private int actuallySpawned = 0;
|
||||||
private int cooldown = 0;
|
private int cooldown = 0;
|
||||||
|
private List<Entity> precount = new KList<>();
|
||||||
private KSet<Position2> injectBiomes = new KSet<>();
|
private KSet<Position2> injectBiomes = new KSet<>();
|
||||||
|
|
||||||
public IrisWorldManager() {
|
public IrisWorldManager() {
|
||||||
super(null);
|
super(null);
|
||||||
|
cl = null;
|
||||||
ecl = null;
|
ecl = null;
|
||||||
cln = null;
|
cln = null;
|
||||||
clw = null;
|
clw = null;
|
||||||
@@ -99,6 +103,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
chunkUpdater = new ChronoLatch(3000);
|
chunkUpdater = new ChronoLatch(3000);
|
||||||
chunkDiscovery = new ChronoLatch(5000);
|
chunkDiscovery = new ChronoLatch(5000);
|
||||||
cln = new ChronoLatch(60000);
|
cln = new ChronoLatch(60000);
|
||||||
|
cl = new ChronoLatch(3000);
|
||||||
ecl = new ChronoLatch(250);
|
ecl = new ChronoLatch(250);
|
||||||
clw = new ChronoLatch(1000, true);
|
clw = new ChronoLatch(1000, true);
|
||||||
id = engine.getCacheID();
|
id = engine.getCacheID();
|
||||||
@@ -146,12 +151,27 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
engine.getEngineData().cleanup(getEngine());
|
engine.getEngineData().cleanup(getEngine());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (precount != null) {
|
||||||
|
entityCount = 0;
|
||||||
|
for (Entity i : precount) {
|
||||||
|
if (i instanceof LivingEntity) {
|
||||||
|
if (!i.isDead()) {
|
||||||
|
entityCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
precount = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (energy < 650) {
|
if (energy < 650) {
|
||||||
if (ecl.flip()) {
|
if (ecl.flip()) {
|
||||||
energy *= 1 + (0.02 * M.clip((1D - getEntitySaturation()), 0D, 1D));
|
energy *= 1 + (0.02 * M.clip((1D - getEntitySaturation()), 0D, 1D));
|
||||||
fixEnergy();
|
fixEnergy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAsyncTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
return IrisSettings.get().getWorld().getAsyncTickIntervalMS();
|
return IrisSettings.get().getWorld().getAsyncTickIntervalMS();
|
||||||
@@ -194,7 +214,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
int finalZ = c.getZ() + z;
|
int finalZ = c.getZ() + z;
|
||||||
J.a(() -> getMantle().raiseFlag(finalX, finalZ, MantleFlag.INITIAL_SPAWNED_MARKER,
|
J.a(() -> getMantle().raiseFlag(finalX, finalZ, MantleFlag.INITIAL_SPAWNED_MARKER,
|
||||||
() -> {
|
() -> {
|
||||||
J.a(() -> spawnIn(cx), RNG.r.i(5, 200));
|
J.a(() -> spawnIn(cx, true), RNG.r.i(5, 200));
|
||||||
getSpawnersFromMarkers(cx).forEach((blockf, spawners) -> {
|
getSpawnersFromMarkers(cx).forEach((blockf, spawners) -> {
|
||||||
if (spawners.isEmpty()) {
|
if (spawners.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -202,7 +222,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
|
|
||||||
IrisPosition block = new IrisPosition(blockf.getX(), blockf.getY() + getEngine().getWorld().minHeight(), blockf.getZ());
|
IrisPosition block = new IrisPosition(blockf.getX(), blockf.getY() + getEngine().getWorld().minHeight(), blockf.getZ());
|
||||||
IrisSpawner s = new KList<>(spawners).getRandom();
|
IrisSpawner s = new KList<>(spawners).getRandom();
|
||||||
spawn(block, s);
|
spawn(block, s, true);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -212,16 +232,73 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean onAsyncTick() {
|
||||||
|
if (getEngine().isClosed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
actuallySpawned = 0;
|
||||||
|
|
||||||
|
if (energy < 100) {
|
||||||
|
J.sleep(200);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getEngine().getWorld().hasRealWorld()) {
|
||||||
|
Iris.debug("Can't spawn. No real world");
|
||||||
|
J.sleep(5000);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double epx = getEntitySaturation();
|
||||||
|
if (epx > IrisSettings.get().getWorld().getTargetSpawnEntitiesPerChunk()) {
|
||||||
|
Iris.debug("Can't spawn. The entity per chunk ratio is at " + Form.pc(epx, 2) + " > 100% (total entities " + entityCount + ")");
|
||||||
|
J.sleep(5000);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cl.flip()) {
|
||||||
|
try {
|
||||||
|
J.s(() -> precount = getEngine().getWorld().realWorld().getEntities());
|
||||||
|
} catch (Throwable e) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int spawnBuffer = RNG.r.i(2, 12);
|
||||||
|
|
||||||
|
Chunk[] cc = getEngine().getWorld().realWorld().getLoadedChunks();
|
||||||
|
while (spawnBuffer-- > 0) {
|
||||||
|
if (cc.length == 0) {
|
||||||
|
Iris.debug("Can't spawn. No chunks!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Chunk c = cc[RNG.r.nextInt(cc.length)];
|
||||||
|
|
||||||
|
if (!c.isLoaded() || !Chunks.isSafe(c.getWorld(), c.getX(), c.getZ())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
spawnIn(c, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
energy -= (actuallySpawned / 2D);
|
||||||
|
return actuallySpawned > 0;
|
||||||
|
}
|
||||||
|
|
||||||
private void fixEnergy() {
|
private void fixEnergy() {
|
||||||
energy = M.clip(energy, 1D, getDimension().getMaximumEnergy());
|
energy = M.clip(energy, 1D, getDimension().getMaximumEnergy());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void spawnIn(Chunk c) {
|
private void spawnIn(Chunk c, boolean initial) {
|
||||||
if (getEngine().isClosed()) {
|
if (getEngine().isClosed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
energy += 1.2;
|
if (initial) {
|
||||||
|
energy += 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
|
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
|
||||||
getSpawnersFromMarkers(c).forEach((blockf, spawners) -> {
|
getSpawnersFromMarkers(c).forEach((blockf, spawners) -> {
|
||||||
@@ -231,8 +308,9 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
|
|
||||||
IrisPosition block = new IrisPosition(blockf.getX(), blockf.getY() + getEngine().getWorld().minHeight(), blockf.getZ());
|
IrisPosition block = new IrisPosition(blockf.getX(), blockf.getY() + getEngine().getWorld().minHeight(), blockf.getZ());
|
||||||
IrisSpawner s = new KList<>(spawners).getRandom();
|
IrisSpawner s = new KList<>(spawners).getRandom();
|
||||||
|
spawn(block, s, false);
|
||||||
J.a(() -> getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.INITIAL_SPAWNED_MARKER,
|
J.a(() -> getMantle().raiseFlag(c.getX(), c.getZ(), MantleFlag.INITIAL_SPAWNED_MARKER,
|
||||||
() -> spawn(block, s)));
|
() -> spawn(block, s, true)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,7 +341,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
.stream()
|
.stream()
|
||||||
.filter(filter)))
|
.filter(filter)))
|
||||||
.filter(counter)
|
.filter(counter)
|
||||||
.flatMap(this::stream)
|
.flatMap((i) -> stream(i, initial))
|
||||||
.collect(Collectors.toList()))
|
.collect(Collectors.toList()))
|
||||||
.getRandom();
|
.getRandom();
|
||||||
//@done
|
//@done
|
||||||
@@ -300,13 +378,13 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream<IrisEntitySpawn> stream(IrisSpawner s) {
|
private Stream<IrisEntitySpawn> stream(IrisSpawner s, boolean initial) {
|
||||||
for (IrisEntitySpawn i : s.getInitialSpawns()) {
|
for (IrisEntitySpawn i : initial ? s.getInitialSpawns() : s.getSpawns()) {
|
||||||
i.setReferenceSpawner(s);
|
i.setReferenceSpawner(s);
|
||||||
i.setReferenceMarker(s.getReferenceMarker());
|
i.setReferenceMarker(s.getReferenceMarker());
|
||||||
}
|
}
|
||||||
|
|
||||||
return (s.getInitialSpawns()).stream();
|
return (initial ? s.getInitialSpawns() : s.getSpawns()).stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
private KList<IrisEntitySpawn> spawnRandomly(List<IrisEntitySpawn> types) {
|
private KList<IrisEntitySpawn> spawnRandomly(List<IrisEntitySpawn> types) {
|
||||||
@@ -353,7 +431,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void spawn(IrisPosition block, IrisSpawner spawner) {
|
private void spawn(IrisPosition block, IrisSpawner spawner, boolean initial) {
|
||||||
if (getEngine().isClosed()) {
|
if (getEngine().isClosed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -362,7 +440,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KList<IrisEntitySpawn> s = spawner.getInitialSpawns();
|
KList<IrisEntitySpawn> s = initial ? spawner.getInitialSpawns() : spawner.getSpawns();
|
||||||
if (s.isEmpty()) {
|
if (s.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,12 @@ package com.volmit.iris.engine.object;
|
|||||||
|
|
||||||
import com.volmit.iris.core.nms.INMS;
|
import com.volmit.iris.core.nms.INMS;
|
||||||
import com.volmit.iris.core.nms.container.AutoClosing;
|
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||||
import com.volmit.iris.util.collection.KList;
|
|
||||||
import com.volmit.iris.util.misc.ServerProperties;
|
import com.volmit.iris.util.misc.ServerProperties;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.NamespacedKey;
|
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.world.WorldInitEvent;
|
import org.bukkit.event.world.WorldInitEvent;
|
||||||
|
|
||||||
@@ -22,9 +19,14 @@ public class IrisContextInjector implements Listener {
|
|||||||
@Getter
|
@Getter
|
||||||
private static boolean missingDimensionTypes = false;
|
private static boolean missingDimensionTypes = false;
|
||||||
private AutoClosing autoClosing = null;
|
private AutoClosing autoClosing = null;
|
||||||
|
private final int totalWorlds;
|
||||||
|
private int worldCounter = 0;
|
||||||
|
|
||||||
public IrisContextInjector() {
|
public IrisContextInjector() {
|
||||||
if (!Bukkit.getWorlds().isEmpty()) return;
|
if (!Bukkit.getWorlds().isEmpty()) {
|
||||||
|
totalWorlds = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String levelName = ServerProperties.LEVEL_NAME;
|
String levelName = ServerProperties.LEVEL_NAME;
|
||||||
List<String> irisWorlds = irisWorlds();
|
List<String> irisWorlds = irisWorlds();
|
||||||
@@ -32,20 +34,29 @@ public class IrisContextInjector implements Listener {
|
|||||||
boolean nether = irisWorlds.contains(levelName + "_nether");
|
boolean nether = irisWorlds.contains(levelName + "_nether");
|
||||||
boolean end = irisWorlds.contains(levelName + "_end");
|
boolean end = irisWorlds.contains(levelName + "_end");
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
if (Bukkit.getAllowNether()) i++;
|
||||||
|
if (Bukkit.getAllowEnd()) i++;
|
||||||
|
|
||||||
if (INMS.get().missingDimensionTypes(overworld, nether, end)) {
|
if (INMS.get().missingDimensionTypes(overworld, nether, end)) {
|
||||||
missingDimensionTypes = true;
|
missingDimensionTypes = true;
|
||||||
|
totalWorlds = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (overworld || nether || end) {
|
if (overworld || nether || end) {
|
||||||
autoClosing = INMS.get().injectUncached(overworld, nether, end);
|
var pair = INMS.get().injectUncached(overworld, nether, end);
|
||||||
|
i += pair.getA() - 3;
|
||||||
|
autoClosing = pair.getB();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalWorlds = i;
|
||||||
instance.registerListener(this);
|
instance.registerListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler
|
||||||
public void on(WorldInitEvent event) {
|
public void on(WorldInitEvent event) {
|
||||||
|
if (++worldCounter < totalWorlds) return;
|
||||||
if (autoClosing != null) {
|
if (autoClosing != null) {
|
||||||
autoClosing.close();
|
autoClosing.close();
|
||||||
autoClosing = null;
|
autoClosing = null;
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
package com.volmit.iris.engine.object;
|
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public abstract class IrisEngineService implements Listener {
|
|
||||||
protected final Engine engine;
|
|
||||||
|
|
||||||
public abstract void onEnable(boolean hotload);
|
|
||||||
|
|
||||||
public abstract void onDisable(boolean hotload);
|
|
||||||
|
|
||||||
public final void postShutdown(Runnable r) {
|
|
||||||
Iris.instance.postShutdown(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -404,7 +404,7 @@ public class IrisEntity extends IrisRegistrant {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
return e.isValid() ? e : null;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int surfaceY(Location l) {
|
private int surfaceY(Location l) {
|
||||||
|
|||||||
@@ -28,12 +28,19 @@ import com.volmit.iris.util.math.RNG;
|
|||||||
import com.volmit.iris.util.math.Vector3d;
|
import com.volmit.iris.util.math.Vector3d;
|
||||||
import com.volmit.iris.util.matter.MatterMarker;
|
import com.volmit.iris.util.matter.MatterMarker;
|
||||||
import com.volmit.iris.util.matter.slices.MarkerMatter;
|
import com.volmit.iris.util.matter.slices.MarkerMatter;
|
||||||
|
import io.lumine.mythic.bukkit.adapters.BukkitEntity;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
import org.bukkit.*;
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.EntityType;
|
||||||
|
import org.bukkit.entity.LivingEntity;
|
||||||
|
import org.bukkit.util.BoundingBox;
|
||||||
|
|
||||||
@Snippet("entity-spawn")
|
@Snippet("entity-spawn")
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@@ -62,10 +69,6 @@ public class IrisEntitySpawn implements IRare {
|
|||||||
private transient IrisSpawner referenceSpawner;
|
private transient IrisSpawner referenceSpawner;
|
||||||
private transient IrisMarker referenceMarker;
|
private transient IrisMarker referenceMarker;
|
||||||
|
|
||||||
public boolean check(Engine eng, IrisPosition c, ChunkSnapshot snapshot) {
|
|
||||||
return getRealEntity(eng).getSurface().matches(snapshot.getBlockData(c.getX() & 15, c.getY(), c.getZ() & 15));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int spawn(Engine gen, Chunk c, RNG rng) {
|
public int spawn(Engine gen, Chunk c, RNG rng) {
|
||||||
int spawns = minSpawns == maxSpawns ? minSpawns : rng.i(Math.min(minSpawns, maxSpawns), Math.max(minSpawns, maxSpawns));
|
int spawns = minSpawns == maxSpawns ? minSpawns : rng.i(Math.min(minSpawns, maxSpawns), Math.max(minSpawns, maxSpawns));
|
||||||
int s = 0;
|
int s = 0;
|
||||||
@@ -165,7 +168,7 @@ public class IrisEntitySpawn implements IRare {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ignoreSurfaces && !irisEntity.getSurface().matches(at.clone().subtract(0, 1, 0).getBlock().getBlockData())) {
|
if (!ignoreSurfaces && !irisEntity.getSurface().matches(at.clone().subtract(0, 1, 0).getBlock())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,10 +183,6 @@ public class IrisEntitySpawn implements IRare {
|
|||||||
Entity e = irisEntity.spawn(g, at.add(0.5, 0.5, 0.5), rng.aquire(() -> new RNG(g.getSeedManager().getEntity())));
|
Entity e = irisEntity.spawn(g, at.add(0.5, 0.5, 0.5), rng.aquire(() -> new RNG(g.getSeedManager().getEntity())));
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
Iris.debug("Spawned " + C.DARK_AQUA + "Entity<" + getEntity() + "> " + C.GREEN + e.getType() + C.LIGHT_PURPLE + " @ " + C.GRAY + e.getLocation().getX() + ", " + e.getLocation().getY() + ", " + e.getLocation().getZ());
|
Iris.debug("Spawned " + C.DARK_AQUA + "Entity<" + getEntity() + "> " + C.GREEN + e.getType() + C.LIGHT_PURPLE + " @ " + C.GRAY + e.getLocation().getX() + ", " + e.getLocation().getY() + ", " + e.getLocation().getZ());
|
||||||
|
|
||||||
if (referenceSpawner != null) {
|
|
||||||
referenceSpawner.getConditions().apply(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return e;
|
return e;
|
||||||
|
|||||||
@@ -123,8 +123,6 @@ public class IrisImage extends IrisRegistrant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void writeDebug(IrisImageChannel channel) {
|
public void writeDebug(IrisImageChannel channel) {
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
File at = new File(getLoadFile().getParentFile(), "debug-see-" + getLoadFile().getName());
|
File at = new File(getLoadFile().getParentFile(), "debug-see-" + getLoadFile().getName());
|
||||||
BufferedImage b = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
|
BufferedImage b = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
package com.volmit.iris.engine.object;
|
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.engine.object.annotations.Desc;
|
|
||||||
import com.volmit.iris.util.collection.KList;
|
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
import org.bukkit.NamespacedKey;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.entity.SpawnCategory;
|
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.function.BooleanSupplier;
|
|
||||||
|
|
||||||
@Accessors(chain = true)
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Desc("Conditions for a spawner to be triggered")
|
|
||||||
@Data
|
|
||||||
public class IrisSpawnCondition {
|
|
||||||
private static final NamespacedKey CATEGORY_KEY = new NamespacedKey(Iris.instance, "spawn_category");
|
|
||||||
|
|
||||||
private SpawnCategory category = SpawnCategory.AMBIENT;
|
|
||||||
private int maxEntities = 60;
|
|
||||||
|
|
||||||
public boolean check(KMap<UUID, KMap<String, Boolean>> cache, KList<Entity> entities) {
|
|
||||||
int entityCount = 0;
|
|
||||||
for (Entity entity : entities) {
|
|
||||||
var map = cache.computeIfAbsent(entity.getUniqueId(), k -> new KMap<>());
|
|
||||||
if (check(map, "category_" + category.name(), () -> checkCategory(entity, category)) && ++entityCount >= maxEntities)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void apply(Entity entity) {
|
|
||||||
var pdc = entity.getPersistentDataContainer();
|
|
||||||
pdc.set(CATEGORY_KEY, PersistentDataType.STRING, category.name());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean check(KMap<String, Boolean> cache, String key, BooleanSupplier predicate) {
|
|
||||||
return cache.computeIfAbsent(key, k -> predicate.getAsBoolean()) == Boolean.TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean checkCategory(Entity entity, SpawnCategory category) {
|
|
||||||
if (entity.getSpawnCategory() == category)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
var pdc = entity.getPersistentDataContainer();
|
|
||||||
if (!pdc.has(CATEGORY_KEY, PersistentDataType.STRING))
|
|
||||||
return false;
|
|
||||||
return category.name().equals(pdc.get(CATEGORY_KEY, PersistentDataType.STRING));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -74,9 +74,6 @@ public class IrisSpawner extends IrisRegistrant {
|
|||||||
@Desc("Where should these spawns be placed")
|
@Desc("Where should these spawns be placed")
|
||||||
private IrisSpawnGroup group = IrisSpawnGroup.NORMAL;
|
private IrisSpawnGroup group = IrisSpawnGroup.NORMAL;
|
||||||
|
|
||||||
@Desc("Conditions for this spawner to be triggered")
|
|
||||||
private IrisSpawnCondition conditions = new IrisSpawnCondition();
|
|
||||||
|
|
||||||
public boolean isValid(IrisBiome biome) {
|
public boolean isValid(IrisBiome biome) {
|
||||||
return switch (group) {
|
return switch (group) {
|
||||||
case NORMAL -> switch (biome.getInferredType()) {
|
case NORMAL -> switch (biome.getInferredType()) {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ package com.volmit.iris.engine.object;
|
|||||||
|
|
||||||
import com.volmit.iris.engine.object.annotations.Desc;
|
import com.volmit.iris.engine.object.annotations.Desc;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.data.Waterlogged;
|
import org.bukkit.block.data.Waterlogged;
|
||||||
|
|
||||||
@Desc("The type of surface entities should spawn on")
|
@Desc("The type of surface entities should spawn on")
|
||||||
@@ -47,8 +47,8 @@ public enum IrisSurface {
|
|||||||
* @param state The blockstate
|
* @param state The blockstate
|
||||||
* @return True if it matches
|
* @return True if it matches
|
||||||
*/
|
*/
|
||||||
public boolean matches(BlockData state) {
|
public boolean matches(Block state) {
|
||||||
Material type = state.getMaterial();
|
Material type = state.getType();
|
||||||
if (type.isSolid()) {
|
if (type.isSolid()) {
|
||||||
return this == LAND || this == OVERWORLD || (this == ANIMAL
|
return this == LAND || this == OVERWORLD || (this == ANIMAL
|
||||||
&& (type == Material.GRASS_BLOCK || type == Material.DIRT
|
&& (type == Material.GRASS_BLOCK || type == Material.DIRT
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ package com.volmit.iris.engine.platform;
|
|||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
import com.volmit.iris.core.nms.INMS;
|
import com.volmit.iris.core.nms.INMS;
|
||||||
import com.volmit.iris.core.nms.container.AutoClosing;
|
|
||||||
import com.volmit.iris.core.service.StudioSVC;
|
import com.volmit.iris.core.service.StudioSVC;
|
||||||
import com.volmit.iris.engine.IrisEngine;
|
import com.volmit.iris.engine.IrisEngine;
|
||||||
import com.volmit.iris.engine.data.chunk.TerrainChunk;
|
import com.volmit.iris.engine.data.chunk.TerrainChunk;
|
||||||
@@ -49,7 +48,6 @@ import org.bukkit.block.data.BlockData;
|
|||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.world.WorldInitEvent;
|
import org.bukkit.event.world.WorldInitEvent;
|
||||||
import org.bukkit.generator.BiomeProvider;
|
import org.bukkit.generator.BiomeProvider;
|
||||||
@@ -124,13 +122,11 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler
|
||||||
public void onWorldInit(WorldInitEvent event) {
|
public void onWorldInit(WorldInitEvent event) {
|
||||||
try {
|
try {
|
||||||
if (initialized || !world.name().equals(event.getWorld().getName()))
|
if (initialized || !world.name().equals(event.getWorld().getName()))
|
||||||
return;
|
return;
|
||||||
AutoClosing.closeContext();
|
|
||||||
INMS.get().removeCustomDimensions(event.getWorld());
|
|
||||||
world.setRawWorldSeed(event.getWorld().getSeed());
|
world.setRawWorldSeed(event.getWorld().getSeed());
|
||||||
Engine engine = getEngine(event.getWorld());
|
Engine engine = getEngine(event.getWorld());
|
||||||
if (engine == null) {
|
if (engine == null) {
|
||||||
|
|||||||
@@ -1,340 +0,0 @@
|
|||||||
package com.volmit.iris.engine.service;
|
|
||||||
|
|
||||||
import com.google.common.util.concurrent.AtomicDouble;
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.IrisSettings;
|
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
|
||||||
import com.volmit.iris.core.nms.container.Pair;
|
|
||||||
import com.volmit.iris.engine.IrisWorldManager;
|
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
|
||||||
import com.volmit.iris.engine.object.*;
|
|
||||||
import com.volmit.iris.util.collection.KList;
|
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.collection.KSet;
|
|
||||||
import com.volmit.iris.util.format.Form;
|
|
||||||
import com.volmit.iris.util.mantle.Mantle;
|
|
||||||
import com.volmit.iris.util.math.BlockPosition;
|
|
||||||
import com.volmit.iris.util.math.Position2;
|
|
||||||
import com.volmit.iris.util.math.RNG;
|
|
||||||
import com.volmit.iris.util.matter.MatterMarker;
|
|
||||||
import com.volmit.iris.util.parallel.Sync;
|
|
||||||
import com.volmit.iris.util.scheduling.J;
|
|
||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
|
||||||
import io.papermc.lib.PaperLib;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import org.bukkit.ChunkSnapshot;
|
|
||||||
import org.bukkit.GameRule;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class EngineMobHandlerSVC extends IrisEngineService {
|
|
||||||
private static final List<String> CAVE_TAGS = List.of("cave_floor", "cave_ceiling");
|
|
||||||
private static final int SAFE_RADIUS = 16;
|
|
||||||
private static final int MAX_RADIUS = 128;
|
|
||||||
|
|
||||||
private final AtomicLong currentTick = new AtomicLong();
|
|
||||||
private final Sync<Long> sync = new Sync<>();
|
|
||||||
private final Set<Player> players = ConcurrentHashMap.newKeySet();
|
|
||||||
private final AtomicBoolean running = new AtomicBoolean(false);
|
|
||||||
private transient KList<Entity> entities = new KList<>();
|
|
||||||
private transient Thread asyncTicker = null;
|
|
||||||
private transient Thread entityCollector = null;
|
|
||||||
private transient boolean charge = false;
|
|
||||||
private transient int task = -1;
|
|
||||||
|
|
||||||
public EngineMobHandlerSVC(Engine engine) {
|
|
||||||
super(engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable(boolean hotload) {
|
|
||||||
if (running.get()) {
|
|
||||||
running.set(false);
|
|
||||||
cancel(asyncTicker);
|
|
||||||
cancel(entityCollector);
|
|
||||||
}
|
|
||||||
|
|
||||||
running.set(true);
|
|
||||||
charge = hotload;
|
|
||||||
asyncTicker = Thread.ofPlatform()
|
|
||||||
.name("Iris Async Mob Spawning - " + engine.getWorld().name())
|
|
||||||
.priority(9)
|
|
||||||
.start(() -> {
|
|
||||||
while (mayLoop()) {
|
|
||||||
try {
|
|
||||||
asyncTick();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
if (isInterrupted(e))
|
|
||||||
return;
|
|
||||||
Iris.error("Error in async tick for " + engine.getWorld().name());
|
|
||||||
e.printStackTrace();
|
|
||||||
|
|
||||||
J.sleep(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
entityCollector = Thread.ofVirtual()
|
|
||||||
.name("Iris Async Entity Collector - " + engine.getWorld().name())
|
|
||||||
.start(() -> {
|
|
||||||
while (mayLoop()) {
|
|
||||||
try {
|
|
||||||
sync.next().get();
|
|
||||||
var world = engine.getWorld().realWorld();
|
|
||||||
if (world == null) continue;
|
|
||||||
J.s(() -> entities = new KList<>(world.getEntities()));
|
|
||||||
} catch (Throwable e) {
|
|
||||||
if (isInterrupted(e))
|
|
||||||
return;
|
|
||||||
|
|
||||||
Iris.error("Error in async tick for " + engine.getWorld().name());
|
|
||||||
e.printStackTrace();
|
|
||||||
|
|
||||||
J.sleep(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (task != -1) J.csr(task);
|
|
||||||
task = J.sr(() -> sync.advance(currentTick.getAndIncrement()), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisable(boolean hotload) {
|
|
||||||
running.set(false);
|
|
||||||
cancel(asyncTicker);
|
|
||||||
cancel(entityCollector);
|
|
||||||
if (!hotload) J.csr(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void asyncTick() throws Throwable {
|
|
||||||
long tick = sync.next().get();
|
|
||||||
var manager = (IrisWorldManager) engine.getWorldManager();
|
|
||||||
if (charge) {
|
|
||||||
manager.chargeEnergy();
|
|
||||||
charge = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var world = engine.getWorld().realWorld();
|
|
||||||
if (world == null
|
|
||||||
|| noSpawning()
|
|
||||||
|| Boolean.FALSE.equals(world.getGameRuleValue(GameRule.DO_MOB_SPAWNING))
|
|
||||||
|| players.isEmpty()
|
|
||||||
|| manager.getEnergy() < 100)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var p = PrecisionStopwatch.start();
|
|
||||||
var entities = new KList<>(this.entities);
|
|
||||||
|
|
||||||
var conditionCache = new KMap<UUID, KMap<String, Boolean>>();
|
|
||||||
var data = engine.getData();
|
|
||||||
var invalid = data.getSpawnerLoader()
|
|
||||||
.streamAllPossible()
|
|
||||||
.filter(Predicate.not(spawner -> spawner.canSpawn(engine)
|
|
||||||
&& spawner.getConditions().check(conditionCache, entities)))
|
|
||||||
.map(IrisSpawner::getLoadKey)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
|
||||||
var centers = players.stream()
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.filter(Player::isOnline)
|
|
||||||
.map(Player::getLocation)
|
|
||||||
.map(BlockPosition::fromLocation)
|
|
||||||
.collect(KList.collector())
|
|
||||||
.shuffle();
|
|
||||||
|
|
||||||
if (centers.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
AtomicDouble delta = new AtomicDouble();
|
|
||||||
int actuallySpawned = 0;
|
|
||||||
|
|
||||||
KMap<Position2, Pair<Entity[], ChunkSnapshot>> cache = new KMap<>();
|
|
||||||
while (centers.isNotEmpty()) {
|
|
||||||
var center = centers.pop();
|
|
||||||
var spawned = trySpawn(world, invalid, cache, center, delta);
|
|
||||||
if (spawned == 0 && p.getMilliseconds() < 1000)
|
|
||||||
centers.add(center);
|
|
||||||
actuallySpawned += spawned;
|
|
||||||
}
|
|
||||||
manager.setEnergy(manager.getEnergy() - delta.get());
|
|
||||||
if (actuallySpawned > 0) {
|
|
||||||
Iris.info("Async Mob Spawning " + world.getName() + " used " + delta + " energy and took " + Form.duration((long) p.getMilliseconds()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int trySpawn(
|
|
||||||
World world,
|
|
||||||
Set<String> invalid,
|
|
||||||
KMap<Position2, Pair<Entity[], ChunkSnapshot>> cache,
|
|
||||||
BlockPosition center,
|
|
||||||
AtomicDouble delta
|
|
||||||
) {
|
|
||||||
var pos = center.randomPoint(MAX_RADIUS, SAFE_RADIUS);
|
|
||||||
if (pos.getY() < world.getMinHeight() || pos.getY() >= world.getMaxHeight())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
var chunkPos = new Position2(center.getX() >> 4, center.getZ() >> 4);
|
|
||||||
var pair = cache.computeIfAbsent(chunkPos, cPos -> {
|
|
||||||
try {
|
|
||||||
return PaperLib.getChunkAtAsync(world, cPos.getX(), cPos.getZ(), false)
|
|
||||||
.thenApply(c -> c != null ? new Pair<>(c.getEntities(), c.getChunkSnapshot(false, false, false)) : null)
|
|
||||||
.get();
|
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (pair == null)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
var spawners = spawnersAt(pair.getB(), pos, invalid);
|
|
||||||
spawners.removeIf(i -> !i.canSpawn(engine, chunkPos.getX(), chunkPos.getZ()));
|
|
||||||
|
|
||||||
if (spawners.isEmpty())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
IrisPosition irisPos = new IrisPosition(pos.getX(), pos.getY(), pos.getZ());
|
|
||||||
for (var spawner : spawners) {
|
|
||||||
var spawns = spawner.getSpawns().copy();
|
|
||||||
spawns.removeIf(spawn -> !spawn.check(engine, irisPos, pair.getB()));
|
|
||||||
|
|
||||||
var entity = IRare.pick(spawns, RNG.r.nextDouble());
|
|
||||||
if (entity == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
entity.setReferenceSpawner(spawner);
|
|
||||||
entity.setReferenceMarker(spawner.getReferenceMarker());
|
|
||||||
int spawned = entity.spawn(engine, irisPos, RNG.r);
|
|
||||||
if (spawned == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
delta.addAndGet(spawned * ((entity.getEnergyMultiplier() * spawner.getEnergyMultiplier() * 1)));
|
|
||||||
spawner.spawn(engine, chunkPos.getX(), chunkPos.getZ());
|
|
||||||
if (!spawner.canSpawn(engine))
|
|
||||||
invalid.add(spawner.getLoadKey());
|
|
||||||
return spawned;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private KSet<IrisSpawner> spawnersAt(ChunkSnapshot chunk, BlockPosition pos, Set<String> invalid) {
|
|
||||||
KSet<IrisSpawner> spawners = markerAt(chunk, pos, invalid);
|
|
||||||
|
|
||||||
var loader = engine.getData().getSpawnerLoader();
|
|
||||||
int y = pos.getY() - engine.getWorld().minHeight();
|
|
||||||
Stream.concat(engine.getRegion(pos.getX(), pos.getZ())
|
|
||||||
.getEntitySpawners()
|
|
||||||
.stream(),
|
|
||||||
engine.getBiomeOrMantle(pos.getX(), y, pos.getZ())
|
|
||||||
.getEntitySpawners()
|
|
||||||
.stream())
|
|
||||||
.filter(Predicate.not(invalid::contains))
|
|
||||||
.map(loader::load)
|
|
||||||
.forEach(spawners::add);
|
|
||||||
|
|
||||||
return spawners;
|
|
||||||
}
|
|
||||||
|
|
||||||
private KSet<IrisSpawner> markerAt(ChunkSnapshot chunk, BlockPosition pos, Set<String> invalid) {
|
|
||||||
if (!IrisSettings.get().getWorld().isMarkerEntitySpawningSystem())
|
|
||||||
return new KSet<>();
|
|
||||||
|
|
||||||
int y = pos.getY() - engine.getWorld().minHeight();
|
|
||||||
Mantle mantle = engine.getMantle().getMantle();
|
|
||||||
MatterMarker matter = mantle.get(pos.getX(), y, pos.getZ(), MatterMarker.class);
|
|
||||||
if (matter == null || CAVE_TAGS.contains(matter.getTag()))
|
|
||||||
return new KSet<>();
|
|
||||||
IrisData data = engine.getData();
|
|
||||||
IrisMarker mark = data.getMarkerLoader().load(matter.getTag());
|
|
||||||
if (mark == null)
|
|
||||||
return new KSet<>();
|
|
||||||
|
|
||||||
if (mark.isEmptyAbove()) {
|
|
||||||
int x = pos.getX() & 15, z = pos.getZ() & 15;
|
|
||||||
boolean remove = chunk.getBlockData(x, pos.getY() + 1, z).getMaterial().isSolid() || chunk.getBlockData(x, pos.getY() + 2, z).getMaterial().isSolid();
|
|
||||||
if (remove) {
|
|
||||||
mantle.remove(pos.getX(), y, pos.getZ(), MatterMarker.class);
|
|
||||||
return new KSet<>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KSet<IrisSpawner> spawners = new KSet<>();
|
|
||||||
for (String key : mark.getSpawners()) {
|
|
||||||
if (invalid.contains(key))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
IrisSpawner spawner = data.getSpawnerLoader().load(key);
|
|
||||||
if (spawner == null) {
|
|
||||||
Iris.error("Cannot load spawner: " + key + " for marker " + matter.getTag());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
spawner.setReferenceMarker(mark);
|
|
||||||
spawners.add(spawner);
|
|
||||||
}
|
|
||||||
return spawners;
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
|
||||||
public void on(PlayerJoinEvent event) {
|
|
||||||
var player = event.getPlayer();
|
|
||||||
if (player.getWorld() != engine.getWorld().realWorld())
|
|
||||||
return;
|
|
||||||
players.add(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST)
|
|
||||||
public void on(PlayerQuitEvent event) {
|
|
||||||
players.remove(event.getPlayer());
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
||||||
public void on(PlayerChangedWorldEvent event) {
|
|
||||||
var player = event.getPlayer();
|
|
||||||
if (player.getWorld() == engine.getWorld().realWorld())
|
|
||||||
players.add(player);
|
|
||||||
else
|
|
||||||
players.remove(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
private static void cancel(Thread thread) {
|
|
||||||
if (thread == null || !thread.isAlive()) return;
|
|
||||||
thread.interrupt();
|
|
||||||
thread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean noSpawning() {
|
|
||||||
var world = IrisSettings.get().getWorld();
|
|
||||||
return !world.isMarkerEntitySpawningSystem() && !world.isAnbientEntitySpawningSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean mayLoop() {
|
|
||||||
return !engine.isClosed() && running.get() && !Thread.interrupted();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isInterrupted(Throwable e) {
|
|
||||||
while (e != null) {
|
|
||||||
if (e instanceof InterruptedException)
|
|
||||||
return true;
|
|
||||||
e = e.getCause();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package com.volmit.iris.engine.service;
|
|
||||||
|
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
|
||||||
import com.volmit.iris.engine.object.IrisEngineService;
|
|
||||||
import com.volmit.iris.util.collection.KList;
|
|
||||||
|
|
||||||
public class EngineStatusSVC extends IrisEngineService {
|
|
||||||
private static final KList<EngineStatusSVC> INSTANCES = new KList<>();
|
|
||||||
|
|
||||||
public EngineStatusSVC(Engine engine) {
|
|
||||||
super(engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable(boolean hotload) {
|
|
||||||
if (hotload) return;
|
|
||||||
synchronized (INSTANCES) {
|
|
||||||
INSTANCES.add(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisable(boolean hotload) {
|
|
||||||
if (hotload) return;
|
|
||||||
|
|
||||||
synchronized (INSTANCES) {
|
|
||||||
INSTANCES.remove(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getEngineCount() {
|
|
||||||
return INSTANCES.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Status getStatus() {
|
|
||||||
synchronized (INSTANCES) {
|
|
||||||
long loadedChunks = 0;
|
|
||||||
long tectonicPlates = 0;
|
|
||||||
long activeTectonicPlates = 0;
|
|
||||||
long queuedTectonicPlates = 0;
|
|
||||||
long minTectonicUnloadDuration = Long.MAX_VALUE;
|
|
||||||
long maxTectonicUnloadDuration = Long.MIN_VALUE;
|
|
||||||
|
|
||||||
for (var service : INSTANCES) {
|
|
||||||
var world = service.engine.getWorld();
|
|
||||||
if (world.hasRealWorld())
|
|
||||||
loadedChunks += world.realWorld().getLoadedChunks().length;
|
|
||||||
|
|
||||||
tectonicPlates += service.engine.getMantle().getLoadedRegionCount();
|
|
||||||
activeTectonicPlates += service.engine.getMantle().getNotQueuedLoadedRegions();
|
|
||||||
queuedTectonicPlates += service.engine.getMantle().getToUnload();
|
|
||||||
minTectonicUnloadDuration = Math.min(minTectonicUnloadDuration, (long) service.engine.getMantle().getTectonicDuration());
|
|
||||||
maxTectonicUnloadDuration = Math.max(maxTectonicUnloadDuration, (long) service.engine.getMantle().getTectonicDuration());
|
|
||||||
}
|
|
||||||
return new Status(INSTANCES.size(), loadedChunks, MantleCleanerSVC.getTectonicLimit(), tectonicPlates, activeTectonicPlates, queuedTectonicPlates, minTectonicUnloadDuration, maxTectonicUnloadDuration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public record Status(int engineCount, long loadedChunks, int tectonicLimit,
|
|
||||||
long tectonicPlates, long activeTectonicPlates,
|
|
||||||
long queuedTectonicPlates,
|
|
||||||
long minTectonicUnloadDuration,
|
|
||||||
long maxTectonicUnloadDuration) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
package com.volmit.iris.engine.service;
|
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.IrisSettings;
|
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
|
||||||
import com.volmit.iris.engine.object.IrisEngineService;
|
|
||||||
import com.volmit.iris.util.format.C;
|
|
||||||
import com.volmit.iris.util.math.M;
|
|
||||||
import com.volmit.iris.util.misc.getHardware;
|
|
||||||
import com.volmit.iris.util.scheduling.Looper;
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.function.LongSupplier;
|
|
||||||
|
|
||||||
public class MantleCleanerSVC extends IrisEngineService {
|
|
||||||
private static final AtomicInteger tectonicLimit = new AtomicInteger(30);
|
|
||||||
|
|
||||||
static {
|
|
||||||
// todo: Redo this
|
|
||||||
tectonicLimit.set(2);
|
|
||||||
long t = getHardware.getProcessMemory();
|
|
||||||
while (t > 200) {
|
|
||||||
tectonicLimit.incrementAndGet();
|
|
||||||
t = t - 200;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Ticker trimmer;
|
|
||||||
private Ticker unloader;
|
|
||||||
|
|
||||||
public MantleCleanerSVC(Engine engine) {
|
|
||||||
super(engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getTectonicLimit() {
|
|
||||||
return tectonicLimit.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Ticker createTrimmer(Engine engine) {
|
|
||||||
return new Ticker(() -> {
|
|
||||||
if (engine.isClosed()) return -1;
|
|
||||||
long start = M.ms();
|
|
||||||
try {
|
|
||||||
engine.getMantle().trim(tectonicLimit.get() / getEngineCount());
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Iris.debug(C.RED + "Mantle: Failed to trim.");
|
|
||||||
Iris.reportError(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (engine.isClosed()) return -1;
|
|
||||||
int size = getEngineCount();
|
|
||||||
return Math.max(1000 / size - (M.ms() - start), 0);
|
|
||||||
}, "Iris Mantle Trimmer - " + engine.getWorld().name());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Ticker createUnloader(Engine engine) {
|
|
||||||
return new Ticker(() -> {
|
|
||||||
if (engine.isClosed()) return -1;
|
|
||||||
long start = M.ms();
|
|
||||||
try {
|
|
||||||
engine.getMantle().unloadTectonicPlate(tectonicLimit.get() / getEngineCount());
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Iris.debug(C.RED + "Mantle: Failed to unload.");
|
|
||||||
Iris.reportError(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (engine.isClosed()) return -1;
|
|
||||||
int size = getEngineCount();
|
|
||||||
return Math.max(1000 / size - (M.ms() - start), 0);
|
|
||||||
}, "Iris Mantle Unloader - " + engine.getWorld().name());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getEngineCount() {
|
|
||||||
return Math.max(EngineStatusSVC.getEngineCount(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable(boolean hotload) {
|
|
||||||
if (engine.isStudio() && !IrisSettings.get().getPerformance().trimMantleInStudio)
|
|
||||||
return;
|
|
||||||
if (trimmer == null || !trimmer.isAlive())
|
|
||||||
trimmer = createTrimmer(engine);
|
|
||||||
if (unloader == null || !unloader.isAlive())
|
|
||||||
unloader = createUnloader(engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisable(boolean hotload) {
|
|
||||||
if (hotload) return;
|
|
||||||
if (trimmer != null) trimmer.await();
|
|
||||||
if (unloader != null) unloader.await();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Ticker extends Looper {
|
|
||||||
private final LongSupplier supplier;
|
|
||||||
|
|
||||||
private Ticker(LongSupplier supplier, String name) {
|
|
||||||
this.supplier = supplier;
|
|
||||||
setPriority(Thread.MIN_PRIORITY);
|
|
||||||
setName(name);
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected long loop() {
|
|
||||||
try {
|
|
||||||
return supplier.getAsLong();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Iris.error("Exception in Looper " + getName());
|
|
||||||
StringWriter sw = new StringWriter();
|
|
||||||
e.printStackTrace(new PrintWriter(sw));
|
|
||||||
Iris.error(sw.toString());
|
|
||||||
return 3000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
public void await() {
|
|
||||||
join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -26,8 +26,6 @@ import com.volmit.iris.util.math.RNG;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collector;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@SuppressWarnings("ALL")
|
@SuppressWarnings("ALL")
|
||||||
public class KList<T> extends ArrayList<T> implements List<T> {
|
public class KList<T> extends ArrayList<T> implements List<T> {
|
||||||
@@ -67,10 +65,6 @@ public class KList<T> extends ArrayList<T> implements List<T> {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> Collector<T, ?, KList<T>> collector() {
|
|
||||||
return Collectors.toCollection(KList::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static KList<String> asStringList(List<?> oo) {
|
public static KList<String> asStringList(List<?> oo) {
|
||||||
KList<String> s = new KList<String>();
|
KList<String> s = new KList<String>();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.util.decree.handlers;
|
||||||
|
|
||||||
|
import com.volmit.iris.engine.object.IrisImageChannel;
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import com.volmit.iris.util.decree.DecreeParameterHandler;
|
||||||
|
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class ImageChannelHandler implements DecreeParameterHandler<IrisImageChannel> {
|
||||||
|
@Override
|
||||||
|
public KList<IrisImageChannel> getPossibilities() {
|
||||||
|
return new KList<>(Arrays.stream(IrisImageChannel.values()).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(IrisImageChannel channel) {
|
||||||
|
return channel.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IrisImageChannel parse(String in, boolean force) throws DecreeParsingException {
|
||||||
|
return IrisImageChannel.valueOf(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(Class<?> type) {
|
||||||
|
return type.equals(IrisImageChannel.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRandomDefault() {
|
||||||
|
return IrisImageChannel.BRIGHTNESS.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2024 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.util.decree.specialhandlers;
|
||||||
|
|
||||||
|
import com.volmit.iris.engine.object.IrisBiome;
|
||||||
|
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
||||||
|
import com.volmit.iris.util.decree.handlers.BiomeHandler;
|
||||||
|
|
||||||
|
public class NullableBiomeHandler extends BiomeHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IrisBiome parse(String in, boolean force) throws DecreeParsingException {
|
||||||
|
return getPossibilities(in).stream().filter((i) -> toString(i).equalsIgnoreCase(in)).findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2024 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.util.decree.specialhandlers;
|
||||||
|
|
||||||
|
import com.volmit.iris.engine.object.IrisRegion;
|
||||||
|
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
||||||
|
import com.volmit.iris.util.decree.handlers.RegionHandler;
|
||||||
|
|
||||||
|
public class NullableRegionHandler extends RegionHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IrisRegion parse(String in, boolean force) throws DecreeParsingException {
|
||||||
|
return getPossibilities(in).stream().filter((i) -> toString(i).equalsIgnoreCase(in)).findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ package com.volmit.iris.util.mantle;
|
|||||||
import com.google.common.util.concurrent.AtomicDouble;
|
import com.google.common.util.concurrent.AtomicDouble;
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.IrisSettings;
|
import com.volmit.iris.core.IrisSettings;
|
||||||
|
import com.volmit.iris.core.service.IrisEngineSVC;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.engine.data.cache.Cache;
|
import com.volmit.iris.engine.data.cache.Cache;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
@@ -424,7 +425,7 @@ public class Mantle {
|
|||||||
ioTrim.set(true);
|
ioTrim.set(true);
|
||||||
unloadLock.lock();
|
unloadLock.lock();
|
||||||
try {
|
try {
|
||||||
if (lastUse != null) {
|
if (lastUse != null && IrisEngineSVC.instance != null) {
|
||||||
if (!lastUse.isEmpty()) {
|
if (!lastUse.isEmpty()) {
|
||||||
Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration.get(), 0));
|
Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration.get(), 0));
|
||||||
for (long i : new ArrayList<>(lastUse.keySet())) {
|
for (long i : new ArrayList<>(lastUse.keySet())) {
|
||||||
@@ -434,6 +435,7 @@ public class Mantle {
|
|||||||
if (lastUseTime != null && M.ms() - lastUseTime >= finalAdjustedIdleDuration) {
|
if (lastUseTime != null && M.ms() - lastUseTime >= finalAdjustedIdleDuration) {
|
||||||
toUnload.add(i);
|
toUnload.add(i);
|
||||||
Iris.debug("Tectonic Region added to unload");
|
Iris.debug("Tectonic Region added to unload");
|
||||||
|
IrisEngineSVC.instance.trimActiveAlive.reset();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -452,49 +454,53 @@ public class Mantle {
|
|||||||
AtomicInteger i = new AtomicInteger();
|
AtomicInteger i = new AtomicInteger();
|
||||||
unloadLock.lock();
|
unloadLock.lock();
|
||||||
BurstExecutor burst = null;
|
BurstExecutor burst = null;
|
||||||
try {
|
if (IrisEngineSVC.instance != null) {
|
||||||
KList<Long> copy = toUnload.copy();
|
try {
|
||||||
if (!disableClear) toUnload.clear();
|
KList<Long> copy = toUnload.copy();
|
||||||
burst = MultiBurst.burst.burst(copy.size());
|
if (!disableClear) toUnload.clear();
|
||||||
burst.setMulticore(copy.size() > tectonicLimit);
|
burst = MultiBurst.burst.burst(copy.size());
|
||||||
for (int j = 0; j < copy.size(); j++) {
|
burst.setMulticore(copy.size() > tectonicLimit);
|
||||||
Long id = copy.get(j);
|
for (int j = 0; j < copy.size(); j++) {
|
||||||
if (id == null) {
|
Long id = copy.get(j);
|
||||||
Iris.error("Null id in unloadTectonicPlate at index " + j);
|
if (id == null) {
|
||||||
continue;
|
Iris.error("Null id in unloadTectonicPlate at index " + j);
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
burst.queue(() ->
|
burst.queue(() ->
|
||||||
hyperLock.withLong(id, () -> {
|
hyperLock.withLong(id, () -> {
|
||||||
TectonicPlate m = loadedRegions.get(id);
|
TectonicPlate m = loadedRegions.get(id);
|
||||||
if (m != null) {
|
if (m != null) {
|
||||||
if (m.inUse()) {
|
if (m.inUse()) {
|
||||||
Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ());
|
Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ());
|
||||||
if (disableClear) toUnload.remove(id);
|
if (disableClear) toUnload.remove(id);
|
||||||
lastUse.put(id, M.ms());
|
lastUse.put(id, M.ms());
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
m.write(fileForRegion(dataFolder, id));
|
||||||
|
loadedRegions.remove(id);
|
||||||
|
lastUse.remove(id);
|
||||||
|
if (disableClear) 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
}));
|
||||||
m.write(fileForRegion(dataFolder, id));
|
}
|
||||||
loadedRegions.remove(id);
|
|
||||||
lastUse.remove(id);
|
|
||||||
if (disableClear) 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
burst.complete();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
if (burst != null)
|
|
||||||
burst.complete();
|
burst.complete();
|
||||||
} finally {
|
} catch (Throwable e) {
|
||||||
unloadLock.unlock();
|
e.printStackTrace();
|
||||||
ioTectonicUnload.set(true);
|
if (burst != null)
|
||||||
|
burst.complete();
|
||||||
|
} finally {
|
||||||
|
unloadLock.unlock();
|
||||||
|
ioTectonicUnload.set(true);
|
||||||
|
}
|
||||||
|
return i.get();
|
||||||
}
|
}
|
||||||
return i.get();
|
return i.get();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,14 +19,11 @@
|
|||||||
package com.volmit.iris.util.math;
|
package com.volmit.iris.util.math;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static com.volmit.iris.util.math.RNG.r;
|
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class BlockPosition {
|
public class BlockPosition {
|
||||||
//Magic numbers
|
//Magic numbers
|
||||||
@@ -46,10 +43,6 @@ public class BlockPosition {
|
|||||||
this.z = z;
|
this.z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BlockPosition fromLocation(Location loc) {
|
|
||||||
return new BlockPosition(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long toLong(int x, int y, int z) {
|
public static long toLong(int x, int y, int z) {
|
||||||
long var3 = 0L;
|
long var3 = 0L;
|
||||||
var3 |= (x & m4) << m3;
|
var3 |= (x & m4) << m3;
|
||||||
@@ -115,18 +108,4 @@ public class BlockPosition {
|
|||||||
setY(Math.max(i.getY(), getY()));
|
setY(Math.max(i.getY(), getY()));
|
||||||
setZ(Math.max(i.getZ(), getZ()));
|
setZ(Math.max(i.getZ(), getZ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockPosition randomPoint(int radius, int innerRadius) {
|
|
||||||
int max = radius * radius;
|
|
||||||
int min = innerRadius * innerRadius;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
int x = r.nextInt(-radius, radius + 1);
|
|
||||||
int y = r.nextInt(-radius, radius + 1);
|
|
||||||
int z = r.nextInt(-radius, radius + 1);
|
|
||||||
double dist = x * x + y * y + z * z;
|
|
||||||
if (dist < min || dist > max) continue;
|
|
||||||
return add(x, y, z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
package com.volmit.iris.util.parallel;
|
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
public class Sync<T> {
|
|
||||||
private final AtomicReference<CompletableFuture<T>> tick = new AtomicReference<>(new CompletableFuture<>());
|
|
||||||
|
|
||||||
public void cancel(boolean mayInterruptIfRunning) {
|
|
||||||
tick.getAndSet(new CompletableFuture<>()).cancel(mayInterruptIfRunning);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<T> next() {
|
|
||||||
return tick.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void advance(T value) {
|
|
||||||
tick.getAndSet(new CompletableFuture<>()).complete(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -645,44 +645,37 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
return inject(this::supplier);
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
|
||||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
|
||||||
var nmsServer = server.getServer();
|
|
||||||
var old = nmsServer.worldLoader;
|
|
||||||
|
|
||||||
field.setAccessible(true);
|
|
||||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
old.resources(),
|
|
||||||
old.dataConfiguration(),
|
|
||||||
old.datapackWorldgen(),
|
|
||||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
|
||||||
)));
|
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
|
||||||
field.set(nmsServer, old);
|
|
||||||
dataContextLock.unlock();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
var reg = registry();
|
var reg = registry();
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
|
|
||||||
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||||
var injected = access.registryOrThrow(Registries.LEVEL_STEM);
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
|
||||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
var fake = new HashMap<>(old);
|
var fake = new HashMap<>(old);
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
field.set(reg, fake);
|
field.set(reg, fake);
|
||||||
|
|
||||||
return new AutoClosing(() -> field.set(reg, old));
|
return new com.volmit.iris.core.nms.container.Pair<>(
|
||||||
|
injected.size(),
|
||||||
|
new AutoClosing(() -> {
|
||||||
|
closing.close();
|
||||||
|
field.set(reg, old);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -694,9 +687,31 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return overworld || nether || end;
|
return overworld || nether || end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||||
public void removeCustomDimensions(World world) {
|
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
((CraftWorld) world).getHandle().K.customDimensions = null;
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||||
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
@@ -720,7 +735,7 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
|||||||
@@ -646,44 +646,37 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
return inject(this::supplier);
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
|
||||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
|
||||||
var nmsServer = server.getServer();
|
|
||||||
var old = nmsServer.worldLoader;
|
|
||||||
|
|
||||||
field.setAccessible(true);
|
|
||||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
old.resources(),
|
|
||||||
old.dataConfiguration(),
|
|
||||||
old.datapackWorldgen(),
|
|
||||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
|
||||||
)));
|
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
|
||||||
field.set(nmsServer, old);
|
|
||||||
dataContextLock.unlock();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
var reg = registry();
|
var reg = registry();
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
|
|
||||||
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||||
var injected = access.registryOrThrow(Registries.LEVEL_STEM);
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
|
||||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
var fake = new HashMap<>(old);
|
var fake = new HashMap<>(old);
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
field.set(reg, fake);
|
field.set(reg, fake);
|
||||||
|
|
||||||
return new AutoClosing(() -> field.set(reg, old));
|
return new com.volmit.iris.core.nms.container.Pair<>(
|
||||||
|
injected.size(),
|
||||||
|
new AutoClosing(() -> {
|
||||||
|
closing.close();
|
||||||
|
field.set(reg, old);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -695,9 +688,31 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return overworld || nether || end;
|
return overworld || nether || end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||||
public void removeCustomDimensions(World world) {
|
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
((CraftWorld) world).getHandle().K.customDimensions = null;
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||||
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
@@ -721,7 +736,7 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
|||||||
@@ -647,44 +647,37 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
return inject(this::supplier);
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
|
||||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
|
||||||
var nmsServer = server.getServer();
|
|
||||||
var old = nmsServer.worldLoader;
|
|
||||||
|
|
||||||
field.setAccessible(true);
|
|
||||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
old.resources(),
|
|
||||||
old.dataConfiguration(),
|
|
||||||
old.datapackWorldgen(),
|
|
||||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
|
||||||
)));
|
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
|
||||||
field.set(nmsServer, old);
|
|
||||||
dataContextLock.unlock();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
var reg = registry();
|
var reg = registry();
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
|
|
||||||
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||||
var injected = access.registryOrThrow(Registries.LEVEL_STEM);
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
|
||||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
var fake = new HashMap<>(old);
|
var fake = new HashMap<>(old);
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
field.set(reg, fake);
|
field.set(reg, fake);
|
||||||
|
|
||||||
return new AutoClosing(() -> field.set(reg, old));
|
return new com.volmit.iris.core.nms.container.Pair<>(
|
||||||
|
injected.size(),
|
||||||
|
new AutoClosing(() -> {
|
||||||
|
closing.close();
|
||||||
|
field.set(reg, old);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -696,9 +689,31 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return overworld || nether || end;
|
return overworld || nether || end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||||
public void removeCustomDimensions(World world) {
|
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
((CraftWorld) world).getHandle().K.customDimensions = null;
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||||
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
@@ -722,7 +737,7 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
|||||||
@@ -672,44 +672,37 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
return inject(this::supplier);
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
|
||||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
|
||||||
var nmsServer = server.getServer();
|
|
||||||
var old = nmsServer.worldLoader;
|
|
||||||
|
|
||||||
field.setAccessible(true);
|
|
||||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
old.resources(),
|
|
||||||
old.dataConfiguration(),
|
|
||||||
old.datapackWorldgen(),
|
|
||||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
|
||||||
)));
|
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
|
||||||
field.set(nmsServer, old);
|
|
||||||
dataContextLock.unlock();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
var reg = registry();
|
var reg = registry();
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
|
|
||||||
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||||
var injected = access.registryOrThrow(Registries.LEVEL_STEM);
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
|
||||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
var fake = new HashMap<>(old);
|
var fake = new HashMap<>(old);
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
field.set(reg, fake);
|
field.set(reg, fake);
|
||||||
|
|
||||||
return new AutoClosing(() -> field.set(reg, old));
|
return new com.volmit.iris.core.nms.container.Pair<>(
|
||||||
|
injected.size(),
|
||||||
|
new AutoClosing(() -> {
|
||||||
|
closing.close();
|
||||||
|
field.set(reg, old);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -721,9 +714,31 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return overworld || nether || end;
|
return overworld || nether || end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||||
public void removeCustomDimensions(World world) {
|
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
((CraftWorld) world).getHandle().K.customDimensions = null;
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||||
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
@@ -747,7 +762,7 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
|||||||
@@ -676,44 +676,37 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
return inject(this::supplier);
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
|
||||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
|
||||||
var nmsServer = server.getServer();
|
|
||||||
var old = nmsServer.worldLoader;
|
|
||||||
|
|
||||||
field.setAccessible(true);
|
|
||||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
old.resources(),
|
|
||||||
old.dataConfiguration(),
|
|
||||||
old.datapackWorldgen(),
|
|
||||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
|
||||||
)));
|
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
|
||||||
field.set(nmsServer, old);
|
|
||||||
dataContextLock.unlock();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
var reg = registry();
|
var reg = registry();
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
|
|
||||||
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||||
var injected = access.registryOrThrow(Registries.LEVEL_STEM);
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
|
||||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
var fake = new HashMap<>(old);
|
var fake = new HashMap<>(old);
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
field.set(reg, fake);
|
field.set(reg, fake);
|
||||||
|
|
||||||
return new AutoClosing(() -> field.set(reg, old));
|
return new com.volmit.iris.core.nms.container.Pair<>(
|
||||||
|
injected.size(),
|
||||||
|
new AutoClosing(() -> {
|
||||||
|
closing.close();
|
||||||
|
field.set(reg, old);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -725,9 +718,31 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return overworld || nether || end;
|
return overworld || nether || end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||||
public void removeCustomDimensions(World world) {
|
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
((CraftWorld) world).getHandle().K.customDimensions = null;
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||||
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
@@ -751,7 +766,7 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
|||||||
@@ -666,44 +666,37 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
return inject(this::supplier);
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
|
||||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
|
||||||
var nmsServer = server.getServer();
|
|
||||||
var old = nmsServer.worldLoader;
|
|
||||||
|
|
||||||
field.setAccessible(true);
|
|
||||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
old.resources(),
|
|
||||||
old.dataConfiguration(),
|
|
||||||
old.datapackWorldgen(),
|
|
||||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
|
||||||
)));
|
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
|
||||||
field.set(nmsServer, old);
|
|
||||||
dataContextLock.unlock();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
public Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
var reg = registry();
|
var reg = registry();
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
|
|
||||||
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||||
var injected = access.lookupOrThrow(Registries.LEVEL_STEM);
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM);
|
||||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
var fake = new HashMap<>(old);
|
var fake = new HashMap<>(old);
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
field.set(reg, fake);
|
field.set(reg, fake);
|
||||||
|
|
||||||
return new AutoClosing(() -> field.set(reg, old));
|
return new Pair<>(
|
||||||
|
injected.size(),
|
||||||
|
new AutoClosing(() -> {
|
||||||
|
closing.close();
|
||||||
|
field.set(reg, old);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -715,9 +708,31 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return overworld || nether || end;
|
return overworld || nether || end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||||
public void removeCustomDimensions(World world) {
|
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
((CraftWorld) world).getHandle().L.customDimensions = null;
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||||
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
@@ -741,7 +756,7 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
if (copy) copy(fake, access.lookupOrThrow(Registries.LEVEL_STEM));
|
if (copy) copy(fake, access.lookupOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
|||||||
+1
-1
@@ -209,7 +209,7 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
||||||
return WeightedRandomList.create();
|
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -665,44 +665,37 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
return inject(this::supplier);
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
|
||||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
|
||||||
var nmsServer = server.getServer();
|
|
||||||
var old = nmsServer.worldLoader;
|
|
||||||
|
|
||||||
field.setAccessible(true);
|
|
||||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
old.resources(),
|
|
||||||
old.dataConfiguration(),
|
|
||||||
old.datapackWorldgen(),
|
|
||||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
|
||||||
)));
|
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
|
||||||
field.set(nmsServer, old);
|
|
||||||
dataContextLock.unlock();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
public Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
var reg = registry();
|
var reg = registry();
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
|
|
||||||
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||||
var injected = access.lookupOrThrow(Registries.LEVEL_STEM);
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM);
|
||||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
var fake = new HashMap<>(old);
|
var fake = new HashMap<>(old);
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
field.set(reg, fake);
|
field.set(reg, fake);
|
||||||
|
|
||||||
return new AutoClosing(() -> field.set(reg, old));
|
return new Pair<>(
|
||||||
|
injected.size(),
|
||||||
|
new AutoClosing(() -> {
|
||||||
|
closing.close();
|
||||||
|
field.set(reg, old);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -714,9 +707,31 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return overworld || nether || end;
|
return overworld || nether || end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||||
public void removeCustomDimensions(World world) {
|
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
((CraftWorld) world).getHandle().L.customDimensions = null;
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||||
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
@@ -740,7 +755,7 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
if (copy) copy(fake, access.lookupOrThrow(Registries.LEVEL_STEM));
|
if (copy) copy(fake, access.lookupOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
|||||||
Reference in New Issue
Block a user