Revert "Merge branch 'mca' into jigsaw_dist"

This reverts commit 0288d35c85ce25d2d7469cc69910447f4504eb08, reversing
changes made to 8b3577dd0b014949fa0f702e5099d7d56a11bcb3.
This commit is contained in:
CrazyDev22 2024-06-16 14:25:47 +02:00
parent 0288d35c85
commit 55017b9ac2
68 changed files with 1240 additions and 3933 deletions

View File

@ -1,5 +1,3 @@
import java.util.function.Consumer
/* /*
* Iris is a World Generator for Minecraft Bukkit Servers * Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2021 Arcane Arts (Volmit Software) * Copyright (c) 2021 Arcane Arts (Volmit Software)
@ -214,8 +212,6 @@ shadowJar {
dependsOn(":nms:${it.key}:build") dependsOn(":nms:${it.key}:build")
from("${project(":nms:${it.key}").layout.buildDirectory.asFile.get()}/libs/${it.key}.jar") from("${project(":nms:${it.key}").layout.buildDirectory.asFile.get()}/libs/${it.key}.jar")
} }
NMS_BINDINGS.each {dependsOn(":nms:${it.key}:build")}
//dependsOn(':com.volmit.gui:build')
//minimize() //minimize()
append("plugin.yml") append("plugin.yml")
@ -284,10 +280,6 @@ allprojects {
compileOnly 'rhino:js:1.7R2' compileOnly 'rhino:js:1.7R2'
compileOnly 'com.github.ben-manes.caffeine:caffeine:3.0.6' compileOnly 'com.github.ben-manes.caffeine:caffeine:3.0.6'
compileOnly 'org.apache.commons:commons-lang3:3.12.0' compileOnly 'org.apache.commons:commons-lang3:3.12.0'
compileOnly 'net.bytebuddy:byte-buddy:1.14.14'
compileOnly 'net.bytebuddy:byte-buddy-agent:1.12.8'
compileOnly 'org.bytedeco:javacpp:1.5.10'
compileOnly 'org.bytedeco:cuda-platform:12.3-8.9-1.5.10'
} }
/** /**

View File

@ -64,10 +64,12 @@ import com.volmit.iris.util.scheduling.Queue;
import com.volmit.iris.util.scheduling.ShurikenQueue; import com.volmit.iris.util.scheduling.ShurikenQueue;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import lombok.Getter; import lombok.Getter;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.serializer.ComponentSerializer; import net.kyori.adventure.text.serializer.ComponentSerializer;
import org.bukkit.*; import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.WorldCreator;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -92,14 +94,12 @@ import java.lang.management.OperatingSystemMXBean;
import java.net.URL; import java.net.URL;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static com.volmit.iris.core.safeguard.IrisSafeguard.*; import static com.volmit.iris.core.safeguard.IrisSafeguard.*;
import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware; import static com.volmit.iris.core.safeguard.ServerBootSFG.passedserversoftware;
import static com.volmit.iris.util.misc.getHardware.getCPUModel; import static com.volmit.iris.util.misc.getHardware.getCPUModel;
import static org.bukkit.Bukkit.getServer;
@SuppressWarnings("CanBeFinal") @SuppressWarnings("CanBeFinal")
public class Iris extends VolmitPlugin implements Listener { public class Iris extends VolmitPlugin implements Listener {
@ -456,28 +456,19 @@ public class Iris extends VolmitPlugin implements Listener {
} }
private void enable() { private void enable() {
instance = this; instance = this;
InitializeSafeguard();
ByteBuddyAgent.install();
services = new KMap<>(); services = new KMap<>();
setupAudience(); setupAudience();
initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class<? extends IrisService>) i.getClass(), (IrisService) i)); initialize("com.volmit.iris.core.service").forEach((i) -> services.put((Class<? extends IrisService>) i.getClass(), (IrisService) i));
INMS.get(); INMS.get();
IO.delete(new File("iris")); IO.delete(new File("iris"));
IrisSafeguard.instance.IrisSafeguardSystem(); IrisSafeguard.IrisSafeguardSystem();
getSender().setTag(getTag()); getSender().setTag(getTag());
INMS.get().injectBukkit();
if (IrisSafeguard.instance.unstablemode && !IrisSafeguard.instance.acceptUnstable) IrisSafeguard.instance.earlySplash();
compat = IrisCompat.configured(getDataFile("compat.json")); compat = IrisCompat.configured(getDataFile("compat.json"));
linkMultiverseCore = new MultiverseCoreLink(); linkMultiverseCore = new MultiverseCoreLink();
linkMythicMobs = new MythicMobsLink(); linkMythicMobs = new MythicMobsLink();
configWatcher = new FileWatcher(getDataFile("settings.json")); configWatcher = new FileWatcher(getDataFile("settings.json"));
services.values().forEach(IrisService::onEnable); services.values().forEach(IrisService::onEnable);
services.values().forEach(this::registerListener); services.values().forEach(this::registerListener);
installMainDimension();
if (!IrisSafeguard.instance.acceptUnstable && IrisSafeguard.instance.unstablemode) {
Iris.info(C.RED + "World loading has been disabled until the incompatibility is resolved.");
Iris.info(C.DARK_RED + "Alternatively, go to plugins/iris/settings.json and set ignoreBootMode to true.");
} else {
J.s(() -> { J.s(() -> {
J.a(() -> PaperLib.suggestPaper(this)); J.a(() -> PaperLib.suggestPaper(this));
J.a(() -> IO.delete(getTemp())); J.a(() -> IO.delete(getTemp()));
@ -489,13 +480,13 @@ public class Iris extends VolmitPlugin implements Listener {
J.a(ServerConfigurator::configure, 20); J.a(ServerConfigurator::configure, 20);
splash(); splash();
UtilsSFG.splash(); UtilsSFG.splash();
autoStartStudio(); autoStartStudio();
checkForBukkitWorlds(); checkForBukkitWorlds();
IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName()); IrisToolbelt.retainMantleDataForSlice(String.class.getCanonicalName());
IrisToolbelt.retainMantleDataForSlice(BlockData.class.getCanonicalName()); IrisToolbelt.retainMantleDataForSlice(BlockData.class.getCanonicalName());
}); });
} }
}
private void checkForBukkitWorlds() { private void checkForBukkitWorlds() {
FileConfiguration fc = new YamlConfiguration(); FileConfiguration fc = new YamlConfiguration();
@ -608,10 +599,10 @@ public class Iris extends VolmitPlugin implements Listener {
@Override @Override
public String getTag(String subTag) { public String getTag(String subTag) {
if (IrisSafeguard.instance.unstablemode) { if (unstablemode) {
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.RED + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": "; return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.RED + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
} }
if (IrisSafeguard.instance.warningmode) { if (warningmode) {
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.GOLD + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": "; return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.GOLD + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
} }
return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.IRIS + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": "; return C.BOLD + "" + C.DARK_GRAY + "[" + C.BOLD + "" + C.IRIS + "Iris" + C.BOLD + C.DARK_GRAY + "]" + C.RESET + "" + C.GRAY + ": ";
@ -620,7 +611,7 @@ public class Iris extends VolmitPlugin implements Listener {
private boolean setupChecks() { private boolean setupChecks() {
boolean passed = true; boolean passed = true;
Iris.info("Server type & version: " + instance.getServer().getVersion() + " | " + instance.getServer().getBukkitVersion()); Iris.info("Version Information: " + instance.getServer().getVersion() + " | " + instance.getServer().getBukkitVersion());
if (INMS.get() instanceof NMSBinding1X) { if (INMS.get() instanceof NMSBinding1X) {
passed = false; passed = false;
Iris.warn("============================================"); Iris.warn("============================================");
@ -686,48 +677,6 @@ public class Iris extends VolmitPlugin implements Listener {
s.sendMessage(C.IRIS + "[" + C.DARK_GRAY + "Iris" + C.IRIS + "]" + C.GRAY + ": " + msg); s.sendMessage(C.IRIS + "[" + C.DARK_GRAY + "Iris" + C.IRIS + "]" + C.GRAY + ": " + msg);
} }
private void installMainDimension() {
try {
Properties props = new Properties();
props.load(new FileInputStream("server.properties"));
String world = props.getProperty("level-name");
if (world == null) return;
FileConfiguration fc = new YamlConfiguration();
fc.load(new File("bukkit.yml"));
String id = fc.getString("worlds." + world + ".generator");
if (id.startsWith("Iris:")) {
id = id.split("\\Q:\\E")[1];
} else if (id.equalsIgnoreCase("Iris")) {
id = IrisSettings.get().getGenerator().getDefaultWorldType();
} else {
return;
}
IrisDimension dim;
if (id == null || id.isEmpty()) {
dim = IrisData.loadAnyDimension(IrisSettings.get().getGenerator().getDefaultWorldType());
} else {
dim = IrisData.loadAnyDimension(id);
}
File w = new File(Bukkit.getWorldContainer(), world);
File packFolder = new File(w, "/iris/pack");
if (!packFolder.exists() || packFolder.listFiles().length == 0) {
packFolder.mkdirs();
service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w);
}
if (packFolder.exists()) {
IrisDimension worldDim = IrisData.get(packFolder).getDimensionLoader().load(id);
if (worldDim != null) dim = worldDim;
}
INMS.get().registerDimension("overworld", dim);
} catch (Throwable e) {
}
}
@Nullable @Nullable
@Override @Override
public BiomeProvider getDefaultBiomeProvider(@NotNull String worldName, @Nullable String id) { public BiomeProvider getDefaultBiomeProvider(@NotNull String worldName, @Nullable String id) {
@ -770,11 +719,6 @@ public class Iris extends VolmitPlugin implements Listener {
Iris.info("Resolved missing dimension, proceeding with generation."); Iris.info("Resolved missing dimension, proceeding with generation.");
} }
} }
File packFolder = new File(Bukkit.getWorldContainer(), worldName + "/iris/pack");
if (packFolder.exists()) {
IrisDimension worldDim = IrisData.get(packFolder).getDimensionLoader().load(id);
if (worldDim != null) dim = worldDim;
}
Iris.debug("Assuming IrisDimension: " + dim.getName()); Iris.debug("Assuming IrisDimension: " + dim.getName());
@ -794,9 +738,6 @@ public class Iris extends VolmitPlugin implements Listener {
ff.mkdirs(); ff.mkdirs();
service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w.worldFolder()); service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w.worldFolder());
} }
if (!INMS.get().registerDimension(worldName, dim)) {
throw new IllegalStateException("Unable to register dimension " + dim.getName());
}
return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey(), false); return new BukkitChunkGenerator(w, false, ff, dim.getLoadKey(), false);
} }
@ -809,10 +750,10 @@ public class Iris extends VolmitPlugin implements Listener {
String padd = Form.repeat(" ", 8); String padd = Form.repeat(" ", 8);
String padd2 = Form.repeat(" ", 4); String padd2 = Form.repeat(" ", 4);
String[] info = {"", "", "", "", "", padd2 + C.IRIS + " Iris", padd2 + C.GRAY + " by " + "<rainbow>Volmit Software", padd2 + C.GRAY + " v" + C.IRIS + getDescription().getVersion()}; String[] info = {"", "", "", "", "", padd2 + C.IRIS + " Iris", padd2 + C.GRAY + " by " + "<rainbow>Volmit Software", padd2 + C.GRAY + " v" + C.IRIS + getDescription().getVersion()};
if (IrisSafeguard.instance.unstablemode) { if (unstablemode) {
info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + getDescription().getVersion()}; info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + getDescription().getVersion()};
} }
if (IrisSafeguard.instance.warningmode) { if (warningmode) {
info = new String[]{"", "", "", "", "", padd2 + C.GOLD + " Iris", padd2 + C.GRAY + " by " + C.GOLD + "Volmit Software", padd2 + C.GRAY + " v" + C.GOLD + getDescription().getVersion()}; info = new String[]{"", "", "", "", "", padd2 + C.GOLD + " Iris", padd2 + C.GRAY + " by " + C.GOLD + "Volmit Software", padd2 + C.GRAY + " v" + C.GOLD + getDescription().getVersion()};
} }
@ -857,15 +798,18 @@ public class Iris extends VolmitPlugin implements Listener {
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@" padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
}; };
String[] splash; String[] splash;
if (IrisSafeguard.instance.unstablemode) { File freeSpace = new File(Bukkit.getWorldContainer() + ".");
if (unstablemode) {
splash = splashunstable; splash = splashunstable;
} else if (IrisSafeguard.instance.warningmode) { } else if (warningmode) {
splash = splashwarning; splash = splashwarning;
} else { } else {
splash = splashstable; splash = splashstable;
} }
setupChecks(); if (!passedserversoftware) {
Iris.info("Server type & version: " + C.RED + Bukkit.getVersion());
} else { Iris.info("Server type & version: " + Bukkit.getVersion()); }
Iris.info("Java: " + getJava()); Iris.info("Java: " + getJava());
if (!instance.getServer().getVersion().contains("Purpur")) { if (!instance.getServer().getVersion().contains("Purpur")) {
if (instance.getServer().getVersion().contains("Spigot") && instance.getServer().getVersion().contains("Bukkit")) { if (instance.getServer().getVersion().contains("Spigot") && instance.getServer().getVersion().contains("Bukkit")) {
@ -880,6 +824,7 @@ public class Iris extends VolmitPlugin implements Listener {
} }
Iris.info("Bukkit distro: " + Bukkit.getName()); Iris.info("Bukkit distro: " + Bukkit.getName());
Iris.info("Custom Biomes: " + INMS.get().countCustomBiomes()); Iris.info("Custom Biomes: " + INMS.get().countCustomBiomes());
setupChecks();
printPacks(); printPacks();
for (int i = 0; i < info.length; i++) { for (int i = 0; i < info.length; i++) {

View File

@ -34,7 +34,6 @@ import java.io.IOException;
@Data @Data
public class IrisSettings { public class IrisSettings {
public static IrisSettings settings; public static IrisSettings settings;
private IrisSafeGuard safeguard = new IrisSafeGuard();
private IrisSettingsGeneral general = new IrisSettingsGeneral(); private IrisSettingsGeneral general = new IrisSettingsGeneral();
private IrisSettingsWorld world = new IrisSettingsWorld(); private IrisSettingsWorld world = new IrisSettingsWorld();
private IrisSettingsGUI gui = new IrisSettingsGUI(); private IrisSettingsGUI gui = new IrisSettingsGUI();
@ -43,7 +42,6 @@ public class IrisSettings {
private IrisSettingsConcurrency concurrency = new IrisSettingsConcurrency(); private IrisSettingsConcurrency concurrency = new IrisSettingsConcurrency();
private IrisSettingsStudio studio = new IrisSettingsStudio(); private IrisSettingsStudio studio = new IrisSettingsStudio();
private IrisSettingsPerformance performance = new IrisSettingsPerformance(); private IrisSettingsPerformance performance = new IrisSettingsPerformance();
private IrisWorldDump worldDump = new IrisWorldDump();
public static int getThreadCount(int c) { public static int getThreadCount(int c) {
return switch (c) { return switch (c) {
@ -104,12 +102,6 @@ public class IrisSettings {
} }
} }
@Data
public static class IrisSafeGuard {
public boolean ignoreBootMode = false;
public boolean userUnstableWarning = true;
}
@Data @Data
public static class IrisSettingsAutoconfiguration { public static class IrisSettingsAutoconfiguration {
public boolean configureSpigotTimeoutTime = true; public boolean configureSpigotTimeoutTime = true;
@ -154,6 +146,7 @@ public class IrisSettings {
@Data @Data
public static class IrisSettingsGeneral { public static class IrisSettingsGeneral {
public boolean ignoreBootMode = false;
public boolean commandSounds = true; public boolean commandSounds = true;
public boolean debug = false; public boolean debug = false;
public boolean disableNMS = false; public boolean disableNMS = false;
@ -194,8 +187,4 @@ public class IrisSettings {
public boolean disableTimeAndWeather = true; public boolean disableTimeAndWeather = true;
public boolean autoStartDefaultStudio = false; public boolean autoStartDefaultStudio = false;
} }
@Data
public static class IrisWorldDump {
public int mcaCacheSize = 3;
}
} }

View File

@ -19,13 +19,28 @@
package com.volmit.iris.core; package com.volmit.iris.core;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.nms.datapack.IDataFixer;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.object.IrisRange;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KSet;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
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 java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class ServerConfigurator { public class ServerConfigurator {
@ -38,10 +53,12 @@ public class ServerConfigurator {
if (s.isConfigurePaperWatchdogDelay()) { if (s.isConfigurePaperWatchdogDelay()) {
J.attempt(ServerConfigurator::increasePaperWatchdog); J.attempt(ServerConfigurator::increasePaperWatchdog);
} }
installDataPacks(true);
} }
private static void increaseKeepAliveSpigot() throws IOException, InvalidConfigurationException { private static void increaseKeepAliveSpigot() throws IOException, InvalidConfigurationException {
File spigotConfig = new File("spigot.yml"); File spigotConfig = new File("config/spigot.yml");
FileConfiguration f = new YamlConfiguration(); FileConfiguration f = new YamlConfiguration();
f.load(spigotConfig); f.load(spigotConfig);
long tt = f.getLong("settings.timeout-time"); long tt = f.getLong("settings.timeout-time");
@ -53,7 +70,6 @@ public class ServerConfigurator {
f.save(spigotConfig); f.save(spigotConfig);
} }
} }
private static void increasePaperWatchdog() throws IOException, InvalidConfigurationException { private static void increasePaperWatchdog() throws IOException, InvalidConfigurationException {
File spigotConfig = new File("config/paper-global.yml"); File spigotConfig = new File("config/paper-global.yml");
FileConfiguration f = new YamlConfiguration(); FileConfiguration f = new YamlConfiguration();
@ -67,4 +83,187 @@ public class ServerConfigurator {
f.save(spigotConfig); f.save(spigotConfig);
} }
} }
private static List<File> getDatapacksFolder() {
if (!IrisSettings.get().getGeneral().forceMainWorld.isEmpty()) {
return new KList<File>().qadd(new File(Bukkit.getWorldContainer(), IrisSettings.get().getGeneral().forceMainWorld + "/datapacks"));
}
KList<File> worlds = new KList<>();
Bukkit.getServer().getWorlds().forEach(w -> worlds.add(new File(w.getWorldFolder(), "datapacks")));
return worlds;
}
public static void installDataPacks(boolean fullInstall) {
installDataPacks(DataVersion.getDefault(), fullInstall);
}
public static void installDataPacks(IDataFixer fixer, boolean fullInstall) {
Iris.info("Checking Data Packs...");
File packs = new File("plugins/Iris/packs");
double ultimateMaxHeight = 0;
double ultimateMinHeight = 0;
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()) {
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()) {
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!");
if (fullInstall)
verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall());
}
private static void verifyDataPacksPost(boolean allowRestarting) {
File packs = new File("plugins/Iris/packs");
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()) {
for (File j : dims.listFiles()) {
if (j.getName().endsWith(".json")) {
IrisDimension dim = data.getDimensionLoader().load(j.getName().split("\\Q.\\E")[0]);
if (dim == null) {
Iris.error("Failed to load " + j.getPath() + " ");
continue;
}
if (!verifyDataPackInstalled(dim)) {
bad = true;
}
}
}
}
}
}
}
if (bad) {
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);
}
}
}
public static void restart() {
J.s(() -> {
Iris.warn("New data pack entries have been installed in Iris! Restarting server!");
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)");
J.s(() -> {
Iris.warn("Looks like the restart command diddn't work. Stopping the server instead!");
Bukkit.shutdown();
}, 100);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "restart");
});
}
public static boolean verifyDataPackInstalled(IrisDimension dimension) {
IrisData idm = IrisData.get(Iris.instance.getDataFolder("packs", dimension.getLoadKey()));
KSet<String> keys = new KSet<>();
boolean warn = false;
for (IrisBiome i : dimension.getAllBiomes(() -> idm)) {
if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
keys.add(dimension.getLoadKey() + ":" + j.getId());
}
}
}
if (!INMS.get().supportsDataPacks()) {
if (!keys.isEmpty()) {
Iris.warn("===================================================================================");
Iris.warn("Pack " + dimension.getLoadKey() + " has " + keys.size() + " custom biome(s). ");
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("====================================================================================");
}
return true;
}
for (String i : keys) {
Object o = INMS.get().getCustomBiomeBaseFor(i);
if (o == null) {
Iris.warn("The Biome " + i + " is not registered on the server.");
warn = true;
}
}
if (warn) {
Iris.error("The Pack " + dimension.getLoadKey() + " is INCAPABLE of generating custom biomes");
Iris.error("If not done automatically, restart your server before generating with this pack!");
}
return !warn;
}
} }

View File

@ -0,0 +1,134 @@
/*
* 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.core.commands;
import com.volmit.iris.Iris;
import com.volmit.iris.core.pregenerator.DeepSearchPregenerator;
import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.TurboPregenerator;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.util.data.Dimension;
import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.math.Position2;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.util.Vector;
import java.io.File;
import java.io.IOException;
@Decree(name = "DeepSearch", aliases = "search", description = "Pregenerate your Iris worlds!")
public class CommandDeepSearch implements DecreeExecutor {
public String worldName;
@Decree(description = "DeepSearch a world")
public void start(
@Param(description = "The radius of the pregen in blocks", aliases = "size")
int radius,
@Param(description = "The world to pregen", contextual = true)
World world,
@Param(aliases = "middle", description = "The center location of the pregen. Use \"me\" for your current location", defaultValue = "0,0")
Vector center
) {
worldName = world.getName();
File worldDirectory = new File(Bukkit.getWorldContainer(), world.getName());
File TurboFile = new File(worldDirectory, "DeepSearch.json");
if (TurboFile.exists()) {
if (DeepSearchPregenerator.getInstance() != null) {
sender().sendMessage(C.BLUE + "DeepSearch is already in progress");
Iris.info(C.YELLOW + "DeepSearch is already in progress");
return;
} else {
try {
TurboFile.delete();
} catch (Exception e){
Iris.error("Failed to delete the old instance file of DeepSearch!");
return;
}
}
}
try {
if (sender().isPlayer() && access() == null) {
sender().sendMessage(C.RED + "The engine access for this world is null!");
sender().sendMessage(C.RED + "Please make sure the world is loaded & the engine is initialized. Generate a new chunk, for example.");
}
DeepSearchPregenerator.DeepSearchJob DeepSearchJob = DeepSearchPregenerator.DeepSearchJob.builder()
.world(world)
.radiusBlocks(radius)
.position(0)
.build();
File SearchGenFile = new File(worldDirectory, "DeepSearch.json");
DeepSearchPregenerator pregenerator = new DeepSearchPregenerator(DeepSearchJob, SearchGenFile);
pregenerator.start();
String msg = C.GREEN + "DeepSearch started in " + C.GOLD + worldName + C.GREEN + " of " + C.GOLD + (radius * 2) + C.GREEN + " by " + C.GOLD + (radius * 2) + C.GREEN + " blocks from " + C.GOLD + center.getX() + "," + center.getZ();
sender().sendMessage(msg);
Iris.info(msg);
} catch (Throwable e) {
sender().sendMessage(C.RED + "Epic fail. See console.");
Iris.reportError(e);
e.printStackTrace();
}
}
@Decree(description = "Stop the active DeepSearch task", aliases = "x")
public void stop(@Param(aliases = "world", description = "The world to pause") World world) throws IOException {
DeepSearchPregenerator DeepSearchInstance = DeepSearchPregenerator.getInstance();
File worldDirectory = new File(Bukkit.getWorldContainer(), world.getName());
File turboFile = new File(worldDirectory, "DeepSearch.json");
if (DeepSearchInstance != null) {
DeepSearchInstance.shutdownInstance(world);
sender().sendMessage(C.LIGHT_PURPLE + "Closed Turbogen instance for " + world.getName());
} else if (turboFile.exists() && turboFile.delete()) {
sender().sendMessage(C.LIGHT_PURPLE + "Closed Turbogen instance for " + world.getName());
} else if (turboFile.exists()) {
Iris.error("Failed to delete the old instance file of Turbo Pregen!");
} else {
sender().sendMessage(C.YELLOW + "No active pregeneration tasks to stop");
}
}
@Decree(description = "Pause / continue the active pregeneration task", aliases = {"t", "resume", "unpause"})
public void pause(
@Param(aliases = "world", description = "The world to pause")
World world
) {
if (TurboPregenerator.getInstance() != null) {
TurboPregenerator.setPausedTurbo(world);
sender().sendMessage(C.GREEN + "Paused/unpaused Turbo Pregen, now: " + (TurboPregenerator.isPausedTurbo(world) ? "Paused" : "Running") + ".");
} else {
File worldDirectory = new File(Bukkit.getWorldContainer(), world.getName());
File TurboFile = new File(worldDirectory, "DeepSearch.json");
if (TurboFile.exists()){
TurboPregenerator.loadTurboGenerator(world.getName());
sender().sendMessage(C.YELLOW + "Started DeepSearch back up!");
} else {
sender().sendMessage(C.YELLOW + "No active DeepSearch tasks to pause/unpause.");
}
}
}
}

View File

@ -28,9 +28,7 @@ import com.volmit.iris.core.pregenerator.ChunkUpdater;
import com.volmit.iris.core.service.IrisEngineSVC; import com.volmit.iris.core.service.IrisEngineSVC;
import com.volmit.iris.core.tools.IrisPackBenchmarking; import com.volmit.iris.core.tools.IrisPackBenchmarking;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.core.tools.IrisWorldDump;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.jvm.VMJavaFX;
import com.volmit.iris.engine.mantle.components.MantleObjectComponent; import com.volmit.iris.engine.mantle.components.MantleObjectComponent;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisCave; import com.volmit.iris.engine.object.IrisCave;
@ -152,18 +150,21 @@ public class CommandDeveloper implements DecreeExecutor {
@Decree(description = "Test") @Decree(description = "Test")
public void packBenchmark( public void packBenchmark(
@Param(description = "The pack to bench", aliases = {"pack"}) @Param(description = "The pack to bench", aliases = {"pack"})
IrisDimension dimension, IrisDimension dimension
@Param(description = "Headless", defaultValue = "true")
boolean headless,
@Param(description = "GUI", defaultValue = "false")
boolean gui
) { ) {
Iris.info("test"); Iris.info("test");
IrisPackBenchmarking benchmark = new IrisPackBenchmarking(dimension, 1, headless, gui); IrisPackBenchmarking benchmark = new IrisPackBenchmarking(dimension, 1);
benchmark.runBenchmark();
} }
@Decree(description = "Upgrade to another Minecraft version")
public void upgrade(
@Param(description = "The version to upgrade to", defaultValue = "latest") DataVersion version) {
sender().sendMessage(C.GREEN + "Upgrading to " + version.getVersion() + "...");
ServerConfigurator.installDataPacks(version.get(), false);
sender().sendMessage(C.GREEN + "Done upgrading! You can now update your server version to " + version.getVersion());
}
@Decree(description = "Test") @Decree(description = "Test")
public void updater( public void updater(
@Param(description = "Updater for chunks") @Param(description = "Updater for chunks")
@ -178,22 +179,12 @@ public class CommandDeveloper implements DecreeExecutor {
@Decree(description = "test") @Decree(description = "test")
public void mca ( public void mca (
@Param(description = "String") World world) { @Param(description = "String") String world) {
try { try {
IrisWorldDump dump = new IrisWorldDump(world, sender()); File[] McaFiles = new File(world, "region").listFiles((dir, name) -> name.endsWith(".mca"));
dump.start(); for (File mca : McaFiles) {
MCAFile MCARegion = MCAUtil.read(mca);
} catch (Exception e) {
e.printStackTrace();
} }
}
@Decree(description = "test")
public void javafx () {
try {
VMJavaFX javaFX = new VMJavaFX(sender());
javaFX.start();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -19,19 +19,13 @@
package com.volmit.iris.core.commands; package com.volmit.iris.core.commands;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeExecutor;
import com.volmit.iris.util.decree.DecreeOrigin; import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree; import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param; import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.decree.specialhandlers.NullableBiomeHandler;
import com.volmit.iris.util.decree.specialhandlers.NullablePlayerHandler;
import com.volmit.iris.util.decree.specialhandlers.NullableRegionHandler;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
import org.bukkit.Location;
import org.bukkit.block.Biome;
import java.awt.*; import java.awt.*;
@ -57,31 +51,12 @@ public class CommandEdit implements DecreeExecutor {
@Decree(description = "Edit the biome you specified", aliases = {"b"}, origin = DecreeOrigin.PLAYER) @Decree(description = "Edit the biome you specified", aliases = {"b"}, origin = DecreeOrigin.PLAYER)
public void biome(@Param(contextual = false, description = "The biome to edit", defaultValue = "---", customHandler = NullableBiomeHandler.class) IrisBiome biome ) { public void biome(@Param(contextual = false, description = "The biome to edit") IrisBiome biome) {
if (noStudio()) { if (noStudio()) {
return; return;
} }
if(biome == null) {
try { try {
IrisBiome b = engine().getBiome(player().getLocation().getBlockX(), player().getLocation().getBlockY() - player().getWorld().getMinHeight(), player().getLocation().getBlockZ()); if (biome == null || biome.getLoadFile() == null) {
Desktop.getDesktop().open(b.getLoadFile());
sender().sendMessage(C.GREEN + "Opening " + b.getTypeName() + " " + b.getLoadFile().getName().split("\\Q.\\E")[0] + " in VSCode! ");
} catch (Throwable e) {
Iris.reportError(e);
sender().sendMessage("Non-Iris Biome: " + player().getLocation().getBlock().getBiome().name());
if (player().getLocation().getBlock().getBiome().equals(Biome.CUSTOM)) {
try {
sender().sendMessage("Data Pack Biome: " + INMS.get().getTrueBiomeBaseKey(player().getLocation()) + " (ID: " + INMS.get().getTrueBiomeBaseId(INMS.get().getTrueBiomeBase(player().getLocation())) + ")");
} catch (Throwable ee) {
Iris.reportError(ee);
}
}
}
return;
}
try {
if (biome.getLoadFile() == null) {
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?"); sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
return; return;
} }
@ -94,20 +69,10 @@ public class CommandEdit implements DecreeExecutor {
} }
@Decree(description = "Edit the region you specified", aliases = {"r"}, origin = DecreeOrigin.PLAYER) @Decree(description = "Edit the region you specified", aliases = {"r"}, origin = DecreeOrigin.PLAYER)
public void region(@Param(contextual = false, description = "The region to edit", defaultValue = "---", customHandler = NullableRegionHandler.class) IrisRegion region) { public void region(@Param(contextual = false, description = "The region to edit") IrisRegion region) {
if (noStudio()) { if (noStudio()) {
return; return;
} }
if(region == null) {
try {
IrisRegion r = engine().getRegion(player().getLocation().getBlockX(), player().getLocation().getBlockZ());
Desktop.getDesktop().open(r.getLoadFile());
sender().sendMessage(C.GREEN + "Opening " + r.getTypeName() + " " + r.getLoadFile().getName().split("\\Q.\\E")[0] + " in VSCode! ");
} catch (Throwable e) {
sender().sendMessage(C.RED + "Failed to get region.");
}
return;
}
try { try {
if (region == null || region.getLoadFile() == null) { if (region == null || region.getLoadFile() == null) {
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?"); sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");

View File

@ -24,7 +24,6 @@ import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.core.pregenerator.ChunkUpdater; import com.volmit.iris.core.pregenerator.ChunkUpdater;
import com.volmit.iris.core.safeguard.IrisSafeguard;
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;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
@ -44,7 +43,6 @@ import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J; import com.volmit.iris.util.scheduling.J;
import io.lumine.mythic.bukkit.adapters.BukkitPlayer;
import lombok.Getter; import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Difficulty; import org.bukkit.Difficulty;
@ -67,6 +65,7 @@ import java.util.List;
import static com.volmit.iris.Iris.service; import static com.volmit.iris.Iris.service;
import static com.volmit.iris.core.service.EditSVC.deletingWorld; import static com.volmit.iris.core.service.EditSVC.deletingWorld;
import static com.volmit.iris.core.tools.IrisBenchmarking.inProgress; import static com.volmit.iris.core.tools.IrisBenchmarking.inProgress;
import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode;
import static com.volmit.iris.core.safeguard.ServerBootSFG.incompatibilities; import static com.volmit.iris.core.safeguard.ServerBootSFG.incompatibilities;
import static org.bukkit.Bukkit.getServer; import static org.bukkit.Bukkit.getServer;
@ -99,7 +98,24 @@ public class CommandIris implements DecreeExecutor {
@Param(description = "If it should convert the dimension to match the vanilla height system.", defaultValue = "false") @Param(description = "If it should convert the dimension to match the vanilla height system.", defaultValue = "false")
boolean vanillaheight boolean vanillaheight
) { ) {
if(sender() instanceof Player) {
if (incompatibilities.get("Multiverse-Core")) {
sender().sendMessage(C.RED + "Your server has an incompatibility that may corrupt all worlds on the server if not handled properly.");
sender().sendMessage(C.RED + "it is strongly advised for you to take action. see log for full detail");
sender().sendMessage(C.RED + "----------------------------------------------------------------");
sender().sendMessage(C.RED + "Command ran: /iris create");
sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings());
sender().sendMessage(C.RED + "----------------------------------------------------------------");
}
if (unstablemode && !incompatibilities.get("Multiverse-Core")) {
sender().sendMessage(C.RED + "Your server is experiencing an incompatibility with the Iris plugin.");
sender().sendMessage(C.RED + "Please rectify this problem to avoid further complications.");
sender().sendMessage(C.RED + "----------------------------------------------------------------");
sender().sendMessage(C.RED + "Command ran: /iris create");
sender().sendMessage(C.RED + UtilsSFG.MSGIncompatibleWarnings());
sender().sendMessage(C.RED + "----------------------------------------------------------------");
}
}
if (name.equals("iris")) { if (name.equals("iris")) {
sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds."); sender().sendMessage(C.RED + "You cannot use the world name \"iris\" for creating worlds as Iris uses this directory for studio worlds.");
sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?"); sender().sendMessage(C.RED + "May we suggest the name \"IrisWorld\" instead?");

View File

@ -22,10 +22,11 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.gui.NoiseExplorerGUI; import com.volmit.iris.core.gui.NoiseExplorerGUI;
import com.volmit.iris.core.gui.VisionGUI; import com.volmit.iris.core.gui.VisionGUI;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.project.IrisProject; import com.volmit.iris.core.project.IrisProject;
import com.volmit.iris.core.service.ConversionSVC; import com.volmit.iris.core.service.ConversionSVC;
import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisNoiseBenchmark; import com.volmit.iris.core.tools.IrisConverter;
import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.object.*;
@ -41,17 +42,22 @@ import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.function.Function2; import com.volmit.iris.util.function.Function2;
import com.volmit.iris.util.function.NoiseProvider;
import com.volmit.iris.util.interpolation.InterpolationMethod;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONArray; import com.volmit.iris.util.json.JSONArray;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.math.Spiraler; import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.parallel.BurstExecutor; import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.parallel.MultiBurst;
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 com.volmit.iris.util.scheduling.O; import com.volmit.iris.util.scheduling.O;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import com.volmit.iris.util.scheduling.jobs.QueueJob; import com.volmit.iris.util.scheduling.jobs.QueueJob;
import io.papermc.lib.PaperLib; import io.papermc.lib.PaperLib;
import org.bukkit.*; import org.bukkit.*;
@ -73,12 +79,14 @@ import java.util.Date;
import java.util.Objects; import java.util.Objects;
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.AtomicInteger;
import java.util.function.Supplier; import java.util.function.Supplier;
@Decree(name = "studio", aliases = {"std", "s"}, description = "Studio Commands", studio = true) @Decree(name = "studio", aliases = {"std", "s"}, description = "Studio Commands", studio = true)
public class CommandStudio implements DecreeExecutor { public class CommandStudio implements DecreeExecutor {
private CommandFind find; private CommandFind find;
private CommandEdit edit; private CommandEdit edit;
//private CommandDeepSearch deepSearch;
public static String hrf(Duration duration) { public static String hrf(Duration duration) {
return duration.toString().substring(2).replaceAll("(\\d[HMS])(?!$)", "$1 ").toLowerCase(); return duration.toString().substring(2).replaceAll("(\\d[HMS])(?!$)", "$1 ").toLowerCase();
@ -278,8 +286,7 @@ public class CommandStudio implements DecreeExecutor {
sender().sendMessage(C.RED + "No studio world open!"); sender().sendMessage(C.RED + "No studio world open!");
return; return;
} }
var provider = Iris.service(StudioSVC.class).getActiveProject().getActiveProvider(); Iris.service(StudioSVC.class).getActiveProject().getActiveProvider().getEngine().hotload();
provider.getEngine().hotload();
sender().sendMessage(C.GREEN + "Hotloaded"); sender().sendMessage(C.GREEN + "Hotloaded");
} }
@ -384,10 +391,18 @@ public class CommandStudio implements DecreeExecutor {
} }
@Decree(description = "Render a world map (External GUI)", aliases = "render") @Decree(description = "Render a world map (External GUI)", aliases = "render")
public void map() { public void map(
@Param(name = "world", description = "The world to open the generator for", contextual = true)
World world
) {
if (noGUI()) return; if (noGUI()) return;
if (noStudio()) return;
VisionGUI.launch(IrisToolbelt.access(player().getWorld()).getEngine(), 0); if (!IrisToolbelt.isIrisWorld(world)) {
sender().sendMessage(C.RED + "You need to be in or specify an Iris-generated world!");
return;
}
VisionGUI.launch(IrisToolbelt.access(world).getEngine(), 0);
sender().sendMessage(C.GREEN + "Opening map!"); sender().sendMessage(C.GREEN + "Opening map!");
} }
@ -408,8 +423,188 @@ public class CommandStudio implements DecreeExecutor {
@Param(description = "The dimension to profile", contextual = true, defaultValue = "default") @Param(description = "The dimension to profile", contextual = true, defaultValue = "default")
IrisDimension dimension IrisDimension dimension
) { ) {
IrisNoiseBenchmark noiseBenchmark = new IrisNoiseBenchmark(dimension, sender()); // Todo: Make this more accurate
noiseBenchmark.runAll(); File pack = dimension.getLoadFile().getParentFile().getParentFile();
File report = Iris.instance.getDataFile("profile.txt");
IrisProject project = new IrisProject(pack);
IrisData data = IrisData.get(pack);
KList<String> fileText = new KList<>();
KMap<NoiseStyle, Double> styleTimings = new KMap<>();
KMap<InterpolationMethod, Double> interpolatorTimings = new KMap<>();
KMap<String, Double> generatorTimings = new KMap<>();
KMap<String, Double> biomeTimings = new KMap<>();
KMap<String, Double> regionTimings = new KMap<>();
sender().sendMessage("Calculating Performance Metrics for Noise generators");
for (NoiseStyle i : NoiseStyle.values()) {
CNG c = i.create(new RNG(i.hashCode()));
for (int j = 0; j < 3000; j++) {
c.noise(j, j + 1000, j * j);
c.noise(j, -j);
}
PrecisionStopwatch px = PrecisionStopwatch.start();
for (int j = 0; j < 100000; j++) {
c.noise(j, j + 1000, j * j);
c.noise(j, -j);
}
styleTimings.put(i, px.getMilliseconds());
}
fileText.add("Noise Style Performance Impacts: ");
for (NoiseStyle i : styleTimings.sortKNumber()) {
fileText.add(i.name() + ": " + styleTimings.get(i));
}
fileText.add("");
sender().sendMessage("Calculating Interpolator Timings...");
for (InterpolationMethod i : InterpolationMethod.values()) {
IrisInterpolator in = new IrisInterpolator();
in.setFunction(i);
in.setHorizontalScale(8);
NoiseProvider np = (x, z) -> Math.random();
for (int j = 0; j < 3000; j++) {
in.interpolate(j, -j, np);
}
PrecisionStopwatch px = PrecisionStopwatch.start();
for (int j = 0; j < 100000; j++) {
in.interpolate(j + 10000, -j - 100000, np);
}
interpolatorTimings.put(i, px.getMilliseconds());
}
fileText.add("Noise Interpolator Performance Impacts: ");
for (InterpolationMethod i : interpolatorTimings.sortKNumber()) {
fileText.add(i.name() + ": " + interpolatorTimings.get(i));
}
fileText.add("");
sender().sendMessage("Processing Generator Scores: ");
KMap<String, KList<String>> btx = new KMap<>();
for (String i : data.getGeneratorLoader().getPossibleKeys()) {
KList<String> vv = new KList<>();
IrisGenerator g = data.getGeneratorLoader().load(i);
KList<IrisNoiseGenerator> composites = g.getAllComposites();
double score = 0;
int m = 0;
for (IrisNoiseGenerator j : composites) {
m++;
score += styleTimings.get(j.getStyle().getStyle());
vv.add("Composite Noise Style " + m + " " + j.getStyle().getStyle().name() + ": " + styleTimings.get(j.getStyle().getStyle()));
}
score += interpolatorTimings.get(g.getInterpolator().getFunction());
vv.add("Interpolator " + g.getInterpolator().getFunction().name() + ": " + interpolatorTimings.get(g.getInterpolator().getFunction()));
generatorTimings.put(i, score);
btx.put(i, vv);
}
fileText.add("Project Generator Performance Impacts: ");
for (String i : generatorTimings.sortKNumber()) {
fileText.add(i + ": " + generatorTimings.get(i));
btx.get(i).forEach((ii) -> fileText.add(" " + ii));
}
fileText.add("");
KMap<String, KList<String>> bt = new KMap<>();
for (String i : data.getBiomeLoader().getPossibleKeys()) {
KList<String> vv = new KList<>();
IrisBiome b = data.getBiomeLoader().load(i);
double score = 0;
int m = 0;
for (IrisBiomePaletteLayer j : b.getLayers()) {
m++;
score += styleTimings.get(j.getStyle().getStyle());
vv.add("Palette Layer " + m + ": " + styleTimings.get(j.getStyle().getStyle()));
}
score += styleTimings.get(b.getBiomeStyle().getStyle());
vv.add("Biome Style: " + styleTimings.get(b.getBiomeStyle().getStyle()));
score += styleTimings.get(b.getChildStyle().getStyle());
vv.add("Child Style: " + styleTimings.get(b.getChildStyle().getStyle()));
biomeTimings.put(i, score);
bt.put(i, vv);
}
fileText.add("Project Biome Performance Impacts: ");
for (String i : biomeTimings.sortKNumber()) {
fileText.add(i + ": " + biomeTimings.get(i));
bt.get(i).forEach((ff) -> fileText.add(" " + ff));
}
fileText.add("");
for (String i : data.getRegionLoader().getPossibleKeys()) {
IrisRegion b = data.getRegionLoader().load(i);
double score = 0;
score += styleTimings.get(b.getLakeStyle().getStyle());
score += styleTimings.get(b.getRiverStyle().getStyle());
regionTimings.put(i, score);
}
fileText.add("Project Region Performance Impacts: ");
for (String i : regionTimings.sortKNumber()) {
fileText.add(i + ": " + regionTimings.get(i));
}
fileText.add("");
double m = 0;
for (double i : biomeTimings.v()) {
m += i;
}
m /= biomeTimings.size();
double mm = 0;
for (double i : generatorTimings.v()) {
mm += i;
}
mm /= generatorTimings.size();
m += mm;
double mmm = 0;
for (double i : regionTimings.v()) {
mmm += i;
}
mmm /= regionTimings.size();
m += mmm;
fileText.add("Average Score: " + m);
sender().sendMessage("Score: " + Form.duration(m, 0));
try {
IO.writeAll(report, fileText.toString("\n"));
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
sender().sendMessage(C.GREEN + "Done! " + report.getPath());
} }
@Decree(description = "Spawn an Iris entity", aliases = "summon", origin = DecreeOrigin.PLAYER) @Decree(description = "Spawn an Iris entity", aliases = "summon", origin = DecreeOrigin.PLAYER)

View File

@ -88,7 +88,8 @@ public class CommandWhat implements DecreeExecutor {
@Decree(description = "What region am i in?", origin = DecreeOrigin.PLAYER) @Decree(description = "What region am i in?", origin = DecreeOrigin.PLAYER)
public void region() { public void region() {
try { try {
IrisRegion r = engine().getRegion(player().getLocation()); Chunk chunk = world().getChunkAt(player().getLocation().getBlockZ() / 16, player().getLocation().getBlockZ() / 16);
IrisRegion r = engine().getRegion(chunk);
sender().sendMessage("IRegion: " + r.getLoadKey() + " (" + r.getName() + ")"); sender().sendMessage("IRegion: " + r.getLoadKey() + " (" + r.getName() + ")");
} catch (Throwable e) { } catch (Throwable e) {

View File

@ -80,7 +80,6 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
private boolean lowtile = false; private boolean lowtile = false;
private boolean follow = false; private boolean follow = false;
private boolean alt = false; private boolean alt = false;
private boolean dragging = false;
private IrisRenderer renderer; private IrisRenderer renderer;
private IrisWorld world; private IrisWorld world;
private double velocity = 0; private double velocity = 0;
@ -202,7 +201,6 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
@Override @Override
public void mouseDragged(MouseEvent e) { public void mouseDragged(MouseEvent e) {
dragging = true;
Point cp = e.getPoint(); Point cp = e.getPoint();
ox += (lx - cp.getX()) * scale; ox += (lx - cp.getX()) * scale;
oz += (lz - cp.getY()) * scale; oz += (lz - cp.getY()) * scale;
@ -415,7 +413,7 @@ public class VisionGUI extends JPanel implements MouseWheelListener, KeyListener
private double getWorldX(double screenX) { private double getWorldX(double screenX) {
//return (mscale * screenX) + ((oxp / scale) * mscale); //return (mscale * screenX) + ((oxp / scale) * mscale);
return (mscale * screenX) + ((oxp / scale) * mscale); return (mscale * screenX) + ((oxp / scale));
} }
private double getWorldZ(double screenZ) { private double getWorldZ(double screenZ) {

View File

@ -1,22 +0,0 @@
package com.volmit.iris.core.nms;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.documentation.RegionCoordinates;
import com.volmit.iris.util.parallel.MultiBurst;
import java.io.Closeable;
public interface IHeadless extends Closeable {
void save();
@ChunkCoordinates
boolean exists(int x, int z);
@RegionCoordinates
void generateRegion(MultiBurst burst, int x, int z, PregenListener listener);
@ChunkCoordinates
void generateChunk(int x, int z);
}

View File

@ -20,8 +20,6 @@ package com.volmit.iris.core.nms;
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.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
@ -117,14 +115,4 @@ public interface INMSBinding {
default DataVersion getDataVersion() { default DataVersion getDataVersion() {
return DataVersion.V1192; return DataVersion.V1192;
} }
boolean registerDimension(String name, IrisDimension dimension);
boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace);
void injectBukkit();
default IHeadless createHeadless(Engine engine) {
throw new IllegalStateException("Headless mode not supported");
}
} }

View File

@ -18,29 +18,20 @@
package com.volmit.iris.core.nms.v1X; package com.volmit.iris.core.nms.v1X;
import com.google.common.base.Preconditions;
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.BlockPos; import com.volmit.iris.core.nms.container.BlockPos;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.math.Vector3d; import com.volmit.iris.util.math.Vector3d;
import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer; import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer;
import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess; import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess;
import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.CompoundTag;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.matcher.ElementMatchers;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.entity.Dolphin; import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
@ -49,8 +40,6 @@ import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import java.io.File;
public class NMSBinding1X implements INMSBinding { public class NMSBinding1X implements INMSBinding {
private static final boolean supportsCustomHeight = testCustomHeight(); private static final boolean supportsCustomHeight = testCustomHeight();
@ -108,16 +97,6 @@ public class NMSBinding1X implements INMSBinding {
return location.getWorld().spawnEntity(location, type); return location.getWorld().spawnEntity(location, type);
} }
@Override
public boolean registerDimension(String name, IrisDimension dimension) {
return false;
}
@Override
public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) {
return false;
}
@Override @Override
public void deserializeTile(CompoundTag s, Location newPosition) { public void deserializeTile(CompoundTag s, Location newPosition) {
@ -246,39 +225,4 @@ public class NMSBinding1X implements INMSBinding {
Iris.error("Cannot use the global data palette! Iris is incapable of using MCA generation on this version of minecraft!"); Iris.error("Cannot use the global data palette! Iris is incapable of using MCA generation on this version of minecraft!");
return null; return null;
} }
public void injectBukkit() {
try {
Iris.info("Injecting Bukkit");
new ByteBuddy()
.redefine(WorldCreator.class)
.visit(Advice.to(WorldCreatorAdvice.class).on(ElementMatchers.isConstructor().and(ElementMatchers.takesArguments(String.class))))
.make()
.load(WorldCreator.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
Iris.info("Injected Bukkit Successfully!");
} catch (Exception e) {
Iris.info(C.RED + "Failed to Inject Bukkit!");
e.printStackTrace();
Iris.reportError(e);
}
}
private static class WorldCreatorAdvice {
@Advice.OnMethodEnter
static void enter(@Advice.Argument(0) String name) {
File isIrisWorld = new File(name, "iris");
boolean isFromIris = false;
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement stack : stackTrace) {
if (stack.getClassName().contains("Iris")) {
isFromIris = true;
break;
}
}
if (!isFromIris) {
Preconditions.checkArgument(!isIrisWorld.exists(), "Only Iris can load Iris Worlds!");
}
}
}
} }

View File

@ -106,7 +106,7 @@ public class ChunkUpdater {
try { try {
if (!paused.get()) { if (!paused.get()) {
long eta = computeETA(); long eta = computeETA();
long elapsedSeconds = (System.currentTimeMillis() - startTime.get()) / 3000; long elapsedSeconds = (System.currentTimeMillis() - startTime.get()) / 1000;
int processed = chunksProcessed.get(); int processed = chunksProcessed.get();
double cps = elapsedSeconds > 0 ? processed / (double) elapsedSeconds : 0; double cps = elapsedSeconds > 0 ? processed / (double) elapsedSeconds : 0;
chunksPerSecond.put(cps); chunksPerSecond.put(cps);

View File

@ -0,0 +1,275 @@
package com.volmit.iris.core.pregenerator;
import com.google.gson.Gson;
import com.volmit.iris.Iris;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
public class DeepSearchPregenerator extends Thread implements Listener {
@Getter
private static DeepSearchPregenerator instance;
private final DeepSearchJob job;
private final File destination;
private final int maxPosition;
private World world;
private final ChronoLatch latch;
private static AtomicInteger foundChunks;
private final AtomicInteger foundLast;
private final AtomicInteger foundTotalChunks;
private final AtomicLong startTime;
private final RollingSequence chunksPerSecond;
private final RollingSequence chunksPerMinute;
private final AtomicInteger chunkCachePos;
private final AtomicInteger chunkCacheSize;
private int pos;
private final AtomicInteger foundCacheLast;
private final AtomicInteger foundCache;
private LinkedHashMap<Integer, Position2> chunkCache;
private KList<Position2> chunkQueue;
private final ReentrantLock cacheLock;
private static final Map<String, DeepSearchJob> jobs = new HashMap<>();
public DeepSearchPregenerator(DeepSearchJob job, File destination) {
this.job = job;
this.chunkCacheSize = new AtomicInteger(); // todo
this.chunkCachePos = new AtomicInteger(1000);
this.foundCacheLast = new AtomicInteger();
this.foundCache = new AtomicInteger();
this.cacheLock = new ReentrantLock();
this.destination = destination;
this.chunkCache = new LinkedHashMap<>();
this.maxPosition = new Spiraler(job.getRadiusBlocks() * 2, job.getRadiusBlocks() * 2, (x, z) -> {
}).count();
this.world = Bukkit.getWorld(job.getWorld().getUID());
this.chunkQueue = new KList<>();
this.latch = new ChronoLatch(3000);
this.startTime = new AtomicLong(M.ms());
this.chunksPerSecond = new RollingSequence(10);
this.chunksPerMinute = new RollingSequence(10);
foundChunks = new AtomicInteger(0);
this.foundLast = new AtomicInteger(0);
this.foundTotalChunks = new AtomicInteger((int) Math.ceil(Math.pow((2.0 * job.getRadiusBlocks()) / 16, 2)));
this.pos = 0;
jobs.put(job.getWorld().getName(), job);
DeepSearchPregenerator.instance = this;
}
@EventHandler
public void on(WorldUnloadEvent e) {
if (e.getWorld().equals(world)) {
interrupt();
}
}
public void run() {
while (!interrupted()) {
tick();
}
try {
saveNow();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void tick() {
DeepSearchJob job = jobs.get(world.getName());
// chunkCache(); //todo finish this
if (latch.flip() && !job.paused) {
if (cacheLock.isLocked()) {
Iris.info("DeepFinder: Caching: " + chunkCachePos.get() + " Of " + chunkCacheSize.get());
} else {
long eta = computeETA();
save();
int secondGenerated = foundChunks.get() - foundLast.get();
foundLast.set(foundChunks.get());
secondGenerated = secondGenerated / 3;
chunksPerSecond.put(secondGenerated);
chunksPerMinute.put(secondGenerated * 60);
Iris.info("DeepFinder: " + C.IRIS + world.getName() + C.RESET + " Searching: " + Form.f(foundChunks.get()) + " of " + Form.f(foundTotalChunks.get()) + " " + Form.f((int) chunksPerSecond.getAverage()) + "/s ETA: " + Form.duration((double) eta, 2));
}
}
if (foundChunks.get() >= foundTotalChunks.get()) {
Iris.info("Completed DeepSearch!");
interrupt();
}
}
private long computeETA() {
return (long) ((foundTotalChunks.get() - foundChunks.get()) / chunksPerSecond.getAverage()) * 1000;
// todo broken
}
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
private void queueSystem(Position2 chunk) {
if (chunkQueue.isEmpty()) {
for (int limit = 512; limit != 0; limit--) {
pos = job.getPosition() + 1;
chunkQueue.add(getChunk(pos));
}
} else {
//MCAUtil.read();
}
}
private void findInChunk(World world, int x, int z) throws IOException {
int xx = x * 16;
int zz = z * 16;
Engine engine = IrisToolbelt.access(world).getEngine();
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
int height = engine.getHeight(xx + i, zz + j);
if (height > 300) {
File found = new File("plugins" + "iris" + "found.txt");
FileWriter writer = new FileWriter(found);
if (!found.exists()) {
found.createNewFile();
}
IrisBiome biome = engine.getBiome(xx, engine.getHeight(), zz);
Iris.info("Found at! " + xx + ", " + zz + "Biome ID: " + biome.getName() + ", ");
writer.write("Biome at: X: " + xx + " Z: " + zz + "Biome ID: " + biome.getName() + ", ");
return;
}
}
}
}
public Position2 getChunk(int position) {
int p = -1;
AtomicInteger xx = new AtomicInteger();
AtomicInteger zz = new AtomicInteger();
Spiraler s = new Spiraler(job.getRadiusBlocks() * 2, job.getRadiusBlocks() * 2, (x, z) -> {
xx.set(x);
zz.set(z);
});
while (s.hasNext() && p++ < position) {
s.next();
}
return new Position2(xx.get(), zz.get());
}
public void save() {
J.a(() -> {
try {
saveNow();
} catch (Throwable e) {
e.printStackTrace();
}
});
}
public static void setPausedDeep(World world) {
DeepSearchJob job = jobs.get(world.getName());
if (isPausedDeep(world)){
job.paused = false;
} else {
job.paused = true;
}
if ( job.paused) {
Iris.info(C.BLUE + "DeepSearch: " + C.IRIS + world.getName() + C.BLUE + " Paused");
} else {
Iris.info(C.BLUE + "DeepSearch: " + C.IRIS + world.getName() + C.BLUE + " Resumed");
}
}
public static boolean isPausedDeep(World world) {
DeepSearchJob job = jobs.get(world.getName());
return job != null && job.isPaused();
}
public void shutdownInstance(World world) throws IOException {
Iris.info("DeepSearch: " + C.IRIS + world.getName() + C.BLUE + " Shutting down..");
DeepSearchJob job = jobs.get(world.getName());
File worldDirectory = new File(Bukkit.getWorldContainer(), world.getName());
File deepFile = new File(worldDirectory, "DeepSearch.json");
if (job == null) {
Iris.error("No DeepSearch job found for world: " + world.getName());
return;
}
try {
if (!job.isPaused()) {
job.setPaused(true);
}
save();
jobs.remove(world.getName());
new BukkitRunnable() {
@Override
public void run() {
while (deepFile.exists()){
deepFile.delete();
J.sleep(1000);
}
Iris.info("DeepSearch: " + C.IRIS + world.getName() + C.BLUE + " File deleted and instance closed.");
}
}.runTaskLater(Iris.instance, 20L);
} catch (Exception e) {
Iris.error("Failed to shutdown DeepSearch for " + world.getName());
e.printStackTrace();
} finally {
saveNow();
interrupt();
}
}
public void saveNow() throws IOException {
IO.writeAll(this.destination, new Gson().toJson(job));
}
@Data
@Builder
public static class DeepSearchJob {
private World world;
@Builder.Default
private int radiusBlocks = 5000;
@Builder.Default
private int position = 0;
@Builder.Default
boolean paused = false;
}
}

View File

@ -82,8 +82,11 @@ public class AsyncPregenMethod implements PregeneratorMethod {
private void completeChunk(int x, int z, PregenListener listener) { private void completeChunk(int x, int z, PregenListener listener) {
try { try {
future.add(PaperLib.getChunkAtAsync(world, x, z, true).thenApply((i) -> { future.add(PaperLib.getChunkAtAsync(world, x, z, true).thenApply((i) -> {
if (i == null) return 0; if (i == null) {
lastUse.put(i, M.ms());
}
Chunk c = Bukkit.getWorld(world.getUID()).getChunkAt(x, z);
lastUse.put(c, M.ms());
listener.onChunkGenerated(x, z); listener.onChunkGenerated(x, z);
listener.onChunkCleaned(x, z); listener.onChunkCleaned(x, z);
return 0; return 0;

View File

@ -1,87 +0,0 @@
package com.volmit.iris.core.pregenerator.methods;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.nms.IHeadless;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.mantle.Mantle;
import com.volmit.iris.util.parallel.MultiBurst;
import java.io.IOException;
import java.util.concurrent.Semaphore;
public class HeadlessPregenMethod implements PregeneratorMethod {
private final Engine engine;
private final IHeadless headless;
private final Semaphore semaphore;
private final int max;
public HeadlessPregenMethod(Engine engine) {
this.max = IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism());
this.engine = engine;
this.headless = INMS.get().createHeadless(engine);
this.semaphore = new Semaphore(max);
}
@Override
public void init() {}
@Override
public void close() {
try {
semaphore.acquire(max);
} catch (InterruptedException ignored) {}
headless.save();
try {
headless.close();
} catch (IOException e) {
Iris.error("Failed to close headless");
e.printStackTrace();
}
}
@Override
public void save() {
headless.save();
}
@Override
public boolean supportsRegions(int x, int z, PregenListener listener) {
return false;
}
@Override
public String getMethod(int x, int z) {
return "Headless";
}
@Override
public void generateRegion(int x, int z, PregenListener listener) {}
@Override
public void generateChunk(int x, int z, PregenListener listener) {
try {
semaphore.acquire();
} catch (InterruptedException ignored) {
semaphore.release();
return;
}
MultiBurst.burst.complete(() -> {
try {
listener.onChunkGenerating(x, z);
headless.generateChunk(x, z);
listener.onChunkGenerated(x, z);
} finally {
semaphore.release();
}
});
}
@Override
public Mantle getMantle() {
return engine.getMantle().getMantle();
}
}

View File

@ -119,7 +119,8 @@ public class MedievalPregenMethod implements PregeneratorMethod {
listener.onChunkGenerating(x, z); listener.onChunkGenerating(x, z);
futures.add(J.sfut(() -> { futures.add(J.sfut(() -> {
Chunk c = world.getChunkAt(x, z); world.getChunkAt(x, z);
Chunk c = Bukkit.getWorld(world.getUID()).getChunkAt(x, z);
lastUse.put(c, M.ms()); lastUse.put(c, M.ms());
listener.onChunkGenerated(x, z); listener.onChunkGenerated(x, z);
listener.onChunkCleaned(x, z); listener.onChunkCleaned(x, z);

View File

@ -1,71 +1,15 @@
package com.volmit.iris.core.safeguard; package com.volmit.iris.core.safeguard;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.safeguard.handler.onCommandWarning;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.misc.getHardware;
import static org.bukkit.Bukkit.getServer;
public class IrisSafeguard { public class IrisSafeguard {
public static IrisSafeguard instance; public static boolean unstablemode = false;
public boolean acceptUnstable = false; public static boolean warningmode = false;
public boolean unstablemode = false; public static boolean stablemode = false;
public boolean warningmode = false;
public boolean stablemode = false;
public static void InitializeSafeguard() { public static void IrisSafeguardSystem() {
instance = new IrisSafeguard();
}
public void IrisSafeguardSystem() {
acceptUnstable = IrisSettings.get().getSafeguard().ignoreBootMode;
getServer().getPluginManager().registerEvents(new onCommandWarning(), Iris.instance);
Iris.info("Enabled Iris SafeGuard"); Iris.info("Enabled Iris SafeGuard");
ServerBootSFG.BootCheck(); ServerBootSFG.BootCheck();
} }
public void earlySplash() {
String padd = Form.repeat(" ", 8);
String padd2 = Form.repeat(" ", 4);
String[] info = new String[]{"", "", "", "", "", padd2 + C.RED + " Iris", padd2 + C.GRAY + " by " + C.DARK_RED + "Volmit Software", padd2 + C.GRAY + " v" + C.RED + Iris.instance.getDescription().getVersion()};
String[] splashunstable = {
padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@",
padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + C.RED + " .(((()))). ",
padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + C.RED + " .((((((())))))). ",
padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + C.RED + " ((((((((())))))))) " + C.GRAY + " @",
padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + C.RED + " ((((((((-))))))))) " + C.GRAY + " @@",
padd + C.GRAY + "@@@&&" + C.RED + " ((((((({ })))))))) " + C.GRAY + " &&@@@",
padd + C.GRAY + "@@" + C.RED + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@",
padd + C.GRAY + "@" + C.RED + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@",
padd + C.GRAY + "" + C.RED + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@",
padd + C.GRAY + "" + C.RED + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@",
padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@"
};
for (int i = 0; i < info.length; i++) {
splashunstable[i] += info[i];
}
Iris.info("Java: " + Iris.instance.getJava());
if (!Iris.instance.getServer().getVersion().contains("Purpur")) {
if (Iris.instance.getServer().getVersion().contains("Spigot") && Iris.instance.getServer().getVersion().contains("Bukkit")) {
Iris.info(C.RED + " Iris requires paper or above to function properly..");
} else {
Iris.info(C.YELLOW + "Purpur is recommended to use with iris.");
}
}
if (getHardware.getProcessMemory() < 5999) {
Iris.warn("6GB+ Ram is recommended");
Iris.warn("Process Memory: " + getHardware.getProcessMemory() + " MB");
}
Iris.info("Custom Biomes: " + INMS.get().countCustomBiomes());
Iris.info("\n\n " + new KList<>(splashunstable).toString("\n") + "\n");
UtilsSFG.splash();
}
} }

View File

@ -3,20 +3,18 @@ package com.volmit.iris.core.safeguard;
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.util.format.C; import com.volmit.iris.util.format.C;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitScheduler;
public class ModesSFG { public class ModesSFG {
public static void selectMode() { public static void selectMode() {
if (IrisSafeguard.instance.unstablemode) { if (IrisSafeguard.unstablemode) {
Iris.safeguard(C.DARK_RED + "Iris is running in Unstable Mode"); Iris.safeguard(C.DARK_RED + "Iris is running in Unstable Mode");
unstable(); unstable();
} }
if (IrisSafeguard.instance.warningmode) { if (IrisSafeguard.warningmode) {
Iris.safeguard(C.GOLD + "Iris is running in Warning Mode"); Iris.safeguard(C.GOLD + "Iris is running in Warning Mode");
warning(); warning();
} }
if (IrisSafeguard.instance.stablemode) { if (IrisSafeguard.stablemode) {
stable(); stable();
} }
} }
@ -29,7 +27,7 @@ public class ModesSFG {
UtilsSFG.printIncompatibleWarnings(); UtilsSFG.printIncompatibleWarnings();
if (IrisSafeguard.instance.unstablemode) { if (IrisSafeguard.unstablemode) {
Iris.info(""); Iris.info("");
Iris.info(C.DARK_GRAY + "--==<" + C.RED + " IMPORTANT " + C.DARK_GRAY + ">==--"); Iris.info(C.DARK_GRAY + "--==<" + C.RED + " IMPORTANT " + C.DARK_GRAY + ">==--");
Iris.info(C.RED + "Iris is running in unstable mode which may cause the following issues:"); Iris.info(C.RED + "Iris is running in unstable mode which may cause the following issues:");
@ -46,26 +44,27 @@ public class ModesSFG {
Iris.info(C.DARK_RED + "ATTENTION: " + C.RED + "While running Iris in unstable mode, you won't be eligible for support."); Iris.info(C.DARK_RED + "ATTENTION: " + C.RED + "While running Iris in unstable mode, you won't be eligible for support.");
Iris.info(C.DARK_RED + "CAUSE: " + C.RED + UtilsSFG.MSGIncompatibleWarnings()); Iris.info(C.DARK_RED + "CAUSE: " + C.RED + UtilsSFG.MSGIncompatibleWarnings());
if (IrisSettings.get().getSafeguard().ignoreBootMode) { if (IrisSettings.get().getGeneral().ignoreBootMode) {
Iris.info(C.DARK_RED + "Boot Unstable is set to true, continuing with the startup process."); Iris.info(C.DARK_RED + "Boot Unstable is set to true, continuing with the startup process.");
} else { } else {
Iris.info(C.DARK_RED + "Go to plugins/iris/settings.json and set ignoreBootMode to true if you wish to proceed."); Iris.info(C.DARK_RED + "Go to plugins/iris/settings.json and set ignoreBootMode to true if you wish to proceed.");
Iris.info(C.DARK_RED + "Shutting down server in " + C.UNDERLINE + "" + C.DARK_RED + "50 Seconds"); while (true) {
try { try {
Thread.sleep(50000); Thread.sleep(1000);
Bukkit.shutdown(); } catch (InterruptedException e) {
} catch (Exception ignored) { // no
} }
} }
} }
Iris.info(""); Iris.info("");
} }
}
public static void warning() { public static void warning() {
UtilsSFG.printIncompatibleWarnings(); UtilsSFG.printIncompatibleWarnings();
if (IrisSafeguard.instance.warningmode) { if (IrisSafeguard.warningmode) {
Iris.info(""); Iris.info("");
Iris.info(C.DARK_GRAY + "--==<" + C.GOLD + " IMPORTANT " + C.DARK_GRAY + ">==--"); Iris.info(C.DARK_GRAY + "--==<" + C.GOLD + " IMPORTANT " + C.DARK_GRAY + ">==--");
Iris.info(C.GOLD + "Iris is running in warning mode which may cause the following issues:"); Iris.info(C.GOLD + "Iris is running in warning mode which may cause the following issues:");

View File

@ -0,0 +1,8 @@
package com.volmit.iris.core.safeguard;
public class PerformanceSFG {
public static void calculatePerformance() {
}
}

View File

@ -116,16 +116,16 @@ public class ServerBootSFG {
safeguardPassed = (severityHigh == 0 && severityMedium == 0 && severityLow == 0); safeguardPassed = (severityHigh == 0 && severityMedium == 0 && severityLow == 0);
count = severityHigh + severityMedium + severityLow; count = severityHigh + severityMedium + severityLow;
if (safeguardPassed) { if (safeguardPassed) {
IrisSafeguard.instance.stablemode = true; stablemode = true;
Iris.safeguard("Stable mode has been activated."); Iris.safeguard("Stable mode has been activated.");
} }
if (!safeguardPassed) { if (!safeguardPassed) {
if (severityMedium >= 1 && severityHigh == 0) { if (severityMedium >= 1 && severityHigh == 0) {
IrisSafeguard.instance.warningmode = true; warningmode = true;
Iris.safeguard("Warning mode has been activated."); Iris.safeguard("Warning mode has been activated.");
} }
if (severityHigh >= 1) { if (severityHigh >= 1) {
IrisSafeguard.instance.unstablemode = true; unstablemode = true;
Iris.safeguard("Unstable mode has been activated."); Iris.safeguard("Unstable mode has been activated.");
} }
} }

View File

@ -14,10 +14,10 @@ public class UtilsSFG {
if (ServerBootSFG.safeguardPassed) { if (ServerBootSFG.safeguardPassed) {
Iris.safeguard(C.BLUE + "0 Conflicts found"); Iris.safeguard(C.BLUE + "0 Conflicts found");
} else { } else {
if (IrisSafeguard.instance.unstablemode) { if (IrisSafeguard.unstablemode) {
Iris.safeguard(C.DARK_RED + "" + ServerBootSFG.count + " Conflicts found"); Iris.safeguard(C.DARK_RED + "" + ServerBootSFG.count + " Conflicts found");
} }
if (IrisSafeguard.instance.warningmode) { if (IrisSafeguard.warningmode) {
Iris.safeguard(C.YELLOW + "" + ServerBootSFG.count + " Conflicts found"); Iris.safeguard(C.YELLOW + "" + ServerBootSFG.count + " Conflicts found");
} }

View File

@ -1,27 +0,0 @@
package com.volmit.iris.core.safeguard.handler;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.safeguard.IrisSafeguard;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
public class onCommandWarning implements Listener {
@EventHandler
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
if (IrisSettings.get().getSafeguard().userUnstableWarning && IrisSafeguard.instance.unstablemode) {
String command = event.getMessage();
Player player = event.getPlayer();
if (command.startsWith("/iris")) {
VolmitSender sender = new VolmitSender(player);
boolean perm = sender.hasPermission("iris.all") || sender.isOp();
if (perm) {
sender.sendMessage(C.DARK_GRAY + "[" + C.RED + "!" + C.DARK_GRAY+ "]" + C.DARK_RED + "Iris is running unstably! Please resolve this.");
}
}
}
}
}

View File

@ -22,6 +22,7 @@ import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
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.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
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;
@ -295,6 +296,7 @@ public class StudioSVC implements IrisService {
} }
sender.sendMessage("Successfully Aquired " + d.getName()); sender.sendMessage("Successfully Aquired " + d.getName());
ServerConfigurator.installDataPacks(true);
} }
public KMap<String, String> getListing(boolean cached) { public KMap<String, String> getListing(boolean cached) {

View File

@ -21,10 +21,13 @@ package com.volmit.iris.core.tools;
import com.google.common.util.concurrent.AtomicDouble; import com.google.common.util.concurrent.AtomicDouble;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.ServerConfigurator;
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.framework.Engine;
import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.engine.platform.PlatformChunkGenerator; import com.volmit.iris.engine.platform.PlatformChunkGenerator;
import com.volmit.iris.core.safeguard.UtilsSFG;
import com.volmit.iris.util.exceptions.IrisException; import com.volmit.iris.util.exceptions.IrisException;
import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form; import com.volmit.iris.util.format.Form;
@ -43,6 +46,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier; import java.util.function.Supplier;
import static com.volmit.iris.core.safeguard.IrisSafeguard.unstablemode;
/** /**
* Makes it a lot easier to setup an engine, world, studio or whatever * Makes it a lot easier to setup an engine, world, studio or whatever
@ -141,6 +145,7 @@ public class IrisCreator {
.studio(studio) .studio(studio)
.smartVanillaHeight(smartVanillaHeight) .smartVanillaHeight(smartVanillaHeight)
.create(); .create();
ServerConfigurator.installDataPacks(false);
access = (PlatformChunkGenerator) wc.generator(); access = (PlatformChunkGenerator) wc.generator();
PlatformChunkGenerator finalAccess1 = access; PlatformChunkGenerator finalAccess1 = access;

View File

@ -1,254 +0,0 @@
package com.volmit.iris.core.tools;
import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.project.IrisProject;
import com.volmit.iris.engine.object.*;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.decree.DecreeOrigin;
import com.volmit.iris.util.decree.annotations.Decree;
import com.volmit.iris.util.decree.annotations.Param;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.function.NoiseProvider;
import com.volmit.iris.util.interpolation.InterpolationMethod;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.noise.CNG;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import java.io.File;
import java.io.IOException;
public class IrisNoiseBenchmark {
private IrisDimension dimension;
private VolmitSender sender;
public IrisNoiseBenchmark(IrisDimension dimension, VolmitSender sender) {
this.dimension = dimension;
this.sender = sender;
}
public void runAll() {
// Todo: Make this more accurate
File pack = dimension.getLoadFile().getParentFile().getParentFile();
File report = Iris.instance.getDataFile(pack.getName() + "-profile.txt");
IrisProject project = new IrisProject(pack);
IrisData data = IrisData.get(pack);
KList<String> fileText = new KList<>();
KMap<NoiseStyle, Double> styleTimings = new KMap<>();
KMap<InterpolationMethod, Double> interpolatorTimings = new KMap<>();
KMap<String, Double> generatorTimings = new KMap<>();
KMap<String, Double> biomeTimings = new KMap<>();
KMap<String, Double> regionTimings = new KMap<>();
KMap<String, Double> dimensionTimings = new KMap<>();
sender.sendMessage("Calculating Performance Metrics for Noise generators");
for (NoiseStyle i : NoiseStyle.values()) {
CNG c = i.create(new RNG(i.hashCode()));
for (int j = 0; j < 3000; j++) {
c.noise(j, j + 1000, j * j);
c.noise(j, -j);
}
PrecisionStopwatch px = PrecisionStopwatch.start();
for (int j = 0; j < 100000; j++) {
c.noise(j, j + 1000, j * j);
c.noise(j, -j);
}
styleTimings.put(i, px.getMilliseconds());
}
fileText.add("Noise Style Performance Impacts: ");
for (NoiseStyle i : styleTimings.sortKNumber()) {
fileText.add(i.name() + ": " + styleTimings.get(i));
}
fileText.add("");
sender.sendMessage("Calculating Interpolator Timings...");
for (InterpolationMethod i : InterpolationMethod.values()) {
IrisInterpolator in = new IrisInterpolator();
in.setFunction(i);
in.setHorizontalScale(8);
NoiseProvider np = (x, z) -> Math.random();
for (int j = 0; j < 3000; j++) {
in.interpolate(j, -j, np);
}
PrecisionStopwatch px = PrecisionStopwatch.start();
for (int j = 0; j < 100000; j++) {
in.interpolate(j + 10000, -j - 100000, np);
}
interpolatorTimings.put(i, px.getMilliseconds());
}
fileText.add("Noise Interpolator Performance Impacts: ");
for (InterpolationMethod i : interpolatorTimings.sortKNumber()) {
fileText.add(i.name() + ": " + interpolatorTimings.get(i));
}
fileText.add("");
sender.sendMessage("Processing Generator Scores: ");
KMap<String, KList<String>> btx = new KMap<>();
for (String i : data.getGeneratorLoader().getPossibleKeys()) {
KList<String> vv = new KList<>();
IrisGenerator g = data.getGeneratorLoader().load(i);
KList<IrisNoiseGenerator> composites = g.getAllComposites();
double score = 0;
int m = 0;
for (IrisNoiseGenerator j : composites) {
m++;
score += styleTimings.get(j.getStyle().getStyle());
vv.add("Composite Noise Style " + m + " " + j.getStyle().getStyle().name() + ": " + styleTimings.get(j.getStyle().getStyle()));
}
score += interpolatorTimings.get(g.getInterpolator().getFunction());
vv.add("Interpolator " + g.getInterpolator().getFunction().name() + ": " + interpolatorTimings.get(g.getInterpolator().getFunction()));
generatorTimings.put(i, score);
btx.put(i, vv);
}
fileText.add("Project Generator Performance Impacts: ");
for (String i : generatorTimings.sortKNumber()) {
fileText.add(i + ": " + generatorTimings.get(i));
btx.get(i).forEach((ii) -> fileText.add(" " + ii));
}
fileText.add("");
KMap<String, KList<String>> bt = new KMap<>();
for (String i : data.getBiomeLoader().getPossibleKeys()) {
KList<String> vv = new KList<>();
IrisBiome b = data.getBiomeLoader().load(i);
double score = 0;
int m = 0;
for (IrisBiomePaletteLayer j : b.getLayers()) {
m++;
score += styleTimings.get(j.getStyle().getStyle());
vv.add("Palette Layer " + m + ": " + styleTimings.get(j.getStyle().getStyle()));
}
score += styleTimings.get(b.getBiomeStyle().getStyle());
vv.add("Biome Style: " + styleTimings.get(b.getBiomeStyle().getStyle()));
score += styleTimings.get(b.getChildStyle().getStyle());
vv.add("Child Style: " + styleTimings.get(b.getChildStyle().getStyle()));
biomeTimings.put(i, score);
bt.put(i, vv);
}
fileText.add("Project Biome Performance Impacts: ");
for (String i : biomeTimings.sortKNumber()) {
fileText.add(i + ": " + biomeTimings.get(i));
bt.get(i).forEach((ff) -> fileText.add(" " + ff));
}
fileText.add("");
for (String i : data.getRegionLoader().getPossibleKeys()) {
IrisRegion b = data.getRegionLoader().load(i);
double score = 0;
score += styleTimings.get(b.getLakeStyle().getStyle());
score += styleTimings.get(b.getRiverStyle().getStyle());
regionTimings.put(i, score);
}
fileText.add("Project Region Performance Impacts: ");
for (String i : regionTimings.sortKNumber()) {
fileText.add(i + ": " + regionTimings.get(i));
}
fileText.add("");
double m = 0;
for (double i : biomeTimings.v()) {
m += i;
}
m /= biomeTimings.size();
double mm = 0;
for (double i : generatorTimings.v()) {
mm += i;
}
mm /= generatorTimings.size();
m += mm;
double mmm = 0;
for (double i : regionTimings.v()) {
mmm += i;
}
mmm /= regionTimings.size();
m += mmm;
KMap<String, KList<String>> dt = new KMap<>();
for (String i : data.getDimensionLoader().getPossibleKeys()) {
IrisDimension d = data.getDimensionLoader().load(i);
KList<String> vv = new KList<>();
double score = 0;
score += styleTimings.get(d.getContinentalStyle().getStyle());
vv.add("Continental Style: " + styleTimings.get(d.getContinentalStyle().getStyle()));
score += styleTimings.get(d.getRegionStyle().getStyle());
vv.add("Region Style: " + styleTimings.get(d.getRegionStyle().getStyle()));
score += styleTimings.get(d.getBiomeStyle(InferredType.LAND).getStyle());
vv.add("LandBiome Style: " + styleTimings.get(d.getBiomeStyle(InferredType.LAND).getStyle()));
score += styleTimings.get(d.getBiomeStyle(InferredType.SEA).getStyle());
vv.add("OceanBiome Style: " + styleTimings.get(d.getBiomeStyle(InferredType.SEA).getStyle()));
score += styleTimings.get(d.getCaveBiomeStyle().getStyle());
vv.add("CaveBiome Style: " + styleTimings.get(d.getCaveBiomeStyle().getStyle()));
score += styleTimings.get(d.getShoreBiomeStyle().getStyle());
vv.add("ShoreBiome Style: " + styleTimings.get(d.getShoreBiomeStyle().getStyle()));
dimensionTimings.put(i, score);
dt.put(i, vv);
}
fileText.add("Project Dimension Performance Impacts: ");
for (String i : dimensionTimings.sortKNumber()) {
fileText.add(i + ": " + dimensionTimings.get(i));
dt.get(i).forEach((ff) -> fileText.add(" " + ff));
}
fileText.add("");
fileText.add("Average Score: " + m);
sender.sendMessage("Score: " + Form.duration(m, 0));
try {
IO.writeAll(report, fileText.toString("\n"));
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
sender.sendMessage(C.GREEN + "Done! " + report.getPath());
}
}

View File

@ -2,17 +2,9 @@ package com.volmit.iris.core.tools;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.pregenerator.PregenTask; import com.volmit.iris.core.pregenerator.PregenTask;
import com.volmit.iris.core.pregenerator.methods.HeadlessPregenMethod;
import com.volmit.iris.core.pregenerator.methods.HybridPregenMethod;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineTarget;
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.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.exceptions.IrisException; import com.volmit.iris.util.exceptions.IrisException;
@ -44,32 +36,28 @@ public class IrisPackBenchmarking {
public static boolean benchmarkInProgress = false; public static boolean benchmarkInProgress = false;
private IrisDimension IrisDimension; private IrisDimension IrisDimension;
private int radius; private int radius;
private final boolean headless;
private final boolean gui;
private boolean finished = false; private boolean finished = false;
private Engine engine;
PrecisionStopwatch stopwatch; PrecisionStopwatch stopwatch;
public IrisPackBenchmarking(IrisDimension dimension, int r, boolean headless, boolean gui) { public IrisPackBenchmarking(IrisDimension dimension, int r) {
instance = this; instance = this;
this.IrisDimension = dimension; this.IrisDimension = dimension;
this.radius = r; this.radius = r;
this.headless = headless; runBenchmark();
this.gui = gui;
} }
public void runBenchmark() { private void runBenchmark() {
this.stopwatch = new PrecisionStopwatch(); this.stopwatch = new PrecisionStopwatch();
ExecutorService service = Executors.newSingleThreadExecutor(); ExecutorService service = Executors.newSingleThreadExecutor();
service.submit(() -> { service.submit(() -> {
Iris.info("Setting up benchmark environment "); Iris.info("Setting up benchmark environment ");
benchmarkInProgress = true; benchmarkInProgress = true;
File file = new File(Bukkit.getWorldContainer(), "benchmark"); File file = new File("benchmark");
if (file.exists()) { if (file.exists()) {
deleteDirectory(file.toPath()); deleteDirectory(file.toPath());
} }
engine = createBenchmark(); createBenchmark();
while (!headless && !IrisToolbelt.isIrisWorld(Bukkit.getWorld("benchmark"))) { while (!IrisToolbelt.isIrisWorld(Bukkit.getWorld("benchmark"))) {
J.sleep(1000); J.sleep(1000);
Iris.debug("Iris PackBenchmark: Waiting..."); Iris.debug("Iris PackBenchmark: Waiting...");
} }
@ -87,6 +75,7 @@ public class IrisPackBenchmarking {
public void finishedBenchmark(KList<Integer> cps) { public void finishedBenchmark(KList<Integer> cps) {
try { try {
String time = Form.duration(stopwatch.getMillis()); String time = Form.duration(stopwatch.getMillis());
Engine engine = IrisToolbelt.access(Bukkit.getWorld("benchmark")).getEngine();
Iris.info("-----------------"); Iris.info("-----------------");
Iris.info("Results:"); Iris.info("Results:");
Iris.info("- Total time: " + time); Iris.info("- Total time: " + time);
@ -99,8 +88,8 @@ public class IrisPackBenchmarking {
File profilers = new File("plugins" + File.separator + "Iris" + File.separator + "packbenchmarks"); File profilers = new File("plugins" + File.separator + "Iris" + File.separator + "packbenchmarks");
profilers.mkdir(); profilers.mkdir();
File results = new File("plugins" + File.separator + "Iris", IrisDimension.getName() + " " + LocalDateTime.now(Clock.systemDefaultZone()).toString().replace(':', '-') + ".txt"); File results = new File("plugins " + File.separator + "Iris", IrisDimension.getName() + LocalDateTime.now(Clock.systemDefaultZone()) + ".txt");
results.getParentFile().mkdirs(); results.createNewFile();
KMap<String, Double> metrics = engine.getMetrics().pull(); KMap<String, Double> metrics = engine.getMetrics().pull();
try (FileWriter writer = new FileWriter(results)) { try (FileWriter writer = new FileWriter(results)) {
writer.write("-----------------\n"); writer.write("-----------------\n");
@ -134,34 +123,15 @@ public class IrisPackBenchmarking {
e.printStackTrace(); e.printStackTrace();
} }
} }
private Engine createBenchmark(){ private void createBenchmark(){
try { try {
if (headless) { IrisToolbelt.createWorld()
Iris.info("Using headless benchmark!"); .dimension(IrisDimension.getName())
IrisWorld world = IrisWorld.builder()
.name("benchmark")
.minHeight(IrisDimension.getMinHeight())
.maxHeight(IrisDimension.getMaxHeight())
.seed(1337)
.worldFolder(new File(Bukkit.getWorldContainer(), "benchmark"))
.environment(IrisDimension.getEnvironment())
.build();
Iris.service(StudioSVC.class).installIntoWorld(
Iris.getSender(),
IrisDimension.getLoadKey(),
world.worldFolder());
var data = IrisData.get(new File(world.worldFolder(), "iris/pack"));
var dim = data.getDimensionLoader().load(IrisDimension.getLoadKey());
return new IrisEngine(new EngineTarget(world, dim, data), false);
}
Iris.info("Using Standard benchmark!");
return IrisToolbelt.access(IrisToolbelt.createWorld()
.dimension(IrisDimension.getLoadKey())
.name("benchmark") .name("benchmark")
.seed(1337) .seed(1337)
.studio(false) .studio(false)
.benchmark(true) .benchmark(true)
.create()).getEngine(); .create();
} catch (IrisException e) { } catch (IrisException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -172,12 +142,12 @@ public class IrisPackBenchmarking {
int z = 0; int z = 0;
IrisToolbelt.pregenerate(PregenTask IrisToolbelt.pregenerate(PregenTask
.builder() .builder()
.gui(gui) .gui(false)
.center(new Position2(x, z)) .center(new Position2(x, z))
.width(5) .width(5)
.height(5) .height(5)
.build(), headless ? new HeadlessPregenMethod(engine) : new HybridPregenMethod(engine.getWorld().realWorld(), .build(), Bukkit.getWorld("benchmark")
IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), engine); );
} }
private double calculateAverage(KList<Integer> list) { private double calculateAverage(KList<Integer> list) {

View File

@ -19,7 +19,6 @@
package com.volmit.iris.core.tools; package com.volmit.iris.core.tools;
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.engine.object.*; import com.volmit.iris.engine.object.*;
import com.volmit.iris.engine.platform.BukkitChunkGenerator; import com.volmit.iris.engine.platform.BukkitChunkGenerator;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -85,9 +84,6 @@ public class IrisWorldCreator {
? dim.getLoader().getDataFolder() : ? dim.getLoader().getDataFolder() :
new File(w.worldFolder(), "iris/pack"), dimensionName, smartVanillaHeight); new File(w.worldFolder(), "iris/pack"), dimensionName, smartVanillaHeight);
if (!INMS.get().registerDimension(name, dim)) {
throw new IllegalStateException("Unable to register dimension " + dim.getName());
}
return new WorldCreator(name) return new WorldCreator(name)
.environment(findEnvironment()) .environment(findEnvironment())

View File

@ -1,241 +0,0 @@
package com.volmit.iris.core.tools;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RollingSequence;
import com.volmit.iris.util.nbt.mca.Chunk;
import com.volmit.iris.util.nbt.mca.MCAFile;
import com.volmit.iris.util.nbt.mca.MCAUtil;
import com.volmit.iris.util.nbt.tag.CompoundTag;
import com.volmit.iris.util.nbt.tag.StringTag;
import com.volmit.iris.util.plugin.VolmitSender;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.World;
import java.io.File;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReferenceArray;
public class IrisWorldDump {
private KMap<blockData, Long> storage;
private AtomicLong airStorage;
private World world;
private File MCADirectory;
private AtomicInteger threads;
private AtomicInteger regionsProcessed;
private AtomicInteger chunksProcessed;
private AtomicInteger totalToProcess;
private AtomicInteger totalMaxChunks;
private AtomicInteger totalMCAFiles;
private RollingSequence chunksPerSecond;
private Engine engine = null;
private Boolean IrisWorld;
private VolmitSender sender;
private ExecutorService executor;
private ScheduledExecutorService scheduler;
private AtomicLong startTime;
private File dumps;
private File worldDump;
private int mcaCacheSize;
private File temp;
private File blocks;
private File structures;
public IrisWorldDump(World world, VolmitSender sender) {
sender.sendMessage("Initializing IrisWorldDump...");
this.world = world;
this.sender = sender;
this.MCADirectory = new File(world.getWorldFolder(), "region");
this.dumps = new File("plugins" + File.separator + "iris", "dumps");
this.worldDump = new File(dumps, world.getName());
this.mcaCacheSize = IrisSettings.get().getWorldDump().mcaCacheSize;
this.regionsProcessed = new AtomicInteger(0);
this.chunksProcessed = new AtomicInteger(0);
this.totalToProcess = new AtomicInteger(0);
this.chunksPerSecond = new RollingSequence(10);
this.temp = new File(worldDump, "temp");
this.executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() - 1);
this.scheduler = Executors.newSingleThreadScheduledExecutor();
this.startTime = new AtomicLong();
this.storage = new KMap<>();
this.airStorage = new AtomicLong(0);
this.blocks = new File(worldDump, "blocks");
this.structures = new File(worldDump, "structures");
try {
this.engine = IrisToolbelt.access(world).getEngine();
this.IrisWorld = true;
} catch (Exception e) {
this.IrisWorld = false;
}
}
public void start() {
if (!dumps.exists()) {
if (!dumps.mkdirs()) {
System.err.println("Failed to create dump directory.");
return;
}
}
try {
CompletableFuture<Integer> mcaCount = CompletableFuture.supplyAsync(this::totalMcaFiles);
CompletableFuture<Integer> chunkCount = CompletableFuture.supplyAsync(this::totalMCAChunks);
this.totalMCAFiles = new AtomicInteger(mcaCount.get());
this.totalMaxChunks = new AtomicInteger(chunkCount.get());
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
dump();
updater();
}
private void updater() {
startTime.set(System.currentTimeMillis());
scheduler.scheduleAtFixedRate(() -> {
long eta = computeETA();
long elapsedSeconds = (System.currentTimeMillis() - startTime.get()) / 3000;
int processed = chunksProcessed.get();
double cps = elapsedSeconds > 0 ? processed / (double) elapsedSeconds : 0;
chunksPerSecond.put(cps);
double percentage = ((double) chunksProcessed.get() / (double) totalMaxChunks.get()) * 100;
Iris.info("Processed: " + Form.f(processed) + " of " + Form.f(totalMaxChunks.get()) + " (%.0f%%) " + Form.f(chunksPerSecond.getAverage()) + "/s, ETA: " + Form.duration(eta, 2), percentage);
}, 1, 3, TimeUnit.SECONDS);
}
public class blockData {
@Getter
@Setter
private String block;
private int biome;
private int height;
public blockData(String b, int bm, int h) {
this.block = b;
this.height = h;
this.biome = bm;
}
}
private void dump() {
Iris.info("Starting the dump process.");
int threads = Runtime.getRuntime().availableProcessors();
AtomicInteger f = new AtomicInteger();
for (File mcaFile : MCADirectory.listFiles()) {
if (mcaFile.getName().endsWith(".mca")) {
executor.submit(() -> {
try {
processMCARegion( MCAUtil.read(mcaFile));
} catch (Exception e) {
f.getAndIncrement();
Iris.error("Failed to read mca file");
e.printStackTrace();
}
});
}
}
}
private void processMCARegion(MCAFile mca) {
AtomicReferenceArray<Chunk> chunks = new AtomicReferenceArray<>(1024);
for (int i = 0; i < chunks.length(); i++) {
chunks.set(i, mca.getChunks().get(i));
}
for (int i = 0; i < chunks.length(); i++) {
Chunk chunk = chunks.get(i);
if (chunk != null) {
int CHUNK_HEIGHT = (world.getMaxHeight() - world.getMinHeight());
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = 0; y < CHUNK_HEIGHT; y++) {
CompoundTag tag = chunk.getBlockStateAt(x, y, z);
int biome = chunk.getBiomeAt(x, y, z);
if (tag == null) {
String blockName = "minecraft:air";
//storage.compute(blockName, (key, count) -> (count == null) ? 1 : count + 1);
airStorage.getAndIncrement();
int ii = 0;
} else {
StringTag nameTag = tag.getStringTag("Name");
String blockName = nameTag.getValue();
blockData data = new blockData(blockName, biome, y);
storage.compute(data, (key, count) -> (count == null) ? 1 : count + 1);
int ii = 0;
}
}
}
}
chunksProcessed.getAndIncrement();
}
}
regionsProcessed.getAndIncrement();
}
private int totalMCAChunks() {
AtomicInteger chunks = new AtomicInteger();
CountDownLatch latch = new CountDownLatch(totalMcaFiles() * 1024);
for (File mcafile : MCADirectory.listFiles()) {
executor.submit(() -> {
try {
if (mcafile.getName().endsWith(".mca")) {
MCAFile mca = MCAUtil.read(mcafile);
for (int width = 0; width < 32; width++) {
for (int depth = 0; depth < 32; depth++) {
Chunk chunk = mca.getChunk(width, depth);
if (chunk != null) {
chunks.getAndIncrement();
}
latch.countDown();
}
}
}
} catch (Exception e) {
Iris.error("Failed to read mca file");
e.printStackTrace();
}
});
}
try {
latch.await();
} catch (Exception e) {
e.printStackTrace();
}
return chunks.get();
}
private int totalMcaFiles() {
int size = 0;
for (File mca : MCADirectory.listFiles()) {
if (mca.getName().endsWith(".mca")) {
size++;
}
}
return size;
}
private long computeETA() {
return (long) (totalMaxChunks.get() > 1024 ? // Generated chunks exceed 1/8th of total?
// If yes, use smooth function (which gets more accurate over time since its less sensitive to outliers)
((totalMaxChunks.get() - chunksProcessed.get()) * ((double) (M.ms() - startTime.get()) / (double) chunksProcessed.get())) :
// If no, use quick function (which is less accurate over time but responds better to the initial delay)
((totalMaxChunks.get() - chunksProcessed.get()) / chunksPerSecond.getAverage()) * 1000
);
}
}

View File

@ -21,6 +21,8 @@ package com.volmit.iris.engine;
import com.google.common.util.concurrent.AtomicDouble; import com.google.common.util.concurrent.AtomicDouble;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.events.IrisEngineHotloadEvent; import com.volmit.iris.core.events.IrisEngineHotloadEvent;
import com.volmit.iris.core.gui.PregeneratorJob; import com.volmit.iris.core.gui.PregeneratorJob;
import com.volmit.iris.core.nms.container.BlockPos; import com.volmit.iris.core.nms.container.BlockPos;
@ -51,6 +53,7 @@ import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
@ -63,6 +66,8 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Data @Data
@EqualsAndHashCode(exclude = "context") @EqualsAndHashCode(exclude = "context")
@ -237,6 +242,11 @@ public class IrisEngine implements Engine {
getTarget().setDimension(getData().getDimensionLoader().load(getDimension().getLoadKey())); getTarget().setDimension(getData().getDimensionLoader().load(getDimension().getLoadKey()));
prehotload(); prehotload();
setupEngine(); setupEngine();
J.a(() -> {
synchronized (ServerConfigurator.class) {
ServerConfigurator.installDataPacks(false);
}
});
} }
@Override @Override
@ -276,13 +286,6 @@ public class IrisEngine implements Engine {
return generated.get(); return generated.get();
} }
@Override
public void addGenerated() {
if (generated.incrementAndGet() == 661) {
J.a(() -> getData().savePrefetch(this));
}
}
@Override @Override
public double getGeneratedPerSecond() { public double getGeneratedPerSecond() {
if (perSecondLatch.flip()) { if (perSecondLatch.flip()) {
@ -465,7 +468,11 @@ public class IrisEngine implements Engine {
getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.REAL, true); getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.REAL, true);
getMetrics().getTotal().put(p.getMilliseconds()); getMetrics().getTotal().put(p.getMilliseconds());
addGenerated(); generated.incrementAndGet();
if (generated.get() == 661) {
J.a(() -> getData().savePrefetch(this));
}
} catch (Throwable e) { } catch (Throwable e) {
Iris.reportError(e); Iris.reportError(e);
fail("Failed to generate " + x + ", " + z, e); fail("Failed to generate " + x + ", " + z, e);

View File

@ -41,11 +41,9 @@ public class IrisSeaFloorDecorator extends IrisEngineDecorator {
if (!decorator.isStacking()) { if (!decorator.isStacking()) {
if (height >= 0 || height < getEngine().getHeight()) { if (height >= 0 || height < getEngine().getHeight()) {
if (null != decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())) { if (null != decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())) {
if (height == getDimension().getFluidHeight() - 1) {
data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData())); data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
height++; height++;
data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData())); data.set(x, height, z, decorator.getBlockDataForTop(biome, getRng(), realX, height, realZ, getData()));
}
} else { } else {
data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData())); data.set(x, height, z, decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData()));
} }
@ -75,5 +73,6 @@ public class IrisSeaFloorDecorator extends IrisEngineDecorator {
} }
} }
} }
} }
} }

View File

@ -577,8 +577,6 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
int getGenerated(); int getGenerated();
void addGenerated();
default <T> IrisPosition lookForStreamResult(T find, ProceduralStream<T> stream, Function2<T, T, Boolean> matcher, long timeout) { default <T> IrisPosition lookForStreamResult(T find, ProceduralStream<T> stream, Function2<T, T, Boolean> matcher, long timeout) {
AtomicInteger checked = new AtomicInteger(); AtomicInteger checked = new AtomicInteger();
AtomicLong time = new AtomicLong(M.ms()); AtomicLong time = new AtomicLong(M.ms());

View File

@ -1,32 +0,0 @@
package com.volmit.iris.engine.jvm;
import com.volmit.iris.util.plugin.VolmitSender;
public class VMJavaFX {
private VolmitSender sender;
public VMJavaFX(VolmitSender user) {
this.sender = user;
}
public void start() {
try {
// Start JavaFX in a new JVM
ProcessBuilder processBuilder = new ProcessBuilder(
"java",
"--module-path", "path/to/javafx-sdk/lib", // Set path to JavaFX SDK
"--add-modules", "javafx.controls,javafx.fxml",
"-jar", "path/to/javafx-application.jar"
);
processBuilder.inheritIO();
processBuilder.start();
sender.sendMessage("JavaFX application is launched!");
} catch (Exception e) {
sender.sendMessage("Failed to launch JavaFX application.");
e.printStackTrace();
}
}
}

View File

@ -170,6 +170,7 @@ public class IrisBiome extends IrisRegistrant implements IRare {
@Desc("Collection of ores to be generated") @Desc("Collection of ores to be generated")
@ArrayType(type = IrisOreGenerator.class, min = 1) @ArrayType(type = IrisOreGenerator.class, min = 1)
private KList<IrisOreGenerator> ores = new KList<>(); private KList<IrisOreGenerator> ores = new KList<>();
public BlockData generateOres(int x, int y, int z, RNG rng, IrisData data) { public BlockData generateOres(int x, int y, int z, RNG rng, IrisData data) {
if (ores.isEmpty()) { if (ores.isEmpty()) {
return null; return null;

View File

@ -19,7 +19,7 @@
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.nms.datapack.DataVersion; import com.volmit.iris.core.nms.datapack.IDataFixer;
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.KMap; import com.volmit.iris.util.collection.KMap;
@ -92,7 +92,7 @@ public class IrisBiomeCustom {
@Desc("The color of foliage (hex format). Leave blank / don't define to not change") @Desc("The color of foliage (hex format). Leave blank / don't define to not change")
private String foliageColor = ""; private String foliageColor = "";
public String generateJson() { public String generateJson(IDataFixer fixer) {
JSONObject effects = new JSONObject(); JSONObject effects = new JSONObject();
effects.put("sky_color", parseColor(getSkyColor())); effects.put("sky_color", parseColor(getSkyColor()));
effects.put("fog_color", parseColor(getFogColor())); effects.put("fog_color", parseColor(getFogColor()));
@ -158,7 +158,7 @@ public class IrisBiomeCustom {
j.put("spawners", spawners); j.put("spawners", spawners);
} }
return DataVersion.getDefault().fixCustomBiome(this, j).toString(4); return fixer.fixCustomBiome(this, j).toString(4);
} }
private int parseColor(String c) { private int parseColor(String c) {

View File

@ -18,12 +18,15 @@
package com.volmit.iris.engine.object; package com.volmit.iris.engine.object;
import com.volmit.iris.Iris;
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.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.data.DataProvider; import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.math.RNG;
@ -38,6 +41,9 @@ import org.bukkit.Material;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import java.io.File;
import java.io.IOException;
@Accessors(chain = true) @Accessors(chain = true)
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@ -47,6 +53,73 @@ import org.bukkit.block.data.BlockData;
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<>();
@ -64,6 +137,10 @@ public class IrisDimension extends IrisRegistrant {
@MaxNumber(2032) @MaxNumber(2032)
@Desc("Maximum height at which players can be teleported to through gameplay.") @Desc("Maximum height at which players can be teleported to through gameplay.")
private int logicalHeight = 256; private int logicalHeight = 256;
@Desc("Maximum height at which players can be teleported to through gameplay.")
private int logicalHeightEnd = 256;
@Desc("Maximum height at which players can be teleported to through gameplay.")
private int logicalHeightNether = 256;
@RegistryListResource(IrisJigsawStructure.class) @RegistryListResource(IrisJigsawStructure.class)
@Desc("If defined, Iris will place the given jigsaw structure where minecraft should place the overworld stronghold.") @Desc("If defined, Iris will place the given jigsaw structure where minecraft should place the overworld stronghold.")
private String stronghold; private String stronghold;
@ -152,6 +229,10 @@ public class IrisDimension extends IrisRegistrant {
private int fluidHeight = 63; private int fluidHeight = 63;
@Desc("Define the min and max Y bounds of this dimension. Please keep in mind that Iris internally generates from 0 to (max - min). \n\nFor example at -64 to 320, Iris is internally generating to 0 to 384, then on outputting chunks, it shifts it down by the min height (64 blocks). The default is -64 to 320. \n\nThe fluid height is placed at (fluid height + min height). So a fluid height of 63 would actually show up in the world at 1.") @Desc("Define the min and max Y bounds of this dimension. Please keep in mind that Iris internally generates from 0 to (max - min). \n\nFor example at -64 to 320, Iris is internally generating to 0 to 384, then on outputting chunks, it shifts it down by the min height (64 blocks). The default is -64 to 320. \n\nThe fluid height is placed at (fluid height + min height). So a fluid height of 63 would actually show up in the world at 1.")
private IrisRange dimensionHeight = new IrisRange(-64, 320); private IrisRange dimensionHeight = new IrisRange(-64, 320);
@Desc("Define the min and max Y bounds of this dimension. Please keep in mind that Iris internally generates from 0 to (max - min). \n\nFor example at -64 to 320, Iris is internally generating to 0 to 384, then on outputting chunks, it shifts it down by the min height (64 blocks). The default is -64 to 320. \n\nThe fluid height is placed at (fluid height + min height). So a fluid height of 63 would actually show up in the world at 1.")
private IrisRange dimensionHeightEnd = new IrisRange(-64, 320);
@Desc("Define the min and max Y bounds of this dimension. Please keep in mind that Iris internally generates from 0 to (max - min). \n\nFor example at -64 to 320, Iris is internally generating to 0 to 384, then on outputting chunks, it shifts it down by the min height (64 blocks). The default is -64 to 320. \n\nThe fluid height is placed at (fluid height + min height). So a fluid height of 63 would actually show up in the world at 1.")
private IrisRange dimensionHeightNether = new IrisRange(-64, 320);
@Desc("Enable smart vanilla height") @Desc("Enable smart vanilla height")
private boolean smartVanillaHeight = false; private boolean smartVanillaHeight = false;
@RegistryListResource(IrisBiome.class) @RegistryListResource(IrisBiome.class)
@ -294,14 +375,6 @@ public class IrisDimension extends IrisRegistrant {
return environment; return environment;
} }
public IrisRange getDimensionHeight() {
return smartVanillaHeight ? new IrisRange(-64, 320) : dimensionHeight;
}
public int getLogicalHeight() {
return smartVanillaHeight ? 256 : logicalHeight;
}
public boolean hasFocusRegion() { public boolean hasFocusRegion() {
return !focusRegion.equals(""); return !focusRegion.equals("");
} }
@ -373,6 +446,63 @@ public class IrisDimension extends IrisRegistrant {
return landBiomeStyle; return landBiomeStyle;
} }
public boolean installDataPack(IDataFixer fixer, DataProvider data, File datapacks, double ultimateMaxHeight, double ultimateMinHeight) {
boolean write = false;
boolean changed = false;
IO.delete(new File(datapacks, "iris/data/" + getLoadKey().toLowerCase()));
for (IrisBiome i : getAllBiomes(data)) {
if (i.isCustom()) {
write = true;
for (IrisBiomeCustom j : i.getCustomDerivitives()) {
File output = new File(datapacks, "iris/data/" + getLoadKey().toLowerCase() + "/worldgen/biome/" + j.getId() + ".json");
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": 10
}
}
""");
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
Iris.verbose(" Installing Data Pack MCMeta: " + mcm.getPath());
}
return changed;
}
@Override @Override
public String getFolderName() { public String getFolderName() {
return "dimensions"; return "dimensions";
@ -387,4 +517,67 @@ public class IrisDimension extends IrisRegistrant {
public void scanForErrors(JSONObject p, VolmitSender sender) { public void scanForErrors(JSONObject p, VolmitSender sender) {
} }
public boolean writeDimensionType(IDataFixer fixer, boolean changed, File datapacks) {
File dimTypeOverworld = new File(datapacks, "iris/data/minecraft/dimension_type/overworld.json");
if (!dimTypeOverworld.exists())
changed = true;
dimTypeOverworld.getParentFile().mkdirs();
try {
IO.writeAll(dimTypeOverworld, generateDatapackJsonOverworld(fixer));
} catch (IOException e) {
Iris.reportError(e);
e.printStackTrace();
}
File dimTypeNether = new File(datapacks, "iris/data/minecraft/dimension_type/the_nether.json");
if (!dimTypeNether.exists())
changed = true;
dimTypeNether.getParentFile().mkdirs();
try {
IO.writeAll(dimTypeNether, generateDatapackJsonNether(fixer));
} 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);
}
} }

View File

@ -454,19 +454,14 @@ public class IrisEntity extends IrisRegistrant {
return ae.get(); return ae.get();
} }
if (isSpecialType() && Iris.linkMythicMobs.isEnabled()) { if (isSpecialType()) {
if (specialType.toLowerCase().startsWith("mythicmobs:")) { if (specialType.toLowerCase().startsWith("mythicmobs:")) {
return Iris.linkMythicMobs.spawnMob(specialType.substring(11), at); return Iris.linkMythicMobs.spawnMob(specialType.substring(11), at);
} else { } else {
Iris.warn("Invalid mob type to spawn: '" + specialType + "'!"); Iris.warn("Invalid mob type to spawn: '" + specialType + "'!");
return null; return null;
} }
} else {
if (isSpecialType()) {
Iris.warn("MythicMobs is not enabled, falling back to: " + type + "'!");
} }
}
return INMS.get().spawnEntity(at, getType(), getReason()); return INMS.get().spawnEntity(at, getType(), getReason());

View File

@ -21,7 +21,6 @@ package com.volmit.iris.engine.platform;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.safeguard.IrisSafeguard;
import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.engine.IrisEngine; import com.volmit.iris.engine.IrisEngine;
import com.volmit.iris.engine.data.chunk.TerrainChunk; import com.volmit.iris.engine.data.chunk.TerrainChunk;
@ -33,7 +32,6 @@ import com.volmit.iris.engine.object.StudioMode;
import com.volmit.iris.engine.platform.studio.StudioGenerator; import com.volmit.iris.engine.platform.studio.StudioGenerator;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.IrisBiomeStorage; import com.volmit.iris.util.data.IrisBiomeStorage;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder; import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder;
import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder; import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder;
@ -265,15 +263,6 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
} }
private Engine getEngine(WorldInfo world) { private Engine getEngine(WorldInfo world) {
// if (!IrisSafeguard.instance.acceptUnstable && IrisSafeguard.instance.unstablemode) {
// Iris.info(C.RED + "------------------------------------------------------------");
// Iris.info(C.DARK_RED + "Cancelled World Loading of " + world.getName() + "!");
// Iris.info(C.RED + "World loading has been disabled until the incompatibility is resolved.");
// Iris.info(C.DARK_RED + "Alternatively, go to plugins/iris/settings.json and set ignoreBootMode to true.");
// Iris.info(C.RED + "------------------------------------------------------------");
// return null;
// }
if (setup.get()) { if (setup.get()) {
return getEngine(); return getEngine();
} }

View File

@ -1,15 +0,0 @@
package com.volmit.iris.util.decree.specialhandlers;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.handlers.BiomeHandler;
import com.volmit.iris.util.decree.handlers.PlayerHandler;
import org.bukkit.entity.Player;
public class NullableBiomeHandler extends BiomeHandler {
@Override
public IrisBiome parse(String in, boolean force) throws DecreeParsingException {
return getPossibilities(in).stream().filter((i) -> toString(i).equalsIgnoreCase(in)).findFirst().orElse(null);
}
}

View File

@ -1,17 +0,0 @@
package com.volmit.iris.util.decree.specialhandlers;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.engine.object.IrisRegion;
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
import com.volmit.iris.util.decree.handlers.BiomeHandler;
import com.volmit.iris.util.decree.handlers.RegionHandler;
import javax.swing.plaf.synth.Region;
public class NullableRegionHandler extends RegionHandler {
@Override
public IrisRegion parse(String in, boolean force) throws DecreeParsingException {
return getPossibilities(in).stream().filter((i) -> toString(i).equalsIgnoreCase(in)).findFirst().orElse(null);
}
}

View File

@ -20,9 +20,7 @@ package com.volmit.iris.util.nbt.mca;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.tools.IrisWorldDump;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.nbt.io.NBTDeserializer; import com.volmit.iris.util.nbt.io.NBTDeserializer;
import com.volmit.iris.util.nbt.io.NBTSerializer; import com.volmit.iris.util.nbt.io.NBTSerializer;
import com.volmit.iris.util.nbt.io.NamedTag; import com.volmit.iris.util.nbt.io.NamedTag;
@ -59,8 +57,6 @@ public class Chunk {
private ListTag<ListTag<?>> postProcessing; private ListTag<ListTag<?>> postProcessing;
private String status; private String status;
private CompoundTag structures; private CompoundTag structures;
private int d;
private int f;
Chunk(int lastMCAUpdate) { Chunk(int lastMCAUpdate) {
this.lastMCAUpdate = lastMCAUpdate; this.lastMCAUpdate = lastMCAUpdate;
@ -73,8 +69,6 @@ public class Chunk {
*/ */
public Chunk(CompoundTag data) { public Chunk(CompoundTag data) {
this.data = data; this.data = data;
d = 0;
f = 0;
initReferences(ALL_DATA); initReferences(ALL_DATA);
setStatus("full"); setStatus("full");
} }
@ -156,8 +150,8 @@ public class Chunk {
if ((loadFlags & STRUCTURES) != 0) { if ((loadFlags & STRUCTURES) != 0) {
structures = level.getCompoundTag("Structures"); structures = level.getCompoundTag("Structures");
} }
if ((loadFlags & (BLOCK_LIGHTS | BLOCK_STATES | SKY_LIGHT)) != 0 && level.containsKey("sections")) { if ((loadFlags & (BLOCK_LIGHTS | BLOCK_STATES | SKY_LIGHT)) != 0 && level.containsKey("Sections")) {
for (CompoundTag section : level.getListTag("sections").asCompoundTagList()) { for (CompoundTag section : level.getListTag("Sections").asCompoundTagList()) {
int sectionIndex = section.getByte("Y"); int sectionIndex = section.getByte("Y");
if (sectionIndex > 15 || sectionIndex < 0) { if (sectionIndex > 15 || sectionIndex < 0) {
continue; continue;

View File

@ -37,17 +37,12 @@ public class Section {
public Section(CompoundTag sectionRoot, int dataVersion, long loadFlags) { public Section(CompoundTag sectionRoot, int dataVersion, long loadFlags) {
data = sectionRoot; data = sectionRoot;
//ListTag<?> rawPalette = sectionRoot.getListTag("palette"); ListTag<?> rawPalette = sectionRoot.getListTag("Palette");
ListTag<?> rawPalette = sectionRoot.getCompoundTag("biomes").getListTag("palette");
if (rawPalette == null) { if (rawPalette == null) {
return; return;
} }
palette = INMS.get().createPalette(); palette = INMS.get().createPalette();
try {
palette.readFromSection(sectionRoot); palette.readFromSection(sectionRoot);
} catch (Exception e) {
e.printStackTrace();
}
ByteArrayTag blockLight = sectionRoot.getByteArrayTag("BlockLight"); ByteArrayTag blockLight = sectionRoot.getByteArrayTag("BlockLight");
ByteArrayTag skyLight = sectionRoot.getByteArrayTag("SkyLight"); ByteArrayTag skyLight = sectionRoot.getByteArrayTag("SkyLight");
this.blockLight = blockLight != null ? blockLight.getValue() : null; this.blockLight = blockLight != null ? blockLight.getValue() : null;

View File

@ -20,10 +20,9 @@ package com.volmit.iris.util.nbt.mca.palette;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import java.util.BitSet;
import java.util.function.IntConsumer; import java.util.function.IntConsumer;
public class MCABitStorageLongArray { public class MCABitStorage {
private static final int[] MAGIC = new int[]{ private static final int[] MAGIC = new int[]{
-1, -1, 0, Integer.MIN_VALUE, 0, 0, 1431655765, 1431655765, 0, Integer.MIN_VALUE, -1, -1, 0, Integer.MIN_VALUE, 0, 0, 1431655765, 1431655765, 0, Integer.MIN_VALUE,
0, 1, 858993459, 858993459, 0, 715827882, 715827882, 0, 613566756, 613566756, 0, 1, 858993459, 858993459, 0, 715827882, 715827882, 0, 613566756, 613566756,
@ -62,11 +61,11 @@ public class MCABitStorageLongArray {
private final int divideShift; private final int divideShift;
public MCABitStorageLongArray(int bits, int length) { public MCABitStorage(int bits, int length) {
this(bits, length, null); this(bits, length, null);
} }
public MCABitStorageLongArray(int bits, int length, long[] data) { public MCABitStorage(int bits, int length, long[] data) {
Validate.inclusiveBetween(1L, 32L, bits); Validate.inclusiveBetween(1L, 32L, bits);
this.size = length; this.size = length;
this.bits = bits; this.bits = bits;

View File

@ -1,112 +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
* abyte with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.volmit.iris.util.nbt.mca.palette;
import org.apache.commons.lang3.Validate;
// todo Cool idea but im way to dumb for this for now
public class MCABitStorageByteArray {
private final byte[] data;
private final int bits;
private final int mask;
private final int size;
private final int valuesPerByte;
private final int divideMul;
private final int divideAdd;
private final int divideShift;
public MCABitStorageByteArray(int bits, int length) {
this(bits, length, null);
}
public MCABitStorageByteArray(int bits, int length, byte[] data) {
Validate.inclusiveBetween(1L, 8L, bits); // Ensure bits are between 1 and 8
this.size = length;
this.bits = bits;
this.mask = (1 << bits) - 1;
this.valuesPerByte = 8 / bits;
int[] divisionParams = computeDivisionParameters(this.valuesPerByte);
this.divideMul = divisionParams[0];
this.divideAdd = divisionParams[1];
this.divideShift = divisionParams[2];
int numBytes = (length + this.valuesPerByte - 1) / this.valuesPerByte;
if (data != null) {
if (data.length != numBytes)
throw new IllegalArgumentException("Data array length does not match the required size.");
this.data = data;
} else {
this.data = new byte[numBytes];
}
}
private int[] computeDivisionParameters(int denom) {
long two32 = 1L << 32;
long magic = two32 / denom;
int shift = 0;
while ((1L << (shift + 32)) < magic * denom) {
shift++;
}
return new int[]{(int) magic, 0, shift};
}
private int cellIndex(int index) {
long indexLong = Integer.toUnsignedLong(this.divideMul);
long addLong = Integer.toUnsignedLong(this.divideAdd);
return (int) ((index * indexLong + addLong) >>> 32 >>> this.divideShift);
}
public int getAndSet(int index, int newValue) {
Validate.inclusiveBetween(0L, (this.size - 1), index);
Validate.inclusiveBetween(0L, this.mask, newValue);
int byteIndex = cellIndex(index);
int bitOffset = (index - byteIndex * this.valuesPerByte) * this.bits;
int currentValue = (this.data[byteIndex] >> bitOffset) & this.mask;
this.data[byteIndex] = (byte) ((this.data[byteIndex] & ~(this.mask << bitOffset)) | (newValue & this.mask) << bitOffset);
return currentValue;
}
public void set(int index, int value) {
Validate.inclusiveBetween(0L, (this.size - 1), index);
Validate.inclusiveBetween(0L, this.mask, value);
int byteIndex = cellIndex(index);
int bitOffset = (index - byteIndex * this.valuesPerByte) * this.bits;
this.data[byteIndex] = (byte) ((this.data[byteIndex] & ~(this.mask << bitOffset)) | (value & this.mask) << bitOffset);
}
public int get(int index) {
Validate.inclusiveBetween(0L, (this.size - 1), index);
int byteIndex = cellIndex(index);
int bitOffset = (index - byteIndex * this.valuesPerByte) * this.bits;
return (this.data[byteIndex] >> bitOffset) & this.mask;
}
public byte[] getRaw() {
return this.data;
}
public int getSize() {
return this.size;
}
public int getBits() {
return this.bits;
}
}

View File

@ -41,8 +41,7 @@ public class MCAPalettedContainer<T> implements MCAPaletteResize<T> {
private final T defaultValue; private final T defaultValue;
// Todo multiple storage systems cause long isnt the only one? protected MCABitStorage storage;
protected MCABitStorageLongArray storage;
private MCAPalette<T> palette; private MCAPalette<T> palette;
@ -75,11 +74,11 @@ public class MCAPalettedContainer<T> implements MCAPaletteResize<T> {
this.bits = MCAMth.ceillog2(this.registry.size()); this.bits = MCAMth.ceillog2(this.registry.size());
} }
this.palette.idFor(this.defaultValue); this.palette.idFor(this.defaultValue);
this.storage = new MCABitStorageLongArray(this.bits, 4096); this.storage = new MCABitStorage(this.bits, 4096);
} }
public int onResize(int var0, T var1) { public int onResize(int var0, T var1) {
MCABitStorageLongArray var2 = this.storage; MCABitStorage var2 = this.storage;
MCAPalette<T> var3 = this.palette; MCAPalette<T> var3 = this.palette;
setBits(var0); setBits(var0);
for (int var4 = 0; var4 < var2.getSize(); var4++) { for (int var4 = 0; var4 < var2.getSize(); var4++) {
@ -122,12 +121,6 @@ public class MCAPalettedContainer<T> implements MCAPaletteResize<T> {
T var1 = this.palette.valueFor(this.storage.get(var0)); T var1 = this.palette.valueFor(this.storage.get(var0));
return (var1 == null) ? this.defaultValue : var1; return (var1 == null) ? this.defaultValue : var1;
} }
/**
/**
* Reads and processes block data from encoded byte arrays.
* @param var0 BlockID Strings - List of block types identified by strings.
* @param var1 Encoded Locations - Long array containing compactly encoded block IDs, representing sequential block positions within a chunk.
*/
public void read(ListTag var0, long[] var1) { public void read(ListTag var0, long[] var1) {
int var2 = Math.max(4, MCAMth.ceillog2(var0.size())); int var2 = Math.max(4, MCAMth.ceillog2(var0.size()));
@ -138,69 +131,18 @@ public class MCAPalettedContainer<T> implements MCAPaletteResize<T> {
if (this.palette == this.globalPalette) { if (this.palette == this.globalPalette) {
MCAPalette<T> var4 = new MCAHashMapPalette<>(this.registry, var2, this.dummyPaletteResize, this.reader, this.writer); MCAPalette<T> var4 = new MCAHashMapPalette<>(this.registry, var2, this.dummyPaletteResize, this.reader, this.writer);
var4.read(var0); var4.read(var0);
MCABitStorageLongArray var5 = new MCABitStorageLongArray(var2, 4096, var1); MCABitStorage var5 = new MCABitStorage(var2, 4096, var1);
for (int var6 = 0; var6 < 4096; var6++) for (int var6 = 0; var6 < 4096; var6++)
this.storage.set(var6, this.globalPalette.idFor(var4.valueFor(var5.get(var6)))); this.storage.set(var6, this.globalPalette.idFor(var4.valueFor(var5.get(var6))));
} else if (var3 == this.bits) { } else if (var3 == this.bits) {
System.arraycopy(var1, 0, this.storage.getRaw(), 0, var1.length); System.arraycopy(var1, 0, this.storage.getRaw(), 0, var1.length);
} else { } else {
MCABitStorageLongArray var4 = new MCABitStorageLongArray(var3, 4096, var1); MCABitStorage var4 = new MCABitStorage(var3, 4096, var1);
for (int var5 = 0; var5 < 4096; var5++) for (int var5 = 0; var5 < 4096; var5++)
this.storage.set(var5, var4.get(var5)); this.storage.set(var5, var4.get(var5));
} }
} }
/**
* Reads and processes block data from encoded byte arrays.
* @param var0 BlockID Strings - List of block types identified by strings.
* @param var1 Encoded Locations - Byte array containing compactly encoded block IDs, representing sequential block positions within a chunk.
* Currently, Minecraft doesn't use ByteArray storage.
*/
public void read(ListTag var0, byte[] var1) {
int requiredBits = Math.max(4, MCAMth.ceillog2(var0.size()));
if (requiredBits != this.bits) {
setBits(requiredBits);
}
this.palette.read(var0);
int bitsPerByte = 8 * var1.length / 4096;
if (this.palette == this.globalPalette) {
MCAPalette<T> var4 = new MCAHashMapPalette<>(this.registry, requiredBits, this.dummyPaletteResize, this.reader, this.writer);
var4.read(var0);
MCABitStorageByteArray var5 = new MCABitStorageByteArray(requiredBits, 4096, var1);
for (int var6 = 0; var6 < 4096; var6++) {
this.storage.set(var6, this.globalPalette.idFor(var4.valueFor(var5.get(var6))));
}
} else if (bitsPerByte == this.bits) {
System.arraycopy(var1, 0, this.storage.getRaw(), 0, var1.length);
} else {
MCABitStorageByteArray var4 = new MCABitStorageByteArray(bitsPerByte, 4096, var1);
for (int var5 = 0; var5 < 4096; var5++) {
this.storage.set(var5, var4.get(var5));
}
}
}
/**
* Reads and processes block data from encoded byte arrays.
* @param var0 BlockID Strings - List of block types identified by strings.
* This method is primarily used to read air sections.
*/
public void read(ListTag var0) {
int requiredBits = Math.max(4, MCAMth.ceillog2(var0.size()));
if (requiredBits != this.bits) {
setBits(requiredBits);
}
this.palette.read(var0);
int defaultValue = 0;
for (int i = 0; i < 4096; i++) {
this.storage.set(i, defaultValue);
}
}
public void write(CompoundTag var0, String var1, String var2) { public void write(CompoundTag var0, String var1, String var2) {
MCAHashMapPalette<T> var3 = new MCAHashMapPalette<>(this.registry, this.bits, this.dummyPaletteResize, this.reader, this.writer); MCAHashMapPalette<T> var3 = new MCAHashMapPalette<>(this.registry, this.bits, this.dummyPaletteResize, this.reader, this.writer);
T var4 = this.defaultValue; T var4 = this.defaultValue;
@ -218,7 +160,7 @@ public class MCAPalettedContainer<T> implements MCAPaletteResize<T> {
var3.write(paletteList); var3.write(paletteList);
var0.put(var1, paletteList); var0.put(var1, paletteList);
int var8 = Math.max(4, MCAMth.ceillog2(paletteList.size())); int var8 = Math.max(4, MCAMth.ceillog2(paletteList.size()));
MCABitStorageLongArray var9 = new MCABitStorageLongArray(var8, 4096); MCABitStorage var9 = new MCABitStorage(var8, 4096);
for (int var10 = 0; var10 < var6.length; var10++) { for (int var10 = 0; var10 < var6.length; var10++) {
var9.set(var10, var6[var10]); var9.set(var10, var6[var10]);
} }

View File

@ -18,10 +18,7 @@
package com.volmit.iris.util.nbt.mca.palette; package com.volmit.iris.util.nbt.mca.palette;
import com.volmit.iris.Iris;
import com.volmit.iris.util.nbt.tag.ByteArrayTag;
import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.CompoundTag;
import com.volmit.iris.util.nbt.tag.LongArrayTag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import java.util.function.Function; import java.util.function.Function;
@ -45,22 +42,6 @@ public class MCAWrappedPalettedContainer<T> implements MCAPaletteAccess {
} }
public void readFromSection(CompoundTag tag) { public void readFromSection(CompoundTag tag) {
// container.read(tag.getCompoundTag("block_states").getListTag("palette"), tag.getCompoundTag("block_states").getLongArrayTag("data").getValue()); container.read(tag.getListTag("Palette"), tag.getLongArrayTag("BlockStates").getValue());
CompoundTag blockStates = tag.getCompoundTag("block_states");
if (blockStates == null) {
throw new IllegalArgumentException("block_states tag is missing");
} }
LongArrayTag longData = blockStates.getLongArrayTag("data");
if (longData != null && longData.getValue() != null) {
container.read(tag.getCompoundTag("block_states").getListTag("palette"), tag.getCompoundTag("block_states").getLongArrayTag("data").getValue());
} else {
ByteArrayTag byteData = blockStates.getByteArrayTag("data");
if (byteData == null) {
container.read(tag.getCompoundTag("block_states").getListTag("palette"));
} else {
throw new IllegalArgumentException("No palette data tag found or data value is null");
}
}
}
} }

View File

@ -6,10 +6,6 @@ authors: [ cyberpwn, NextdoorPsycho, Vatuu ]
website: volmit.com website: volmit.com
description: More than a Dimension! description: More than a Dimension!
libraries: libraries:
- org.bytedeco:cuda-platform:12.3-8.9-1.5.10
- org.bytedeco:javacpp:1.5.10
- net.bytebuddy:byte-buddy:1.14.14
- net.bytebuddy:byte-buddy-agent:1.12.8
- com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2 - com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2
- com.github.ben-manes.caffeine:caffeine:3.0.5 - com.github.ben-manes.caffeine:caffeine:3.0.5
- org.apache.commons:commons-lang3:3.12.0 - org.apache.commons:commons-lang3:3.12.0

View File

@ -2,7 +2,6 @@ package com.volmit.iris.core.nms.v1_19_R1;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
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;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
@ -12,7 +11,6 @@ import com.volmit.iris.util.math.RNG;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.BiomeSource;
@ -27,7 +25,6 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
public class CustomBiomeSource extends BiomeSource { public class CustomBiomeSource extends BiomeSource {
private final long seed; private final long seed;
@ -121,28 +118,8 @@ public class CustomBiomeSource extends BiomeSource {
for (IrisBiome i : engine.getAllBiomes()) { for (IrisBiome i : engine.getAllBiomes()) {
if (i.isCustom()) { if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) {
ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); m.put(j.getId(), customRegistry.getHolder(customRegistry.getResourceKey(customRegistry
Biome biome = customRegistry.get(location); .get(new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()))).get()).get());
if (biome == null) {
INMS.get().registerBiome(location.getNamespace(), j, false);
biome = customRegistry.get(location);
if (biome == null) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());
continue;
}
}
Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome);
if (optionalBiomeKey.isEmpty()) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());
continue;
}
ResourceKey<Biome> biomeKey = optionalBiomeKey.get();
Optional<Holder<Biome>> optionalReferenceHolder = customRegistry.getHolder(biomeKey);
if (optionalReferenceHolder.isEmpty()) {
Iris.error("Cannot find reference to biome " + biomeKey + " for engine " + engine.getName());
continue;
}
m.put(j.getId(), optionalReferenceHolder.get());
} }
} }
} }

View File

@ -4,44 +4,14 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File;
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.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.Lifecycle;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.format.C;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.matcher.ElementMatchers;
import net.minecraft.core.MappedRegistry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
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;
@ -55,7 +25,6 @@ import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack;
import org.bukkit.entity.Dolphin; import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -201,17 +170,6 @@ public class NMSBinding implements INMSBinding {
return null; return null;
} }
private RegistryAccess getRegistryAccess(World world) {
try {
var field = getField(Level.class, RegistryAccess.class);
field.setAccessible(true);
return (RegistryAccess) field.get(((CraftWorld) world).getHandle());
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(CompoundTag c, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c));
@ -295,7 +253,8 @@ public class NMSBinding implements INMSBinding {
@Override @Override
public Object getBiomeBase(World world, Biome biome) { public Object getBiomeBase(World world, Biome biome) {
return CraftBlock.biomeToBiomeBase(getRegistryAccess(world).registry(Registry.BIOME_REGISTRY).orElse(null), biome); return CraftBlock.biomeToBiomeBase(((CraftWorld) world).getHandle()
.registryAccess().registry(Registry.BIOME_REGISTRY).orElse(null), biome);
} }
@Override @Override
@ -332,11 +291,8 @@ public class NMSBinding implements INMSBinding {
public int getBiomeId(Biome biome) { public int getBiomeId(Biome biome) {
for (World i : Bukkit.getWorlds()) { for (World i : Bukkit.getWorlds()) {
if (i.getEnvironment().equals(World.Environment.NORMAL)) { if (i.getEnvironment().equals(World.Environment.NORMAL)) {
var registry = getRegistryAccess(i).registry(Registry.BIOME_REGISTRY).orElse(null); Registry<net.minecraft.world.level.biome.Biome> registry = ((CraftWorld) i).getHandle().registryAccess().registry(Registry.BIOME_REGISTRY).orElse(null);
if (registry != null) { return registry.getId((net.minecraft.world.level.biome.Biome) getBiomeBase(registry, biome));
var holder = (Holder<net.minecraft.world.level.biome.Biome>) getBiomeBase(registry, biome);
return registry.getId(holder.value());
}
} }
} }
@ -561,139 +517,6 @@ public class NMSBinding implements INMSBinding {
return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason);
} }
@Override
public boolean registerDimension(String name, IrisDimension dimension) {
var registry = registry(Registry.DIMENSION_TYPE_REGISTRY);
var baseLocation = switch (dimension.getEnvironment()) {
case NORMAL -> new ResourceLocation("minecraft", "overworld");
case NETHER -> new ResourceLocation("minecraft", "the_nether");
case THE_END -> new ResourceLocation("minecraft", "the_end");
case CUSTOM -> throw new IllegalArgumentException("Cannot register custom dimension");
};
var base = registry.getHolder(ResourceKey.create(Registry.DIMENSION_TYPE_REGISTRY, baseLocation)).orElse(null);
if (base == null) return false;
var json = encode(DimensionType.CODEC, base).orElse(null);
if (json == null) return false;
var object = json.getAsJsonObject();
var height = dimension.getDimensionHeight();
object.addProperty("min_y", height.getMin());
object.addProperty("height", height.getMax() - height.getMin());
object.addProperty("logical_height", dimension.getLogicalHeight());
var value = decode(DimensionType.CODEC, object.toString()).map(Holder::value).orElse(null);
if (value == null) return false;
return register(Registry.DIMENSION_TYPE_REGISTRY, new ResourceLocation("iris", name), value, true);
}
@Override
public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) {
var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null);
if (biomeBase == null) return false;
return register(Registry.BIOME_REGISTRY, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace);
}
private <T> Optional<T> decode(Codec<T> codec, String json) {
return codec.decode(JsonOps.INSTANCE, GsonHelper.parse(json)).get().left().map(Pair::getFirst);
}
private <T> Optional<JsonElement> encode(Codec<T> codec, T value) {
return codec.encode(value, JsonOps.INSTANCE, new JsonObject()).result();
}
private <T> boolean register(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value, boolean replace) {
Preconditions.checkArgument(registryKey != null, "The registry cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
if (registry.containsKey(key)) {
if (!replace) return false;
return replace(registryKey, location, value);
}
Field field = getField(MappedRegistry.class, boolean.class);
field.setAccessible(true);
boolean frozen = field.getBoolean(registry);
field.setBoolean(registry, false);
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
try {
var holder = registry.register(key, value, Lifecycle.stable());
if (frozen) valueField.set(holder, value);
return true;
} finally {
field.setBoolean(registry, frozen);
}
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
@SuppressWarnings("unchecked")
private <T> boolean replace(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value) {
Preconditions.checkArgument(registryKey != null, "The registryKey cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
var holder = registry.getHolder(key).orElse(null);
if (holder == null) return false;
var oldValue = holder.value();
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T"));
toIdField.setAccessible(true);
Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T")));
byValueField.setAccessible(true);
Field lifecyclesField = getField(MappedRegistry.class, buildType(Map.class, "T", Lifecycle.class.getName()));
lifecyclesField.setAccessible(true);
var toId = (Reference2IntMap<T>) toIdField.get(registry);
var byValue = (Map<T, Holder.Reference<T>>) byValueField.get(registry);
var lifecycles = (Map<T, Lifecycle>) lifecyclesField.get(registry);
valueField.set(holder, value);
toId.put(value, toId.removeInt(oldValue));
byValue.put(value, byValue.remove(oldValue));
lifecycles.put(value, lifecycles.remove(oldValue));
return true;
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
private <T> MappedRegistry<T> registry(ResourceKey<Registry<T>> registryKey) {
var rawRegistry = registry().registry(registryKey).orElse(null);
if (!(rawRegistry instanceof MappedRegistry<T> registry))
throw new IllegalStateException("The Registry is not a mapped Registry!");
return registry;
}
private static String buildType(Class<?> clazz, String... parameterTypes) {
if (parameterTypes.length == 0) return clazz.getName();
var builder = new StringBuilder(clazz.getName())
.append("<");
for (int i = 0; i < parameterTypes.length; i++) {
builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", ");
}
return builder.toString();
}
private static Field getField(Class<?> clazz, String type) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
if (f.getGenericType().getTypeName().equals(type))
return f;
}
throw new NoSuchFieldException(type);
} catch (NoSuchFieldException e) {
Class<?> superClass = clazz.getSuperclass();
if (superClass == null) throw e;
return getField(superClass, type);
}
}
private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException { private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException {
try { try {
for (Field f : clazz.getDeclaredFields()) { for (Field f : clazz.getDeclaredFields()) {
@ -710,76 +533,4 @@ public class NMSBinding implements INMSBinding {
} }
} }
} }
public void injectBukkit() {
try {
Iris.info("Injecting Bukkit");
new ByteBuddy()
.redefine(CraftServer.class)
.visit(Advice.to(CraftServerAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(WorldCreator.class))))
.make()
.load(CraftServer.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
new ByteBuddy()
.redefine(ServerLevel.class)
.visit(Advice.to(ServerLevelAdvice.class).on(ElementMatchers.isConstructor().and(ElementMatchers.takesArguments(MinecraftServer.class, Executor.class, LevelStorageSource.LevelStorageAccess.class,
PrimaryLevelData.class, ResourceKey.class, LevelStem.class, ChunkProgressListener.class, boolean.class, long.class,
List.class, boolean.class, World.Environment.class, ChunkGenerator.class, BiomeProvider.class))))
.make()
.load(ServerLevel.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
Iris.info("Injected Bukkit Successfully!");
} catch (Exception e) {
Iris.info(C.RED + "Failed to Inject Bukkit!");
e.printStackTrace();
Iris.reportError(e);
}
}
private static class ServerLevelAdvice {
@Advice.OnMethodEnter
static void enter(@Advice.Argument(0) MinecraftServer server, @Advice.Argument(2) LevelStorageSource.LevelStorageAccess access, @Advice.Argument(4) ResourceKey<Level> key, @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem) {
File iris = new File(access.levelDirectory.path().toFile(), "iris");
if (!iris.exists() && !key.location().getPath().startsWith("iris/")) return;
var logger = MinecraftServer.LOGGER;
ResourceKey<DimensionType> typeKey = ResourceKey.create(Registry.DIMENSION_TYPE_REGISTRY, new ResourceLocation("iris", key.location().getPath()));
RegistryAccess registryAccess = server.registryAccess();
Registry<DimensionType> registry = registryAccess.registry(Registry.DIMENSION_TYPE_REGISTRY).orElse(null);
if (registry == null) throw new IllegalStateException("Unable to find registry for dimension type " + typeKey);
Holder<DimensionType> holder = registry.getHolder(typeKey).orElse(null);
if (holder == null) throw new IllegalStateException("Unable to find dimension type " + typeKey);
levelStem = new LevelStem(holder, levelStem.generator());
}
}
private static class CraftServerAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
static boolean enter(@Advice.This CraftServer self, @Advice.Argument(0) WorldCreator creator) {
File isIrisWorld = new File(self.getWorldContainer(), creator.name() + "/iris");
boolean isFromIris = false;
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement stack : stackTrace) {
if (stack.getClassName().contains("Iris")) {
isFromIris = true;
break;
}
}
if (isIrisWorld.exists() && !isFromIris) {
var logger = Logger.getLogger("Iris");
logger.warning("detected another Plugin trying to load " + creator.name() + ". This is not supported and will be ignored.");
if (System.getProperty("iris.debug", "false").equals("true")) {
new RuntimeException().printStackTrace();
}
return true;
}
return false;
}
@Advice.OnMethodExit
static void exit(@Advice.Enter boolean bool, @Advice.Return(readOnly = false) World returned) {
if (bool) {
returned = null;
}
}
}
} }

View File

@ -2,7 +2,6 @@ package com.volmit.iris.core.nms.v1_19_R2;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
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;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
@ -13,7 +12,6 @@ import net.minecraft.core.Holder;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; 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.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.BiomeSource;
@ -28,7 +26,6 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
public class CustomBiomeSource extends BiomeSource { public class CustomBiomeSource extends BiomeSource {
@ -123,28 +120,8 @@ public class CustomBiomeSource extends BiomeSource {
for (IrisBiome i : engine.getAllBiomes()) { for (IrisBiome i : engine.getAllBiomes()) {
if (i.isCustom()) { if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) {
ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); m.put(j.getId(), customRegistry.getHolder(customRegistry.getResourceKey(customRegistry
Biome biome = customRegistry.get(location); .get(new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()))).get()).get());
if (biome == null) {
INMS.get().registerBiome(location.getNamespace(), j, false);
biome = customRegistry.get(location);
if (biome == null) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());
continue;
}
}
Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome);
if (optionalBiomeKey.isEmpty()) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());
continue;
}
ResourceKey<Biome> biomeKey = optionalBiomeKey.get();
Optional<Holder.Reference<Biome>> optionalReferenceHolder = customRegistry.getHolder(biomeKey);
if (optionalReferenceHolder.isEmpty()) {
Iris.error("Cannot find reference to biome " + biomeKey + " for engine " + engine.getName());
continue;
}
m.put(j.getId(), optionalReferenceHolder.get());
} }
} }
} }

View File

@ -4,44 +4,14 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File;
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.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.Lifecycle;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.format.C;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.matcher.ElementMatchers;
import net.minecraft.core.MappedRegistry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
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;
@ -55,7 +25,6 @@ import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack;
import org.bukkit.entity.Dolphin; import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -202,17 +171,6 @@ public class NMSBinding implements INMSBinding {
return null; return null;
} }
private RegistryAccess getRegistryAccess(World world) {
try {
var field = getField(Level.class, RegistryAccess.class);
field.setAccessible(true);
return (RegistryAccess) field.get(((CraftWorld) world).getHandle());
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(CompoundTag c, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c));
@ -296,7 +254,8 @@ public class NMSBinding implements INMSBinding {
@Override @Override
public Object getBiomeBase(World world, Biome biome) { public Object getBiomeBase(World world, Biome biome) {
return CraftBlock.biomeToBiomeBase(getRegistryAccess(world).registry(Registries.BIOME).orElse(null), biome); return CraftBlock.biomeToBiomeBase(((CraftWorld) world).getHandle()
.registryAccess().registry(Registries.BIOME).orElse(null), biome);
} }
@Override @Override
@ -333,11 +292,8 @@ public class NMSBinding implements INMSBinding {
public int getBiomeId(Biome biome) { public int getBiomeId(Biome biome) {
for (World i : Bukkit.getWorlds()) { for (World i : Bukkit.getWorlds()) {
if (i.getEnvironment().equals(World.Environment.NORMAL)) { if (i.getEnvironment().equals(World.Environment.NORMAL)) {
var registry = getRegistryAccess(i).registry(Registries.BIOME).orElse(null); Registry<net.minecraft.world.level.biome.Biome> registry = ((CraftWorld) i).getHandle().registryAccess().registry(Registries.BIOME).orElse(null);
if (registry != null) { return registry.getId((net.minecraft.world.level.biome.Biome) getBiomeBase(registry, biome));
var holder = (Holder<net.minecraft.world.level.biome.Biome>) getBiomeBase(registry, biome);
return registry.getId(holder.value());
}
} }
} }
@ -563,138 +519,6 @@ public class NMSBinding implements INMSBinding {
return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason);
} }
@Override
public boolean registerDimension(String name, IrisDimension dimension) {
var registry = registry(Registries.DIMENSION_TYPE);
var baseLocation = switch (dimension.getEnvironment()) {
case NORMAL -> new ResourceLocation("minecraft", "overworld");
case NETHER -> new ResourceLocation("minecraft", "the_nether");
case THE_END -> new ResourceLocation("minecraft", "the_end");
case CUSTOM -> throw new IllegalArgumentException("Cannot register custom dimension");
};
var base = registry.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, baseLocation)).orElse(null);
if (base == null) return false;
var json = encode(DimensionType.CODEC, base).orElse(null);
if (json == null) return false;
var object = json.getAsJsonObject();
var height = dimension.getDimensionHeight();
object.addProperty("min_y", height.getMin());
object.addProperty("height", height.getMax() - height.getMin());
object.addProperty("logical_height", dimension.getLogicalHeight());
var value = decode(DimensionType.CODEC, object.toString()).map(Holder::value).orElse(null);
if (value == null) return false;
return register(Registries.DIMENSION_TYPE, new ResourceLocation("iris", name), value, true);
}
@Override
public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) {
var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null);
if (biomeBase == null) return false;
return register(Registries.BIOME, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace);
}
private <T> Optional<T> decode(Codec<T> codec, String json) {
return codec.decode(JsonOps.INSTANCE, GsonHelper.parse(json)).get().left().map(Pair::getFirst);
}
private <T> Optional<JsonElement> encode(Codec<T> codec, T value) {
return codec.encode(value, JsonOps.INSTANCE, new JsonObject()).result();
}
private <T> boolean register(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value, boolean replace) {
Preconditions.checkArgument(registryKey != null, "The registry cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
if (registry.containsKey(key)) {
if (!replace) return false;
return replace(registryKey, location, value);
}
Field field = getField(MappedRegistry.class, boolean.class);
field.setAccessible(true);
boolean frozen = field.getBoolean(registry);
field.setBoolean(registry, false);
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
try {
var holder = registry.register(key, value, Lifecycle.stable());
if (frozen) valueField.set(holder, value);
return true;
} finally {
field.setBoolean(registry, frozen);
}
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
@SuppressWarnings("unchecked")
private <T> boolean replace(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value) {
Preconditions.checkArgument(registryKey != null, "The registryKey cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
var holder = registry.getHolder(key).orElse(null);
if (holder == null) return false;
var oldValue = holder.value();
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T"));
toIdField.setAccessible(true);
Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T")));
byValueField.setAccessible(true);
Field lifecyclesField = getField(MappedRegistry.class, buildType(Map.class, "T", Lifecycle.class.getName()));
lifecyclesField.setAccessible(true);
var toId = (Reference2IntMap<T>) toIdField.get(registry);
var byValue = (Map<T, Holder.Reference<T>>) byValueField.get(registry);
var lifecycles = (Map<T, Lifecycle>) lifecyclesField.get(registry);
valueField.set(holder, value);
toId.put(value, toId.removeInt(oldValue));
byValue.put(value, byValue.remove(oldValue));
lifecycles.put(value, lifecycles.remove(oldValue));
return true;
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
private <T> MappedRegistry<T> registry(ResourceKey<Registry<T>> registryKey) {
var rawRegistry = registry().registry(registryKey).orElse(null);
if (!(rawRegistry instanceof MappedRegistry<T> registry))
throw new IllegalStateException("The Registry is not a mapped Registry!");
return registry;
}
private static String buildType(Class<?> clazz, String... parameterTypes) {
if (parameterTypes.length == 0) return clazz.getName();
var builder = new StringBuilder(clazz.getName())
.append("<");
for (int i = 0; i < parameterTypes.length; i++) {
builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", ");
}
return builder.toString();
}
private static Field getField(Class<?> clazz, String type) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
if (f.getGenericType().getTypeName().equals(type))
return f;
}
throw new NoSuchFieldException(type);
} catch (NoSuchFieldException e) {
Class<?> superClass = clazz.getSuperclass();
if (superClass == null) throw e;
return getField(superClass, type);
}
}
private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException { private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException {
try { try {
for (Field f : clazz.getDeclaredFields()) { for (Field f : clazz.getDeclaredFields()) {
@ -711,75 +535,4 @@ public class NMSBinding implements INMSBinding {
} }
} }
} }
public void injectBukkit() {
try {
Iris.info("Injecting Bukkit");
new ByteBuddy()
.redefine(CraftServer.class)
.visit(Advice.to(CraftServerAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(WorldCreator.class))))
.make()
.load(CraftServer.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
new ByteBuddy()
.redefine(ServerLevel.class)
.visit(Advice.to(ServerLevelAdvice.class).on(ElementMatchers.isConstructor().and(ElementMatchers.takesArguments(MinecraftServer.class, Executor.class, LevelStorageSource.LevelStorageAccess.class,
PrimaryLevelData.class, ResourceKey.class, LevelStem.class, ChunkProgressListener.class, boolean.class, long.class,
List.class, boolean.class, World.Environment.class, ChunkGenerator.class, BiomeProvider.class))))
.make()
.load(ServerLevel.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
Iris.info("Injected Bukkit Successfully!");
} catch (Exception e) {
Iris.info(C.RED + "Failed to Inject Bukkit!");
e.printStackTrace();
Iris.reportError(e);
}
}
private static class ServerLevelAdvice {
@Advice.OnMethodEnter
static void enter(@Advice.Argument(0) MinecraftServer server, @Advice.Argument(2) LevelStorageSource.LevelStorageAccess access, @Advice.Argument(4) ResourceKey<Level> key, @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem) {
File iris = new File(access.levelDirectory.path().toFile(), "iris");
if (!iris.exists() && !key.location().getPath().startsWith("iris/")) return;
ResourceKey<DimensionType> typeKey = ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath()));
RegistryAccess registryAccess = server.registryAccess();
Registry<DimensionType> registry = registryAccess.registry(Registries.DIMENSION_TYPE).orElse(null);
if (registry == null) throw new IllegalStateException("Unable to find registry for dimension type " + typeKey);
Holder<DimensionType> holder = registry.getHolder(typeKey).orElse(null);
if (holder == null) throw new IllegalStateException("Unable to find dimension type " + typeKey);
levelStem = new LevelStem(holder, levelStem.generator());
}
}
private static class CraftServerAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
static boolean enter(@Advice.This CraftServer self, @Advice.Argument(0) WorldCreator creator) {
File isIrisWorld = new File(self.getWorldContainer(), creator.name() + "/iris");
boolean isFromIris = false;
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement stack : stackTrace) {
if (stack.getClassName().contains("Iris")) {
isFromIris = true;
break;
}
}
if (isIrisWorld.exists() && !isFromIris) {
var logger = Logger.getLogger("Iris");
logger.warning("detected another Plugin trying to load " + creator.name() + ". This is not supported and will be ignored.");
if (System.getProperty("iris.debug", "false").equals("true")) {
new RuntimeException().printStackTrace();
}
return true;
}
return false;
}
@Advice.OnMethodExit
static void exit(@Advice.Enter boolean bool, @Advice.Return(readOnly = false) World returned) {
if (bool) {
returned = null;
}
}
}
} }

