mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-05-20 00:20:24 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b96b4d619 | |||
| 9e0258089b | |||
| e6874a0e10 | |||
| ab4770400e | |||
| 1a810d5d62 | |||
| 536d20bca7 | |||
| 9a691ac5b4 | |||
| 71078a20a9 | |||
| 74e2576ca2 | |||
| 407e51378c | |||
| c468eb1ab1 | |||
| bdb7cc61e5 | |||
| e8f9e841c4 | |||
| 1b1b9d97b7 | |||
| 24355064ff | |||
| 06a45056d9 | |||
| 647214a335 |
+27
-6
@@ -1,3 +1,5 @@
|
|||||||
|
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)
|
||||||
@@ -30,10 +32,11 @@ 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.4-1.20.1-1.21.4'
|
version '3.6.6-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 =============================
|
||||||
@@ -53,6 +56,11 @@ 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",
|
||||||
@@ -62,21 +70,34 @@ 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.of()
|
def JVM_VERSION = Map.<String, Integer>of()
|
||||||
NMS_BINDINGS.each { nms ->
|
NMS_BINDINGS.forEach { key, value ->
|
||||||
project(":nms:${nms.key}") {
|
project(":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(nms.key, 21)
|
it.jvm = JVM_VERSION.getOrDefault(key, 21)
|
||||||
it.version = nms.value
|
it.version = 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 {
|
||||||
|
|||||||
@@ -459,15 +459,17 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class<? extends IrisService>) i.getClass(), (IrisService) i));
|
initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class<? extends IrisService>) i.getClass(), (IrisService) i));
|
||||||
INMS.get();
|
INMS.get();
|
||||||
IO.delete(new File("iris"));
|
IO.delete(new File("iris"));
|
||||||
|
compat = IrisCompat.configured(getDataFile("compat.json"));
|
||||||
|
ServerConfigurator.configure();
|
||||||
|
new IrisContextInjector();
|
||||||
IrisSafeguard.IrisSafeguardSystem();
|
IrisSafeguard.IrisSafeguardSystem();
|
||||||
getSender().setTag(getTag());
|
getSender().setTag(getTag());
|
||||||
compat = IrisCompat.configured(getDataFile("compat.json"));
|
IrisSafeguard.earlySplash();
|
||||||
linkMultiverseCore = new MultiverseCoreLink();
|
linkMultiverseCore = new MultiverseCoreLink();
|
||||||
linkMythicMobs = new MythicMobsLink();
|
linkMythicMobs = new MythicMobsLink();
|
||||||
configWatcher = new FileWatcher(getDataFile("settings.json"));
|
configWatcher = new FileWatcher(getDataFile("settings.json"));
|
||||||
services.values().forEach(IrisService::onEnable);
|
services.values().forEach(IrisService::onEnable);
|
||||||
services.values().forEach(this::registerListener);
|
services.values().forEach(this::registerListener);
|
||||||
registerListener(new IrisContextInjector());
|
|
||||||
J.s(() -> {
|
J.s(() -> {
|
||||||
J.a(() -> PaperLib.suggestPaper(this));
|
J.a(() -> PaperLib.suggestPaper(this));
|
||||||
J.a(() -> IO.delete(getTemp()));
|
J.a(() -> IO.delete(getTemp()));
|
||||||
|
|||||||
@@ -31,6 +31,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.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.format.C;
|
import com.volmit.iris.util.format.C;
|
||||||
|
import com.volmit.iris.util.misc.ServerProperties;
|
||||||
import com.volmit.iris.util.plugin.VolmitSender;
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -97,6 +98,7 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
KList<File> worlds = new KList<>();
|
KList<File> worlds = new KList<>();
|
||||||
Bukkit.getServer().getWorlds().forEach(w -> worlds.add(new File(w.getWorldFolder(), "datapacks")));
|
Bukkit.getServer().getWorlds().forEach(w -> worlds.add(new File(w.getWorldFolder(), "datapacks")));
|
||||||
|
if (worlds.isEmpty()) worlds.add(new File(Bukkit.getWorldContainer(), ServerProperties.LEVEL_NAME + "/datapacks"));
|
||||||
return worlds;
|
return worlds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,53 +66,20 @@ 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() {
|
||||||
List<World> IrisWorlds = new ArrayList<>();
|
var status = EngineStatusSVC.getStatus();
|
||||||
int TotalLoadedChunks = 0;
|
|
||||||
int TotalQueuedTectonicPlates = 0;
|
|
||||||
int TotalNotQueuedTectonicPlates = 0;
|
|
||||||
int TotalTectonicPlates = 0;
|
|
||||||
|
|
||||||
long lowestUnloadDuration = 0;
|
sender().sendMessage("-------------------------");
|
||||||
long highestUnloadDuration = 0;
|
sender().sendMessage(C.DARK_PURPLE + "Engine Status");
|
||||||
|
sender().sendMessage(C.DARK_PURPLE + "Total Engines: " + C.LIGHT_PURPLE + status.engineCount());
|
||||||
for (World world : Bukkit.getWorlds()) {
|
sender().sendMessage(C.DARK_PURPLE + "Total Loaded Chunks: " + C.LIGHT_PURPLE + status.loadedChunks());
|
||||||
try {
|
sender().sendMessage(C.DARK_PURPLE + "Tectonic Limit: " + C.LIGHT_PURPLE + status.tectonicLimit());
|
||||||
if (IrisToolbelt.access(world).getEngine() != null) {
|
sender().sendMessage(C.DARK_PURPLE + "Tectonic Total Plates: " + C.LIGHT_PURPLE + status.tectonicPlates());
|
||||||
IrisWorlds.add(world);
|
sender().sendMessage(C.DARK_PURPLE + "Tectonic Active Plates: " + C.LIGHT_PURPLE + status.activeTectonicPlates());
|
||||||
}
|
sender().sendMessage(C.DARK_PURPLE + "Tectonic ToUnload: " + C.LIGHT_PURPLE + status.queuedTectonicPlates());
|
||||||
} catch (Exception e) {
|
sender().sendMessage(C.DARK_PURPLE + "Lowest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(status.minTectonicUnloadDuration()));
|
||||||
// no
|
sender().sendMessage(C.DARK_PURPLE + "Highest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(status.maxTectonicUnloadDuration()));
|
||||||
}
|
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")
|
||||||
@@ -140,7 +107,7 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
public void packBenchmark(
|
public void packBenchmark(
|
||||||
@Param(description = "The pack to bench", aliases = {"pack"}, defaultValue = "overworld")
|
@Param(description = "The pack to bench", aliases = {"pack"}, defaultValue = "overworld")
|
||||||
IrisDimension dimension,
|
IrisDimension dimension,
|
||||||
@Param(description = "Radius in regions", defaultValue = "5")
|
@Param(description = "Radius in regions", defaultValue = "2048")
|
||||||
int radius,
|
int radius,
|
||||||
@Param(description = "Open GUI while benchmarking", defaultValue = "false")
|
@Param(description = "Open GUI while benchmarking", defaultValue = "false")
|
||||||
boolean gui
|
boolean gui
|
||||||
|
|||||||
@@ -19,9 +19,7 @@
|
|||||||
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.IrisSettings;
|
|
||||||
import com.volmit.iris.core.gui.PregeneratorJob;
|
import com.volmit.iris.core.gui.PregeneratorJob;
|
||||||
import com.volmit.iris.core.pregenerator.LazyPregenerator;
|
|
||||||
import com.volmit.iris.core.pregenerator.PregenTask;
|
import com.volmit.iris.core.pregenerator.PregenTask;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.util.decree.DecreeExecutor;
|
import com.volmit.iris.util.decree.DecreeExecutor;
|
||||||
@@ -29,12 +27,9 @@ 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.format.C;
|
import com.volmit.iris.util.format.C;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
@Decree(name = "pregen", aliases = "pregenerate", description = "Pregenerate your Iris worlds!")
|
@Decree(name = "pregen", aliases = "pregenerate", description = "Pregenerate your Iris worlds!")
|
||||||
public class CommandPregen implements DecreeExecutor {
|
public class CommandPregen implements DecreeExecutor {
|
||||||
@Decree(description = "Pregenerate a world")
|
@Decree(description = "Pregenerate a world")
|
||||||
@@ -52,13 +47,12 @@ public class CommandPregen implements DecreeExecutor {
|
|||||||
sender().sendMessage(C.RED + "Please make sure the world is loaded & the engine is initialized. Generate a new chunk, for example.");
|
sender().sendMessage(C.RED + "Please make sure the world is loaded & the engine is initialized. Generate a new chunk, for example.");
|
||||||
}
|
}
|
||||||
radius = Math.max(radius, 1024);
|
radius = Math.max(radius, 1024);
|
||||||
int w = (radius >> 9 + 1) * 2;
|
|
||||||
IrisToolbelt.pregenerate(PregenTask
|
IrisToolbelt.pregenerate(PregenTask
|
||||||
.builder()
|
.builder()
|
||||||
.center(new Position2(center.getBlockX() >> 9, center.getBlockZ() >> 9))
|
.center(new Position2(center.getBlockX(), center.getBlockZ()))
|
||||||
.gui(true)
|
.gui(true)
|
||||||
.width(w)
|
.radiusX(radius)
|
||||||
.height(w)
|
.radiusZ(radius)
|
||||||
.build(), world);
|
.build(), world);
|
||||||
String msg = C.GREEN + "Pregen started in " + C.GOLD + world.getName() + C.GREEN + " of " + C.GOLD + (radius * 2) + C.GREEN + " by " + C.GOLD + (radius * 2) + C.GREEN + " blocks from " + C.GOLD + center.getX() + "," + center.getZ();
|
String msg = C.GREEN + "Pregen started in " + C.GOLD + world.getName() + C.GREEN + " of " + C.GOLD + (radius * 2) + C.GREEN + " by " + C.GOLD + (radius * 2) + C.GREEN + " blocks from " + C.GOLD + center.getX() + "," + center.getZ();
|
||||||
sender().sendMessage(msg);
|
sender().sendMessage(msg);
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ 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;
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import com.volmit.iris.core.pregenerator.IrisPregenerator;
|
|||||||
import com.volmit.iris.core.pregenerator.PregenListener;
|
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||||
import com.volmit.iris.core.pregenerator.PregenTask;
|
import com.volmit.iris.core.pregenerator.PregenTask;
|
||||||
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||||
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
|
||||||
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;
|
||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
@@ -45,8 +44,6 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static com.volmit.iris.core.tools.IrisPackBenchmarking.benchmarkInProgress;
|
|
||||||
|
|
||||||
public class PregeneratorJob implements PregenListener {
|
public class PregeneratorJob implements PregenListener {
|
||||||
private static final Color COLOR_EXISTS = parseColor("#4d7d5b");
|
private static final Color COLOR_EXISTS = parseColor("#4d7d5b");
|
||||||
private static final Color COLOR_BLACK = parseColor("#4d7d5b");
|
private static final Color COLOR_BLACK = parseColor("#4d7d5b");
|
||||||
@@ -81,12 +78,12 @@ public class PregeneratorJob implements PregenListener {
|
|||||||
this.task = task;
|
this.task = task;
|
||||||
this.pregenerator = new IrisPregenerator(task, method, this);
|
this.pregenerator = new IrisPregenerator(task, method, this);
|
||||||
max = new Position2(0, 0);
|
max = new Position2(0, 0);
|
||||||
min = new Position2(0, 0);
|
min = new Position2(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||||
task.iterateRegions((xx, zz) -> {
|
task.iterateAllChunks((xx, zz) -> {
|
||||||
min.setX(Math.min(xx << 5, min.getX()));
|
min.setX(Math.min(xx, min.getX()));
|
||||||
min.setZ(Math.min(zz << 5, min.getZ()));
|
min.setZ(Math.min(zz, min.getZ()));
|
||||||
max.setX(Math.max((xx << 5) + 31, max.getX()));
|
max.setX(Math.max(xx, max.getX()));
|
||||||
max.setZ(Math.max((zz << 5) + 31, max.getZ()));
|
max.setZ(Math.max(zz, max.getZ()));
|
||||||
});
|
});
|
||||||
|
|
||||||
if (IrisSettings.get().getGui().isUseServerLaunchedGuis() && task.isGui()) {
|
if (IrisSettings.get().getGui().isUseServerLaunchedGuis() && task.isGui()) {
|
||||||
@@ -162,7 +159,7 @@ public class PregeneratorJob implements PregenListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void drawRegion(int x, int z, Color color) {
|
public void drawRegion(int x, int z, Color color) {
|
||||||
J.a(() -> PregenTask.iterateRegion(x, z, (xx, zz) -> {
|
J.a(() -> task.iterateChunks(x, z, (xx, zz) -> {
|
||||||
draw(xx, zz, color);
|
draw(xx, zz, color);
|
||||||
J.sleep(3);
|
J.sleep(3);
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ 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;
|
||||||
@@ -219,6 +220,10 @@ 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<>();
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class INMS {
|
|||||||
"1.21.4", "v1_21_R3"
|
"1.21.4", "v1_21_R3"
|
||||||
);
|
);
|
||||||
private static final List<Version> PACKS = List.of(
|
private static final List<Version> PACKS = List.of(
|
||||||
new Version(21, 4, "31010"),
|
new Version(21, 4, "31020"),
|
||||||
new Version(21, 2, "31000"),
|
new Version(21, 2, "31000"),
|
||||||
new Version(20, 1, "3910")
|
new Version(20, 1, "3910")
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ 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;
|
||||||
@@ -32,15 +31,12 @@ import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess;
|
|||||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Biome;
|
import org.bukkit.block.Biome;
|
||||||
import org.bukkit.entity.Dolphin;
|
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
import org.bukkit.generator.ChunkGenerator;
|
import org.bukkit.generator.ChunkGenerator;
|
||||||
import org.bukkit.generator.structure.Structure;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
|
||||||
public interface INMSBinding {
|
public interface INMSBinding {
|
||||||
@@ -93,7 +89,11 @@ public interface INMSBinding {
|
|||||||
MCABiomeContainer newBiomeContainer(int min, int max);
|
MCABiomeContainer newBiomeContainer(int min, int max);
|
||||||
|
|
||||||
default World createWorld(WorldCreator c) {
|
default World createWorld(WorldCreator c) {
|
||||||
|
if (missingDimensionTypes(true, true, true))
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,11 +130,13 @@ public interface INMSBinding {
|
|||||||
|
|
||||||
KList<String> getStructureKeys();
|
KList<String> getStructureKeys();
|
||||||
|
|
||||||
default AutoClosing injectLevelStems() {
|
AutoClosing injectLevelStems();
|
||||||
return new AutoClosing(() -> {});
|
|
||||||
|
default AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
default Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end);
|
||||||
return new Pair<>(0, injectLevelStems());
|
|
||||||
}
|
void removeCustomDimensions(World world);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
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;
|
||||||
|
|
||||||
@@ -7,6 +8,7 @@ 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;
|
||||||
|
|
||||||
@@ -14,9 +16,24 @@ 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ package com.volmit.iris.core.nms.v1X;
|
|||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.nms.INMSBinding;
|
import com.volmit.iris.core.nms.INMSBinding;
|
||||||
|
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.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
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;
|
||||||
@@ -118,6 +120,26 @@ public class NMSBinding1X implements INMSBinding {
|
|||||||
return new KList<>(list);
|
return new KList<>(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AutoClosing injectLevelStems() {
|
||||||
|
return new AutoClosing(() -> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
|
return injectLevelStems();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCustomDimensions(World world) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag serializeEntity(Entity location) {
|
public CompoundTag serializeEntity(Entity location) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -165,8 +165,11 @@ public class ChunkUpdater {
|
|||||||
if (rX < dimensions.min.getX() || rX > dimensions.max.getX() || rZ < dimensions.min.getZ() || rZ > dimensions.max.getZ()) {
|
if (rX < dimensions.min.getX() || rX > dimensions.max.getX() || rZ < dimensions.min.getZ() || rZ > dimensions.max.getZ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!new File(world.getWorldFolder(), "region" + File.separator + rX + "." + rZ + ".mca").exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
PregenTask.iterateRegion(rX, rZ, (x, z) -> {
|
task.iterateChunks(rX, rZ, (x, z) -> {
|
||||||
while (paused.get() && !cancelled.get()) {
|
while (paused.get() && !cancelled.get()) {
|
||||||
J.sleep(50);
|
J.sleep(50);
|
||||||
}
|
}
|
||||||
@@ -348,8 +351,8 @@ public class ChunkUpdater {
|
|||||||
int width = maxZ - minZ + 1;
|
int width = maxZ - minZ + 1;
|
||||||
|
|
||||||
return new Dimensions(new Position2(minX, minZ), new Position2(maxX, maxZ), height * width, PregenTask.builder()
|
return new Dimensions(new Position2(minX, minZ), new Position2(maxX, maxZ), height * width, PregenTask.builder()
|
||||||
.width((int) Math.ceil(width / 2d))
|
.radiusZ((int) Math.ceil(width / 2d * 512))
|
||||||
.height((int) Math.ceil(height / 2d))
|
.radiusX((int) Math.ceil(height / 2d * 512))
|
||||||
.center(new Position2(oX, oZ))
|
.center(new Position2(oX, oZ))
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
package com.volmit.iris.core.pregenerator;
|
package com.volmit.iris.core.pregenerator;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.pack.IrisPack;
|
|
||||||
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
@@ -83,7 +82,7 @@ public class IrisPregenerator {
|
|||||||
generatedLast = new AtomicInteger(0);
|
generatedLast = new AtomicInteger(0);
|
||||||
generatedLastMinute = new AtomicInteger(0);
|
generatedLastMinute = new AtomicInteger(0);
|
||||||
totalChunks = new AtomicInteger(0);
|
totalChunks = new AtomicInteger(0);
|
||||||
task.iterateRegions((_a, _b) -> totalChunks.addAndGet(1024));
|
task.iterateAllChunks((_a, _b) -> totalChunks.incrementAndGet());
|
||||||
startTime = new AtomicLong(M.ms());
|
startTime = new AtomicLong(M.ms());
|
||||||
ticker = new Looper() {
|
ticker = new Looper() {
|
||||||
@Override
|
@Override
|
||||||
@@ -194,7 +193,7 @@ public class IrisPregenerator {
|
|||||||
} else if (!regions) {
|
} else if (!regions) {
|
||||||
hit = true;
|
hit = true;
|
||||||
listener.onRegionGenerating(x, z);
|
listener.onRegionGenerating(x, z);
|
||||||
PregenTask.iterateRegion(x, z, (xx, zz) -> {
|
task.iterateChunks(x, z, (xx, zz) -> {
|
||||||
while (paused.get() && !shutdown.get()) {
|
while (paused.get() && !shutdown.get()) {
|
||||||
J.sleep(50);
|
J.sleep(50);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,17 +32,26 @@ import java.util.Comparator;
|
|||||||
@Data
|
@Data
|
||||||
public class PregenTask {
|
public class PregenTask {
|
||||||
private static final Position2 ZERO = new Position2(0, 0);
|
private static final Position2 ZERO = new Position2(0, 0);
|
||||||
private static final KList<Position2> ORDER_CENTER = computeChunkOrder();
|
|
||||||
private static final KMap<Position2, KList<Position2>> ORDERS = new KMap<>();
|
private static final KMap<Position2, KList<Position2>> ORDERS = new KMap<>();
|
||||||
|
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private boolean gui = false;
|
private final boolean gui = false;
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Position2 center = new Position2(0, 0);
|
private final Position2 center = new Position2(0, 0);
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private int width = 1;
|
private final int radiusX = 1;
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private int height = 1;
|
private final int radiusZ = 1;
|
||||||
|
|
||||||
|
private final Bounds bounds = new Bounds();
|
||||||
|
|
||||||
|
protected PregenTask(boolean gui, Position2 center, int radiusX, int radiusZ) {
|
||||||
|
this.gui = gui;
|
||||||
|
this.center = new ProxiedPos(center);
|
||||||
|
this.radiusX = radiusX;
|
||||||
|
this.radiusZ = radiusZ;
|
||||||
|
bounds.update();
|
||||||
|
}
|
||||||
|
|
||||||
public static void iterateRegion(int xr, int zr, Spiraled s, Position2 pull) {
|
public static void iterateRegion(int xr, int zr, Spiraled s, Position2 pull) {
|
||||||
for (Position2 i : ORDERS.computeIfAbsent(pull, PregenTask::computeOrder)) {
|
for (Position2 i : ORDERS.computeIfAbsent(pull, PregenTask::computeOrder)) {
|
||||||
@@ -70,29 +79,72 @@ public class PregenTask {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static KList<Position2> computeChunkOrder() {
|
public void iterateRegions(Spiraled s) {
|
||||||
Position2 center = new Position2(15, 15);
|
var bound = bounds.region();
|
||||||
KList<Position2> p = new KList<>();
|
new Spiraler(bound.sizeX, bound.sizeZ, ((x, z) -> {
|
||||||
new Spiraler(33, 33, (x, z) -> {
|
if (bound.check(x, z)) s.on(x, z);
|
||||||
int xx = x + 15;
|
})).setOffset(center.getX() >> 9, center.getZ() >> 9).drain();
|
||||||
int zz = z + 15;
|
|
||||||
if (xx < 0 || xx > 31 || zz < 0 || zz > 31) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.add(new Position2(xx, zz));
|
|
||||||
}).drain();
|
|
||||||
p.sort(Comparator.comparing((i) -> i.distance(center)));
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void iterateRegions(Spiraled s) {
|
public void iterateChunks(int rX, int rZ, Spiraled s) {
|
||||||
new Spiraler(getWidth() * 2, getHeight() * 2, s)
|
var bound = bounds.chunk();
|
||||||
.setOffset(center.getX(), center.getZ()).drain();
|
iterateRegion(rX, rZ, ((x, z) -> {
|
||||||
|
if (bound.check(x, z)) s.on(x, z);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void iterateAllChunks(Spiraled s) {
|
public void iterateAllChunks(Spiraled s) {
|
||||||
new Spiraler(getWidth() * 2, getHeight() * 2, (x, z) -> iterateRegion(x, z, s))
|
iterateRegions(((rX, rZ) -> iterateChunks(rX, rZ, s)));
|
||||||
.setOffset(center.getX(), center.getZ()).drain();
|
}
|
||||||
|
|
||||||
|
private class Bounds {
|
||||||
|
private Bound chunk = null;
|
||||||
|
private Bound region = null;
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
int maxX = center.getX() + radiusX;
|
||||||
|
int maxZ = center.getZ() + radiusZ;
|
||||||
|
int minX = center.getX() - radiusX;
|
||||||
|
int minZ = center.getZ() - radiusZ;
|
||||||
|
|
||||||
|
chunk = new Bound(minX >> 4, minZ >> 4, Math.ceilDiv(maxX, 16), Math.ceilDiv(maxZ, 16));
|
||||||
|
region = new Bound(minX >> 9, minZ >> 9, Math.ceilDiv(maxX, 512), Math.ceilDiv(maxZ, 512));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bound chunk() {
|
||||||
|
if (chunk == null) update();
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bound region() {
|
||||||
|
if (region == null) update();
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Bound(int minX, int maxX, int minZ, int maxZ, int sizeX, int sizeZ) {
|
||||||
|
private Bound(int minX, int minZ, int maxX, int maxZ) {
|
||||||
|
this(minX, maxX, minZ, maxZ, maxZ - minZ + 1, maxZ - minZ + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean check(int x, int z) {
|
||||||
|
return x >= minX && x <= maxX && z >= minZ && z <= maxZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ProxiedPos extends Position2 {
|
||||||
|
public ProxiedPos(Position2 p) {
|
||||||
|
super(p.getX(), p.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setX(int x) {
|
||||||
|
throw new IllegalStateException("This Position2 may not be modified");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setZ(int z) {
|
||||||
|
throw new IllegalStateException("This Position2 may not be modified");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.volmit.iris.core.safeguard;
|
package com.volmit.iris.core.safeguard;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.IrisSettings;
|
||||||
|
|
||||||
public class IrisSafeguard {
|
public class IrisSafeguard {
|
||||||
public static boolean unstablemode = false;
|
public static boolean unstablemode = false;
|
||||||
@@ -11,5 +12,13 @@ public class IrisSafeguard {
|
|||||||
Iris.info("Enabled Iris SafeGuard");
|
Iris.info("Enabled Iris SafeGuard");
|
||||||
ServerBootSFG.BootCheck();
|
ServerBootSFG.BootCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void earlySplash() {
|
||||||
|
if (ServerBootSFG.safeguardPassed || IrisSettings.get().getGeneral().DoomsdayAnnihilationSelfDestructMode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Iris.instance.splash();
|
||||||
|
UtilsSFG.splash();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.volmit.iris.core.safeguard;
|
|||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.nms.INMS;
|
import com.volmit.iris.core.nms.INMS;
|
||||||
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
||||||
|
import com.volmit.iris.engine.object.IrisContextInjector;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
@@ -29,6 +30,7 @@ public class ServerBootSFG {
|
|||||||
public static boolean isJRE = false;
|
public static boolean isJRE = false;
|
||||||
public static boolean hasPrivileges = true;
|
public static boolean hasPrivileges = true;
|
||||||
public static boolean unsuportedversion = false;
|
public static boolean unsuportedversion = false;
|
||||||
|
public static boolean missingDimensionTypes = false;
|
||||||
protected static boolean safeguardPassed;
|
protected static boolean safeguardPassed;
|
||||||
public static boolean passedserversoftware = true;
|
public static boolean passedserversoftware = true;
|
||||||
protected static int count;
|
protected static int count;
|
||||||
@@ -110,6 +112,12 @@ public class ServerBootSFG {
|
|||||||
severityMedium++;
|
severityMedium++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IrisContextInjector.isMissingDimensionTypes()) {
|
||||||
|
missingDimensionTypes = true;
|
||||||
|
joiner.add("Missing Dimension Types");
|
||||||
|
severityHigh++;
|
||||||
|
}
|
||||||
|
|
||||||
allIncompatibilities = joiner.toString();
|
allIncompatibilities = joiner.toString();
|
||||||
|
|
||||||
safeguardPassed = (severityHigh == 0 && severityMedium == 0 && severityLow == 0);
|
safeguardPassed = (severityHigh == 0 && severityMedium == 0 && severityLow == 0);
|
||||||
|
|||||||
@@ -39,6 +39,11 @@ public class UtilsSFG {
|
|||||||
Iris.safeguard(C.RED + "Server Version");
|
Iris.safeguard(C.RED + "Server Version");
|
||||||
Iris.safeguard(C.RED + "- Iris only supports 1.20.1 > 1.21.4");
|
Iris.safeguard(C.RED + "- Iris only supports 1.20.1 > 1.21.4");
|
||||||
}
|
}
|
||||||
|
if (ServerBootSFG.missingDimensionTypes) {
|
||||||
|
Iris.safeguard(C.RED + "Dimension Types");
|
||||||
|
Iris.safeguard(C.RED + "- Required Iris dimension types were not loaded.");
|
||||||
|
Iris.safeguard(C.RED + "- If this still happens after a restart please contact support.");
|
||||||
|
}
|
||||||
if (!ServerBootSFG.passedserversoftware) {
|
if (!ServerBootSFG.passedserversoftware) {
|
||||||
Iris.safeguard(C.YELLOW + "Unsupported Server Software");
|
Iris.safeguard(C.YELLOW + "Unsupported Server Software");
|
||||||
Iris.safeguard(C.YELLOW + "- Please consider using Paper or Purpur instead.");
|
Iris.safeguard(C.YELLOW + "- Please consider using Paper or Purpur instead.");
|
||||||
|
|||||||
@@ -1,317 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -146,8 +146,8 @@ public class IrisPackBenchmarking {
|
|||||||
IrisToolbelt.pregenerate(PregenTask
|
IrisToolbelt.pregenerate(PregenTask
|
||||||
.builder()
|
.builder()
|
||||||
.gui(gui)
|
.gui(gui)
|
||||||
.width(radius)
|
.radiusX(radius)
|
||||||
.height(radius)
|
.radiusZ(radius)
|
||||||
.build(), Bukkit.getWorld("benchmark")
|
.build(), Bukkit.getWorld("benchmark")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ 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;
|
||||||
@@ -60,7 +61,11 @@ 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;
|
||||||
@@ -71,6 +76,8 @@ 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;
|
||||||
@@ -111,6 +118,7 @@ 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);
|
||||||
@@ -137,6 +145,26 @@ 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());
|
||||||
@@ -161,6 +189,8 @@ 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());
|
||||||
}
|
}
|
||||||
@@ -169,6 +199,24 @@ 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);
|
||||||
@@ -418,6 +466,7 @@ 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,7 +27,6 @@ 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;
|
||||||
@@ -72,7 +71,6 @@ 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;
|
||||||
@@ -83,12 +81,10 @@ 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;
|
||||||
@@ -103,7 +99,6 @@ 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();
|
||||||
@@ -151,27 +146,12 @@ 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();
|
||||||
@@ -214,7 +194,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, true), RNG.r.i(5, 200));
|
J.a(() -> spawnIn(cx), RNG.r.i(5, 200));
|
||||||
getSpawnersFromMarkers(cx).forEach((blockf, spawners) -> {
|
getSpawnersFromMarkers(cx).forEach((blockf, spawners) -> {
|
||||||
if (spawners.isEmpty()) {
|
if (spawners.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -222,7 +202,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, true);
|
spawn(block, s);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -232,73 +212,16 @@ 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, boolean initial) {
|
private void spawnIn(Chunk c) {
|
||||||
if (getEngine().isClosed()) {
|
if (getEngine().isClosed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initial) {
|
energy += 1.2;
|
||||||
energy += 1.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
|
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
|
||||||
getSpawnersFromMarkers(c).forEach((blockf, spawners) -> {
|
getSpawnersFromMarkers(c).forEach((blockf, spawners) -> {
|
||||||
@@ -308,9 +231,8 @@ 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, true)));
|
() -> spawn(block, s)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,7 +263,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
.stream()
|
.stream()
|
||||||
.filter(filter)))
|
.filter(filter)))
|
||||||
.filter(counter)
|
.filter(counter)
|
||||||
.flatMap((i) -> stream(i, initial))
|
.flatMap(this::stream)
|
||||||
.collect(Collectors.toList()))
|
.collect(Collectors.toList()))
|
||||||
.getRandom();
|
.getRandom();
|
||||||
//@done
|
//@done
|
||||||
@@ -378,13 +300,13 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream<IrisEntitySpawn> stream(IrisSpawner s, boolean initial) {
|
private Stream<IrisEntitySpawn> stream(IrisSpawner s) {
|
||||||
for (IrisEntitySpawn i : initial ? s.getInitialSpawns() : s.getSpawns()) {
|
for (IrisEntitySpawn i : s.getInitialSpawns()) {
|
||||||
i.setReferenceSpawner(s);
|
i.setReferenceSpawner(s);
|
||||||
i.setReferenceMarker(s.getReferenceMarker());
|
i.setReferenceMarker(s.getReferenceMarker());
|
||||||
}
|
}
|
||||||
|
|
||||||
return (initial ? s.getInitialSpawns() : s.getSpawns()).stream();
|
return (s.getInitialSpawns()).stream();
|
||||||
}
|
}
|
||||||
|
|
||||||
private KList<IrisEntitySpawn> spawnRandomly(List<IrisEntitySpawn> types) {
|
private KList<IrisEntitySpawn> spawnRandomly(List<IrisEntitySpawn> types) {
|
||||||
@@ -431,7 +353,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void spawn(IrisPosition block, IrisSpawner spawner, boolean initial) {
|
private void spawn(IrisPosition block, IrisSpawner spawner) {
|
||||||
if (getEngine().isClosed()) {
|
if (getEngine().isClosed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -440,7 +362,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KList<IrisEntitySpawn> s = initial ? spawner.getInitialSpawns() : spawner.getSpawns();
|
KList<IrisEntitySpawn> s = spawner.getInitialSpawns();
|
||||||
if (s.isEmpty()) {
|
if (s.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,15 @@ 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 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;
|
||||||
|
|
||||||
@@ -15,15 +19,12 @@ import java.util.List;
|
|||||||
import static com.volmit.iris.Iris.instance;
|
import static com.volmit.iris.Iris.instance;
|
||||||
|
|
||||||
public class IrisContextInjector implements Listener {
|
public class IrisContextInjector implements Listener {
|
||||||
|
@Getter
|
||||||
|
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()) {
|
if (!Bukkit.getWorlds().isEmpty()) return;
|
||||||
totalWorlds = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String levelName = ServerProperties.LEVEL_NAME;
|
String levelName = ServerProperties.LEVEL_NAME;
|
||||||
List<String> irisWorlds = irisWorlds();
|
List<String> irisWorlds = irisWorlds();
|
||||||
@@ -31,22 +32,20 @@ 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 (INMS.get().missingDimensionTypes(overworld, nether, end)) {
|
||||||
if (Bukkit.getAllowNether()) i++;
|
missingDimensionTypes = true;
|
||||||
if (Bukkit.getAllowEnd()) i++;
|
return;
|
||||||
|
|
||||||
if (overworld || nether || end) {
|
|
||||||
var pair = INMS.get().injectUncached(overworld, nether, end);
|
|
||||||
i += pair.getA() - 3;
|
|
||||||
autoClosing = pair.getB();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
totalWorlds = i;
|
if (overworld || nether || end) {
|
||||||
|
autoClosing = INMS.get().injectUncached(overworld, nether, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.registerListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
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;
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
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;
|
return e.isValid() ? e : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int surfaceY(Location l) {
|
private int surfaceY(Location l) {
|
||||||
|
|||||||
@@ -28,19 +28,12 @@ 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.Chunk;
|
import org.bukkit.*;
|
||||||
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)
|
||||||
@@ -69,6 +62,10 @@ 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;
|
||||||
@@ -168,7 +165,7 @@ public class IrisEntitySpawn implements IRare {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ignoreSurfaces && !irisEntity.getSurface().matches(at.clone().subtract(0, 1, 0).getBlock())) {
|
if (!ignoreSurfaces && !irisEntity.getSurface().matches(at.clone().subtract(0, 1, 0).getBlock().getBlockData())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,6 +180,10 @@ 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;
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
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,6 +74,9 @@ 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.Block;
|
import org.bukkit.block.data.BlockData;
|
||||||
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(Block state) {
|
public boolean matches(BlockData state) {
|
||||||
Material type = state.getType();
|
Material type = state.getMaterial();
|
||||||
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,6 +21,7 @@ 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;
|
||||||
@@ -48,6 +49,7 @@ 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;
|
||||||
@@ -122,11 +124,13 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
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) {
|
||||||
|
|||||||
@@ -0,0 +1,340 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
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,6 +26,8 @@ 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> {
|
||||||
@@ -65,6 +67,10 @@ 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>();
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ 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;
|
||||||
@@ -425,7 +424,7 @@ public class Mantle {
|
|||||||
ioTrim.set(true);
|
ioTrim.set(true);
|
||||||
unloadLock.lock();
|
unloadLock.lock();
|
||||||
try {
|
try {
|
||||||
if (lastUse != null && IrisEngineSVC.instance != null) {
|
if (lastUse != 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())) {
|
||||||
@@ -435,7 +434,6 @@ 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();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -454,53 +452,49 @@ public class Mantle {
|
|||||||
AtomicInteger i = new AtomicInteger();
|
AtomicInteger i = new AtomicInteger();
|
||||||
unloadLock.lock();
|
unloadLock.lock();
|
||||||
BurstExecutor burst = null;
|
BurstExecutor burst = null;
|
||||||
if (IrisEngineSVC.instance != null) {
|
try {
|
||||||
try {
|
KList<Long> copy = toUnload.copy();
|
||||||
KList<Long> copy = toUnload.copy();
|
if (!disableClear) toUnload.clear();
|
||||||
if (!disableClear) toUnload.clear();
|
burst = MultiBurst.burst.burst(copy.size());
|
||||||
burst = MultiBurst.burst.burst(copy.size());
|
burst.setMulticore(copy.size() > tectonicLimit);
|
||||||
burst.setMulticore(copy.size() > tectonicLimit);
|
for (int j = 0; j < copy.size(); j++) {
|
||||||
for (int j = 0; j < copy.size(); j++) {
|
Long id = copy.get(j);
|
||||||
Long id = copy.get(j);
|
if (id == null) {
|
||||||
if (id == null) {
|
Iris.error("Null id in unloadTectonicPlate at index " + j);
|
||||||
Iris.error("Null id in unloadTectonicPlate at index " + j);
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
burst.queue(() ->
|
|
||||||
hyperLock.withLong(id, () -> {
|
|
||||||
TectonicPlate m = loadedRegions.get(id);
|
|
||||||
if (m != null) {
|
|
||||||
if (m.inUse()) {
|
|
||||||
Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ());
|
|
||||||
if (disableClear) toUnload.remove(id);
|
|
||||||
lastUse.put(id, M.ms());
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
burst.complete();
|
|
||||||
} catch (Throwable e) {
|
burst.queue(() ->
|
||||||
e.printStackTrace();
|
hyperLock.withLong(id, () -> {
|
||||||
if (burst != null)
|
TectonicPlate m = loadedRegions.get(id);
|
||||||
burst.complete();
|
if (m != null) {
|
||||||
} finally {
|
if (m.inUse()) {
|
||||||
unloadLock.unlock();
|
Iris.debug("Tectonic Plate was added to unload while in use " + C.DARK_GREEN + m.getX() + " " + m.getZ());
|
||||||
ioTectonicUnload.set(true);
|
if (disableClear) toUnload.remove(id);
|
||||||
|
lastUse.put(id, M.ms());
|
||||||
|
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));
|
||||||
|
} catch (IOException e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
return i.get();
|
burst.complete();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
if (burst != null)
|
||||||
|
burst.complete();
|
||||||
|
} finally {
|
||||||
|
unloadLock.unlock();
|
||||||
|
ioTectonicUnload.set(true);
|
||||||
}
|
}
|
||||||
return i.get();
|
return i.get();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,11 +19,14 @@
|
|||||||
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
|
||||||
@@ -43,6 +46,10 @@ 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;
|
||||||
@@ -108,4 +115,18 @@ 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class Spiraler {
|
|||||||
|
|
||||||
public void next() {
|
public void next() {
|
||||||
if ((-sizeX / 2 <= x) && (x <= sizeX / 2) && (-sizeZ / 2 <= z) && (z <= sizeZ / 2)) {
|
if ((-sizeX / 2 <= x) && (x <= sizeX / 2) && (-sizeZ / 2 <= z) && (z <= sizeZ / 2)) {
|
||||||
spiraled.on(x + ox, z + ox);
|
spiraled.on(x + ox, z + oz);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((x == z) || ((x < 0) && (x == -z)) || ((x > 0) && (x == 1 - z))) {
|
if ((x == z) || ((x < 0) && (x == -z)) || ((x > 0) && (x == 1 - z))) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public class ServerProperties {
|
|||||||
public static final File SERVER_PROPERTIES;
|
public static final File SERVER_PROPERTIES;
|
||||||
public static final File BUKKIT_YML;
|
public static final File BUKKIT_YML;
|
||||||
|
|
||||||
public static final String LEVEL_NAME = DATA.getProperty("level-name", "world");
|
public static final String LEVEL_NAME;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
String[] args = ProcessHandle.current()
|
String[] args = ProcessHandle.current()
|
||||||
@@ -20,11 +20,13 @@ public class ServerProperties {
|
|||||||
|
|
||||||
String propertiesPath = "server.properties";
|
String propertiesPath = "server.properties";
|
||||||
String bukkitYml = "bukkit.yml";
|
String bukkitYml = "bukkit.yml";
|
||||||
|
String levelName = null;
|
||||||
|
|
||||||
for (int i = 0; i < args.length - 1; i++) {
|
for (int i = 0; i < args.length - 1; i++) {
|
||||||
switch (args[i]) {
|
switch (args[i]) {
|
||||||
case "-c", "--config" -> propertiesPath = args[i + 1];
|
case "-c", "--config" -> propertiesPath = args[i + 1];
|
||||||
case "-b", "--bukkit-settings" -> bukkitYml = args[i + 1];
|
case "-b", "--bukkit-settings" -> bukkitYml = args[i + 1];
|
||||||
|
case "-w", "--level-name", "--world" -> levelName = args[i + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,5 +37,8 @@ public class ServerProperties {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (levelName != null) LEVEL_NAME = levelName;
|
||||||
|
else LEVEL_NAME = DATA.getProperty("level-name", "world");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,7 +38,9 @@ import net.minecraft.tags.TagKey;
|
|||||||
import net.minecraft.world.entity.EntityDimensions;
|
import net.minecraft.world.entity.EntityDimensions;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
import net.minecraft.world.level.biome.BiomeSource;
|
import net.minecraft.world.level.biome.BiomeSource;
|
||||||
|
import net.minecraft.world.level.biome.Biomes;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
@@ -47,6 +49,9 @@ import net.minecraft.world.level.chunk.ChunkStatus;
|
|||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
import net.minecraft.world.level.dimension.LevelStem;
|
import net.minecraft.world.level.dimension.LevelStem;
|
||||||
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Biome;
|
import org.bukkit.block.Biome;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
@@ -640,50 +645,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
return inject(this::supplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
|
||||||
var reg = registry();
|
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
|
||||||
field.setAccessible(true);
|
|
||||||
|
|
||||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
|
||||||
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 fake = new HashMap<>(old);
|
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
|
||||||
field.set(reg, fake);
|
|
||||||
|
|
||||||
return new com.volmit.iris.core.nms.container.Pair<>(
|
|
||||||
injected.size(),
|
|
||||||
new AutoClosing(() -> {
|
|
||||||
closing.close();
|
|
||||||
field.set(reg, old);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
|
||||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
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!");
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
@@ -692,7 +655,12 @@ public class NMSBinding implements INMSBinding {
|
|||||||
var old = nmsServer.worldLoader;
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(nmsServer, transformer.apply(old));
|
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
)));
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
return new AutoClosing(() -> {
|
||||||
field.set(nmsServer, old);
|
field.set(nmsServer, old);
|
||||||
@@ -700,26 +668,66 @@ public class NMSBinding implements INMSBinding {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var reg = registry();
|
||||||
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
|
field.setAccessible(true);
|
||||||
|
|
||||||
|
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
||||||
|
var injected = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||||
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
|
var fake = new HashMap<>(old);
|
||||||
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
|
field.set(reg, fake);
|
||||||
|
|
||||||
|
return new AutoClosing(() -> field.set(reg, old));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var registry = registry().registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD));
|
||||||
|
if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER));
|
||||||
|
if (end) end = !registry.containsKey(createIrisKey(LevelStem.END));
|
||||||
|
return overworld || nether || end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCustomDimensions(World world) {
|
||||||
|
((CraftWorld) world).getHandle().K.customDimensions = null;
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
var access = registry();
|
var access = registry();
|
||||||
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
|
||||||
|
|
||||||
|
var settings = new FlatLevelGeneratorSettings(
|
||||||
|
Optional.empty(),
|
||||||
|
access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID),
|
||||||
|
List.of()
|
||||||
|
);
|
||||||
|
settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR));
|
||||||
|
settings.updateLayers();
|
||||||
|
|
||||||
|
var source = new FlatLevelSource(settings);
|
||||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD);
|
||||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
if (nether) register(fake, dimensions, source, LevelStem.NETHER);
|
||||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
if (end) register(fake, dimensions, source, LevelStem.END);
|
||||||
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
if (copy) copy(fake, levelStems);
|
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
var loc = createIrisKey(key);
|
||||||
target.register(key, new LevelStem(
|
target.register(key, new LevelStem(
|
||||||
dimensions.getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath()))),
|
dimensions.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, loc)).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())),
|
||||||
levelStems.getOrThrow(key).generator()
|
source
|
||||||
), Lifecycle.stable());
|
), Lifecycle.stable());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,4 +740,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
target.register(key, value, info);
|
target.register(key, value, info);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResourceLocation createIrisKey(ResourceKey<LevelStem> key) {
|
||||||
|
return new ResourceLocation("iris", key.location().getPath());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,14 @@ import net.minecraft.server.WorldLoader;
|
|||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.biome.Biomes;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
import net.minecraft.world.level.dimension.LevelStem;
|
import net.minecraft.world.level.dimension.LevelStem;
|
||||||
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Biome;
|
import org.bukkit.block.Biome;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
@@ -641,50 +646,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
return inject(this::supplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
|
||||||
var reg = registry();
|
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
|
||||||
field.setAccessible(true);
|
|
||||||
|
|
||||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
|
||||||
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 fake = new HashMap<>(old);
|
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
|
||||||
field.set(reg, fake);
|
|
||||||
|
|
||||||
return new com.volmit.iris.core.nms.container.Pair<>(
|
|
||||||
injected.size(),
|
|
||||||
new AutoClosing(() -> {
|
|
||||||
closing.close();
|
|
||||||
field.set(reg, old);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
|
||||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
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!");
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
@@ -693,7 +656,12 @@ public class NMSBinding implements INMSBinding {
|
|||||||
var old = nmsServer.worldLoader;
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(nmsServer, transformer.apply(old));
|
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
)));
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
return new AutoClosing(() -> {
|
||||||
field.set(nmsServer, old);
|
field.set(nmsServer, old);
|
||||||
@@ -701,26 +669,66 @@ public class NMSBinding implements INMSBinding {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var reg = registry();
|
||||||
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
|
field.setAccessible(true);
|
||||||
|
|
||||||
|
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
||||||
|
var injected = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||||
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
|
var fake = new HashMap<>(old);
|
||||||
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
|
field.set(reg, fake);
|
||||||
|
|
||||||
|
return new AutoClosing(() -> field.set(reg, old));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var registry = registry().registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD));
|
||||||
|
if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER));
|
||||||
|
if (end) end = !registry.containsKey(createIrisKey(LevelStem.END));
|
||||||
|
return overworld || nether || end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCustomDimensions(World world) {
|
||||||
|
((CraftWorld) world).getHandle().K.customDimensions = null;
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
var access = registry();
|
var access = registry();
|
||||||
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
|
||||||
|
|
||||||
|
var settings = new FlatLevelGeneratorSettings(
|
||||||
|
Optional.empty(),
|
||||||
|
access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID),
|
||||||
|
List.of()
|
||||||
|
);
|
||||||
|
settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR));
|
||||||
|
settings.updateLayers();
|
||||||
|
|
||||||
|
var source = new FlatLevelSource(settings);
|
||||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD);
|
||||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
if (nether) register(fake, dimensions, source, LevelStem.NETHER);
|
||||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
if (end) register(fake, dimensions, source, LevelStem.END);
|
||||||
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
if (copy) copy(fake, levelStems);
|
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
var loc = createIrisKey(key);
|
||||||
target.register(key, new LevelStem(
|
target.register(key, new LevelStem(
|
||||||
dimensions.getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath()))),
|
dimensions.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, loc)).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())),
|
||||||
levelStems.getOrThrow(key).generator()
|
source
|
||||||
), Lifecycle.stable());
|
), Lifecycle.stable());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -733,4 +741,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
target.register(key, value, info);
|
target.register(key, value, info);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResourceLocation createIrisKey(ResourceKey<LevelStem> key) {
|
||||||
|
return new ResourceLocation("iris", key.location().getPath());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,14 @@ import net.minecraft.server.WorldLoader;
|
|||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.biome.Biomes;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
import net.minecraft.world.level.dimension.LevelStem;
|
import net.minecraft.world.level.dimension.LevelStem;
|
||||||
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Biome;
|
import org.bukkit.block.Biome;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
@@ -642,50 +647,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
return inject(this::supplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
|
||||||
var reg = registry();
|
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
|
||||||
field.setAccessible(true);
|
|
||||||
|
|
||||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
|
||||||
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 fake = new HashMap<>(old);
|
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
|
||||||
field.set(reg, fake);
|
|
||||||
|
|
||||||
return new com.volmit.iris.core.nms.container.Pair<>(
|
|
||||||
injected.size(),
|
|
||||||
new AutoClosing(() -> {
|
|
||||||
closing.close();
|
|
||||||
field.set(reg, old);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
|
||||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
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!");
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
@@ -694,7 +657,12 @@ public class NMSBinding implements INMSBinding {
|
|||||||
var old = nmsServer.worldLoader;
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(nmsServer, transformer.apply(old));
|
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
)));
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
return new AutoClosing(() -> {
|
||||||
field.set(nmsServer, old);
|
field.set(nmsServer, old);
|
||||||
@@ -702,26 +670,66 @@ public class NMSBinding implements INMSBinding {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var reg = registry();
|
||||||
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
|
field.setAccessible(true);
|
||||||
|
|
||||||
|
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
||||||
|
var injected = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||||
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
|
var fake = new HashMap<>(old);
|
||||||
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
|
field.set(reg, fake);
|
||||||
|
|
||||||
|
return new AutoClosing(() -> field.set(reg, old));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var registry = registry().registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD));
|
||||||
|
if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER));
|
||||||
|
if (end) end = !registry.containsKey(createIrisKey(LevelStem.END));
|
||||||
|
return overworld || nether || end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCustomDimensions(World world) {
|
||||||
|
((CraftWorld) world).getHandle().K.customDimensions = null;
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
var access = registry();
|
var access = registry();
|
||||||
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
|
||||||
|
|
||||||
|
var settings = new FlatLevelGeneratorSettings(
|
||||||
|
Optional.empty(),
|
||||||
|
access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID),
|
||||||
|
List.of()
|
||||||
|
);
|
||||||
|
settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR));
|
||||||
|
settings.updateLayers();
|
||||||
|
|
||||||
|
var source = new FlatLevelSource(settings);
|
||||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD);
|
||||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
if (nether) register(fake, dimensions, source, LevelStem.NETHER);
|
||||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
if (end) register(fake, dimensions, source, LevelStem.END);
|
||||||
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
if (copy) copy(fake, levelStems);
|
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
var loc = createIrisKey(key);
|
||||||
target.register(key, new LevelStem(
|
target.register(key, new LevelStem(
|
||||||
dimensions.getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath()))),
|
dimensions.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, loc)).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())),
|
||||||
levelStems.getOrThrow(key).generator()
|
source
|
||||||
), Lifecycle.stable());
|
), Lifecycle.stable());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -734,4 +742,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
target.register(key, value, info);
|
target.register(key, value, info);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResourceLocation createIrisKey(ResourceKey<LevelStem> key) {
|
||||||
|
return new ResourceLocation("iris", key.location().getPath());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,11 +38,16 @@ import net.minecraft.server.level.ServerLevel;
|
|||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.item.component.CustomData;
|
import net.minecraft.world.item.component.CustomData;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.biome.Biomes;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
import net.minecraft.world.level.dimension.LevelStem;
|
import net.minecraft.world.level.dimension.LevelStem;
|
||||||
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Biome;
|
import org.bukkit.block.Biome;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
@@ -667,50 +672,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
return inject(this::supplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
|
||||||
var reg = registry();
|
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
|
||||||
field.setAccessible(true);
|
|
||||||
|
|
||||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
|
||||||
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 fake = new HashMap<>(old);
|
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
|
||||||
field.set(reg, fake);
|
|
||||||
|
|
||||||
return new com.volmit.iris.core.nms.container.Pair<>(
|
|
||||||
injected.size(),
|
|
||||||
new AutoClosing(() -> {
|
|
||||||
closing.close();
|
|
||||||
field.set(reg, old);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
|
||||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
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!");
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
@@ -719,7 +682,12 @@ public class NMSBinding implements INMSBinding {
|
|||||||
var old = nmsServer.worldLoader;
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(nmsServer, transformer.apply(old));
|
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
)));
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
return new AutoClosing(() -> {
|
||||||
field.set(nmsServer, old);
|
field.set(nmsServer, old);
|
||||||
@@ -727,26 +695,66 @@ public class NMSBinding implements INMSBinding {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var reg = registry();
|
||||||
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
|
field.setAccessible(true);
|
||||||
|
|
||||||
|
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
||||||
|
var injected = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||||
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
|
var fake = new HashMap<>(old);
|
||||||
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
|
field.set(reg, fake);
|
||||||
|
|
||||||
|
return new AutoClosing(() -> field.set(reg, old));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var registry = registry().registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD));
|
||||||
|
if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER));
|
||||||
|
if (end) end = !registry.containsKey(createIrisKey(LevelStem.END));
|
||||||
|
return overworld || nether || end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCustomDimensions(World world) {
|
||||||
|
((CraftWorld) world).getHandle().K.customDimensions = null;
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
var access = registry();
|
var access = registry();
|
||||||
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
|
||||||
|
|
||||||
|
var settings = new FlatLevelGeneratorSettings(
|
||||||
|
Optional.empty(),
|
||||||
|
access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID),
|
||||||
|
List.of()
|
||||||
|
);
|
||||||
|
settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR));
|
||||||
|
settings.updateLayers();
|
||||||
|
|
||||||
|
var source = new FlatLevelSource(settings);
|
||||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD);
|
||||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
if (nether) register(fake, dimensions, source, LevelStem.NETHER);
|
||||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
if (end) register(fake, dimensions, source, LevelStem.END);
|
||||||
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
if (copy) copy(fake, levelStems);
|
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
var loc = createIrisKey(key);
|
||||||
target.register(key, new LevelStem(
|
target.register(key, new LevelStem(
|
||||||
dimensions.getHolder(new ResourceLocation("iris", key.location().getPath())).orElseThrow(),
|
dimensions.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, loc)).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())),
|
||||||
levelStems.getOrThrow(key).generator()
|
source
|
||||||
), RegistrationInfo.BUILT_IN);
|
), RegistrationInfo.BUILT_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -759,4 +767,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
target.register(key, value, info);
|
target.register(key, value, info);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResourceLocation createIrisKey(ResourceKey<LevelStem> key) {
|
||||||
|
return new ResourceLocation("iris", key.location().getPath());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,11 +32,16 @@ import net.minecraft.server.level.ChunkMap;
|
|||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.item.component.CustomData;
|
import net.minecraft.world.item.component.CustomData;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.biome.Biomes;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.chunk.status.WorldGenContext;
|
import net.minecraft.world.level.chunk.status.WorldGenContext;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
import net.minecraft.world.level.dimension.LevelStem;
|
import net.minecraft.world.level.dimension.LevelStem;
|
||||||
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Biome;
|
import org.bukkit.block.Biome;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
@@ -671,50 +676,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
return inject(this::supplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
|
||||||
var reg = registry();
|
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
|
||||||
field.setAccessible(true);
|
|
||||||
|
|
||||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
|
||||||
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 fake = new HashMap<>(old);
|
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
|
||||||
field.set(reg, fake);
|
|
||||||
|
|
||||||
return new com.volmit.iris.core.nms.container.Pair<>(
|
|
||||||
injected.size(),
|
|
||||||
new AutoClosing(() -> {
|
|
||||||
closing.close();
|
|
||||||
field.set(reg, old);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
|
||||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
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!");
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
@@ -723,7 +686,12 @@ public class NMSBinding implements INMSBinding {
|
|||||||
var old = nmsServer.worldLoader;
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(nmsServer, transformer.apply(old));
|
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
)));
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
return new AutoClosing(() -> {
|
||||||
field.set(nmsServer, old);
|
field.set(nmsServer, old);
|
||||||
@@ -731,26 +699,66 @@ public class NMSBinding implements INMSBinding {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var reg = registry();
|
||||||
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
|
field.setAccessible(true);
|
||||||
|
|
||||||
|
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
||||||
|
var injected = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||||
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
|
var fake = new HashMap<>(old);
|
||||||
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
|
field.set(reg, fake);
|
||||||
|
|
||||||
|
return new AutoClosing(() -> field.set(reg, old));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var registry = registry().registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD));
|
||||||
|
if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER));
|
||||||
|
if (end) end = !registry.containsKey(createIrisKey(LevelStem.END));
|
||||||
|
return overworld || nether || end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCustomDimensions(World world) {
|
||||||
|
((CraftWorld) world).getHandle().K.customDimensions = null;
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
var access = registry();
|
var access = registry();
|
||||||
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
|
||||||
|
|
||||||
|
var settings = new FlatLevelGeneratorSettings(
|
||||||
|
Optional.empty(),
|
||||||
|
access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID),
|
||||||
|
List.of()
|
||||||
|
);
|
||||||
|
settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR));
|
||||||
|
settings.updateLayers();
|
||||||
|
|
||||||
|
var source = new FlatLevelSource(settings);
|
||||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD);
|
||||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
if (nether) register(fake, dimensions, source, LevelStem.NETHER);
|
||||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
if (end) register(fake, dimensions, source, LevelStem.END);
|
||||||
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
if (copy) copy(fake, levelStems);
|
if (copy) copy(fake, access.registryOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
var loc = createIrisKey(key);
|
||||||
target.register(key, new LevelStem(
|
target.register(key, new LevelStem(
|
||||||
dimensions.getHolder(ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath())).orElseThrow(),
|
dimensions.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, loc)).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())),
|
||||||
levelStems.getOrThrow(key).generator()
|
source
|
||||||
), RegistrationInfo.BUILT_IN);
|
), RegistrationInfo.BUILT_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -763,4 +771,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
target.register(key, value, info);
|
target.register(key, value, info);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResourceLocation createIrisKey(ResourceKey<LevelStem> key) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,11 +27,16 @@ import net.minecraft.server.commands.data.BlockDataAccessor;
|
|||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.item.component.CustomData;
|
import net.minecraft.world.item.component.CustomData;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.biome.Biomes;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.chunk.status.WorldGenContext;
|
import net.minecraft.world.level.chunk.status.WorldGenContext;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
import net.minecraft.world.level.dimension.LevelStem;
|
import net.minecraft.world.level.dimension.LevelStem;
|
||||||
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Biome;
|
import org.bukkit.block.Biome;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
@@ -661,50 +666,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
return inject(this::supplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
|
||||||
var reg = registry();
|
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
|
||||||
field.setAccessible(true);
|
|
||||||
|
|
||||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
|
||||||
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 fake = new HashMap<>(old);
|
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
|
||||||
field.set(reg, fake);
|
|
||||||
|
|
||||||
return new Pair<>(
|
|
||||||
injected.size(),
|
|
||||||
new AutoClosing(() -> {
|
|
||||||
closing.close();
|
|
||||||
field.set(reg, old);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
|
||||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
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!");
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
@@ -713,7 +676,12 @@ public class NMSBinding implements INMSBinding {
|
|||||||
var old = nmsServer.worldLoader;
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(nmsServer, transformer.apply(old));
|
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
)));
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
return new AutoClosing(() -> {
|
||||||
field.set(nmsServer, old);
|
field.set(nmsServer, old);
|
||||||
@@ -721,26 +689,66 @@ public class NMSBinding implements INMSBinding {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var reg = registry();
|
||||||
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
|
field.setAccessible(true);
|
||||||
|
|
||||||
|
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
||||||
|
var injected = access.lookupOrThrow(Registries.LEVEL_STEM);
|
||||||
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
|
var fake = new HashMap<>(old);
|
||||||
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
|
field.set(reg, fake);
|
||||||
|
|
||||||
|
return new AutoClosing(() -> field.set(reg, old));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var registry = registry().lookupOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD));
|
||||||
|
if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER));
|
||||||
|
if (end) end = !registry.containsKey(createIrisKey(LevelStem.END));
|
||||||
|
return overworld || nether || end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCustomDimensions(World world) {
|
||||||
|
((CraftWorld) world).getHandle().L.customDimensions = null;
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
var access = registry();
|
var access = registry();
|
||||||
var dimensions = access.lookupOrThrow(Registries.DIMENSION_TYPE);
|
var dimensions = access.lookupOrThrow(Registries.DIMENSION_TYPE);
|
||||||
var levelStems = access.lookupOrThrow(Registries.LEVEL_STEM);
|
|
||||||
|
|
||||||
|
var settings = new FlatLevelGeneratorSettings(
|
||||||
|
Optional.empty(),
|
||||||
|
access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID),
|
||||||
|
List.of()
|
||||||
|
);
|
||||||
|
settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR));
|
||||||
|
settings.updateLayers();
|
||||||
|
|
||||||
|
var source = new FlatLevelSource(settings);
|
||||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD);
|
||||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
if (nether) register(fake, dimensions, source, LevelStem.NETHER);
|
||||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
if (end) register(fake, dimensions, source, LevelStem.END);
|
||||||
copy(fake, datapack.lookup(Registries.LEVEL_STEM).orElse(null));
|
copy(fake, datapack.lookup(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
if (copy) copy(fake, levelStems);
|
if (copy) copy(fake, access.lookupOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
var loc = createIrisKey(key);
|
||||||
target.register(key, new LevelStem(
|
target.register(key, new LevelStem(
|
||||||
dimensions.get(ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath())).orElseThrow(),
|
dimensions.get(loc).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())),
|
||||||
levelStems.getValueOrThrow(key).generator()
|
source
|
||||||
), RegistrationInfo.BUILT_IN);
|
), RegistrationInfo.BUILT_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,4 +761,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
target.register(key, value, info);
|
target.register(key, value, info);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResourceLocation createIrisKey(ResourceKey<LevelStem> key) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+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 delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
return WeightedRandomList.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ import net.minecraft.tags.TagKey;
|
|||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
import net.minecraft.world.item.component.CustomData;
|
import net.minecraft.world.item.component.CustomData;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.biome.Biomes;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
@@ -49,6 +51,9 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
|
|||||||
import net.minecraft.world.level.chunk.status.WorldGenContext;
|
import net.minecraft.world.level.chunk.status.WorldGenContext;
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
import net.minecraft.world.level.dimension.LevelStem;
|
import net.minecraft.world.level.dimension.LevelStem;
|
||||||
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Biome;
|
import org.bukkit.block.Biome;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
@@ -660,50 +665,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
public AutoClosing injectLevelStems() {
|
public AutoClosing injectLevelStems() {
|
||||||
return inject(this::supplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SneakyThrows
|
|
||||||
public Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
|
||||||
var reg = registry();
|
|
||||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
|
||||||
field.setAccessible(true);
|
|
||||||
|
|
||||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
|
||||||
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 fake = new HashMap<>(old);
|
|
||||||
fake.put(Registries.LEVEL_STEM, injected);
|
|
||||||
field.set(reg, fake);
|
|
||||||
|
|
||||||
return new Pair<>(
|
|
||||||
injected.size(),
|
|
||||||
new AutoClosing(() -> {
|
|
||||||
closing.close();
|
|
||||||
field.set(reg, old);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
|
||||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
|
||||||
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!");
|
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||||
|
|
||||||
var server = ((CraftServer) Bukkit.getServer());
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
@@ -712,7 +675,12 @@ public class NMSBinding implements INMSBinding {
|
|||||||
var old = nmsServer.worldLoader;
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
field.set(nmsServer, transformer.apply(old));
|
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||||
|
old.resources(),
|
||||||
|
old.dataConfiguration(),
|
||||||
|
old.datapackWorldgen(),
|
||||||
|
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||||
|
)));
|
||||||
|
|
||||||
return new AutoClosing(() -> {
|
return new AutoClosing(() -> {
|
||||||
field.set(nmsServer, old);
|
field.set(nmsServer, old);
|
||||||
@@ -720,26 +688,66 @@ public class NMSBinding implements INMSBinding {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SneakyThrows
|
||||||
|
public AutoClosing injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var reg = registry();
|
||||||
|
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||||
|
field.setAccessible(true);
|
||||||
|
|
||||||
|
var access = createRegistryAccess(((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions(), true, overworld, nether, end);
|
||||||
|
var injected = access.lookupOrThrow(Registries.LEVEL_STEM);
|
||||||
|
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||||
|
var fake = new HashMap<>(old);
|
||||||
|
fake.put(Registries.LEVEL_STEM, injected);
|
||||||
|
field.set(reg, fake);
|
||||||
|
|
||||||
|
return new AutoClosing(() -> field.set(reg, old));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean missingDimensionTypes(boolean overworld, boolean nether, boolean end) {
|
||||||
|
var registry = registry().lookupOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
if (overworld) overworld = !registry.containsKey(createIrisKey(LevelStem.OVERWORLD));
|
||||||
|
if (nether) nether = !registry.containsKey(createIrisKey(LevelStem.NETHER));
|
||||||
|
if (end) end = !registry.containsKey(createIrisKey(LevelStem.END));
|
||||||
|
return overworld || nether || end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCustomDimensions(World world) {
|
||||||
|
((CraftWorld) world).getHandle().L.customDimensions = null;
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
var access = registry();
|
var access = registry();
|
||||||
var dimensions = access.lookupOrThrow(Registries.DIMENSION_TYPE);
|
var dimensions = access.lookupOrThrow(Registries.DIMENSION_TYPE);
|
||||||
var levelStems = access.lookupOrThrow(Registries.LEVEL_STEM);
|
|
||||||
|
|
||||||
|
var settings = new FlatLevelGeneratorSettings(
|
||||||
|
Optional.empty(),
|
||||||
|
access.lookupOrThrow(Registries.BIOME).getOrThrow(Biomes.THE_VOID),
|
||||||
|
List.of()
|
||||||
|
);
|
||||||
|
settings.getLayersInfo().add(new FlatLayerInfo(1, Blocks.AIR));
|
||||||
|
settings.updateLayers();
|
||||||
|
|
||||||
|
var source = new FlatLevelSource(settings);
|
||||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
if (overworld) register(fake, dimensions, source, LevelStem.OVERWORLD);
|
||||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
if (nether) register(fake, dimensions, source, LevelStem.NETHER);
|
||||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
if (end) register(fake, dimensions, source, LevelStem.END);
|
||||||
copy(fake, datapack.lookup(Registries.LEVEL_STEM).orElse(null));
|
copy(fake, datapack.lookup(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
if (copy) copy(fake, levelStems);
|
if (copy) copy(fake, access.lookupOrThrow(Registries.LEVEL_STEM));
|
||||||
|
|
||||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake)).freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
private void register(MappedRegistry<LevelStem> target, Registry<DimensionType> dimensions, FlatLevelSource source, ResourceKey<LevelStem> key) {
|
||||||
|
var loc = createIrisKey(key);
|
||||||
target.register(key, new LevelStem(
|
target.register(key, new LevelStem(
|
||||||
dimensions.get(ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath())).orElseThrow(),
|
dimensions.get(loc).orElseThrow(() -> new IllegalStateException("Missing dimension type " + loc + " in " + dimensions.keySet())),
|
||||||
levelStems.getValueOrThrow(key).generator()
|
source
|
||||||
), RegistrationInfo.BUILT_IN);
|
), RegistrationInfo.BUILT_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -752,4 +760,8 @@ public class NMSBinding implements INMSBinding {
|
|||||||
target.register(key, value, info);
|
target.register(key, value, info);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ResourceLocation createIrisKey(ResourceKey<LevelStem> key) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user