mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-05-20 00:20:24 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dfe4894be7 | |||
| 8eb2287ec0 | |||
| c4f0722614 | |||
| 7fa1484b21 | |||
| 1c5eb8b910 | |||
| 94bf530d93 | |||
| 686ae57b5b | |||
| a911685aaf | |||
| 6899761ca9 | |||
| a58958fd62 | |||
| 307f3c9158 | |||
| 4f275c2e06 | |||
| 7e4e3f3cd8 | |||
| 84e5add564 | |||
| 4d4adbb76f | |||
| ff2f285784 | |||
| 8b1636e78a | |||
| 3bdad10562 | |||
| ac03a977aa |
+1
-1
@@ -33,7 +33,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
version '3.6.0-1.20.1-1.21.4'
|
version '3.6.4-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 =============================
|
||||||
|
|||||||
+1
-1
@@ -62,7 +62,7 @@ dependencies {
|
|||||||
|
|
||||||
// Third Party Integrations
|
// Third Party Integrations
|
||||||
compileOnly 'com.ticxo.playeranimator:PlayerAnimator:R1.2.7'
|
compileOnly 'com.ticxo.playeranimator:PlayerAnimator:R1.2.7'
|
||||||
compileOnly 'com.nexomc:nexo:0.6.0-dev.0'
|
compileOnly 'com.nexomc:nexo:1.0.0-dev.38'
|
||||||
compileOnly 'com.github.LoneDev6:api-itemsadder:3.4.1-r4'
|
compileOnly 'com.github.LoneDev6:api-itemsadder:3.4.1-r4'
|
||||||
compileOnly 'com.github.PlaceholderAPI:placeholderapi:2.11.3'
|
compileOnly 'com.github.PlaceholderAPI:placeholderapi:2.11.3'
|
||||||
compileOnly 'com.github.Ssomar-Developement:SCore:4.23.10.8'
|
compileOnly 'com.github.Ssomar-Developement:SCore:4.23.10.8'
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
|||||||
import com.volmit.iris.core.pregenerator.LazyPregenerator;
|
import com.volmit.iris.core.pregenerator.LazyPregenerator;
|
||||||
import com.volmit.iris.core.service.StudioSVC;
|
import com.volmit.iris.core.service.StudioSVC;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
|
import com.volmit.iris.core.tools.IrisWorldCreator;
|
||||||
import com.volmit.iris.engine.EnginePanic;
|
import com.volmit.iris.engine.EnginePanic;
|
||||||
import com.volmit.iris.engine.object.IrisCompat;
|
import com.volmit.iris.engine.object.IrisCompat;
|
||||||
|
import com.volmit.iris.engine.object.IrisContextInjector;
|
||||||
import com.volmit.iris.engine.object.IrisDimension;
|
import com.volmit.iris.engine.object.IrisDimension;
|
||||||
import com.volmit.iris.engine.object.IrisWorld;
|
import com.volmit.iris.engine.object.IrisWorld;
|
||||||
import com.volmit.iris.engine.platform.BukkitChunkGenerator;
|
import com.volmit.iris.engine.platform.BukkitChunkGenerator;
|
||||||
@@ -101,8 +103,6 @@ import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware;
|
|||||||
|
|
||||||
@SuppressWarnings("CanBeFinal")
|
@SuppressWarnings("CanBeFinal")
|
||||||
public class Iris extends VolmitPlugin implements Listener {
|
public class Iris extends VolmitPlugin implements Listener {
|
||||||
public static final String OVERWORLD_TAG = "31010";
|
|
||||||
|
|
||||||
private static final Queue<Runnable> syncJobs = new ShurikenQueue<>();
|
private static final Queue<Runnable> syncJobs = new ShurikenQueue<>();
|
||||||
|
|
||||||
public static Iris instance;
|
public static Iris instance;
|
||||||
@@ -467,6 +467,7 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
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()));
|
||||||
@@ -516,10 +517,10 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
Iris.info("Loading World: %s | Generator: %s", s, generator);
|
Iris.info("Loading World: %s | Generator: %s", s, generator);
|
||||||
|
|
||||||
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
|
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
|
||||||
new WorldCreator(s)
|
WorldCreator c = new WorldCreator(s)
|
||||||
.generator(getDefaultWorldGenerator(s, generator))
|
.generator(getDefaultWorldGenerator(s, generator))
|
||||||
.environment(IrisData.loadAnyDimension(generator).getEnvironment())
|
.environment(IrisData.loadAnyDimension(generator).getEnvironment());
|
||||||
.createWorld();
|
INMS.get().createWorld(c);
|
||||||
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
|
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ public class IrisSettings {
|
|||||||
public boolean splashLogoStartup = true;
|
public boolean splashLogoStartup = true;
|
||||||
public boolean useConsoleCustomColors = true;
|
public boolean useConsoleCustomColors = true;
|
||||||
public boolean useCustomColorsIngame = true;
|
public boolean useCustomColorsIngame = true;
|
||||||
|
public boolean adjustVanillaHeight = false;
|
||||||
public String forceMainWorld = "";
|
public String forceMainWorld = "";
|
||||||
public int spinh = -20;
|
public int spinh = -20;
|
||||||
public int spins = 7;
|
public int spins = 7;
|
||||||
|
|||||||
@@ -28,20 +28,27 @@ import com.volmit.iris.engine.object.IrisBiomeCustom;
|
|||||||
import com.volmit.iris.engine.object.IrisDimension;
|
import com.volmit.iris.engine.object.IrisDimension;
|
||||||
import com.volmit.iris.engine.object.IrisRange;
|
import com.volmit.iris.engine.object.IrisRange;
|
||||||
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.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.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.NonNull;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.configuration.InvalidConfigurationException;
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static com.volmit.iris.core.nms.datapack.IDataFixer.Dimension.*;
|
||||||
|
|
||||||
public class ServerConfigurator {
|
public class ServerConfigurator {
|
||||||
public static void configure() {
|
public static void configure() {
|
||||||
@@ -84,7 +91,7 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<File> getDatapacksFolder() {
|
private static KList<File> getDatapacksFolder() {
|
||||||
if (!IrisSettings.get().getGeneral().forceMainWorld.isEmpty()) {
|
if (!IrisSettings.get().getGeneral().forceMainWorld.isEmpty()) {
|
||||||
return new KList<File>().qadd(new File(Bukkit.getWorldContainer(), IrisSettings.get().getGeneral().forceMainWorld + "/datapacks"));
|
return new KList<File>().qadd(new File(Bukkit.getWorldContainer(), IrisSettings.get().getGeneral().forceMainWorld + "/datapacks"));
|
||||||
}
|
}
|
||||||
@@ -99,57 +106,17 @@ public class ServerConfigurator {
|
|||||||
|
|
||||||
public static void installDataPacks(IDataFixer fixer, boolean fullInstall) {
|
public static void installDataPacks(IDataFixer fixer, boolean fullInstall) {
|
||||||
Iris.info("Checking Data Packs...");
|
Iris.info("Checking Data Packs...");
|
||||||
File packs = new File("plugins/Iris/packs");
|
DimensionHeight height = new DimensionHeight(fixer);
|
||||||
double ultimateMaxHeight = 0;
|
KList<File> folders = getDatapacksFolder();
|
||||||
double ultimateMinHeight = 0;
|
KMap<String, KSet<String>> biomes = new KMap<>();
|
||||||
if (packs.exists() && packs.isDirectory()) {
|
|
||||||
for (File pack : packs.listFiles()) {
|
|
||||||
IrisData data = IrisData.get(pack);
|
|
||||||
if (pack.isDirectory()) {
|
|
||||||
File dimensionsFolder = new File(pack, "dimensions");
|
|
||||||
if (dimensionsFolder.exists() && dimensionsFolder.isDirectory()) {
|
|
||||||
for (File file : dimensionsFolder.listFiles()) {
|
|
||||||
if (file.isFile() && file.getName().endsWith(".json")) {
|
|
||||||
IrisDimension dim = data.getDimensionLoader().load(file.getName().split("\\Q.\\E")[0]);
|
|
||||||
if (ultimateMaxHeight < dim.getDimensionHeight().getMax()) {
|
|
||||||
ultimateMaxHeight = dim.getDimensionHeight().getMax();
|
|
||||||
}
|
|
||||||
if (ultimateMinHeight > dim.getDimensionHeight().getMin()) {
|
|
||||||
ultimateMinHeight = dim.getDimensionHeight().getMin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packs.exists()) {
|
allPacks().flatMap(height::merge)
|
||||||
for (File i : packs.listFiles()) {
|
.parallel()
|
||||||
if (i.isDirectory()) {
|
.forEach(dim -> {
|
||||||
Iris.verbose("Checking Pack: " + i.getPath());
|
Iris.verbose(" Checking Dimension " + dim.getLoadFile().getPath());
|
||||||
IrisData data = IrisData.get(i);
|
dim.installBiomes(fixer, dim::getLoader, folders, biomes.computeIfAbsent(dim.getLoadKey(), k -> new KSet<>()));
|
||||||
File dims = new File(i, "dimensions");
|
});
|
||||||
|
IrisDimension.writeShared(folders, height);
|
||||||
if (dims.exists()) {
|
|
||||||
for (File j : dims.listFiles()) {
|
|
||||||
if (j.getName().endsWith(".json")) {
|
|
||||||
IrisDimension dim = data.getDimensionLoader().load(j.getName().split("\\Q.\\E")[0]);
|
|
||||||
|
|
||||||
if (dim == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iris.verbose(" Checking Dimension " + dim.getLoadFile().getPath());
|
|
||||||
for (File dpack : getDatapacksFolder()) {
|
|
||||||
dim.installDataPack(fixer, () -> data, dpack, ultimateMaxHeight, ultimateMinHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Iris.info("Data Packs Setup!");
|
Iris.info("Data Packs Setup!");
|
||||||
|
|
||||||
@@ -158,57 +125,40 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void verifyDataPacksPost(boolean allowRestarting) {
|
private static void verifyDataPacksPost(boolean allowRestarting) {
|
||||||
File packs = new File("plugins/Iris/packs");
|
boolean bad = allPacks()
|
||||||
|
.map(data -> {
|
||||||
|
Iris.verbose("Checking Pack: " + data.getDataFolder().getPath());
|
||||||
|
var loader = data.getDimensionLoader();
|
||||||
|
return loader.loadAll(loader.getPossibleKeys())
|
||||||
|
.stream()
|
||||||
|
.map(ServerConfigurator::verifyDataPackInstalled)
|
||||||
|
.toList()
|
||||||
|
.contains(false);
|
||||||
|
})
|
||||||
|
.toList()
|
||||||
|
.contains(true);
|
||||||
|
if (!bad) return;
|
||||||
|
|
||||||
boolean bad = false;
|
|
||||||
if (packs.exists()) {
|
|
||||||
for (File i : packs.listFiles()) {
|
|
||||||
if (i.isDirectory()) {
|
|
||||||
Iris.verbose("Checking Pack: " + i.getPath());
|
|
||||||
IrisData data = IrisData.get(i);
|
|
||||||
File dims = new File(i, "dimensions");
|
|
||||||
|
|
||||||
if (dims.exists()) {
|
if (allowRestarting) {
|
||||||
for (File j : dims.listFiles()) {
|
restart();
|
||||||
if (j.getName().endsWith(".json")) {
|
} else if (INMS.get().supportsDataPacks()) {
|
||||||
IrisDimension dim = data.getDimensionLoader().load(j.getName().split("\\Q.\\E")[0]);
|
Iris.error("============================================================================");
|
||||||
|
Iris.error(C.ITALIC + "You need to restart your server to properly generate custom biomes.");
|
||||||
|
Iris.error(C.ITALIC + "By continuing, Iris will use backup biomes in place of the custom biomes.");
|
||||||
|
Iris.error("----------------------------------------------------------------------------");
|
||||||
|
Iris.error(C.UNDERLINE + "IT IS HIGHLY RECOMMENDED YOU RESTART THE SERVER BEFORE GENERATING!");
|
||||||
|
Iris.error("============================================================================");
|
||||||
|
|
||||||
if (dim == null) {
|
for (Player i : Bukkit.getOnlinePlayers()) {
|
||||||
Iris.error("Failed to load " + j.getPath() + " ");
|
if (i.isOp() || i.hasPermission("iris.all")) {
|
||||||
continue;
|
VolmitSender sender = new VolmitSender(i, Iris.instance.getTag("WARNING"));
|
||||||
}
|
sender.sendMessage("There are some Iris Packs that have custom biomes in them");
|
||||||
|
sender.sendMessage("You need to restart your server to use these packs.");
|
||||||
if (!verifyDataPackInstalled(dim)) {
|
|
||||||
bad = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (bad) {
|
J.sleep(3000);
|
||||||
if (allowRestarting) {
|
|
||||||
restart();
|
|
||||||
} else if (INMS.get().supportsDataPacks()) {
|
|
||||||
Iris.error("============================================================================");
|
|
||||||
Iris.error(C.ITALIC + "You need to restart your server to properly generate custom biomes.");
|
|
||||||
Iris.error(C.ITALIC + "By continuing, Iris will use backup biomes in place of the custom biomes.");
|
|
||||||
Iris.error("----------------------------------------------------------------------------");
|
|
||||||
Iris.error(C.UNDERLINE + "IT IS HIGHLY RECOMMENDED YOU RESTART THE SERVER BEFORE GENERATING!");
|
|
||||||
Iris.error("============================================================================");
|
|
||||||
|
|
||||||
for (Player i : Bukkit.getOnlinePlayers()) {
|
|
||||||
if (i.isOp() || i.hasPermission("iris.all")) {
|
|
||||||
VolmitSender sender = new VolmitSender(i, Iris.instance.getTag("WARNING"));
|
|
||||||
sender.sendMessage("There are some Iris Packs that have custom biomes in them");
|
|
||||||
sender.sendMessage("You need to restart your server to use these packs.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
J.sleep(3000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +168,7 @@ public class ServerConfigurator {
|
|||||||
Iris.warn("This will only happen when your pack changes (updates/first time setup)");
|
Iris.warn("This will only happen when your pack changes (updates/first time setup)");
|
||||||
Iris.warn("(You can disable this auto restart in iris settings)");
|
Iris.warn("(You can disable this auto restart in iris settings)");
|
||||||
J.s(() -> {
|
J.s(() -> {
|
||||||
Iris.warn("Looks like the restart command diddn't work. Stopping the server instead!");
|
Iris.warn("Looks like the restart command didn't work. Stopping the server instead!");
|
||||||
Bukkit.shutdown();
|
Bukkit.shutdown();
|
||||||
}, 100);
|
}, 100);
|
||||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart");
|
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart");
|
||||||
@@ -226,22 +176,24 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean verifyDataPackInstalled(IrisDimension dimension) {
|
public static boolean verifyDataPackInstalled(IrisDimension dimension) {
|
||||||
IrisData idm = IrisData.get(Iris.instance.getDataFolder("packs", dimension.getLoadKey()));
|
|
||||||
KSet<String> keys = new KSet<>();
|
KSet<String> keys = new KSet<>();
|
||||||
boolean warn = false;
|
boolean warn = false;
|
||||||
|
|
||||||
for (IrisBiome i : dimension.getAllBiomes(() -> idm)) {
|
for (IrisBiome i : dimension.getAllBiomes(dimension::getLoader)) {
|
||||||
if (i.isCustom()) {
|
if (i.isCustom()) {
|
||||||
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
|
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
|
||||||
keys.add(dimension.getLoadKey() + ":" + j.getId());
|
keys.add(dimension.getLoadKey() + ":" + j.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
String key = getWorld(dimension.getLoader());
|
||||||
|
if (key == null) key = dimension.getLoadKey();
|
||||||
|
else key += "/" + dimension.getLoadKey();
|
||||||
|
|
||||||
if (!INMS.get().supportsDataPacks()) {
|
if (!INMS.get().supportsDataPacks()) {
|
||||||
if (!keys.isEmpty()) {
|
if (!keys.isEmpty()) {
|
||||||
Iris.warn("===================================================================================");
|
Iris.warn("===================================================================================");
|
||||||
Iris.warn("Pack " + dimension.getLoadKey() + " has " + keys.size() + " custom biome(s). ");
|
Iris.warn("Pack " + key + " has " + keys.size() + " custom biome(s). ");
|
||||||
Iris.warn("Your server version does not yet support datapacks for iris.");
|
Iris.warn("Your server version does not yet support datapacks for iris.");
|
||||||
Iris.warn("The world will generate these biomes as backup biomes.");
|
Iris.warn("The world will generate these biomes as backup biomes.");
|
||||||
Iris.warn("====================================================================================");
|
Iris.warn("====================================================================================");
|
||||||
@@ -260,10 +212,74 @@ public class ServerConfigurator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (warn) {
|
if (warn) {
|
||||||
Iris.error("The Pack " + dimension.getLoadKey() + " is INCAPABLE of generating custom biomes");
|
Iris.error("The Pack " + key + " is INCAPABLE of generating custom biomes");
|
||||||
Iris.error("If not done automatically, restart your server before generating with this pack!");
|
Iris.error("If not done automatically, restart your server before generating with this pack!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return !warn;
|
return !warn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Stream<IrisData> allPacks() {
|
||||||
|
return Stream.concat(listFiles(new File("plugins/Iris/packs")),
|
||||||
|
listFiles(Bukkit.getWorldContainer()).map(w -> new File(w, "iris/pack")))
|
||||||
|
.filter(File::isDirectory)
|
||||||
|
.map(IrisData::get);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static String getWorld(@NonNull IrisData data) {
|
||||||
|
String worldContainer = Bukkit.getWorldContainer().getAbsolutePath();
|
||||||
|
if (!worldContainer.endsWith(File.separator)) worldContainer += File.separator;
|
||||||
|
|
||||||
|
String path = data.getDataFolder().getAbsolutePath();
|
||||||
|
if (!path.startsWith(worldContainer)) return null;
|
||||||
|
int l = path.endsWith(File.separator) ? 11 : 10;
|
||||||
|
return path.substring(worldContainer.length(), path.length() - l);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Stream<File> listFiles(File parent) {
|
||||||
|
var files = parent.listFiles();
|
||||||
|
return files == null ? Stream.empty() : Arrays.stream(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class DimensionHeight {
|
||||||
|
private final IDataFixer fixer;
|
||||||
|
private IrisRange overworld = new IrisRange();
|
||||||
|
private IrisRange nether = new IrisRange();
|
||||||
|
private IrisRange end = new IrisRange();
|
||||||
|
private int logicalOverworld = 0;
|
||||||
|
private int logicalNether = 0;
|
||||||
|
private int logicalEnd = 0;
|
||||||
|
|
||||||
|
public Stream<IrisDimension> merge(IrisData data) {
|
||||||
|
Iris.verbose("Checking Pack: " + data.getDataFolder().getPath());
|
||||||
|
var loader = data.getDimensionLoader();
|
||||||
|
return loader.loadAll(loader.getPossibleKeys())
|
||||||
|
.stream()
|
||||||
|
.peek(this::merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void merge(IrisDimension dimension) {
|
||||||
|
overworld.merge(dimension.getDimensionHeight());
|
||||||
|
nether.merge(dimension.getDimensionHeight());
|
||||||
|
end.merge(dimension.getDimensionHeight());
|
||||||
|
|
||||||
|
logicalOverworld = Math.max(logicalOverworld, dimension.getLogicalHeight());
|
||||||
|
logicalNether = Math.max(logicalNether, dimension.getLogicalHeightNether());
|
||||||
|
logicalEnd = Math.max(logicalEnd, dimension.getLogicalHeightEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String overworldType() {
|
||||||
|
return fixer.createDimension(OVERRWORLD, overworld, logicalOverworld).toString(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String netherType() {
|
||||||
|
return fixer.createDimension(NETHER, nether, logicalNether).toString(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String endType() {
|
||||||
|
return fixer.createDimension(THE_END, end, logicalEnd).toString(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package com.volmit.iris.core.commands;
|
|||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.IrisSettings;
|
import com.volmit.iris.core.IrisSettings;
|
||||||
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.pregenerator.ChunkUpdater;
|
import com.volmit.iris.core.pregenerator.ChunkUpdater;
|
||||||
import com.volmit.iris.core.service.StudioSVC;
|
import com.volmit.iris.core.service.StudioSVC;
|
||||||
import com.volmit.iris.core.tools.IrisBenchmarking;
|
import com.volmit.iris.core.tools.IrisBenchmarking;
|
||||||
@@ -412,7 +413,7 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
) {
|
) {
|
||||||
sender().sendMessage(C.GREEN + "Downloading pack: " + pack + "/" + branch + (trim ? " trimmed" : "") + (overwrite ? " overwriting" : ""));
|
sender().sendMessage(C.GREEN + "Downloading pack: " + pack + "/" + branch + (trim ? " trimmed" : "") + (overwrite ? " overwriting" : ""));
|
||||||
if (pack.equals("overworld")) {
|
if (pack.equals("overworld")) {
|
||||||
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + Iris.OVERWORLD_TAG + "/overworld.zip";
|
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + INMS.OVERWORLD_TAG + "/overworld.zip";
|
||||||
Iris.service(StudioSVC.class).downloadRelease(sender(), url, trim, overwrite);
|
Iris.service(StudioSVC.class).downloadRelease(sender(), url, trim, overwrite);
|
||||||
} else {
|
} else {
|
||||||
Iris.service(StudioSVC.class).downloadSearch(sender(), "IrisDimensions/" + pack + "/" + branch, trim, overwrite);
|
Iris.service(StudioSVC.class).downloadSearch(sender(), "IrisDimensions/" + pack + "/" + branch, trim, overwrite);
|
||||||
@@ -598,10 +599,10 @@ public class CommandIris implements DecreeExecutor {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
|
Iris.info(C.LIGHT_PURPLE + "Preparing Spawn for " + s + "' using Iris:" + generator + "...");
|
||||||
new WorldCreator(s)
|
WorldCreator c = new WorldCreator(s)
|
||||||
.generator(getDefaultWorldGenerator(s, generator))
|
.generator(getDefaultWorldGenerator(s, generator))
|
||||||
.environment(IrisData.loadAnyDimension(generator).getEnvironment())
|
.environment(IrisData.loadAnyDimension(generator).getEnvironment());
|
||||||
.createWorld();
|
INMS.get().createWorld(c);
|
||||||
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
|
Iris.info(C.LIGHT_PURPLE + "Loaded " + s + "!");
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ public class NexoDataProvider extends ExternalDataProvider {
|
|||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Identifier[] getBlockTypes() {
|
public Identifier[] getBlockTypes() {
|
||||||
return Arrays.stream(NexoItems.itemNames())
|
return NexoItems.itemNames().stream()
|
||||||
.map(i -> new Identifier("nexo", i))
|
.map(i -> new Identifier("nexo", i))
|
||||||
.filter(i -> {
|
.filter(i -> {
|
||||||
try {
|
try {
|
||||||
@@ -140,7 +140,7 @@ public class NexoDataProvider extends ExternalDataProvider {
|
|||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public Identifier[] getItemTypes() {
|
public Identifier[] getItemTypes() {
|
||||||
return Arrays.stream(NexoItems.itemNames())
|
return NexoItems.itemNames().stream()
|
||||||
.map(i -> new Identifier("nexo", i))
|
.map(i -> new Identifier("nexo", i))
|
||||||
.filter(i -> {
|
.filter(i -> {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.volmit.iris.core.IrisSettings;
|
|||||||
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
import com.volmit.iris.core.nms.v1X.NMSBinding1X;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class INMS {
|
public class INMS {
|
||||||
@@ -35,8 +36,15 @@ public class INMS {
|
|||||||
"1.21.3", "v1_21_R2",
|
"1.21.3", "v1_21_R2",
|
||||||
"1.21.4", "v1_21_R3"
|
"1.21.4", "v1_21_R3"
|
||||||
);
|
);
|
||||||
|
private static final List<Version> PACKS = List.of(
|
||||||
|
new Version(21, 4, "31010"),
|
||||||
|
new Version(21, 2, "31000"),
|
||||||
|
new Version(20, 1, "3910")
|
||||||
|
);
|
||||||
|
|
||||||
//@done
|
//@done
|
||||||
private static final INMSBinding binding = bind();
|
private static final INMSBinding binding = bind();
|
||||||
|
public static final String OVERWORLD_TAG = getOverworldTag();
|
||||||
|
|
||||||
public static INMSBinding get() {
|
public static INMSBinding get() {
|
||||||
return binding;
|
return binding;
|
||||||
@@ -87,4 +95,26 @@ public class INMS {
|
|||||||
|
|
||||||
return new NMSBinding1X();
|
return new NMSBinding1X();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getOverworldTag() {
|
||||||
|
var version = Bukkit.getServer().getBukkitVersion().split("-")[0].split("\\.", 3);
|
||||||
|
int major = 0;
|
||||||
|
int minor = 0;
|
||||||
|
|
||||||
|
if (version.length > 2) {
|
||||||
|
major = Integer.parseInt(version[1]);
|
||||||
|
minor = Integer.parseInt(version[2]);
|
||||||
|
} else if (version.length == 2) {
|
||||||
|
major = Integer.parseInt(version[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var p : PACKS) {
|
||||||
|
if (p.major > major || p.minor > minor)
|
||||||
|
continue;
|
||||||
|
return p.tag;
|
||||||
|
}
|
||||||
|
return "3910";
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Version(int major, int minor, String tag) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,9 @@
|
|||||||
|
|
||||||
package com.volmit.iris.core.nms;
|
package com.volmit.iris.core.nms;
|
||||||
|
|
||||||
|
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;
|
||||||
@@ -91,7 +93,9 @@ 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) {
|
||||||
return c.createWorld();
|
try (var ignored = injectLevelStems()) {
|
||||||
|
return c.createWorld();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int countCustomBiomes();
|
int countCustomBiomes();
|
||||||
@@ -125,4 +129,12 @@ public interface INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KList<String> getStructureKeys();
|
KList<String> getStructureKeys();
|
||||||
|
|
||||||
|
default AutoClosing injectLevelStems() {
|
||||||
|
return new AutoClosing(() -> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
default Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||||
|
return new Pair<>(0, injectLevelStems());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.volmit.iris.core.nms.container;
|
||||||
|
|
||||||
|
import com.volmit.iris.util.function.NastyRunnable;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AutoClosing implements AutoCloseable {
|
||||||
|
private final AtomicBoolean closed = new AtomicBoolean();
|
||||||
|
private final NastyRunnable action;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (closed.getAndSet(true)) return;
|
||||||
|
try {
|
||||||
|
action.run();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,28 @@
|
|||||||
package com.volmit.iris.core.nms.datapack;
|
package com.volmit.iris.core.nms.datapack;
|
||||||
|
|
||||||
import com.volmit.iris.engine.object.IrisBiomeCustom;
|
import com.volmit.iris.engine.object.IrisBiomeCustom;
|
||||||
|
import com.volmit.iris.engine.object.IrisRange;
|
||||||
import com.volmit.iris.util.json.JSONObject;
|
import com.volmit.iris.util.json.JSONObject;
|
||||||
|
|
||||||
public interface IDataFixer {
|
public interface IDataFixer {
|
||||||
|
|
||||||
JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json);
|
default JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
JSONObject fixDimension(JSONObject json);
|
JSONObject rawDimension(Dimension dimension);
|
||||||
|
|
||||||
|
default JSONObject createDimension(Dimension dimension, IrisRange height, int logicalHeight) {
|
||||||
|
JSONObject obj = rawDimension(dimension);
|
||||||
|
obj.put("min_y", height.getMin());
|
||||||
|
obj.put("height", height.getMax() - height.getMin());
|
||||||
|
obj.put("logical_height", logicalHeight);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Dimension {
|
||||||
|
OVERRWORLD,
|
||||||
|
NETHER,
|
||||||
|
THE_END
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,81 @@
|
|||||||
package com.volmit.iris.core.nms.datapack.v1192;
|
package com.volmit.iris.core.nms.datapack.v1192;
|
||||||
|
|
||||||
import com.volmit.iris.core.nms.datapack.IDataFixer;
|
import com.volmit.iris.core.nms.datapack.IDataFixer;
|
||||||
import com.volmit.iris.engine.object.IrisBiomeCustom;
|
|
||||||
import com.volmit.iris.util.json.JSONObject;
|
import com.volmit.iris.util.json.JSONObject;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class DataFixerV1192 implements IDataFixer {
|
public class DataFixerV1192 implements IDataFixer {
|
||||||
|
|
||||||
@Override
|
private static final Map<Dimension, String> DIMENSIONS = Map.of(
|
||||||
public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
|
Dimension.OVERRWORLD, """
|
||||||
return json;
|
{
|
||||||
}
|
"ambient_light": 0.0,
|
||||||
|
"bed_works": true,
|
||||||
|
"coordinate_scale": 1.0,
|
||||||
|
"effects": "minecraft:overworld",
|
||||||
|
"has_ceiling": false,
|
||||||
|
"has_raids": true,
|
||||||
|
"has_skylight": true,
|
||||||
|
"infiniburn": "#minecraft:infiniburn_overworld",
|
||||||
|
"monster_spawn_block_light_limit": 0,
|
||||||
|
"monster_spawn_light_level": {
|
||||||
|
"type": "minecraft:uniform",
|
||||||
|
"value": {
|
||||||
|
"max_inclusive": 7,
|
||||||
|
"min_inclusive": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"natural": true,
|
||||||
|
"piglin_safe": false,
|
||||||
|
"respawn_anchor_works": false,
|
||||||
|
"ultrawarm": false
|
||||||
|
}""",
|
||||||
|
Dimension.NETHER, """
|
||||||
|
{
|
||||||
|
"ambient_light": 0.1,
|
||||||
|
"bed_works": false,
|
||||||
|
"coordinate_scale": 8.0,
|
||||||
|
"effects": "minecraft:the_nether",
|
||||||
|
"fixed_time": 18000,
|
||||||
|
"has_ceiling": true,
|
||||||
|
"has_raids": false,
|
||||||
|
"has_skylight": false,
|
||||||
|
"infiniburn": "#minecraft:infiniburn_nether",
|
||||||
|
"monster_spawn_block_light_limit": 15,
|
||||||
|
"monster_spawn_light_level": 7,
|
||||||
|
"natural": false,
|
||||||
|
"piglin_safe": true,
|
||||||
|
"respawn_anchor_works": true,
|
||||||
|
"ultrawarm": true
|
||||||
|
}""",
|
||||||
|
Dimension.THE_END, """
|
||||||
|
{
|
||||||
|
"ambient_light": 0.0,
|
||||||
|
"bed_works": false,
|
||||||
|
"coordinate_scale": 1.0,
|
||||||
|
"effects": "minecraft:the_end",
|
||||||
|
"fixed_time": 6000,
|
||||||
|
"has_ceiling": false,
|
||||||
|
"has_raids": true,
|
||||||
|
"has_skylight": false,
|
||||||
|
"infiniburn": "#minecraft:infiniburn_end",
|
||||||
|
"monster_spawn_block_light_limit": 0,
|
||||||
|
"monster_spawn_light_level": {
|
||||||
|
"type": "minecraft:uniform",
|
||||||
|
"value": {
|
||||||
|
"max_inclusive": 7,
|
||||||
|
"min_inclusive": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"natural": false,
|
||||||
|
"piglin_safe": false,
|
||||||
|
"respawn_anchor_works": false,
|
||||||
|
"ultrawarm": false
|
||||||
|
}"""
|
||||||
|
);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject fixDimension(JSONObject json) {
|
public JSONObject rawDimension(Dimension dimension) {
|
||||||
return json;
|
return new JSONObject(DIMENSIONS.get(dimension));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.volmit.iris.core.nms.datapack.v1206;
|
package com.volmit.iris.core.nms.datapack.v1206;
|
||||||
|
|
||||||
import com.volmit.iris.core.nms.datapack.IDataFixer;
|
import com.volmit.iris.core.nms.datapack.v1192.DataFixerV1192;
|
||||||
import com.volmit.iris.engine.object.IrisBiomeCustom;
|
import com.volmit.iris.engine.object.IrisBiomeCustom;
|
||||||
import com.volmit.iris.engine.object.IrisBiomeCustomSpawn;
|
import com.volmit.iris.engine.object.IrisBiomeCustomSpawn;
|
||||||
import com.volmit.iris.engine.object.IrisBiomeCustomSpawnType;
|
import com.volmit.iris.engine.object.IrisBiomeCustomSpawnType;
|
||||||
@@ -10,7 +10,7 @@ import com.volmit.iris.util.json.JSONObject;
|
|||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class DataFixerV1206 implements IDataFixer {
|
public class DataFixerV1206 extends DataFixerV1192 {
|
||||||
@Override
|
@Override
|
||||||
public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
|
public JSONObject fixCustomBiome(IrisBiomeCustom biome, JSONObject json) {
|
||||||
int spawnRarity = biome.getSpawnRarity();
|
int spawnRarity = biome.getSpawnRarity();
|
||||||
@@ -45,7 +45,8 @@ public class DataFixerV1206 implements IDataFixer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JSONObject fixDimension(JSONObject json) {
|
public JSONObject rawDimension(Dimension dimension) {
|
||||||
|
JSONObject json = super.rawDimension(dimension);
|
||||||
if (!(json.get("monster_spawn_light_level") instanceof JSONObject lightLevel))
|
if (!(json.get("monster_spawn_light_level") instanceof JSONObject lightLevel))
|
||||||
return json;
|
return json;
|
||||||
var value = (JSONObject) lightLevel.remove("value");
|
var value = (JSONObject) lightLevel.remove("value");
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.volmit.iris.Iris;
|
|||||||
import com.volmit.iris.core.IrisSettings;
|
import com.volmit.iris.core.IrisSettings;
|
||||||
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.INMS;
|
||||||
import com.volmit.iris.core.pack.IrisPack;
|
import com.volmit.iris.core.pack.IrisPack;
|
||||||
import com.volmit.iris.core.project.IrisProject;
|
import com.volmit.iris.core.project.IrisProject;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
@@ -64,7 +65,7 @@ public class StudioSVC implements IrisService {
|
|||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
Iris.info("Downloading Default Pack " + pack);
|
Iris.info("Downloading Default Pack " + pack);
|
||||||
if (pack.equals("overworld")) {
|
if (pack.equals("overworld")) {
|
||||||
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + Iris.OVERWORLD_TAG + "/overworld.zip";
|
String url = "https://github.com/IrisDimensions/overworld/releases/download/" + INMS.OVERWORLD_TAG + "/overworld.zip";
|
||||||
Iris.service(StudioSVC.class).downloadRelease(Iris.getSender(), url, false, false);
|
Iris.service(StudioSVC.class).downloadRelease(Iris.getSender(), url, false, false);
|
||||||
} else {
|
} else {
|
||||||
downloadSearch(Iris.getSender(), pack, false);
|
downloadSearch(Iris.getSender(), pack, false);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ 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.ServerConfigurator;
|
import com.volmit.iris.core.ServerConfigurator;
|
||||||
|
import com.volmit.iris.core.nms.INMS;
|
||||||
import com.volmit.iris.core.pregenerator.PregenTask;
|
import com.volmit.iris.core.pregenerator.PregenTask;
|
||||||
import com.volmit.iris.core.service.StudioSVC;
|
import com.volmit.iris.core.service.StudioSVC;
|
||||||
import com.volmit.iris.engine.object.IrisDimension;
|
import com.volmit.iris.engine.object.IrisDimension;
|
||||||
@@ -170,7 +171,7 @@ public class IrisCreator {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
J.sfut(() -> {
|
J.sfut(() -> {
|
||||||
world.set(wc.createWorld());
|
world.set(INMS.get().createWorld(wc));
|
||||||
}).get();
|
}).get();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@@ -21,10 +21,13 @@ package com.volmit.iris.core.tools;
|
|||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
import com.volmit.iris.engine.object.*;
|
import com.volmit.iris.engine.object.*;
|
||||||
import com.volmit.iris.engine.platform.BukkitChunkGenerator;
|
import com.volmit.iris.engine.platform.BukkitChunkGenerator;
|
||||||
|
import com.volmit.iris.util.reflect.WrappedField;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.WorldCreator;
|
import org.bukkit.WorldCreator;
|
||||||
|
import org.bukkit.WorldType;
|
||||||
import org.bukkit.generator.ChunkGenerator;
|
import org.bukkit.generator.ChunkGenerator;
|
||||||
|
import sun.misc.Unsafe;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ import java.util.concurrent.CompletableFuture;
|
|||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@@ -299,28 +300,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
energy += 1.2;
|
energy += 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//@builder
|
|
||||||
IrisBiome biome = IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()
|
|
||||||
? getEngine().getSurfaceBiome(c) : null;
|
|
||||||
IrisEntitySpawn v = IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()
|
|
||||||
? spawnRandomly(Stream.concat(getData().getSpawnerLoader()
|
|
||||||
.loadAll(getDimension().getEntitySpawners())
|
|
||||||
.shuffleCopy(RNG.r).stream()
|
|
||||||
.filter(this::canSpawn)
|
|
||||||
.filter((i) -> i.isValid(biome))
|
|
||||||
.flatMap((i) -> stream(i, initial)),
|
|
||||||
Stream.concat(getData().getSpawnerLoader()
|
|
||||||
.loadAll(getEngine().getRegion(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
|
|
||||||
.shuffleCopy(RNG.r).stream().filter(this::canSpawn)
|
|
||||||
.flatMap((i) -> stream(i, initial)),
|
|
||||||
getData().getSpawnerLoader()
|
|
||||||
.loadAll(getEngine().getSurfaceBiome(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
|
|
||||||
.shuffleCopy(RNG.r).stream().filter(this::canSpawn)
|
|
||||||
.flatMap((i) -> stream(i, initial))))
|
|
||||||
.collect(Collectors.toList()))
|
|
||||||
.popRandom(RNG.r) : null;
|
|
||||||
//@done
|
|
||||||
|
|
||||||
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
|
if (IrisSettings.get().getWorld().isMarkerEntitySpawningSystem()) {
|
||||||
getSpawnersFromMarkers(c).forEach((blockf, spawners) -> {
|
getSpawnersFromMarkers(c).forEach((blockf, spawners) -> {
|
||||||
if (spawners.isEmpty()) {
|
if (spawners.isEmpty()) {
|
||||||
@@ -335,94 +314,67 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v != null && v.getReferenceSpawner() != null) {
|
if (!IrisSettings.get().getWorld().isAnbientEntitySpawningSystem()) {
|
||||||
int maxEntCount = v.getReferenceSpawner().getMaxEntitiesPerChunk();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (Entity i : c.getEntities()) {
|
//@builder
|
||||||
if (i instanceof LivingEntity) {
|
Predicate<IrisSpawner> filter = i -> i.canSpawn(getEngine(), c.getX(), c.getZ());
|
||||||
if (-maxEntCount <= 0) {
|
ChunkCounter counter = new ChunkCounter(c.getEntities());
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
IrisBiome biome = getEngine().getSurfaceBiome(c);
|
||||||
spawn(c, v);
|
IrisEntitySpawn v = spawnRandomly(Stream.concat(getData().getSpawnerLoader()
|
||||||
} catch (Throwable e) {
|
.loadAll(getDimension().getEntitySpawners())
|
||||||
J.s(() -> spawn(c, v));
|
.shuffleCopy(RNG.r)
|
||||||
}
|
.stream()
|
||||||
|
.filter(filter)
|
||||||
|
.filter((i) -> i.isValid(biome)),
|
||||||
|
Stream.concat(getData()
|
||||||
|
.getSpawnerLoader()
|
||||||
|
.loadAll(getEngine().getRegion(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
|
||||||
|
.shuffleCopy(RNG.r)
|
||||||
|
.stream()
|
||||||
|
.filter(filter),
|
||||||
|
getData().getSpawnerLoader()
|
||||||
|
.loadAll(getEngine().getSurfaceBiome(c.getX() << 4, c.getZ() << 4).getEntitySpawners())
|
||||||
|
.shuffleCopy(RNG.r)
|
||||||
|
.stream()
|
||||||
|
.filter(filter)))
|
||||||
|
.filter(counter)
|
||||||
|
.flatMap((i) -> stream(i, initial))
|
||||||
|
.collect(Collectors.toList()))
|
||||||
|
.getRandom();
|
||||||
|
//@done
|
||||||
|
if (v == null || v.getReferenceSpawner() == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
spawn(c, v);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
J.s(() -> spawn(c, v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void spawn(Chunk c, IrisEntitySpawn i) {
|
private void spawn(Chunk c, IrisEntitySpawn i) {
|
||||||
boolean allow = true;
|
IrisSpawner ref = i.getReferenceSpawner();
|
||||||
|
int s = i.spawn(getEngine(), c, RNG.r);
|
||||||
if (!i.getReferenceSpawner().getMaximumRatePerChunk().isInfinite()) {
|
actuallySpawned += s;
|
||||||
allow = false;
|
if (s > 0) {
|
||||||
IrisEngineChunkData cd = getEngine().getEngineData().getChunk(c.getX(), c.getZ());
|
ref.spawn(getEngine(), c.getX(), c.getZ());
|
||||||
IrisEngineSpawnerCooldown sc = null;
|
energy -= s * ((i.getEnergyMultiplier() * ref.getEnergyMultiplier() * 1));
|
||||||
for (IrisEngineSpawnerCooldown j : cd.getCooldowns()) {
|
|
||||||
if (j.getSpawner().equals(i.getReferenceSpawner().getLoadKey())) {
|
|
||||||
sc = j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sc == null) {
|
|
||||||
sc = new IrisEngineSpawnerCooldown();
|
|
||||||
sc.setSpawner(i.getReferenceSpawner().getLoadKey());
|
|
||||||
cd.getCooldowns().add(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sc.canSpawn(i.getReferenceSpawner().getMaximumRatePerChunk())) {
|
|
||||||
sc.spawn(getEngine());
|
|
||||||
allow = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allow) {
|
|
||||||
int s = i.spawn(getEngine(), c, RNG.r);
|
|
||||||
actuallySpawned += s;
|
|
||||||
if (s > 0) {
|
|
||||||
getCooldown(i.getReferenceSpawner()).spawn(getEngine());
|
|
||||||
energy -= s * ((i.getEnergyMultiplier() * i.getReferenceSpawner().getEnergyMultiplier() * 1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void spawn(IrisPosition c, IrisEntitySpawn i) {
|
private void spawn(IrisPosition pos, IrisEntitySpawn i) {
|
||||||
boolean allow = true;
|
IrisSpawner ref = i.getReferenceSpawner();
|
||||||
|
if (!ref.canSpawn(getEngine(), pos.getX() >> 4, pos.getZ()))
|
||||||
|
return;
|
||||||
|
|
||||||
if (!i.getReferenceSpawner().getMaximumRatePerChunk().isInfinite()) {
|
int s = i.spawn(getEngine(), pos, RNG.r);
|
||||||
allow = false;
|
actuallySpawned += s;
|
||||||
IrisEngineChunkData cd = getEngine().getEngineData().getChunk(c.getX() >> 4, c.getZ() >> 4);
|
if (s > 0) {
|
||||||
IrisEngineSpawnerCooldown sc = null;
|
ref.spawn(getEngine(), pos.getX() >> 4, pos.getZ() >> 4);
|
||||||
for (IrisEngineSpawnerCooldown j : cd.getCooldowns()) {
|
energy -= s * ((i.getEnergyMultiplier() * ref.getEnergyMultiplier() * 1));
|
||||||
if (j.getSpawner().equals(i.getReferenceSpawner().getLoadKey())) {
|
|
||||||
sc = j;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sc == null) {
|
|
||||||
sc = new IrisEngineSpawnerCooldown();
|
|
||||||
sc.setSpawner(i.getReferenceSpawner().getLoadKey());
|
|
||||||
cd.getCooldowns().add(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sc.canSpawn(i.getReferenceSpawner().getMaximumRatePerChunk())) {
|
|
||||||
sc.spawn(getEngine());
|
|
||||||
allow = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allow) {
|
|
||||||
int s = i.spawn(getEngine(), c, RNG.r);
|
|
||||||
actuallySpawned += s;
|
|
||||||
if (s > 0) {
|
|
||||||
getCooldown(i.getReferenceSpawner()).spawn(getEngine());
|
|
||||||
energy -= s * ((i.getEnergyMultiplier() * i.getReferenceSpawner().getEnergyMultiplier() * 1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,31 +402,6 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
return rarityTypes;
|
return rarityTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canSpawn(IrisSpawner i) {
|
|
||||||
return i.isValid(getEngine().getWorld().realWorld())
|
|
||||||
&& getCooldown(i).canSpawn(i.getMaximumRate());
|
|
||||||
}
|
|
||||||
|
|
||||||
private IrisEngineSpawnerCooldown getCooldown(IrisSpawner i) {
|
|
||||||
IrisEngineData ed = getEngine().getEngineData();
|
|
||||||
IrisEngineSpawnerCooldown cd = null;
|
|
||||||
|
|
||||||
for (IrisEngineSpawnerCooldown j : ed.getSpawnerCooldowns().copy()) {
|
|
||||||
if (j.getSpawner().equals(i.getLoadKey())) {
|
|
||||||
cd = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cd == null) {
|
|
||||||
cd = new IrisEngineSpawnerCooldown();
|
|
||||||
cd.setSpawner(i.getLoadKey());
|
|
||||||
cd.setLastSpawn(M.ms() - i.getMaximumRate().getInterval());
|
|
||||||
ed.getSpawnerCooldowns().add(cd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return cd;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTick() {
|
public void onTick() {
|
||||||
|
|
||||||
@@ -708,4 +635,27 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
|
|
||||||
return (double) entityCount / (getEngine().getWorld().realWorld().getLoadedChunks().length + 1) * 1.28;
|
return (double) entityCount / (getEngine().getWorld().realWorld().getLoadedChunks().length + 1) * 1.28;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
private static class ChunkCounter implements Predicate<IrisSpawner> {
|
||||||
|
private final Entity[] entities;
|
||||||
|
private transient int index = 0;
|
||||||
|
private transient int count = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(IrisSpawner spawner) {
|
||||||
|
int max = spawner.getMaxEntitiesPerChunk();
|
||||||
|
if (max <= count)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (index < entities.length) {
|
||||||
|
if (entities[index++] instanceof LivingEntity) {
|
||||||
|
if (++count >= max)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
|
import com.volmit.iris.core.nms.INMS;
|
||||||
|
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||||
|
import com.volmit.iris.util.misc.ServerProperties;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.world.WorldInitEvent;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.volmit.iris.Iris.instance;
|
||||||
|
|
||||||
|
public class IrisContextInjector implements Listener {
|
||||||
|
private AutoClosing autoClosing = null;
|
||||||
|
private final int totalWorlds;
|
||||||
|
private int worldCounter = 0;
|
||||||
|
|
||||||
|
public IrisContextInjector() {
|
||||||
|
if (!Bukkit.getWorlds().isEmpty()) {
|
||||||
|
totalWorlds = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String levelName = ServerProperties.LEVEL_NAME;
|
||||||
|
List<String> irisWorlds = irisWorlds();
|
||||||
|
boolean overworld = irisWorlds.contains(levelName);
|
||||||
|
boolean nether = irisWorlds.contains(levelName + "_nether");
|
||||||
|
boolean end = irisWorlds.contains(levelName + "_end");
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
if (Bukkit.getAllowNether()) i++;
|
||||||
|
if (Bukkit.getAllowEnd()) i++;
|
||||||
|
|
||||||
|
if (overworld || nether || end) {
|
||||||
|
var pair = INMS.get().injectUncached(overworld, nether, end);
|
||||||
|
i += pair.getA() - 3;
|
||||||
|
autoClosing = pair.getB();
|
||||||
|
}
|
||||||
|
|
||||||
|
totalWorlds = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void on(WorldInitEvent event) {
|
||||||
|
if (++worldCounter < totalWorlds) return;
|
||||||
|
if (autoClosing != null) {
|
||||||
|
autoClosing.close();
|
||||||
|
autoClosing = null;
|
||||||
|
}
|
||||||
|
instance.unregisterListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> irisWorlds() {
|
||||||
|
var config = YamlConfiguration.loadConfiguration(ServerProperties.BUKKIT_YML);
|
||||||
|
ConfigurationSection section = config.getConfigurationSection("worlds");
|
||||||
|
if (section == null) return List.of();
|
||||||
|
|
||||||
|
return section.getKeys(false)
|
||||||
|
.stream()
|
||||||
|
.filter(k -> section.getString(k + ".generator", "").startsWith("Iris"))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
package com.volmit.iris.engine.object;
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.IrisSettings;
|
||||||
|
import com.volmit.iris.core.ServerConfigurator.DimensionHeight;
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
import com.volmit.iris.core.loader.IrisRegistrant;
|
import com.volmit.iris.core.loader.IrisRegistrant;
|
||||||
import com.volmit.iris.core.nms.INMS;
|
import com.volmit.iris.core.nms.INMS;
|
||||||
@@ -26,6 +28,7 @@ import com.volmit.iris.core.nms.datapack.IDataFixer;
|
|||||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||||
import com.volmit.iris.engine.object.annotations.*;
|
import com.volmit.iris.engine.object.annotations.*;
|
||||||
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.data.DataProvider;
|
import com.volmit.iris.util.data.DataProvider;
|
||||||
import com.volmit.iris.util.io.IO;
|
import com.volmit.iris.util.io.IO;
|
||||||
import com.volmit.iris.util.json.JSONObject;
|
import com.volmit.iris.util.json.JSONObject;
|
||||||
@@ -54,73 +57,6 @@ import java.io.IOException;
|
|||||||
public class IrisDimension extends IrisRegistrant {
|
public class IrisDimension extends IrisRegistrant {
|
||||||
public static final BlockData STONE = Material.STONE.createBlockData();
|
public static final BlockData STONE = Material.STONE.createBlockData();
|
||||||
public static final BlockData WATER = Material.WATER.createBlockData();
|
public static final BlockData WATER = Material.WATER.createBlockData();
|
||||||
private static final String DP_OVERWORLD_DEFAULT = """
|
|
||||||
{
|
|
||||||
"ambient_light": 0.0,
|
|
||||||
"bed_works": true,
|
|
||||||
"coordinate_scale": 1.0,
|
|
||||||
"effects": "minecraft:overworld",
|
|
||||||
"has_ceiling": false,
|
|
||||||
"has_raids": true,
|
|
||||||
"has_skylight": true,
|
|
||||||
"infiniburn": "#minecraft:infiniburn_overworld",
|
|
||||||
"monster_spawn_block_light_limit": 0,
|
|
||||||
"monster_spawn_light_level": {
|
|
||||||
"type": "minecraft:uniform",
|
|
||||||
"value": {
|
|
||||||
"max_inclusive": 7,
|
|
||||||
"min_inclusive": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"natural": true,
|
|
||||||
"piglin_safe": false,
|
|
||||||
"respawn_anchor_works": false,
|
|
||||||
"ultrawarm": false
|
|
||||||
}""";
|
|
||||||
|
|
||||||
private static final String DP_NETHER_DEFAULT = """
|
|
||||||
{
|
|
||||||
"ambient_light": 0.1,
|
|
||||||
"bed_works": false,
|
|
||||||
"coordinate_scale": 8.0,
|
|
||||||
"effects": "minecraft:the_nether",
|
|
||||||
"fixed_time": 18000,
|
|
||||||
"has_ceiling": true,
|
|
||||||
"has_raids": false,
|
|
||||||
"has_skylight": false,
|
|
||||||
"infiniburn": "#minecraft:infiniburn_nether",
|
|
||||||
"monster_spawn_block_light_limit": 15,
|
|
||||||
"monster_spawn_light_level": 7,
|
|
||||||
"natural": false,
|
|
||||||
"piglin_safe": true,
|
|
||||||
"respawn_anchor_works": true,
|
|
||||||
"ultrawarm": true
|
|
||||||
}""";
|
|
||||||
|
|
||||||
private static final String DP_END_DEFAULT = """
|
|
||||||
{
|
|
||||||
"ambient_light": 0.0,
|
|
||||||
"bed_works": false,
|
|
||||||
"coordinate_scale": 1.0,
|
|
||||||
"effects": "minecraft:the_end",
|
|
||||||
"fixed_time": 6000,
|
|
||||||
"has_ceiling": false,
|
|
||||||
"has_raids": true,
|
|
||||||
"has_skylight": false,
|
|
||||||
"infiniburn": "#minecraft:infiniburn_end",
|
|
||||||
"monster_spawn_block_light_limit": 0,
|
|
||||||
"monster_spawn_light_level": {
|
|
||||||
"type": "minecraft:uniform",
|
|
||||||
"value": {
|
|
||||||
"max_inclusive": 7,
|
|
||||||
"min_inclusive": 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"natural": false,
|
|
||||||
"piglin_safe": false,
|
|
||||||
"respawn_anchor_works": false,
|
|
||||||
"ultrawarm": false
|
|
||||||
}""";
|
|
||||||
private final transient AtomicCache<Position2> parallaxSize = new AtomicCache<>();
|
private final transient AtomicCache<Position2> parallaxSize = new AtomicCache<>();
|
||||||
private final transient AtomicCache<CNG> rockLayerGenerator = new AtomicCache<>();
|
private final transient AtomicCache<CNG> rockLayerGenerator = new AtomicCache<>();
|
||||||
private final transient AtomicCache<CNG> fluidLayerGenerator = new AtomicCache<>();
|
private final transient AtomicCache<CNG> fluidLayerGenerator = new AtomicCache<>();
|
||||||
@@ -443,61 +379,35 @@ public class IrisDimension extends IrisRegistrant {
|
|||||||
return landBiomeStyle;
|
return landBiomeStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean installDataPack(IDataFixer fixer, DataProvider data, File datapacks, double ultimateMaxHeight, double ultimateMinHeight) {
|
public void installBiomes(IDataFixer fixer, DataProvider data, KList<File> folders, KSet<String> biomes) {
|
||||||
boolean write = false;
|
getAllBiomes(data)
|
||||||
boolean changed = false;
|
.stream()
|
||||||
|
.filter(IrisBiome::isCustom)
|
||||||
IO.delete(new File(datapacks, "iris/data/" + getLoadKey().toLowerCase()));
|
.map(IrisBiome::getCustomDerivitives)
|
||||||
|
.flatMap(KList::stream)
|
||||||
for (IrisBiome i : getAllBiomes(data)) {
|
.parallel()
|
||||||
if (i.isCustom()) {
|
.forEach(j -> {
|
||||||
write = true;
|
String json = j.generateJson(fixer);
|
||||||
|
synchronized (biomes) {
|
||||||
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
|
if (!biomes.add(j.getId())) {
|
||||||
File output = new File(datapacks, "iris/data/" + getLoadKey().toLowerCase() + "/worldgen/biome/" + j.getId() + ".json");
|
Iris.verbose("Duplicate Data Pack Biome: " + getLoadKey() + "/" + j.getId());
|
||||||
|
return;
|
||||||
if (!output.exists()) {
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iris.verbose(" Installing Data Pack Biome: " + output.getPath());
|
|
||||||
output.getParentFile().mkdirs();
|
|
||||||
try {
|
|
||||||
IO.writeAll(output, j.generateJson(fixer));
|
|
||||||
} catch (IOException e) {
|
|
||||||
Iris.reportError(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dimensionHeight.equals(new IrisRange(-64, 320)) && this.name.equalsIgnoreCase("overworld")) {
|
|
||||||
Iris.verbose(" Installing Data Pack Dimension Types: \"minecraft:overworld\", \"minecraft:the_nether\", \"minecraft:the_end\"");
|
|
||||||
dimensionHeight.setMax(ultimateMaxHeight);
|
|
||||||
dimensionHeight.setMin(ultimateMinHeight);
|
|
||||||
changed = writeDimensionType(fixer, changed, datapacks);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (write) {
|
|
||||||
File mcm = new File(datapacks, "iris/pack.mcmeta");
|
|
||||||
try {
|
|
||||||
IO.writeAll(mcm, """
|
|
||||||
{
|
|
||||||
"pack": {
|
|
||||||
"description": "Iris Data Pack. This pack contains all installed Iris Packs' resources.",
|
|
||||||
"pack_format": {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
""".replace("{}", INMS.get().getDataVersion().getPackFormat() + ""));
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
Iris.reportError(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
Iris.verbose(" Installing Data Pack MCMeta: " + mcm.getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
for (File datapacks : folders) {
|
||||||
|
File output = new File(datapacks, "iris/data/" + getLoadKey().toLowerCase() + "/worldgen/biome/" + j.getId() + ".json");
|
||||||
|
|
||||||
|
Iris.verbose(" Installing Data Pack Biome: " + output.getPath());
|
||||||
|
output.getParentFile().mkdirs();
|
||||||
|
try {
|
||||||
|
IO.writeAll(output, json);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -515,66 +425,55 @@ public class IrisDimension extends IrisRegistrant {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean writeDimensionType(IDataFixer fixer, boolean changed, File datapacks) {
|
public static void writeShared(KList<File> folders, DimensionHeight height) {
|
||||||
File dimTypeOverworld = new File(datapacks, "iris/data/minecraft/dimension_type/overworld.json");
|
Iris.verbose(" Installing Data Pack Dimension Types: \"iris:overworld\", \"iris:the_nether\", \"iris:the_end\"");
|
||||||
if (!dimTypeOverworld.exists())
|
for (File datapacks : folders) {
|
||||||
changed = true;
|
write(datapacks, "overworld", height.overworldType());
|
||||||
dimTypeOverworld.getParentFile().mkdirs();
|
write(datapacks, "the_nether", height.netherType());
|
||||||
|
write(datapacks, "the_end", height.endType());
|
||||||
|
}
|
||||||
|
|
||||||
|
String raw = """
|
||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "Iris Data Pack. This pack contains all installed Iris Packs' resources.",
|
||||||
|
"pack_format": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".replace("{}", INMS.get().getDataVersion().getPackFormat() + "");
|
||||||
|
|
||||||
|
for (File datapacks : folders) {
|
||||||
|
File mcm = new File(datapacks, "iris/pack.mcmeta");
|
||||||
|
try {
|
||||||
|
IO.writeAll(mcm, raw);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
Iris.verbose(" Installing Data Pack MCMeta: " + mcm.getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void write(File datapacks, String type, String json) {
|
||||||
|
File dimType = new File(datapacks, "iris/data/iris/dimension_type/" + type + ".json");
|
||||||
|
File dimTypeVanilla = new File(datapacks, "iris/data/minecraft/dimension_type/" + type + ".json");
|
||||||
|
|
||||||
|
dimType.getParentFile().mkdirs();
|
||||||
try {
|
try {
|
||||||
IO.writeAll(dimTypeOverworld, generateDatapackJsonOverworld(fixer));
|
IO.writeAll(dimType, json);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IrisSettings.get().getGeneral().adjustVanillaHeight || dimTypeVanilla.exists()) {
|
||||||
File dimTypeNether = new File(datapacks, "iris/data/minecraft/dimension_type/the_nether.json");
|
dimTypeVanilla.getParentFile().mkdirs();
|
||||||
if (!dimTypeNether.exists())
|
try {
|
||||||
changed = true;
|
IO.writeAll(dimTypeVanilla, json);
|
||||||
dimTypeNether.getParentFile().mkdirs();
|
} catch (IOException e) {
|
||||||
try {
|
Iris.reportError(e);
|
||||||
IO.writeAll(dimTypeNether, generateDatapackJsonNether(fixer));
|
e.printStackTrace();
|
||||||
} catch (IOException e) {
|
}
|
||||||
Iris.reportError(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
File dimTypeEnd = new File(datapacks, "iris/data/minecraft/dimension_type/the_end.json");
|
|
||||||
if (!dimTypeEnd.exists())
|
|
||||||
changed = true;
|
|
||||||
dimTypeEnd.getParentFile().mkdirs();
|
|
||||||
try {
|
|
||||||
IO.writeAll(dimTypeEnd, generateDatapackJsonEnd(fixer));
|
|
||||||
} catch (IOException e) {
|
|
||||||
Iris.reportError(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String generateDatapackJsonOverworld(IDataFixer fixer) {
|
|
||||||
JSONObject obj = new JSONObject(DP_OVERWORLD_DEFAULT);
|
|
||||||
obj.put("min_y", dimensionHeight.getMin());
|
|
||||||
obj.put("height", dimensionHeight.getMax() - dimensionHeight.getMin());
|
|
||||||
obj.put("logical_height", logicalHeight);
|
|
||||||
return fixer.fixDimension(obj).toString(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String generateDatapackJsonNether(IDataFixer fixer) {
|
|
||||||
JSONObject obj = new JSONObject(DP_NETHER_DEFAULT);
|
|
||||||
obj.put("min_y", dimensionHeightNether.getMin());
|
|
||||||
obj.put("height", dimensionHeightNether.getMax() - dimensionHeightNether.getMin());
|
|
||||||
obj.put("logical_height", logicalHeightNether);
|
|
||||||
return fixer.fixDimension(obj).toString(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String generateDatapackJsonEnd(IDataFixer fixer) {
|
|
||||||
JSONObject obj = new JSONObject(DP_END_DEFAULT);
|
|
||||||
obj.put("min_y", dimensionHeightEnd.getMin());
|
|
||||||
obj.put("height", dimensionHeightEnd.getMax() - dimensionHeightEnd.getMin());
|
|
||||||
obj.put("logical_height", logicalHeightEnd);
|
|
||||||
return fixer.fixDimension(obj).toString(4);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
|
||||||
* Copyright (c) 2022 Arcane Arts (Volmit Software)
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.volmit.iris.engine.object;
|
|
||||||
|
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
|
||||||
import com.volmit.iris.util.collection.KList;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class IrisEngineChunkData {
|
|
||||||
private long chunk;
|
|
||||||
private KList<IrisEngineSpawnerCooldown> cooldowns = new KList<>();
|
|
||||||
|
|
||||||
public void cleanup(Engine engine) {
|
|
||||||
for (IrisEngineSpawnerCooldown i : getCooldowns().copy()) {
|
|
||||||
IrisSpawner sp = engine.getData().getSpawnerLoader().load(i.getSpawner());
|
|
||||||
|
|
||||||
if (sp == null || i.canSpawn(sp.getMaximumRate())) {
|
|
||||||
getCooldowns().remove(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return cooldowns.isEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,51 +20,31 @@ package com.volmit.iris.engine.object;
|
|||||||
|
|
||||||
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;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class IrisEngineData {
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class IrisEngineData extends IrisSpawnerCooldowns {
|
||||||
private IrisEngineStatistics statistics = new IrisEngineStatistics();
|
private IrisEngineStatistics statistics = new IrisEngineStatistics();
|
||||||
private KList<IrisEngineSpawnerCooldown> spawnerCooldowns = new KList<>();
|
private KMap<Long, IrisSpawnerCooldowns> chunks = new KMap<>();
|
||||||
private KList<IrisEngineChunkData> chunks = new KList<>();
|
|
||||||
private Long seed = null;
|
private Long seed = null;
|
||||||
|
|
||||||
public void removeChunk(int x, int z) {
|
public void removeChunk(int x, int z) {
|
||||||
long k = Cache.key(x, z);
|
chunks.remove(Cache.key(x, z));
|
||||||
chunks.removeWhere((i) -> i.getChunk() == k);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IrisEngineChunkData getChunk(int x, int z) {
|
public IrisSpawnerCooldowns getChunk(int x, int z) {
|
||||||
long k = Cache.key(x, z);
|
return chunks.computeIfAbsent(Cache.key(x, z), k -> new IrisSpawnerCooldowns());
|
||||||
|
|
||||||
for (IrisEngineChunkData i : chunks) {
|
|
||||||
if (i.getChunk() == k) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IrisEngineChunkData c = new IrisEngineChunkData();
|
|
||||||
c.setChunk(k);
|
|
||||||
chunks.add(c);
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cleanup(Engine engine) {
|
public void cleanup(Engine engine) {
|
||||||
for (IrisEngineSpawnerCooldown i : getSpawnerCooldowns().copy()) {
|
super.cleanup(engine);
|
||||||
IrisSpawner sp = engine.getData().getSpawnerLoader().load(i.getSpawner());
|
|
||||||
|
|
||||||
if (sp == null || i.canSpawn(sp.getMaximumRate())) {
|
chunks.values().removeIf(chunk -> {
|
||||||
getSpawnerCooldowns().remove(i);
|
chunk.cleanup(engine);
|
||||||
}
|
return chunk.isEmpty();
|
||||||
}
|
});
|
||||||
|
|
||||||
for (IrisEngineChunkData i : chunks.copy()) {
|
|
||||||
i.cleanup(engine);
|
|
||||||
|
|
||||||
if (i.isEmpty()) {
|
|
||||||
getChunks().remove(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,4 +50,10 @@ public class IrisRange {
|
|||||||
public boolean contains(int v) {
|
public boolean contains(int v) {
|
||||||
return v >= min && v <= max;
|
return v >= min && v <= max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IrisRange merge(IrisRange other) {
|
||||||
|
min = Math.min(min, other.min);
|
||||||
|
max = Math.max(max, other.max);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class IrisRate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getInterval() {
|
public long getInterval() {
|
||||||
long t = per.getMilliseconds() / (amount == 0 ? 1 : amount);
|
long t = per.toMilliseconds() / (amount == 0 ? 1 : amount);
|
||||||
return Math.abs(t <= 0 ? 1 : t);
|
return Math.abs(t <= 0 ? 1 : t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
package com.volmit.iris.engine.object;
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
import com.volmit.iris.core.loader.IrisRegistrant;
|
import com.volmit.iris.core.loader.IrisRegistrant;
|
||||||
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.engine.object.annotations.ArrayType;
|
import com.volmit.iris.engine.object.annotations.ArrayType;
|
||||||
import com.volmit.iris.engine.object.annotations.Desc;
|
import com.volmit.iris.engine.object.annotations.Desc;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
@@ -95,6 +96,37 @@ public class IrisSpawner extends IrisRegistrant {
|
|||||||
return timeBlock.isWithin(world) && weather.is(world);
|
return timeBlock.isWithin(world) && weather.is(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canSpawn(Engine engine) {
|
||||||
|
if (!isValid(engine.getWorld().realWorld()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var rate = getMaximumRate();
|
||||||
|
return rate.isInfinite() || engine.getEngineData().getCooldown(this).canSpawn(rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canSpawn(Engine engine, int x, int z) {
|
||||||
|
if (!canSpawn(engine))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var rate = getMaximumRatePerChunk();
|
||||||
|
return rate.isInfinite() || engine.getEngineData().getChunk(x, z).getCooldown(this).canSpawn(rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawn(Engine engine) {
|
||||||
|
if (getMaximumRate().isInfinite())
|
||||||
|
return;
|
||||||
|
|
||||||
|
engine.getEngineData().getCooldown(this).spawn(engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawn(Engine engine, int x, int z) {
|
||||||
|
spawn(engine);
|
||||||
|
if (getMaximumRatePerChunk().isInfinite())
|
||||||
|
return;
|
||||||
|
|
||||||
|
engine.getEngineData().getChunk(x, z).getCooldown(this).spawn(engine);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFolderName() {
|
public String getFolderName() {
|
||||||
return "spawners";
|
return "spawners";
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
import com.volmit.iris.util.collection.KMap;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
@EqualsAndHashCode
|
||||||
|
public class IrisSpawnerCooldowns {
|
||||||
|
private final KMap<String, IrisEngineSpawnerCooldown> cooldowns = new KMap<>();
|
||||||
|
|
||||||
|
public IrisEngineSpawnerCooldown getCooldown(@NonNull IrisSpawner spawner) {
|
||||||
|
return getCooldown(spawner.getLoadKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IrisEngineSpawnerCooldown getCooldown(@NonNull String loadKey) {
|
||||||
|
return cooldowns.computeIfAbsent(loadKey, k -> {
|
||||||
|
IrisEngineSpawnerCooldown cd = new IrisEngineSpawnerCooldown();
|
||||||
|
cd.setSpawner(loadKey);
|
||||||
|
return cd;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup(Engine engine) {
|
||||||
|
cooldowns.values().removeIf(cd -> {
|
||||||
|
IrisSpawner sp = engine.getData().getSpawnerLoader().load(cd.getSpawner());
|
||||||
|
return sp == null || cd.canSpawn(sp.getMaximumRate());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return cooldowns.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package com.volmit.iris.util.misc;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class ServerProperties {
|
||||||
|
public static final Properties DATA = new Properties();
|
||||||
|
public static final File SERVER_PROPERTIES;
|
||||||
|
public static final File BUKKIT_YML;
|
||||||
|
|
||||||
|
public static final String LEVEL_NAME = DATA.getProperty("level-name", "world");
|
||||||
|
|
||||||
|
static {
|
||||||
|
String[] args = ProcessHandle.current()
|
||||||
|
.info()
|
||||||
|
.arguments()
|
||||||
|
.orElse(new String[0]);
|
||||||
|
|
||||||
|
String propertiesPath = "server.properties";
|
||||||
|
String bukkitYml = "bukkit.yml";
|
||||||
|
|
||||||
|
for (int i = 0; i < args.length - 1; i++) {
|
||||||
|
switch (args[i]) {
|
||||||
|
case "-c", "--config" -> propertiesPath = args[i + 1];
|
||||||
|
case "-b", "--bukkit-settings" -> bukkitYml = args[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SERVER_PROPERTIES = new File(propertiesPath);
|
||||||
|
BUKKIT_YML = new File(bukkitYml);
|
||||||
|
try (FileInputStream in = new FileInputStream(SERVER_PROPERTIES)){
|
||||||
|
DATA.load(in);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,10 @@ package com.volmit.iris.core.nms.v1_20_R1;
|
|||||||
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import com.mojang.serialization.Lifecycle;
|
||||||
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.engine.data.cache.AtomicCache;
|
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
@@ -20,14 +22,16 @@ import com.volmit.iris.util.nbt.mca.palette.*;
|
|||||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import net.minecraft.core.BlockPos;
|
import lombok.SneakyThrows;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.RegistryAccess;
|
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.WorldLoader;
|
||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
@@ -41,6 +45,8 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
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.LevelStem;
|
||||||
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;
|
||||||
@@ -73,11 +79,10 @@ import java.io.DataOutputStream;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Iterator;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Vector;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class NMSBinding implements INMSBinding {
|
public class NMSBinding implements INMSBinding {
|
||||||
|
|
||||||
@@ -85,9 +90,11 @@ public class NMSBinding implements INMSBinding {
|
|||||||
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
||||||
private final BlockData AIR = Material.AIR.createBlockData();
|
private final BlockData AIR = Material.AIR.createBlockData();
|
||||||
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
||||||
|
private final AtomicCache<WorldLoader.DataLoadContext> dataLoadContext = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||||
|
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||||
private Field biomeStorageCache = null;
|
private Field biomeStorageCache = null;
|
||||||
|
|
||||||
@@ -568,6 +575,9 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
public void inject(long seed, Engine engine, World world) {
|
public void inject(long seed, Engine engine, World world) {
|
||||||
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||||
|
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||||
|
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||||
|
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||||
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -628,4 +638,98 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
|
var access = registry();
|
||||||
|
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||||
|
|
||||||
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
|
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||||
|
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||||
|
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||||
|
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
|
if (copy) copy(fake, levelStems);
|
||||||
|
|
||||||
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
||||||
|
target.register(key, new LevelStem(
|
||||||
|
dimensions.getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath()))),
|
||||||
|
levelStems.getOrThrow(key).generator()
|
||||||
|
), Lifecycle.stable());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||||
|
if (source == null) return;
|
||||||
|
source.registryKeySet().forEach(key -> {
|
||||||
|
var value = source.get(key);
|
||||||
|
var info = source.lifecycle(value);
|
||||||
|
if (value != null && info != null && !target.containsKey(key))
|
||||||
|
target.register(key, value, info);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,21 +8,29 @@ import java.io.DataOutputStream;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Iterator;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Vector;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
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.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import net.minecraft.core.*;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
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.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
|
import net.minecraft.world.level.dimension.LevelStem;
|
||||||
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;
|
||||||
@@ -61,10 +69,6 @@ import com.volmit.iris.util.nbt.mca.palette.*;
|
|||||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.core.Holder;
|
|
||||||
import net.minecraft.core.Registry;
|
|
||||||
import net.minecraft.core.RegistryAccess;
|
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -83,9 +87,11 @@ public class NMSBinding implements INMSBinding {
|
|||||||
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
||||||
private final BlockData AIR = Material.AIR.createBlockData();
|
private final BlockData AIR = Material.AIR.createBlockData();
|
||||||
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
||||||
|
private final AtomicCache<WorldLoader.DataLoadContext> dataLoadContext = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||||
|
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||||
private Field biomeStorageCache = null;
|
private Field biomeStorageCache = null;
|
||||||
|
|
||||||
@@ -538,6 +544,9 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
public void inject(long seed, Engine engine, World world) {
|
public void inject(long seed, Engine engine, World world) {
|
||||||
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||||
|
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||||
|
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||||
|
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||||
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -630,4 +639,98 @@ public class NMSBinding implements INMSBinding {
|
|||||||
public static Holder<net.minecraft.world.level.biome.Biome> biomeToBiomeBase(Registry<net.minecraft.world.level.biome.Biome> registry, Biome biome) {
|
public static Holder<net.minecraft.world.level.biome.Biome> biomeToBiomeBase(Registry<net.minecraft.world.level.biome.Biome> registry, Biome biome) {
|
||||||
return registry.getHolderOrThrow(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(biome.getKey())));
|
return registry.getHolderOrThrow(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(biome.getKey())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
|
var access = registry();
|
||||||
|
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||||
|
|
||||||
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
|
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||||
|
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||||
|
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||||
|
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
|
if (copy) copy(fake, levelStems);
|
||||||
|
|
||||||
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
||||||
|
target.register(key, new LevelStem(
|
||||||
|
dimensions.getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath()))),
|
||||||
|
levelStems.getOrThrow(key).generator()
|
||||||
|
), Lifecycle.stable());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||||
|
if (source == null) return;
|
||||||
|
source.registryKeySet().forEach(key -> {
|
||||||
|
var value = source.get(key);
|
||||||
|
var info = source.lifecycle(value);
|
||||||
|
if (value != null && info != null && !target.containsKey(key))
|
||||||
|
target.register(key, value, info);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,21 +8,29 @@ import java.io.DataOutputStream;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Iterator;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Vector;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
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.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import net.minecraft.core.*;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
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.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
|
import net.minecraft.world.level.dimension.LevelStem;
|
||||||
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;
|
||||||
@@ -61,10 +69,6 @@ import com.volmit.iris.util.nbt.mca.palette.*;
|
|||||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.core.Holder;
|
|
||||||
import net.minecraft.core.Registry;
|
|
||||||
import net.minecraft.core.RegistryAccess;
|
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -83,9 +87,11 @@ public class NMSBinding implements INMSBinding {
|
|||||||
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
||||||
private final BlockData AIR = Material.AIR.createBlockData();
|
private final BlockData AIR = Material.AIR.createBlockData();
|
||||||
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
||||||
|
private final AtomicCache<WorldLoader.DataLoadContext> dataLoadContext = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||||
|
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||||
private Field biomeStorageCache = null;
|
private Field biomeStorageCache = null;
|
||||||
|
|
||||||
@@ -538,6 +544,9 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
public void inject(long seed, Engine engine, World world) {
|
public void inject(long seed, Engine engine, World world) {
|
||||||
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||||
|
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||||
|
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||||
|
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||||
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,4 +640,98 @@ public class NMSBinding implements INMSBinding {
|
|||||||
public static Holder<net.minecraft.world.level.biome.Biome> biomeToBiomeBase(Registry<net.minecraft.world.level.biome.Biome> registry, Biome biome) {
|
public static Holder<net.minecraft.world.level.biome.Biome> biomeToBiomeBase(Registry<net.minecraft.world.level.biome.Biome> registry, Biome biome) {
|
||||||
return registry.getHolderOrThrow(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(biome.getKey())));
|
return registry.getHolderOrThrow(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(biome.getKey())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
|
var access = registry();
|
||||||
|
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||||
|
|
||||||
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
|
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||||
|
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||||
|
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||||
|
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
|
if (copy) copy(fake, levelStems);
|
||||||
|
|
||||||
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
||||||
|
target.register(key, new LevelStem(
|
||||||
|
dimensions.getHolderOrThrow(ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath()))),
|
||||||
|
levelStems.getOrThrow(key).generator()
|
||||||
|
), Lifecycle.stable());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||||
|
if (source == null) return;
|
||||||
|
source.registryKeySet().forEach(key -> {
|
||||||
|
var value = source.get(key);
|
||||||
|
var info = source.lifecycle(value);
|
||||||
|
if (value != null && info != null && !target.containsKey(key))
|
||||||
|
target.register(key, value, info);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,12 +6,17 @@ import java.lang.reflect.Method;
|
|||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
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.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import net.minecraft.core.*;
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
@@ -25,6 +30,8 @@ import net.minecraft.nbt.LongTag;
|
|||||||
import net.minecraft.nbt.ShortTag;
|
import net.minecraft.nbt.ShortTag;
|
||||||
import net.minecraft.nbt.StringTag;
|
import net.minecraft.nbt.StringTag;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.WorldLoader;
|
||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
import net.minecraft.server.commands.data.DataCommands;
|
import net.minecraft.server.commands.data.DataCommands;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@@ -34,6 +41,8 @@ import net.minecraft.world.level.LevelReader;
|
|||||||
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.LevelStem;
|
||||||
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;
|
||||||
@@ -86,9 +95,11 @@ public class NMSBinding implements INMSBinding {
|
|||||||
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
||||||
private final BlockData AIR = Material.AIR.createBlockData();
|
private final BlockData AIR = Material.AIR.createBlockData();
|
||||||
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
||||||
|
private final AtomicCache<WorldLoader.DataLoadContext> dataLoadContext = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||||
|
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||||
private Field biomeStorageCache = null;
|
private Field biomeStorageCache = null;
|
||||||
|
|
||||||
@@ -544,6 +555,10 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
public void inject(long seed, Engine engine, World world) {
|
public void inject(long seed, Engine engine, World world) {
|
||||||
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||||
|
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||||
|
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||||
|
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||||
|
|
||||||
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,4 +665,98 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
|
var access = registry();
|
||||||
|
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||||
|
|
||||||
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
|
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||||
|
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||||
|
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||||
|
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
|
if (copy) copy(fake, levelStems);
|
||||||
|
|
||||||
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
||||||
|
target.register(key, new LevelStem(
|
||||||
|
dimensions.getHolder(new ResourceLocation("iris", key.location().getPath())).orElseThrow(),
|
||||||
|
levelStems.getOrThrow(key).generator()
|
||||||
|
), RegistrationInfo.BUILT_IN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||||
|
if (source == null) return;
|
||||||
|
source.registryKeySet().forEach(key -> {
|
||||||
|
var value = source.get(key);
|
||||||
|
var info = source.registrationInfo(key).orElse(null);
|
||||||
|
if (value != null && info != null && !target.containsKey(key))
|
||||||
|
target.register(key, value, info);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,14 +10,23 @@ import java.lang.reflect.Method;
|
|||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
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.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import net.minecraft.core.*;
|
||||||
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.WorldLoader;
|
||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
@@ -26,6 +35,8 @@ import net.minecraft.world.level.LevelReader;
|
|||||||
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.LevelStem;
|
||||||
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;
|
||||||
@@ -64,10 +75,6 @@ import com.volmit.iris.util.nbt.mca.palette.*;
|
|||||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.core.Holder;
|
|
||||||
import net.minecraft.core.Registry;
|
|
||||||
import net.minecraft.core.RegistryAccess;
|
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -85,9 +92,11 @@ public class NMSBinding implements INMSBinding {
|
|||||||
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
||||||
private final BlockData AIR = Material.AIR.createBlockData();
|
private final BlockData AIR = Material.AIR.createBlockData();
|
||||||
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
||||||
|
private final AtomicCache<WorldLoader.DataLoadContext> dataLoadContext = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||||
|
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||||
private Field biomeStorageCache = null;
|
private Field biomeStorageCache = null;
|
||||||
|
|
||||||
@@ -546,6 +555,9 @@ public class NMSBinding implements INMSBinding {
|
|||||||
var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class);
|
var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class);
|
||||||
worldGenContextField.setAccessible(true);
|
worldGenContextField.setAccessible(true);
|
||||||
var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap);
|
var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap);
|
||||||
|
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||||
|
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||||
|
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||||
|
|
||||||
var newContext = new WorldGenContext(
|
var newContext = new WorldGenContext(
|
||||||
worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world),
|
worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world),
|
||||||
@@ -657,4 +669,98 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
|
var access = registry();
|
||||||
|
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||||
|
|
||||||
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
|
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||||
|
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||||
|
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||||
|
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
|
if (copy) copy(fake, levelStems);
|
||||||
|
|
||||||
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
||||||
|
target.register(key, new LevelStem(
|
||||||
|
dimensions.getHolder(ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath())).orElseThrow(),
|
||||||
|
levelStems.getOrThrow(key).generator()
|
||||||
|
), RegistrationInfo.BUILT_IN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||||
|
if (source == null) return;
|
||||||
|
source.registryKeySet().forEach(key -> {
|
||||||
|
var value = source.get(key);
|
||||||
|
var info = source.registrationInfo(key).orElse(null);
|
||||||
|
if (value != null && info != null && !target.containsKey(key))
|
||||||
|
target.register(key, value, info);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,15 +6,23 @@ import java.lang.reflect.Method;
|
|||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
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.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import net.minecraft.core.*;
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
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.item.component.CustomData;
|
import net.minecraft.world.item.component.CustomData;
|
||||||
@@ -22,6 +30,8 @@ import net.minecraft.world.level.LevelReader;
|
|||||||
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.LevelStem;
|
||||||
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;
|
||||||
@@ -72,9 +82,11 @@ public class NMSBinding implements INMSBinding {
|
|||||||
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
||||||
private final BlockData AIR = Material.AIR.createBlockData();
|
private final BlockData AIR = Material.AIR.createBlockData();
|
||||||
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
||||||
|
private final AtomicCache<WorldLoader.DataLoadContext> dataLoadContext = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||||
|
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||||
private Field biomeStorageCache = null;
|
private Field biomeStorageCache = null;
|
||||||
|
|
||||||
@@ -533,6 +545,9 @@ public class NMSBinding implements INMSBinding {
|
|||||||
var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class);
|
var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class);
|
||||||
worldGenContextField.setAccessible(true);
|
worldGenContextField.setAccessible(true);
|
||||||
var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap);
|
var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap);
|
||||||
|
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||||
|
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||||
|
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||||
|
|
||||||
var newContext = new WorldGenContext(
|
var newContext = new WorldGenContext(
|
||||||
worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world),
|
worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world),
|
||||||
@@ -644,4 +659,98 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
|
var access = registry();
|
||||||
|
var dimensions = access.lookupOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
var levelStems = access.lookupOrThrow(Registries.LEVEL_STEM);
|
||||||
|
|
||||||
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
|
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||||
|
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||||
|
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||||
|
copy(fake, datapack.lookup(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
|
if (copy) copy(fake, levelStems);
|
||||||
|
|
||||||
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
||||||
|
target.register(key, new LevelStem(
|
||||||
|
dimensions.get(ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath())).orElseThrow(),
|
||||||
|
levelStems.getValueOrThrow(key).generator()
|
||||||
|
), RegistrationInfo.BUILT_IN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||||
|
if (source == null) return;
|
||||||
|
source.listElementIds().forEach(key -> {
|
||||||
|
var value = source.getValue(key);
|
||||||
|
var info = source.registrationInfo(key).orElse(null);
|
||||||
|
if (value != null && info != null && !target.containsKey(key))
|
||||||
|
target.register(key, value, info);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package com.volmit.iris.core.nms.v1_21_R3;
|
package com.volmit.iris.core.nms.v1_21_R3;
|
||||||
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import com.mojang.serialization.Lifecycle;
|
||||||
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.core.nms.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
@@ -19,6 +22,7 @@ import com.volmit.iris.util.nbt.mca.palette.*;
|
|||||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.*;
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
@@ -27,6 +31,8 @@ import net.minecraft.nbt.Tag;
|
|||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.WorldLoader;
|
||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
@@ -41,6 +47,8 @@ import net.minecraft.world.level.chunk.ChunkAccess;
|
|||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
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.LevelStem;
|
||||||
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;
|
||||||
@@ -66,14 +74,18 @@ import java.lang.reflect.Modifier;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class NMSBinding implements INMSBinding {
|
public class NMSBinding implements INMSBinding {
|
||||||
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
||||||
private final BlockData AIR = Material.AIR.createBlockData();
|
private final BlockData AIR = Material.AIR.createBlockData();
|
||||||
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMap<net.minecraft.world.level.biome.Biome>> biomeMapCache = new AtomicCache<>();
|
||||||
|
private final AtomicCache<WorldLoader.DataLoadContext> dataLoadContext = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||||
|
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||||
private Field biomeStorageCache = null;
|
private Field biomeStorageCache = null;
|
||||||
|
|
||||||
@@ -532,6 +544,9 @@ public class NMSBinding implements INMSBinding {
|
|||||||
var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class);
|
var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class);
|
||||||
worldGenContextField.setAccessible(true);
|
worldGenContextField.setAccessible(true);
|
||||||
var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap);
|
var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap);
|
||||||
|
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||||
|
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||||
|
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||||
|
|
||||||
var newContext = new WorldGenContext(
|
var newContext = new WorldGenContext(
|
||||||
worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world),
|
worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world),
|
||||||
@@ -643,4 +658,98 @@ public class NMSBinding implements INMSBinding {
|
|||||||
|
|
||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
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!");
|
||||||
|
|
||||||
|
var server = ((CraftServer) Bukkit.getServer());
|
||||||
|
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||||
|
var nmsServer = server.getServer();
|
||||||
|
var old = nmsServer.worldLoader;
|
||||||
|
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(nmsServer, transformer.apply(old));
|
||||||
|
|
||||||
|
return new AutoClosing(() -> {
|
||||||
|
field.set(nmsServer, old);
|
||||||
|
dataContextLock.unlock();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||||
|
var access = registry();
|
||||||
|
var dimensions = access.lookupOrThrow(Registries.DIMENSION_TYPE);
|
||||||
|
var levelStems = access.lookupOrThrow(Registries.LEVEL_STEM);
|
||||||
|
|
||||||
|
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||||
|
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||||
|
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||||
|
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||||
|
copy(fake, datapack.lookup(Registries.LEVEL_STEM).orElse(null));
|
||||||
|
|
||||||
|
if (copy) copy(fake, levelStems);
|
||||||
|
|
||||||
|
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void register(MappedRegistry<LevelStem> target, Registry<LevelStem> levelStems, Registry<DimensionType> dimensions, ResourceKey<LevelStem> key) {
|
||||||
|
target.register(key, new LevelStem(
|
||||||
|
dimensions.get(ResourceLocation.fromNamespaceAndPath("iris", key.location().getPath())).orElseThrow(),
|
||||||
|
levelStems.getValueOrThrow(key).generator()
|
||||||
|
), RegistrationInfo.BUILT_IN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||||
|
if (source == null) return;
|
||||||
|
source.listElementIds().forEach(key -> {
|
||||||
|
var value = source.getValue(key);
|
||||||
|
var info = source.registrationInfo(key).orElse(null);
|
||||||
|
if (value != null && info != null && !target.containsKey(key))
|
||||||
|
target.register(key, value, info);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user