mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-04 00:46:08 +00:00
Revert "Merge branch 'mca' into jigsaw_dist"
This reverts commit 0288d35c85ce25d2d7469cc69910447f4504eb08, reversing changes made to 8b3577dd0b014949fa0f702e5099d7d56a11bcb3.
This commit is contained in:
parent
0288d35c85
commit
55017b9ac2
@ -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'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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++) {
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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?");
|
||||||
|
@ -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?");
|
||||||
|
@ -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)
|
||||||
|
@ -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) {
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
|
||||||
}
|
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
||||||
|
@ -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();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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:");
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.volmit.iris.core.safeguard;
|
||||||
|
|
||||||
|
public class PerformanceSFG {
|
||||||
|
public static void calculatePerformance() {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -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) {
|
||||||
|
@ -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())
|
||||||
|
@ -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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -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);
|
||||||
|
@ -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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -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;
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -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]);
|
||||||
}
|
}
|
||||||
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -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());
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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());
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user