View File

@ -2,7 +2,6 @@ package com.volmit.iris.core.nms.v1_19_R3;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
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;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
@ -126,16 +125,8 @@ public class CustomBiomeSource extends BiomeSource {
for (IrisBiome i : engine.getAllBiomes()) { for (IrisBiome i : engine.getAllBiomes()) {
if (i.isCustom()) { if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) {
ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); ResourceLocation resourceLocation = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId());
Biome biome = customRegistry.get(location); Biome biome = customRegistry.get(resourceLocation);
if (biome == null) {
INMS.get().registerBiome(location.getNamespace(), j, false);
biome = customRegistry.get(location);
if (biome == null) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());
continue;
}
}
Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome); Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome);
if (optionalBiomeKey.isEmpty()) { if (optionalBiomeKey.isEmpty()) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());

View File

@ -4,44 +4,14 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File;
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.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.Lifecycle;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.format.C;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.matcher.ElementMatchers;
import net.minecraft.core.MappedRegistry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
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;
@ -55,7 +25,6 @@ import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack;
import org.bukkit.entity.Dolphin; import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -203,17 +172,6 @@ public class NMSBinding implements INMSBinding {
return null; return null;
} }
private RegistryAccess getRegistryAccess(World world) {
try {
var field = getField(Level.class, RegistryAccess.class);
field.setAccessible(true);
return (RegistryAccess) field.get(((CraftWorld) world).getHandle());
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(CompoundTag c, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c));
@ -297,7 +255,8 @@ public class NMSBinding implements INMSBinding {
@Override @Override
public Object getBiomeBase(World world, Biome biome) { public Object getBiomeBase(World world, Biome biome) {
return CraftBlock.biomeToBiomeBase(getRegistryAccess(world).registry(Registries.BIOME).orElse(null), biome); return CraftBlock.biomeToBiomeBase(((CraftWorld) world).getHandle()
.registryAccess().registry(Registries.BIOME).orElse(null), biome);
} }
@Override @Override
@ -335,11 +294,8 @@ public class NMSBinding implements INMSBinding {
public int getBiomeId(Biome biome) { public int getBiomeId(Biome biome) {
for (World i : Bukkit.getWorlds()) { for (World i : Bukkit.getWorlds()) {
if (i.getEnvironment().equals(World.Environment.NORMAL)) { if (i.getEnvironment().equals(World.Environment.NORMAL)) {
var registry = getRegistryAccess(i).registry(Registries.BIOME).orElse(null); Registry<net.minecraft.world.level.biome.Biome> registry = ((CraftWorld) i).getHandle().registryAccess().registry(Registries.BIOME).orElse(null);
if (registry != null) { return registry.getId((net.minecraft.world.level.biome.Biome) getBiomeBase(registry, biome));
var holder = (Holder<net.minecraft.world.level.biome.Biome>) getBiomeBase(registry, biome);
return registry.getId(holder.value());
}
} }
} }
@ -567,138 +523,6 @@ public class NMSBinding implements INMSBinding {
return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason);
} }
@Override
public boolean registerDimension(String name, IrisDimension dimension) {
var registry = registry(Registries.DIMENSION_TYPE);
var baseLocation = switch (dimension.getEnvironment()) {
case NORMAL -> new ResourceLocation("minecraft", "overworld");
case NETHER -> new ResourceLocation("minecraft", "the_nether");
case THE_END -> new ResourceLocation("minecraft", "the_end");
case CUSTOM -> throw new IllegalArgumentException("Cannot register custom dimension");
};
var base = registry.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, baseLocation)).orElse(null);
if (base == null) return false;
var json = encode(DimensionType.CODEC, base).orElse(null);
if (json == null) return false;
var object = json.getAsJsonObject();
var height = dimension.getDimensionHeight();
object.addProperty("min_y", height.getMin());
object.addProperty("height", height.getMax() - height.getMin());
object.addProperty("logical_height", dimension.getLogicalHeight());
var value = decode(DimensionType.CODEC, object.toString()).map(Holder::value).orElse(null);
if (value == null) return false;
return register(Registries.DIMENSION_TYPE, new ResourceLocation("iris", name), value, true);
}
@Override
public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) {
var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null);
if (biomeBase == null) return false;
return register(Registries.BIOME, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace);
}
private <T> Optional<T> decode(Codec<T> codec, String json) {
return codec.decode(JsonOps.INSTANCE, GsonHelper.parse(json)).get().left().map(Pair::getFirst);
}
private <T> Optional<JsonElement> encode(Codec<T> codec, T value) {
return codec.encode(value, JsonOps.INSTANCE, new JsonObject()).result();
}
private <T> boolean register(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value, boolean replace) {
Preconditions.checkArgument(registryKey != null, "The registry cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
if (registry.containsKey(key)) {
if (!replace) return false;
return replace(registryKey, location, value);
}
Field field = getField(MappedRegistry.class, boolean.class);
field.setAccessible(true);
boolean frozen = field.getBoolean(registry);
field.setBoolean(registry, false);
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
try {
var holder = registry.register(key, value, Lifecycle.stable());
if (frozen) valueField.set(holder, value);
return true;
} finally {
field.setBoolean(registry, frozen);
}
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
@SuppressWarnings("unchecked")
private <T> boolean replace(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value) {
Preconditions.checkArgument(registryKey != null, "The registryKey cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
var holder = registry.getHolder(key).orElse(null);
if (holder == null) return false;
var oldValue = holder.value();
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T"));
toIdField.setAccessible(true);
Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T")));
byValueField.setAccessible(true);
Field lifecyclesField = getField(MappedRegistry.class, buildType(Map.class, "T", Lifecycle.class.getName()));
lifecyclesField.setAccessible(true);
var toId = (Reference2IntMap<T>) toIdField.get(registry);
var byValue = (Map<T, Holder.Reference<T>>) byValueField.get(registry);
var lifecycles = (Map<T, Lifecycle>) lifecyclesField.get(registry);
valueField.set(holder, value);
toId.put(value, toId.removeInt(oldValue));
byValue.put(value, byValue.remove(oldValue));
lifecycles.put(value, lifecycles.remove(oldValue));
return true;
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
private <T> MappedRegistry<T> registry(ResourceKey<Registry<T>> registryKey) {
var rawRegistry = registry().registry(registryKey).orElse(null);
if (!(rawRegistry instanceof MappedRegistry<T> registry))
throw new IllegalStateException("The Registry is not a mapped Registry!");
return registry;
}
private static String buildType(Class<?> clazz, String... parameterTypes) {
if (parameterTypes.length == 0) return clazz.getName();
var builder = new StringBuilder(clazz.getName())
.append("<");
for (int i = 0; i < parameterTypes.length; i++) {
builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", ");
}
return builder.toString();
}
private static Field getField(Class<?> clazz, String type) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
if (f.getGenericType().getTypeName().equals(type))
return f;
}
throw new NoSuchFieldException(type);
} catch (NoSuchFieldException e) {
Class<?> superClass = clazz.getSuperclass();
if (superClass == null) throw e;
return getField(superClass, type);
}
}
private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException { private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException {
try { try {
for (Field f : clazz.getDeclaredFields()) { for (Field f : clazz.getDeclaredFields()) {
@ -715,75 +539,4 @@ public class NMSBinding implements INMSBinding {
} }
} }
} }
public void injectBukkit() {
try {
Iris.info("Injecting Bukkit");
new ByteBuddy()
.redefine(CraftServer.class)
.visit(Advice.to(CraftServerAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(WorldCreator.class))))
.make()
.load(CraftServer.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
new ByteBuddy()
.redefine(ServerLevel.class)
.visit(Advice.to(ServerLevelAdvice.class).on(ElementMatchers.isConstructor().and(ElementMatchers.takesArguments(MinecraftServer.class, Executor.class, LevelStorageSource.LevelStorageAccess.class,
PrimaryLevelData.class, ResourceKey.class, LevelStem.class, ChunkProgressListener.class, boolean.class, long.class,
List.class, boolean.class, World.Environment.class, ChunkGenerator.class, BiomeProvider.class))))
.make()
.load(ServerLevel.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
Iris.info("Injected Bukkit Successfully!");
} catch (Exception e) {
Iris.info(C.RED + "Failed to Inject Bukkit!");
e.printStackTrace();
Iris.reportError(e);
}
}
private static class ServerLevelAdvice {
@Advice.OnMethodEnter
static void enter(@Advice.Argument(0) MinecraftServer server, @Advice.Argument(2) LevelStorageSource.LevelStorageAccess access, @Advice.Argument(4) ResourceKey<Level> key, @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem) {
File iris = new File(access.levelDirectory.path().toFile(), "iris");
if (!iris.exists() && !key.location().getPath().startsWith("iris/")) return;
ResourceKey<DimensionType> typeKey = ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath()));
RegistryAccess registryAccess = server.registryAccess();
Registry<DimensionType> registry = registryAccess.registry(Registries.DIMENSION_TYPE).orElse(null);
if (registry == null) throw new IllegalStateException("Unable to find registry for dimension type " + typeKey);
Holder<DimensionType> holder = registry.getHolder(typeKey).orElse(null);
if (holder == null) throw new IllegalStateException("Unable to find dimension type " + typeKey);
levelStem = new LevelStem(holder, levelStem.generator());
}
}
private static class CraftServerAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
static boolean enter(@Advice.This CraftServer self, @Advice.Argument(0) WorldCreator creator) {
File isIrisWorld = new File(self.getWorldContainer(), creator.name() + "/iris");
boolean isFromIris = false;
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement stack : stackTrace) {
if (stack.getClassName().contains("Iris")) {
isFromIris = true;
break;
}
}
if (isIrisWorld.exists() && !isFromIris) {
var logger = Logger.getLogger("Iris");
logger.warning("detected another Plugin trying to load " + creator.name() + ". This is not supported and will be ignored.");
if (System.getProperty("iris.debug", "false").equals("true")) {
new RuntimeException().printStackTrace();
}
return true;
}
return false;
}
@Advice.OnMethodExit
static void exit(@Advice.Enter boolean bool, @Advice.Return(readOnly = false) World returned) {
if (bool) {
returned = null;
}
}
}
} }

View File

@ -2,7 +2,6 @@ package com.volmit.iris.core.nms.v1_20_R1;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
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;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
@ -126,16 +125,8 @@ public class CustomBiomeSource extends BiomeSource {
for (IrisBiome i : engine.getAllBiomes()) { for (IrisBiome i : engine.getAllBiomes()) {
if (i.isCustom()) { if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) {
ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); ResourceLocation resourceLocation = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId());
Biome biome = customRegistry.get(location); Biome biome = customRegistry.get(resourceLocation);
if (biome == null) {
INMS.get().registerBiome(location.getNamespace(), j, false);
biome = customRegistry.get(location);
if (biome == null) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());
continue;
}
}
Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome); Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome);
if (optionalBiomeKey.isEmpty()) { if (optionalBiomeKey.isEmpty()) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());

View File

@ -1,22 +1,12 @@
package com.volmit.iris.core.nms.v1_20_R1; package com.volmit.iris.core.nms.v1_20_R1;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
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.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;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.hunk.Hunk; import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.json.JSONObject; import com.volmit.iris.util.json.JSONObject;
import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.Mantle;
@ -27,27 +17,16 @@ import com.volmit.iris.util.nbt.mca.NBTWorld;
import com.volmit.iris.util.nbt.mca.palette.*; 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 it.unimi.dsi.fastutil.objects.Reference2IntMap;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.matcher.ElementMatchers;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry; import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.TagParser; import net.minecraft.nbt.TagParser;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.RandomSequences;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.BiomeSource; import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -55,10 +34,6 @@ 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 net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
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,8 +47,9 @@ import org.bukkit.craftbukkit.v1_20_R1.entity.CraftDolphin;
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
import org.bukkit.entity.Dolphin; import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.BiomeProvider; import org.bukkit.entity.EntityType;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -83,18 +59,13 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File;
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.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
public class NMSBinding implements INMSBinding { public class NMSBinding implements INMSBinding {
@ -204,17 +175,6 @@ public class NMSBinding implements INMSBinding {
return null; return null;
} }
private RegistryAccess getRegistryAccess(World world) {
try {
var field = getField(Level.class, RegistryAccess.class);
field.setAccessible(true);
return (RegistryAccess) field.get(((CraftWorld) world).getHandle());
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(CompoundTag c, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c));
@ -298,7 +258,8 @@ public class NMSBinding implements INMSBinding {
@Override @Override
public Object getBiomeBase(World world, Biome biome) { public Object getBiomeBase(World world, Biome biome) {
return CraftBlock.biomeToBiomeBase(getRegistryAccess(world).registry(Registries.BIOME).orElse(null), biome); return CraftBlock.biomeToBiomeBase(((CraftWorld) world).getHandle()
.registryAccess().registry(Registries.BIOME).orElse(null), biome);
} }
@Override @Override
@ -335,11 +296,8 @@ public class NMSBinding implements INMSBinding {
public int getBiomeId(Biome biome) { public int getBiomeId(Biome biome) {
for (World i : Bukkit.getWorlds()) { for (World i : Bukkit.getWorlds()) {
if (i.getEnvironment().equals(World.Environment.NORMAL)) { if (i.getEnvironment().equals(World.Environment.NORMAL)) {
var registry = getRegistryAccess(i).registry(Registries.BIOME).orElse(null); Registry<net.minecraft.world.level.biome.Biome> registry = ((CraftWorld) i).getHandle().registryAccess().registry(Registries.BIOME).orElse(null);
if (registry != null) { return registry.getId((net.minecraft.world.level.biome.Biome) getBiomeBase(registry, biome));
var holder = (Holder<net.minecraft.world.level.biome.Biome>) getBiomeBase(registry, biome);
return registry.getId(holder.value());
}
} }
} }
@ -551,138 +509,6 @@ public class NMSBinding implements INMSBinding {
return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason);
} }
@Override
public boolean registerDimension(String name, IrisDimension dimension) {
var registry = registry(Registries.DIMENSION_TYPE);
var baseLocation = switch (dimension.getEnvironment()) {
case NORMAL -> new ResourceLocation("minecraft", "overworld");
case NETHER -> new ResourceLocation("minecraft", "the_nether");
case THE_END -> new ResourceLocation("minecraft", "the_end");
case CUSTOM -> throw new IllegalArgumentException("Cannot register custom dimension");
};
var base = registry.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, baseLocation)).orElse(null);
if (base == null) return false;
var json = encode(DimensionType.CODEC, base).orElse(null);
if (json == null) return false;
var object = json.getAsJsonObject();
var height = dimension.getDimensionHeight();
object.addProperty("min_y", height.getMin());
object.addProperty("height", height.getMax() - height.getMin());
object.addProperty("logical_height", dimension.getLogicalHeight());
var value = decode(DimensionType.CODEC, object.toString()).map(Holder::value).orElse(null);
if (value == null) return false;
return register(Registries.DIMENSION_TYPE, new ResourceLocation("iris", name), value, true);
}
@Override
public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) {
var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null);
if (biomeBase == null) return false;
return register(Registries.BIOME, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace);
}
private <T> Optional<T> decode(Codec<T> codec, String json) {
return codec.decode(JsonOps.INSTANCE, GsonHelper.parse(json)).get().left().map(Pair::getFirst);
}
private <T> Optional<JsonElement> encode(Codec<T> codec, T value) {
return codec.encode(value, JsonOps.INSTANCE, new JsonObject()).result();
}
private <T> boolean register(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value, boolean replace) {
Preconditions.checkArgument(registryKey != null, "The registry cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
if (registry.containsKey(key)) {
if (!replace) return false;
return replace(registryKey, location, value);
}
Field field = getField(MappedRegistry.class, boolean.class);
field.setAccessible(true);
boolean frozen = field.getBoolean(registry);
field.setBoolean(registry, false);
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
try {
var holder = registry.register(key, value, Lifecycle.stable());
if (frozen) valueField.set(holder, value);
return true;
} finally {
field.setBoolean(registry, frozen);
}
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
@SuppressWarnings("unchecked")
private <T> boolean replace(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value) {
Preconditions.checkArgument(registryKey != null, "The registryKey cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
var holder = registry.getHolder(key).orElse(null);
if (holder == null) return false;
var oldValue = holder.value();
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T"));
toIdField.setAccessible(true);
Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T")));
byValueField.setAccessible(true);
Field lifecyclesField = getField(MappedRegistry.class, buildType(Map.class, "T", Lifecycle.class.getName()));
lifecyclesField.setAccessible(true);
var toId = (Reference2IntMap<T>) toIdField.get(registry);
var byValue = (Map<T, Holder.Reference<T>>) byValueField.get(registry);
var lifecycles = (Map<T, Lifecycle>) lifecyclesField.get(registry);
valueField.set(holder, value);
toId.put(value, toId.removeInt(oldValue));
byValue.put(value, byValue.remove(oldValue));
lifecycles.put(value, lifecycles.remove(oldValue));
return true;
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
private <T> MappedRegistry<T> registry(ResourceKey<Registry<T>> registryKey) {
var rawRegistry = registry().registry(registryKey).orElse(null);
if (!(rawRegistry instanceof MappedRegistry<T> registry))
throw new IllegalStateException("The Registry is not a mapped Registry!");
return registry;
}
private static String buildType(Class<?> clazz, String... parameterTypes) {
if (parameterTypes.length == 0) return clazz.getName();
var builder = new StringBuilder(clazz.getName())
.append("<");
for (int i = 0; i < parameterTypes.length; i++) {
builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", ");
}
return builder.toString();
}
private static Field getField(Class<?> clazz, String type) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
if (f.getGenericType().getTypeName().equals(type))
return f;
}
throw new NoSuchFieldException(type);
} catch (NoSuchFieldException e) {
Class<?> superClass = clazz.getSuperclass();
if (superClass == null) throw e;
return getField(superClass, type);
}
}
public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException { public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
ServerLevel serverLevel = ((CraftWorld)world).getHandle(); ServerLevel serverLevel = ((CraftWorld)world).getHandle();
Class<?> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass(); Class<?> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass();
@ -712,75 +538,4 @@ public class NMSBinding implements INMSBinding {
} }
} }
} }
public void injectBukkit() {
try {
Iris.info("Injecting Bukkit");
new ByteBuddy()
.redefine(CraftServer.class)
.visit(Advice.to(CraftServerAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(WorldCreator.class))))
.make()
.load(CraftServer.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
new ByteBuddy()
.redefine(ServerLevel.class)
.visit(Advice.to(ServerLevelAdvice.class).on(ElementMatchers.isConstructor().and(ElementMatchers.takesArguments(MinecraftServer.class, Executor.class, LevelStorageSource.LevelStorageAccess.class,
PrimaryLevelData.class, ResourceKey.class, LevelStem.class, ChunkProgressListener.class, boolean.class, long.class,
List.class, boolean.class, RandomSequences.class, World.Environment.class, ChunkGenerator.class, BiomeProvider.class))))
.make()
.load(ServerLevel.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
Iris.info("Injected Bukkit Successfully!");
} catch (Exception e) {
Iris.info(C.RED + "Failed to Inject Bukkit!");
e.printStackTrace();
Iris.reportError(e);
}
}
private static class ServerLevelAdvice {
@Advice.OnMethodEnter
static void enter(@Advice.Argument(0) MinecraftServer server, @Advice.Argument(2) LevelStorageSource.LevelStorageAccess access, @Advice.Argument(4) ResourceKey<Level> key, @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem) {
File iris = new File(access.levelDirectory.path().toFile(), "iris");
if (!iris.exists() && !key.location().getPath().startsWith("iris/")) return;
ResourceKey<DimensionType> typeKey = ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath()));
RegistryAccess registryAccess = server.registryAccess();
Registry<DimensionType> registry = registryAccess.registry(Registries.DIMENSION_TYPE).orElse(null);
if (registry == null) throw new IllegalStateException("Unable to find registry for dimension type " + typeKey);
Holder<DimensionType> holder = registry.getHolder(typeKey).orElse(null);
if (holder == null) throw new IllegalStateException("Unable to find dimension type " + typeKey);
levelStem = new LevelStem(holder, levelStem.generator());
}
}
private static class CraftServerAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
static boolean enter(@Advice.This CraftServer self, @Advice.Argument(0) WorldCreator creator) {
File isIrisWorld = new File(self.getWorldContainer(), creator.name() + "/iris");
boolean isFromIris = false;
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement stack : stackTrace) {
if (stack.getClassName().contains("Iris")) {
isFromIris = true;
break;
}
}
if (isIrisWorld.exists() && !isFromIris) {
var logger = Logger.getLogger("Iris");
logger.warning("detected another Plugin trying to load " + creator.name() + ". This is not supported and will be ignored.");
if (System.getProperty("iris.debug", "false").equals("true")) {
new RuntimeException().printStackTrace();
}
return true;
}
return false;
}
@Advice.OnMethodExit
static void exit(@Advice.Enter boolean bool, @Advice.Return(readOnly = false) World returned) {
if (bool) {
returned = null;
}
}
}
} }

View File

@ -2,7 +2,6 @@ package com.volmit.iris.core.nms.v1_20_R2;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
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;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
@ -125,16 +124,8 @@ public class CustomBiomeSource extends BiomeSource {
for (IrisBiome i : engine.getAllBiomes()) { for (IrisBiome i : engine.getAllBiomes()) {
if (i.isCustom()) { if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) {
ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); ResourceLocation resourceLocation = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId());
Biome biome = customRegistry.get(location); Biome biome = customRegistry.get(resourceLocation);
if (biome == null) {
INMS.get().registerBiome(location.getNamespace(), j, false);
biome = customRegistry.get(location);
if (biome == null) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());
continue;
}
}
Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome); Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome);
if (optionalBiomeKey.isEmpty()) { if (optionalBiomeKey.isEmpty()) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());

View File

@ -4,44 +4,14 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File;
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.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.Lifecycle;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.format.C;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.matcher.ElementMatchers;
import net.minecraft.core.MappedRegistry;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.RandomSequences;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
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;
@ -55,7 +25,6 @@ import org.bukkit.craftbukkit.v1_20_R2.util.CraftNamespacedKey;
import org.bukkit.entity.Dolphin; import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -204,17 +173,6 @@ public class NMSBinding implements INMSBinding {
return null; return null;
} }
private RegistryAccess getRegistryAccess(World world) {
try {
var field = getField(Level.class, RegistryAccess.class);
field.setAccessible(true);
return (RegistryAccess) field.get(((CraftWorld) world).getHandle());
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(CompoundTag c, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c));
@ -298,7 +256,8 @@ public class NMSBinding implements INMSBinding {
@Override @Override
public Object getBiomeBase(World world, Biome biome) { public Object getBiomeBase(World world, Biome biome) {
return biomeToBiomeBase(getRegistryAccess(world).registry(Registries.BIOME).orElse(null), biome); return biomeToBiomeBase(((CraftWorld) world).getHandle()
.registryAccess().registry(Registries.BIOME).orElse(null), biome);
} }
@Override @Override
@ -335,11 +294,8 @@ public class NMSBinding implements INMSBinding {
public int getBiomeId(Biome biome) { public int getBiomeId(Biome biome) {
for (World i : Bukkit.getWorlds()) { for (World i : Bukkit.getWorlds()) {
if (i.getEnvironment().equals(World.Environment.NORMAL)) { if (i.getEnvironment().equals(World.Environment.NORMAL)) {
var registry = getRegistryAccess(i).registry(Registries.BIOME).orElse(null); Registry<net.minecraft.world.level.biome.Biome> registry = ((CraftWorld) i).getHandle().registryAccess().registry(Registries.BIOME).orElse(null);
if (registry != null) { return registry.getId((net.minecraft.world.level.biome.Biome) getBiomeBase(registry, biome));
var holder = (Holder<net.minecraft.world.level.biome.Biome>) getBiomeBase(registry, biome);
return registry.getId(holder.value());
}
} }
} }
@ -564,139 +520,6 @@ public class NMSBinding implements INMSBinding {
return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason);
} }
@Override
public boolean registerDimension(String name, IrisDimension dimension) {
var registry = registry(Registries.DIMENSION_TYPE);
var baseLocation = switch (dimension.getEnvironment()) {
case NORMAL -> new ResourceLocation("minecraft", "overworld");
case NETHER -> new ResourceLocation("minecraft", "the_nether");
case THE_END -> new ResourceLocation("minecraft", "the_end");
case CUSTOM -> throw new IllegalArgumentException("Cannot register custom dimension");
};
var base = registry.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, baseLocation)).orElse(null);
if (base == null) return false;
var json = encode(DimensionType.CODEC, base).orElse(null);
if (json == null) return false;
var object = json.getAsJsonObject();
var height = dimension.getDimensionHeight();
object.addProperty("min_y", height.getMin());
object.addProperty("height", height.getMax() - height.getMin());
object.addProperty("logical_height", dimension.getLogicalHeight());
var value = decode(DimensionType.CODEC, object.toString()).map(Holder::value).orElse(null);
if (value == null) return false;
return register(Registries.DIMENSION_TYPE, new ResourceLocation("iris", name), value, true);
}
@Override
public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) {
var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null);
if (biomeBase == null) return false;
return register(Registries.BIOME, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace);
}
private <T> Optional<T> decode(Codec<T> codec, String json) {
return codec.decode(JsonOps.INSTANCE, GsonHelper.parse(json)).get().left().map(Pair::getFirst);
}
private <T> Optional<JsonElement> encode(Codec<T> codec, T value) {
return codec.encode(value, JsonOps.INSTANCE, new JsonObject()).result();
}
private <T> boolean register(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value, boolean replace) {
Preconditions.checkArgument(registryKey != null, "The registry cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
if (registry.containsKey(key)) {
if (!replace) return false;
return replace(registryKey, location, value);
}
Field field = getField(MappedRegistry.class, boolean.class);
field.setAccessible(true);
boolean frozen = field.getBoolean(registry);
field.setBoolean(registry, false);
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
try {
var holder = registry.register(key, value, Lifecycle.stable());
if (frozen) valueField.set(holder, value);
return true;
} finally {
field.setBoolean(registry, frozen);
}
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
@SuppressWarnings("unchecked")
private <T> boolean replace(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value) {
Preconditions.checkArgument(registryKey != null, "The registryKey cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
var holder = registry.getHolder(key).orElse(null);
if (holder == null) return false;
var oldValue = holder.value();
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T"));
toIdField.setAccessible(true);
Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T")));
byValueField.setAccessible(true);
Field lifecyclesField = getField(MappedRegistry.class, buildType(Map.class, "T", Lifecycle.class.getName()));
lifecyclesField.setAccessible(true);
var toId = (Reference2IntMap<T>) toIdField.get(registry);
var byValue = (Map<T, Holder.Reference<T>>) byValueField.get(registry);
var lifecycles = (Map<T, Lifecycle>) lifecyclesField.get(registry);
valueField.set(holder, value);
toId.put(value, toId.removeInt(oldValue));
byValue.put(value, byValue.remove(oldValue));
lifecycles.put(value, lifecycles.remove(oldValue));
return true;
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
private <T> MappedRegistry<T> registry(ResourceKey<Registry<T>> registryKey) {
var rawRegistry = registry().registry(registryKey).orElse(null);
if (!(rawRegistry instanceof MappedRegistry<T> registry))
throw new IllegalStateException("The Registry is not a mapped Registry!");
return registry;
}
private static String buildType(Class<?> clazz, String... parameterTypes) {
if (parameterTypes.length == 0) return clazz.getName();
var builder = new StringBuilder(clazz.getName())
.append("<");
for (int i = 0; i < parameterTypes.length; i++) {
builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", ");
}
return builder.toString();
}
private static Field getField(Class<?> clazz, String type) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
if (f.getGenericType().getTypeName().equals(type))
return f;
}
throw new NoSuchFieldException(type);
} catch (NoSuchFieldException e) {
Class<?> superClass = clazz.getSuperclass();
if (superClass == null) throw e;
return getField(superClass, type);
}
}
private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException { private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException {
try { try {
for (Field f : clazz.getDeclaredFields()) { for (Field f : clazz.getDeclaredFields()) {
@ -717,75 +540,4 @@ 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())));
} }
public void injectBukkit() {
try {
Iris.info("Injecting Bukkit");
new ByteBuddy()
.redefine(CraftServer.class)
.visit(Advice.to(CraftServerAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(WorldCreator.class))))
.make()
.load(CraftServer.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
new ByteBuddy()
.redefine(ServerLevel.class)
.visit(Advice.to(ServerLevelAdvice.class).on(ElementMatchers.isConstructor().and(ElementMatchers.takesArguments(MinecraftServer.class, Executor.class, LevelStorageSource.LevelStorageAccess.class,
PrimaryLevelData.class, ResourceKey.class, LevelStem.class, ChunkProgressListener.class, boolean.class, long.class,
List.class, boolean.class, RandomSequences.class, World.Environment.class, ChunkGenerator.class, BiomeProvider.class))))
.make()
.load(ServerLevel.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
Iris.info("Injected Bukkit Successfully!");
} catch (Exception e) {
Iris.info(C.RED + "Failed to Inject Bukkit!");
e.printStackTrace();
Iris.reportError(e);
}
}
private static class ServerLevelAdvice {
@Advice.OnMethodEnter
static void enter(@Advice.Argument(0) MinecraftServer server, @Advice.Argument(2) LevelStorageSource.LevelStorageAccess access, @Advice.Argument(4) ResourceKey<Level> key, @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem) {
File iris = new File(access.levelDirectory.path().toFile(), "iris");
if (!iris.exists() && !key.location().getPath().startsWith("iris/")) return;
ResourceKey<DimensionType> typeKey = ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath()));
RegistryAccess registryAccess = server.registryAccess();
Registry<DimensionType> registry = registryAccess.registry(Registries.DIMENSION_TYPE).orElse(null);
if (registry == null) throw new IllegalStateException("Unable to find registry for dimension type " + typeKey);
Holder<DimensionType> holder = registry.getHolder(typeKey).orElse(null);
if (holder == null) throw new IllegalStateException("Unable to find dimension type " + typeKey);
levelStem = new LevelStem(holder, levelStem.generator());
}
}
private static class CraftServerAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
static boolean enter(@Advice.This CraftServer self, @Advice.Argument(0) WorldCreator creator) {
File isIrisWorld = new File(self.getWorldContainer(), creator.name() + "/iris");
boolean isFromIris = false;
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement stack : stackTrace) {
if (stack.getClassName().contains("Iris")) {
isFromIris = true;
break;
}
}
if (isIrisWorld.exists() && !isFromIris) {
var logger = Logger.getLogger("Iris");
logger.warning("detected another Plugin trying to load " + creator.name() + ". This is not supported and will be ignored.");
if (System.getProperty("iris.debug", "false").equals("true")) {
new RuntimeException().printStackTrace();
}
return true;
}
return false;
}
@Advice.OnMethodExit
static void exit(@Advice.Enter boolean bool, @Advice.Return(readOnly = false) World returned) {
if (bool) {
returned = null;
}
}
}
} }

View File

@ -2,7 +2,6 @@ package com.volmit.iris.core.nms.v1_20_R3;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
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;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
@ -125,16 +124,8 @@ public class CustomBiomeSource extends BiomeSource {
for (IrisBiome i : engine.getAllBiomes()) { for (IrisBiome i : engine.getAllBiomes()) {
if (i.isCustom()) { if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) {
ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); ResourceLocation resourceLocation = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId());
Biome biome = customRegistry.get(location); Biome biome = customRegistry.get(resourceLocation);
if (biome == null) {
INMS.get().registerBiome(location.getNamespace(), j, false);
biome = customRegistry.get(location);
if (biome == null) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());
continue;
}
}
Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome); Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome);
if (optionalBiomeKey.isEmpty()) { if (optionalBiomeKey.isEmpty()) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());

View File

@ -1,256 +0,0 @@
package com.volmit.iris.core.nms.v1_20_R3;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.BiomeBaseInjector;
import com.volmit.iris.core.nms.IHeadless;
import com.volmit.iris.core.nms.v1_20_R3.mca.MCATerrainChunk;
import com.volmit.iris.core.nms.v1_20_R3.mca.RegionFileStorage;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineStage;
import com.volmit.iris.engine.framework.WrongEngineBroException;
import com.volmit.iris.engine.object.IrisBiome;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.context.ChunkContext;
import com.volmit.iris.util.context.IrisContext;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.RegionCoordinates;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder;
import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder;
import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.Looper;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import net.minecraft.core.Holder;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.data.BlockData;
import java.io.File;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
public class Headless implements IHeadless, LevelHeightAccessor {
private final NMSBinding binding;
private final Engine engine;
private final RegionFileStorage storage;
private final Queue<ProtoChunk> chunkQueue = new ArrayDeque<>();
private final ReentrantLock saveLock = new ReentrantLock();
private final KMap<String, Holder<Biome>> customBiomes = new KMap<>();
private final KMap<NamespacedKey, Holder<Biome>> minecraftBiomes = new KMap<>();
private boolean closed = false;
public Headless(NMSBinding binding, Engine engine) {
this.binding = binding;
this.engine = engine;
this.storage = new RegionFileStorage(new File(engine.getWorld().worldFolder(), "region").toPath(), false);
var queueLooper = new Looper() {
@Override
protected long loop() {
save();
return closed ? -1 : 100;
}
};
queueLooper.setName("Region Save Looper");
queueLooper.start();
var dimKey = engine.getDimension().getLoadKey();
for (var biome : engine.getAllBiomes()) {
if (!biome.isCustom()) continue;
for (var custom : biome.getCustomDerivitives()) {
binding.registerBiome(dimKey, custom, false);
}
}
}
@Override
public boolean exists(int x, int z) {
if (closed) return false;
try {
CompoundTag tag = storage.read(new ChunkPos(x, z));
return tag != null && !"empty".equals(tag.getString("Status"));
} catch (IOException e) {
return false;
}
}
@Override
public void save() {
if (closed) return;
saveLock.lock();
try {
while (!chunkQueue.isEmpty()) {
ChunkAccess chunk = chunkQueue.poll();
if (chunk == null) break;
try {
storage.write(chunk.getPos(), binding.serializeChunk(chunk, this));
} catch (Throwable e) {
Iris.error("Failed to save chunk " + chunk.getPos().x + ", " + chunk.getPos().z);
e.printStackTrace();
}
}
} finally {
saveLock.unlock();
}
}
@Override
public void generateRegion(MultiBurst burst, int x, int z, PregenListener listener) {
if (closed) return;
boolean listening = listener != null;
if (listening) listener.onRegionGenerating(x, z);
CountDownLatch latch = new CountDownLatch(1024);
iterateRegion(x, z, pos -> burst.complete(() -> {
if (listening) listener.onChunkGenerating(pos.x, pos.z);
generateChunk(pos.x, pos.z);
if (listening) listener.onChunkGenerated(pos.x, pos.z);
latch.countDown();
}));
try {
latch.await();
} catch (InterruptedException ignored) {}
if (listening) listener.onRegionGenerated(x, z);
}
@RegionCoordinates
private static void iterateRegion(int x, int z, Consumer<ChunkPos> chunkPos) {
int cX = x << 5;
int cZ = z << 5;
for (int xx = 0; xx < 32; xx++) {
for (int zz = 0; zz < 32; zz++) {
chunkPos.accept(new ChunkPos(cX + xx, cZ + zz));
}
}
}
@Override
public void generateChunk(int x, int z) {
if (closed || exists(x, z)) return;
try {
var pos = new ChunkPos(x, z);
ProtoChunk chunk = binding.createProtoChunk(pos, this);
var tc = new MCATerrainChunk(chunk);
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
ChunkContext ctx = generate(engine, pos.x << 4, pos.z << 4, blocks, biomes);
blocks.apply();
biomes.apply();
inject(engine, tc.getBiomeBaseInjector(), chunk, ctx); //TODO improve
chunk.setStatus(ChunkStatus.FULL);
chunkQueue.add(chunk);
} catch (Throwable e) {
Iris.error("Failed to generate " + x + ", " + z);
e.printStackTrace();
}
}
@BlockCoordinates
private ChunkContext generate(Engine engine, int x, int z, Hunk<BlockData> vblocks, Hunk<org.bukkit.block.Biome> vbiomes) throws WrongEngineBroException {
if (engine.isClosed()) {
throw new WrongEngineBroException();
}
engine.getContext().touch();
engine.getEngineData().getStatistics().generatedChunk();
ChunkContext ctx = null;
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
Hunk<BlockData> blocks = vblocks.listen((xx, y, zz, t) -> engine.catchBlockUpdates(x + xx, y + engine.getMinHeight(), z + zz, t));
var dimension = engine.getDimension();
if (dimension.isDebugChunkCrossSections() && ((x >> 4) % dimension.getDebugCrossSectionsMod() == 0 || (z >> 4) % dimension.getDebugCrossSectionsMod() == 0)) {
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
blocks.set(i, 0, j, Material.CRYING_OBSIDIAN.createBlockData());
}
}
} else {
ctx = new ChunkContext(x, z, engine.getComplex());
IrisContext.getOr(engine).setChunkContext(ctx);
for (EngineStage i : engine.getMode().getStages()) {
i.generate(x, z, blocks, vbiomes, false, ctx);
}
}
engine.getMantle().getMantle().flag(x >> 4, z >> 4, MantleFlag.REAL, true);
engine.getMetrics().getTotal().put(p.getMilliseconds());
engine.addGenerated();
} catch (Throwable e) {
Iris.reportError(e);
engine.fail("Failed to generate " + x + ", " + z, e);
}
return ctx;
}
private void inject(Engine engine, BiomeBaseInjector injector, ChunkAccess chunk, ChunkContext ctx) {
var pos = chunk.getPos();
for (int y = engine.getMinHeight(); y < engine.getMaxHeight(); y++) {
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
int wX = pos.getBlockX(x);
int wZ = pos.getBlockZ(z);
try {
injector.setBiome(x, y, z, getNoiseBiome(engine, ctx, x, z, wX, y, wZ));
} catch (Throwable e) {
Iris.error("Failed to inject biome for " + wX + ", " + y + ", " + wZ);
e.printStackTrace();
}
}
}
}
}
private Holder<Biome> getNoiseBiome(Engine engine, ChunkContext ctx, int rX, int rZ, int x, int y, int z) {
RNG rng = new RNG(engine.getSeedManager().getBiome());
int m = (y - engine.getMinHeight()) << 2;
IrisBiome ib = ctx == null ?
engine.getComplex().getTrueBiomeStream().get(x << 2, z << 2) :
ctx.getBiome().get(rX, rZ);
if (ib.isCustom()) {
return customBiomes.computeIfAbsent(ib.getCustomBiome(rng, x << 2, m, z << 2).getId(),
id -> binding.getBiomeHolder(engine.getDimension().getLoadKey(), id));
} else {
return minecraftBiomes.computeIfAbsent(ib.getSkyBiome(rng, x << 2, m, z << 2).getKey(),
id -> binding.getBiomeHolder(id.getNamespace(), id.getKey()));
}
}
@Override
public void close() throws IOException {
if (closed) return;
try {
storage.close();
} finally {
closed = true;
customBiomes.clear();
minecraftBiomes.clear();
}
}
@Override
public int getHeight() {
return engine.getHeight();
}
@Override
public int getMinBuildHeight() {
return engine.getMinHeight();
}
}

View File

@ -4,52 +4,14 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File;
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.*; import java.util.Iterator;
import java.util.concurrent.Executor; import java.util.List;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.Lifecycle;
import com.volmit.iris.core.nms.IHeadless;
import com.volmit.iris.core.nms.v1_20_R3.mca.ChunkSerializer;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.format.C;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.assign.Assigner;
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
import net.bytebuddy.matcher.ElementMatchers;
import net.minecraft.core.IdMapper;
import net.minecraft.core.MappedRegistry;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.RandomSequences;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
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;
@ -63,7 +25,6 @@ import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey;
import org.bukkit.entity.Dolphin; import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -106,8 +67,6 @@ import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
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();
@ -214,17 +173,6 @@ public class NMSBinding implements INMSBinding {
return null; return null;
} }
private RegistryAccess getRegistryAccess(World world) {
try {
var field = getField(Level.class, RegistryAccess.class);
field.setAccessible(true);
return (RegistryAccess) field.get(((CraftWorld) world).getHandle());
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Override @Override
public void deserializeTile(CompoundTag c, Location pos) { public void deserializeTile(CompoundTag c, Location pos) {
((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c)); ((CraftWorld) pos.getWorld()).getHandle().getChunkAt(new BlockPos(pos.getBlockX(), 0, pos.getBlockZ())).setBlockEntityNbt(convert(c));
@ -308,7 +256,8 @@ public class NMSBinding implements INMSBinding {
@Override @Override
public Object getBiomeBase(World world, Biome biome) { public Object getBiomeBase(World world, Biome biome) {
return biomeToBiomeBase(getRegistryAccess(world).registry(Registries.BIOME).orElse(null), biome); return biomeToBiomeBase(((CraftWorld) world).getHandle()
.registryAccess().registry(Registries.BIOME).orElse(null), biome);
} }
@Override @Override
@ -345,11 +294,8 @@ public class NMSBinding implements INMSBinding {
public int getBiomeId(Biome biome) { public int getBiomeId(Biome biome) {
for (World i : Bukkit.getWorlds()) { for (World i : Bukkit.getWorlds()) {
if (i.getEnvironment().equals(World.Environment.NORMAL)) { if (i.getEnvironment().equals(World.Environment.NORMAL)) {
var registry = getRegistryAccess(i).registry(Registries.BIOME).orElse(null); Registry<net.minecraft.world.level.biome.Biome> registry = ((CraftWorld) i).getHandle().registryAccess().registry(Registries.BIOME).orElse(null);
if (registry != null) { return registry.getId((net.minecraft.world.level.biome.Biome) getBiomeBase(registry, biome));
var holder = (Holder<net.minecraft.world.level.biome.Biome>) getBiomeBase(registry, biome);
return registry.getId(holder.value());
}
} }
} }
@ -469,13 +415,13 @@ public class NMSBinding implements INMSBinding {
@Override @Override
public MCAPaletteAccess createPalette() { public MCAPaletteAccess createPalette() {
MCAIdMapper<BlockState> registry = registryCache.aquireNasty(() -> { MCAIdMapper<BlockState> registry = registryCache.aquireNasty(() -> {
Field cf = IdMapper.class.getDeclaredField("tToId"); Field cf = net.minecraft.core.IdMapper.class.getDeclaredField("tToId");
Field df = IdMapper.class.getDeclaredField("idToT"); Field df = net.minecraft.core.IdMapper.class.getDeclaredField("idToT");
Field bf = IdMapper.class.getDeclaredField("nextId"); Field bf = net.minecraft.core.IdMapper.class.getDeclaredField("nextId");
cf.setAccessible(true); cf.setAccessible(true);
df.setAccessible(true); df.setAccessible(true);
bf.setAccessible(true); bf.setAccessible(true);
IdMapper<BlockState> blockData = Block.BLOCK_STATE_REGISTRY; net.minecraft.core.IdMapper<BlockState> blockData = Block.BLOCK_STATE_REGISTRY;
int b = bf.getInt(blockData); int b = bf.getInt(blockData);
Object2IntMap<BlockState> c = (Object2IntMap<BlockState>) cf.get(blockData); Object2IntMap<BlockState> c = (Object2IntMap<BlockState>) cf.get(blockData);
List<BlockState> d = (List<BlockState>) df.get(blockData); List<BlockState> d = (List<BlockState>) df.get(blockData);
@ -569,143 +515,12 @@ public class NMSBinding implements INMSBinding {
return null; return null;
} }
@Override @Override
public Entity spawnEntity(Location location, org.bukkit.entity.EntityType type, CreatureSpawnEvent.SpawnReason reason) { public Entity spawnEntity(Location location, org.bukkit.entity.EntityType type, CreatureSpawnEvent.SpawnReason reason) {
return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason); return ((CraftWorld) location.getWorld()).spawn(location, type.getEntityClass(), null, reason);
} }
@Override
public boolean registerDimension(String name, IrisDimension dimension) {
var registry = registry(Registries.DIMENSION_TYPE);
var baseLocation = switch (dimension.getEnvironment()) {
case NORMAL -> new ResourceLocation("minecraft", "overworld");
case NETHER -> new ResourceLocation("minecraft", "the_nether");
case THE_END -> new ResourceLocation("minecraft", "the_end");
case CUSTOM -> throw new IllegalArgumentException("Cannot register custom dimension");
};
var base = registry.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, baseLocation)).orElse(null);
if (base == null) return false;
var json = encode(DimensionType.CODEC, base).orElse(null);
if (json == null) return false;
var object = json.getAsJsonObject();
var height = dimension.getDimensionHeight();
object.addProperty("min_y", height.getMin());
object.addProperty("height", height.getMax() - height.getMin());
object.addProperty("logical_height", dimension.getLogicalHeight());
var value = decode(DimensionType.CODEC, object.toString()).map(Holder::value).orElse(null);
if (value == null) return false;
return register(Registries.DIMENSION_TYPE, new ResourceLocation("iris", name), value, true);
}
@Override
public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) {
var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null);
if (biomeBase == null) return false;
return register(Registries.BIOME, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace);
}
private <T> Optional<T> decode(Codec<T> codec, String json) {
return codec.decode(JsonOps.INSTANCE, GsonHelper.parse(json)).get().left().map(Pair::getFirst);
}
private <T> Optional<JsonElement> encode(Codec<T> codec, T value) {
return codec.encode(value, JsonOps.INSTANCE, new JsonObject()).result();
}
private <T> boolean register(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value, boolean replace) {
Preconditions.checkArgument(registryKey != null, "The registry cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
if (registry.containsKey(key)) {
if (!replace) return false;
return replace(registryKey, location, value);
}
Field field = getField(MappedRegistry.class, boolean.class);
field.setAccessible(true);
boolean frozen = field.getBoolean(registry);
field.setBoolean(registry, false);
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
try {
var holder = registry.register(key, value, Lifecycle.stable());
if (frozen) valueField.set(holder, value);
return true;
} finally {
field.setBoolean(registry, frozen);
}
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
@SuppressWarnings("unchecked")
private <T> boolean replace(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value) {
Preconditions.checkArgument(registryKey != null, "The registryKey cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
var holder = registry.getHolder(key).orElse(null);
if (holder == null) return false;
var oldValue = holder.value();
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T"));
toIdField.setAccessible(true);
Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T")));
byValueField.setAccessible(true);
Field lifecyclesField = getField(MappedRegistry.class, buildType(Map.class, "T", Lifecycle.class.getName()));
lifecyclesField.setAccessible(true);
var toId = (Reference2IntMap<T>) toIdField.get(registry);
var byValue = (Map<T, Holder.Reference<T>>) byValueField.get(registry);
var lifecycles = (Map<T, Lifecycle>) lifecyclesField.get(registry);
valueField.set(holder, value);
toId.put(value, toId.removeInt(oldValue));
byValue.put(value, byValue.remove(oldValue));
lifecycles.put(value, lifecycles.remove(oldValue));
return true;
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
private <T> MappedRegistry<T> registry(ResourceKey<Registry<T>> registryKey) {
var rawRegistry = registry().registry(registryKey).orElse(null);
if (!(rawRegistry instanceof MappedRegistry<T> registry))
throw new IllegalStateException("The Registry is not a mapped Registry!");
return registry;
}
private static String buildType(Class<?> clazz, String... parameterTypes) {
if (parameterTypes.length == 0) return clazz.getName();
var builder = new StringBuilder(clazz.getName())
.append("<");
for (int i = 0; i < parameterTypes.length; i++) {
builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", ");
}
return builder.toString();
}
private static Field getField(Class<?> clazz, String type) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
if (f.getGenericType().getTypeName().equals(type))
return f;
}
throw new NoSuchFieldException(type);
} catch (NoSuchFieldException e) {
Class<?> superClass = clazz.getSuperclass();
if (superClass == null) throw e;
return getField(superClass, type);
}
}
private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException { private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException {
try { try {
for (Field f : clazz.getDeclaredFields()) { for (Field f : clazz.getDeclaredFields()) {
@ -726,92 +541,4 @@ 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())));
} }
public void injectBukkit() {
try {
Iris.info("Injecting Bukkit");
new ByteBuddy()
.redefine(CraftServer.class)
.visit(Advice.to(CraftServerAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(WorldCreator.class))))
.make()
.load(CraftServer.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
new ByteBuddy()
.redefine(ServerLevel.class)
.visit(Advice.to(ServerLevelAdvice.class).on(ElementMatchers.isConstructor().and(ElementMatchers.takesArguments(MinecraftServer.class, Executor.class, LevelStorageSource.LevelStorageAccess.class,
PrimaryLevelData.class, ResourceKey.class, LevelStem.class, ChunkProgressListener.class, boolean.class, long.class,
List.class, boolean.class, RandomSequences.class, World.Environment.class, ChunkGenerator.class, BiomeProvider.class))))
.make()
.load(ServerLevel.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
Iris.info("Injected Bukkit Successfully!");
} catch (Exception e) {
Iris.info(C.RED + "Failed to Inject Bukkit!");
e.printStackTrace();
Iris.reportError(e);
}
}
@Override
public IHeadless createHeadless(Engine engine) {
return new Headless(this, engine);
}
private static class ServerLevelAdvice {
@Advice.OnMethodEnter
static void enter(@Advice.Argument(0) MinecraftServer server, @Advice.Argument(2) LevelStorageSource.LevelStorageAccess access, @Advice.Argument(4) ResourceKey<Level> key, @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem) {
File iris = new File(access.levelDirectory.path().toFile(), "iris");
if (!iris.exists() && !key.location().getPath().startsWith("iris/")) return;
ResourceKey<DimensionType> typeKey = ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath()));
RegistryAccess registryAccess = server.registryAccess();
Registry<DimensionType> registry = registryAccess.registry(Registries.DIMENSION_TYPE).orElse(null);
if (registry == null) throw new IllegalStateException("Unable to find registry for dimension type " + typeKey);
Holder<DimensionType> holder = registry.getHolder(typeKey).orElse(null);
if (holder == null) throw new IllegalStateException("Unable to find dimension type " + typeKey);
levelStem = new LevelStem(holder, levelStem.generator());
}
}
private static class CraftServerAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
static boolean enter(@Advice.This CraftServer self, @Advice.Argument(0) WorldCreator creator) {
File isIrisWorld = new File(self.getWorldContainer(), creator.name() + "/iris");
boolean isFromIris = false;
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement stack : stackTrace) {
if (stack.getClassName().contains("Iris")) {
isFromIris = true;
break;
}
}
if (isIrisWorld.exists() && !isFromIris) {
var logger = Logger.getLogger("Iris");
logger.warning("detected another Plugin trying to load " + creator.name() + ". This is not supported and will be ignored.");
if (System.getProperty("iris.debug", "false").equals("true")) {
new RuntimeException().printStackTrace();
}
return true;
}
return false;
}
@Advice.OnMethodExit
static void exit(@Advice.Enter boolean bool, @Advice.Return(readOnly = false) World returned) {
if (bool) {
returned = null;
}
}
}
Holder.Reference<net.minecraft.world.level.biome.Biome> getBiomeHolder(String namespace, String id) {
return getCustomBiomeRegistry().getHolder(ResourceKey.create(Registries.BIOME, new ResourceLocation(namespace, id))).orElse(null);
}
ProtoChunk createProtoChunk(ChunkPos pos, LevelHeightAccessor heightAccessor) {
return new ProtoChunk(pos, UpgradeData.EMPTY, heightAccessor, getCustomBiomeRegistry(), null);
}
net.minecraft.nbt.CompoundTag serializeChunk(ChunkAccess chunkAccess, LevelHeightAccessor heightAccessor) {
return ChunkSerializer.write(chunkAccess, heightAccessor, getCustomBiomeRegistry());
}
} }

View File

@ -1,181 +0,0 @@
package com.volmit.iris.core.nms.v1_20_R3.mca;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import it.unimi.dsi.fastutil.shorts.ShortList;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map.Entry;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.LongArrayTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.ShortTag;
import net.minecraft.nbt.Tag;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.chunk.CarvingMask;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.PalettedContainerRO;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.chunk.ChunkAccess.TicksToSave;
import net.minecraft.world.level.levelgen.BelowZeroRetrogen;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.GenerationStep.Carving;
import net.minecraft.world.level.levelgen.Heightmap.Types;
import net.minecraft.world.level.levelgen.blending.BlendingData;
import org.slf4j.Logger;
import static net.minecraft.world.level.chunk.storage.ChunkSerializer.BLOCK_STATE_CODEC;
public class ChunkSerializer {
private static final Logger LOGGER = LogUtils.getLogger();
private static Method CODEC = null;
static {
for (Method method : net.minecraft.world.level.chunk.storage.ChunkSerializer.class.getDeclaredMethods()) {
if (method.getReturnType().equals(Codec.class) && method.getParameterCount() == 1) {
CODEC = method;
CODEC.setAccessible(true);
break;
}
}
}
public static CompoundTag write(ChunkAccess chunk, LevelHeightAccessor heightAccessor, Registry<Biome> biomeRegistry) {
ChunkPos pos = chunk.getPos();
CompoundTag data = NbtUtils.addCurrentDataVersion(new CompoundTag());
data.putInt("xPos", pos.x);
data.putInt("yPos", ((LevelHeightAccessor) chunk).getMinSection());
data.putInt("zPos", pos.z);
data.putLong("LastUpdate", 0L);
data.putLong("InhabitedTime", chunk.getInhabitedTime());
data.putString("Status", BuiltInRegistries.CHUNK_STATUS.getKey(chunk.getStatus()).toString());
BlendingData blendingdata = chunk.getBlendingData();
if (blendingdata != null) {
DataResult<Tag> dataResult = BlendingData.CODEC.encodeStart(NbtOps.INSTANCE, blendingdata);
dataResult.resultOrPartial(LOGGER::error).ifPresent(base -> data.put("blending_data", base));
}
BelowZeroRetrogen belowzeroretrogen = chunk.getBelowZeroRetrogen();
if (belowzeroretrogen != null) {
DataResult<Tag> dataResult = BelowZeroRetrogen.CODEC.encodeStart(NbtOps.INSTANCE, belowzeroretrogen);
dataResult.resultOrPartial(LOGGER::error).ifPresent(base -> data.put("below_zero_retrogen", base));
}
UpgradeData upgradeData = chunk.getUpgradeData();
if (!upgradeData.isEmpty()) {
data.put("UpgradeData", upgradeData.write());
}
LevelChunkSection[] chunkSections = chunk.getSections();
ListTag sections = new ListTag();
Codec<PalettedContainerRO<Holder<Biome>>> codec;
try {
codec = (Codec<PalettedContainerRO<Holder<Biome>>>) CODEC.invoke(null, biomeRegistry);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
int minLightSection = heightAccessor.getMinSection() - 1;
int maxLightSection = minLightSection + heightAccessor.getSectionsCount() + 2;
for (int y = minLightSection; y < maxLightSection; y++) {
int i = ((LevelHeightAccessor) chunk).getSectionIndexFromSectionY(y);
if (i >= 0 && i < chunkSections.length) {
CompoundTag section = new CompoundTag();
LevelChunkSection chunkSection = chunkSections[i];
DataResult<Tag> dataResult = BLOCK_STATE_CODEC.encodeStart(NbtOps.INSTANCE, chunkSection.getStates());
section.put("block_states", dataResult.getOrThrow(false, LOGGER::error));
dataResult = codec.encodeStart(NbtOps.INSTANCE, chunkSection.getBiomes());
section.put("biomes", dataResult.getOrThrow(false, LOGGER::error));
if (!section.isEmpty()) {
section.putByte("Y", (byte)y);
sections.add(section);
}
}
}
data.put("sections", sections);
if (chunk.isLightCorrect()) {
data.putBoolean("isLightOn", true);
}
ListTag blockEntities = new ListTag();
for (BlockPos blockPos : chunk.getBlockEntitiesPos()) {
CompoundTag blockEntityNbt = chunk.getBlockEntityNbtForSaving(blockPos);
if (blockEntityNbt != null) {
blockEntities.add(blockEntityNbt);
}
}
data.put("block_entities", blockEntities);
if (chunk instanceof ProtoChunk protoChunk) {
ListTag entities = new ListTag();
entities.addAll(protoChunk.getEntities());
data.put("entities", entities);
CompoundTag carvingMasks = new CompoundTag();
for (Carving carving : Carving.values()) {
CarvingMask carvingMask = protoChunk.getCarvingMask(carving);
if (carvingMask != null) {
carvingMasks.putLongArray(carving.toString(), carvingMask.toArray());
}
}
data.put("CarvingMasks", carvingMasks);
}
saveTicks(data, chunk.getTicksForSerialization());
data.put("PostProcessing", packOffsets(chunk.getPostProcessing()));
CompoundTag heightmaps = new CompoundTag();
for (Entry<Types, Heightmap> entry : chunk.getHeightmaps()) {
if (chunk.getStatus().heightmapsAfter().contains(entry.getKey())) {
heightmaps.put(entry.getKey().getSerializationKey(), new LongArrayTag(entry.getValue().getRawData()));
}
}
data.put("Heightmaps", heightmaps);
CompoundTag structures = new CompoundTag();
structures.put("starts", new CompoundTag());
structures.put("References", new CompoundTag());
data.put("structures", structures);
if (!chunk.persistentDataContainer.isEmpty()) {
data.put("ChunkBukkitValues", chunk.persistentDataContainer.toTagCompound());
}
return data;
}
private static void saveTicks(CompoundTag compoundTag, TicksToSave ticksToSave) {
compoundTag.put("block_ticks", ticksToSave.blocks().save(0, block -> BuiltInRegistries.BLOCK.getKey(block).toString()));
compoundTag.put("fluid_ticks", ticksToSave.fluids().save(0, fluid -> BuiltInRegistries.FLUID.getKey(fluid).toString()));
}
public static ListTag packOffsets(ShortList[] offsets) {
ListTag tags = new ListTag();
for (ShortList shorts : offsets) {
ListTag listTag = new ListTag();
if (shorts != null) {
for (Short s : shorts) {
listTag.add(ShortTag.valueOf(s));
}
}
tags.add(listTag);
}
return tags;
}
}

View File

@ -1,159 +0,0 @@
package com.volmit.iris.core.nms.v1_20_R3.mca;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.BiomeBaseInjector;
import com.volmit.iris.engine.data.chunk.TerrainChunk;
import com.volmit.iris.util.data.IrisBlockData;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import org.bukkit.Material;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome;
import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.material.MaterialData;
import org.jetbrains.annotations.NotNull;
public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk {
@Override
public BiomeBaseInjector getBiomeBaseInjector() {
return (x, y, z, biomeBase) -> chunk.setBiome(x, y, z, (Holder<net.minecraft.world.level.biome.Biome>) biomeBase);
}
@Override
public Biome getBiome(int x, int z) {
return Biome.THE_VOID;
}
@Override
public Biome getBiome(int x, int y, int z) {
return Biome.THE_VOID;
}
@Override
public void setBiome(int x, int z, Biome bio) {
setBiome(x, 0, z, bio);
}
@Override
public void setBiome(int x, int y, int z, Biome bio) {
if (y < 0) return;
y += getMinHeight();
if (y > getMaxHeight()) return;
chunk.setBiome(x & 15, y, z & 15, CraftBiome.bukkitToMinecraftHolder(bio));
}
private LevelHeightAccessor height() {
return chunk;
}
@Override
public int getMinHeight() {
return height().getMinBuildHeight();
}
@Override
public int getMaxHeight() {
return height().getMaxBuildHeight();
}
@Override
public void setBlock(int x, int y, int z, BlockData blockData) {
if (y < 0) return;
y += getMinHeight();
if (y > getMaxHeight()) return;
if (blockData == null) {
Iris.error("NULL BD");
}
if (blockData instanceof IrisBlockData data)
blockData = data.getBase();
if (!(blockData instanceof CraftBlockData craftBlockData))
throw new IllegalArgumentException("Expected CraftBlockData, got " + blockData.getClass().getSimpleName() + " instead");
chunk.setBlockState(new BlockPos(x & 15, y, z & 15), craftBlockData.getState(), false);
}
private BlockState getBlockState(int x, int y, int z) {
if (y < 0) {
y = 0;
}
y += getMinHeight();
if (y > getMaxHeight()) {
y = getMaxHeight();
}
return chunk.getBlockState(new BlockPos(x & 15, y, z & 15));
}
@NotNull
@Override
public org.bukkit.block.data.BlockData getBlockData(int x, int y, int z) {
return CraftBlockData.fromData(getBlockState(x, y, z));
}
@Override
public ChunkGenerator.ChunkData getRaw() {
return null;
}
@Override
public void setRaw(ChunkGenerator.ChunkData data) {
}
@Override
@Deprecated
public void inject(ChunkGenerator.BiomeGrid biome) {
}
@Override
public void setBlock(int x, int y, int z, @NotNull Material material) {
}
@Override
@Deprecated
public void setBlock(int x, int y, int z, @NotNull MaterialData material) {
}
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, @NotNull Material material) {
}
@Override
@Deprecated
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, @NotNull MaterialData material) {
}
@Override
public void setRegion(int xMin, int yMin, int zMin, int xMax, int yMax, int zMax, @NotNull BlockData blockData) {
}
@NotNull
@Override
public Material getType(int x, int y, int z) {
return getBlockData(x, y, z).getMaterial();
}
@NotNull
@Override
public MaterialData getTypeAndData(int x, int y, int z) {
return getBlockData(x, y, z).createBlockState().getData();
}
@Override
public byte getData(int x, int y, int z) {
return getTypeAndData(x, y, z).getData();
}
}

View File

@ -1,109 +0,0 @@
package com.volmit.iris.core.nms.v1_20_R3.mca;
import com.google.common.base.Preconditions;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import javax.annotation.Nullable;
import net.minecraft.FileUtil;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtAccounter;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.StreamTagVisitor;
import net.minecraft.util.ExceptionCollector;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.storage.RegionFile;
public final class RegionFileStorage implements AutoCloseable {
public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>();
private final Path folder;
private final boolean sync;
public RegionFileStorage(Path folder, boolean sync) {
this.folder = folder;
this.sync = sync;
}
public RegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException {
long id = ChunkPos.asLong(chunkPos.getRegionX(), chunkPos.getRegionZ());
RegionFile regionFile = this.regionCache.getAndMoveToFirst(id);
if (regionFile != null) {
return regionFile;
} else {
if (this.regionCache.size() >= 256) {
this.regionCache.removeLast().close();
}
FileUtil.createDirectoriesSafe(this.folder);
Path path = folder.resolve("r." + chunkPos.getRegionX() + "." + chunkPos.getRegionZ() + ".mca");
if (existingOnly && !Files.exists(path)) {
return null;
} else {
regionFile = new RegionFile(path, this.folder, this.sync);
this.regionCache.putAndMoveToFirst(id, regionFile);
return regionFile;
}
}
}
@Nullable
public CompoundTag read(ChunkPos chunkPos) throws IOException {
RegionFile regionFile = this.getRegionFile(chunkPos, true);
if (regionFile != null) {
try (DataInputStream datainputstream = regionFile.getChunkDataInputStream(chunkPos)) {
if (datainputstream != null) {
return NbtIo.read(datainputstream);
}
}
}
return null;
}
public void scanChunk(ChunkPos chunkPos, StreamTagVisitor visitor) throws IOException {
RegionFile regionFile = this.getRegionFile(chunkPos, true);
if (regionFile != null) {
try (DataInputStream din = regionFile.getChunkDataInputStream(chunkPos)) {
if (din != null) {
NbtIo.parse(din, visitor, NbtAccounter.unlimitedHeap());
}
}
}
}
public void write(ChunkPos chunkPos, @Nullable CompoundTag compound) throws IOException {
RegionFile regionFile = this.getRegionFile(chunkPos, false);
Preconditions.checkArgument(regionFile != null, "Failed to find region file for chunk %s", chunkPos);
if (compound == null) {
regionFile.clear(chunkPos);
} else {
try (DataOutputStream dos = regionFile.getChunkDataOutputStream(chunkPos)) {
NbtIo.write(compound, dos);
}
}
}
@Override
public void close() throws IOException {
ExceptionCollector<IOException> collector = new ExceptionCollector<>();
for (RegionFile regionFile : this.regionCache.values()) {
try {
regionFile.close();
} catch (IOException e) {
collector.add(e);
}
}
collector.throwIfPresent();
}
public void flush() throws IOException {
for (RegionFile regionfile : this.regionCache.values()) {
regionfile.flush();
}
}
}

View File

@ -2,7 +2,6 @@ package com.volmit.iris.core.nms.v1_20_R4;
import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapCodec;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
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;
import com.volmit.iris.engine.object.IrisBiome; import com.volmit.iris.engine.object.IrisBiome;
@ -125,16 +124,8 @@ public class CustomBiomeSource extends BiomeSource {
for (IrisBiome i : engine.getAllBiomes()) { for (IrisBiome i : engine.getAllBiomes()) {
if (i.isCustom()) { if (i.isCustom()) {
for (IrisBiomeCustom j : i.getCustomDerivitives()) { for (IrisBiomeCustom j : i.getCustomDerivitives()) {
ResourceLocation location = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()); ResourceLocation resourceLocation = new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId());
Biome biome = customRegistry.get(location); Biome biome = customRegistry.get(resourceLocation);
if (biome == null) {
INMS.get().registerBiome(location.getNamespace(), j, false);
biome = customRegistry.get(location);
if (biome == null) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());
continue;
}
}
Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome); Optional<ResourceKey<Biome>> optionalBiomeKey = customRegistry.getResourceKey(biome);
if (optionalBiomeKey.isEmpty()) { if (optionalBiomeKey.isEmpty()) {
Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName()); Iris.error("Cannot find biome for IrisBiomeCustom " + j.getId() + " from engine " + engine.getName());

View File

@ -4,48 +4,18 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.File;
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.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Vector; import java.util.Vector;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
import com.volmit.iris.core.nms.datapack.DataVersion; import com.volmit.iris.core.nms.datapack.DataVersion;
import com.volmit.iris.engine.object.IrisBiomeCustom;
import com.volmit.iris.engine.object.IrisDimension;
import com.volmit.iris.util.format.C;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.matcher.ElementMatchers;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.RegistrationInfo;
import net.minecraft.core.component.DataComponents; import net.minecraft.core.component.DataComponents;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.RandomSequences;
import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.level.Level;
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 net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
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;
@ -59,7 +29,6 @@ import org.bukkit.craftbukkit.v1_20_R4.util.CraftNamespacedKey;
import org.bukkit.entity.Dolphin; import org.bukkit.entity.Dolphin;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -580,203 +549,4 @@ public class NMSBinding implements INMSBinding {
public DataVersion getDataVersion() { public DataVersion getDataVersion() {
return DataVersion.V1205; return DataVersion.V1205;
} }
@Override
public boolean registerDimension(String name, IrisDimension dimension) {
var registry = registry(Registries.DIMENSION_TYPE);
var baseLocation = switch (dimension.getEnvironment()) {
case NORMAL -> new ResourceLocation("minecraft", "overworld");
case NETHER -> new ResourceLocation("minecraft", "the_nether");
case THE_END -> new ResourceLocation("minecraft", "the_end");
case CUSTOM -> throw new IllegalArgumentException("Cannot register custom dimension");
};
var base = registry.getHolder(ResourceKey.create(Registries.DIMENSION_TYPE, baseLocation)).orElse(null);
if (base == null) return false;
var json = encode(DimensionType.CODEC, base).orElse(null);
if (json == null) return false;
var object = json.getAsJsonObject();
var height = dimension.getDimensionHeight();
object.addProperty("min_y", height.getMin());
object.addProperty("height", height.getMax() - height.getMin());
object.addProperty("logical_height", dimension.getLogicalHeight());
var value = decode(DimensionType.CODEC, object.toString()).map(Holder::value).orElse(null);
if (value == null) return false;
return register(Registries.DIMENSION_TYPE, new ResourceLocation("iris", name), value, true);
}
@Override
public boolean registerBiome(String dimensionId, IrisBiomeCustom biome, boolean replace) {
var biomeBase = decode(net.minecraft.world.level.biome.Biome.CODEC, biome.generateJson()).map(Holder::value).orElse(null);
if (biomeBase == null) return false;
return register(Registries.BIOME, new ResourceLocation(dimensionId, biome.getId()), biomeBase, replace);
}
private <T> Optional<T> decode(Codec<T> codec, String json) {
return codec.decode(JsonOps.INSTANCE, GsonHelper.parse(json)).result().map(Pair::getFirst);
}
private <T> Optional<JsonElement> encode(Codec<T> codec, T value) {
return codec.encode(value, JsonOps.INSTANCE, new JsonObject()).result();
}
private <T> boolean register(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value, boolean replace) {
Preconditions.checkArgument(registryKey != null, "The registry cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
if (registry.containsKey(key)) {
if (!replace) return false;
return replace(registryKey, location, value);
}
Field field = getField(MappedRegistry.class, boolean.class);
field.setAccessible(true);
boolean frozen = field.getBoolean(registry);
field.setBoolean(registry, false);
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
try {
var holder = registry.register(key, value, RegistrationInfo.BUILT_IN);
if (frozen) valueField.set(holder, value);
return true;
} finally {
field.setBoolean(registry, frozen);
}
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
@SuppressWarnings("unchecked")
private <T> boolean replace(ResourceKey<Registry<T>> registryKey, ResourceLocation location, T value) {
Preconditions.checkArgument(registryKey != null, "The registryKey cannot be null!");
Preconditions.checkArgument(location != null, "The location cannot be null!");
Preconditions.checkArgument(value != null, "The value cannot be null!");
var registry = registry(registryKey);
var key = ResourceKey.create(registryKey, location);
try {
var holder = registry.getHolder(key).orElse(null);
if (holder == null) return false;
var oldValue = holder.value();
Field valueField = getField(Holder.Reference.class, "T");
valueField.setAccessible(true);
Field toIdField = getField(MappedRegistry.class, buildType(Reference2IntMap.class, "T"));
toIdField.setAccessible(true);
Field byValueField = getField(MappedRegistry.class, buildType(Map.class, "T", buildType(Holder.Reference.class, "T")));
byValueField.setAccessible(true);
var toId = (Reference2IntMap<T>) toIdField.get(registry);
var byValue = (Map<T, Holder.Reference<T>>) byValueField.get(registry);
valueField.set(holder, value);
toId.put(value, toId.removeInt(oldValue));
byValue.put(value, byValue.remove(oldValue));
return true;
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
private <T> MappedRegistry<T> registry(ResourceKey<Registry<T>> registryKey) {
var rawRegistry = registry().registry(registryKey).orElse(null);
if (!(rawRegistry instanceof MappedRegistry<T> registry))
throw new IllegalStateException("The Registry is not a mapped Registry!");
return registry;
}
private static String buildType(Class<?> clazz, String... parameterTypes) {
if (parameterTypes.length == 0) return clazz.getName();
var builder = new StringBuilder(clazz.getName())
.append("<");
for (int i = 0; i < parameterTypes.length; i++) {
builder.append(parameterTypes[i]).append(parameterTypes.length - 1 == i ? ">" : ", ");
}
return builder.toString();
}
private static Field getField(Class<?> clazz, String type) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
if (f.getGenericType().getTypeName().equals(type))
return f;
}
throw new NoSuchFieldException(type);
} catch (NoSuchFieldException e) {
Class<?> superClass = clazz.getSuperclass();
if (superClass == null) throw e;
return getField(superClass, type);
}
}
public void injectBukkit() {
try {
Iris.info("Injecting Bukkit");
new ByteBuddy()
.redefine(CraftServer.class)
.visit(Advice.to(CraftServerAdvice.class).on(ElementMatchers.isMethod().and(ElementMatchers.takesArguments(WorldCreator.class))))
.make()
.load(CraftServer.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
new ByteBuddy()
.redefine(ServerLevel.class)
.visit(Advice.to(ServerLevelAdvice.class).on(ElementMatchers.isConstructor().and(ElementMatchers.takesArguments(MinecraftServer.class, Executor.class, LevelStorageSource.LevelStorageAccess.class,
PrimaryLevelData.class, ResourceKey.class, LevelStem.class, ChunkProgressListener.class, boolean.class, long.class,
List.class, boolean.class, RandomSequences.class, World.Environment.class, ChunkGenerator.class, BiomeProvider.class))))
.make()
.load(ServerLevel.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());
Iris.info("Injected Bukkit Successfully!");
} catch (Exception e) {
Iris.info(C.RED + "Failed to Inject Bukkit!");
e.printStackTrace();
Iris.reportError(e);
}
}
private static class ServerLevelAdvice {
@Advice.OnMethodEnter
static void enter(@Advice.Argument(0) MinecraftServer server, @Advice.Argument(2) LevelStorageSource.LevelStorageAccess access, @Advice.Argument(4) ResourceKey<Level> key, @Advice.Argument(value = 5, readOnly = false) LevelStem levelStem) {
File iris = new File(access.levelDirectory.path().toFile(), "iris");
if (!iris.exists() && !key.location().getPath().startsWith("iris/")) return;
ResourceKey<DimensionType> typeKey = ResourceKey.create(Registries.DIMENSION_TYPE, new ResourceLocation("iris", key.location().getPath()));
RegistryAccess registryAccess = server.registryAccess();
Registry<DimensionType> registry = registryAccess.registry(Registries.DIMENSION_TYPE).orElse(null);
if (registry == null) throw new IllegalStateException("Unable to find registry for dimension type " + typeKey);
Holder<DimensionType> holder = registry.getHolder(typeKey).orElse(null);
if (holder == null) throw new IllegalStateException("Unable to find dimension type " + typeKey);
levelStem = new LevelStem(holder, levelStem.generator());
}
}
private static class CraftServerAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
static boolean enter(@Advice.This CraftServer self, @Advice.Argument(0) WorldCreator creator) {
File isIrisWorld = new File(self.getWorldContainer(), creator.name() + "/iris");
boolean isFromIris = false;
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement stack : stackTrace) {
if (stack.getClassName().contains("Iris")) {
isFromIris = true;
break;
}
}
if (isIrisWorld.exists() && !isFromIris) {
var logger = Logger.getLogger("Iris");
logger.warning("detected another Plugin trying to load " + creator.name() + ". This is not supported and will be ignored.");
if (System.getProperty("iris.debug", "false").equals("true")) {
new RuntimeException().printStackTrace();
}
return true;
}
return false;
}
@Advice.OnMethodExit
static void exit(@Advice.Enter boolean bool, @Advice.Return(readOnly = false) World returned) {
if (bool) {
returned = null;
}
}
}
} }

View File

@ -27,7 +27,7 @@ plugins {
} }
rootProject.name = 'Iris' rootProject.name = 'Iris'
//include 'app', 'com.volmit.gui'
include(':core') include(':core')
include( include(
':nms:v1_20_R4', ':nms:v1_20_R4',