mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-12-19 15:09:18 +00:00
Merge branch 'refs/heads/dev' into feat/folia
# Conflicts: # core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java # core/src/main/java/com/volmit/iris/core/tools/IrisCreator.java # core/src/main/java/com/volmit/iris/engine/framework/Engine.java
This commit is contained in:
@@ -87,6 +87,7 @@ dependencies {
|
|||||||
slim(libs.commons.io)
|
slim(libs.commons.io)
|
||||||
slim(libs.commons.lang)
|
slim(libs.commons.lang)
|
||||||
slim(libs.commons.lang3)
|
slim(libs.commons.lang3)
|
||||||
|
slim(libs.commons.math3)
|
||||||
slim(libs.oshi)
|
slim(libs.oshi)
|
||||||
slim(libs.lz4)
|
slim(libs.lz4)
|
||||||
slim(libs.fastutil)
|
slim(libs.fastutil)
|
||||||
@@ -165,15 +166,6 @@ tasks {
|
|||||||
"version" to rootProject.version,
|
"version" to rootProject.version,
|
||||||
"apiVersion" to apiVersion,
|
"apiVersion" to apiVersion,
|
||||||
"main" to main,
|
"main" to main,
|
||||||
"environment" to if (project.hasProperty("release")) "production" else "development",
|
|
||||||
"commit" to provider {
|
|
||||||
val res = runCatching { project.extensions.getByType<Grgit>().head().id }
|
|
||||||
res.getOrDefault("")
|
|
||||||
.takeIf { it.length == 40 } ?: {
|
|
||||||
logger.error("Git commit hash not found", res.exceptionOrNull())
|
|
||||||
"unknown"
|
|
||||||
}()
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
filesMatching("**/plugin.yml") {
|
filesMatching("**/plugin.yml") {
|
||||||
expand(inputs.properties)
|
expand(inputs.properties)
|
||||||
@@ -188,9 +180,35 @@ tasks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
val templateSource = file("src/main/templates")
|
||||||
* Gradle is weird sometimes, we need to delete the plugin yml from the build folder to actually filter properly.
|
val templateDest = layout.buildDirectory.dir("generated/sources/templates")
|
||||||
*/
|
val generateTemplates = tasks.register<Copy>("generateTemplates") {
|
||||||
afterEvaluate {
|
inputs.properties(
|
||||||
layout.buildDirectory.file("resources/main/plugin.yml").get().asFile.delete()
|
"environment" to if (project.hasProperty("release")) "production" else "development",
|
||||||
|
"commit" to provider {
|
||||||
|
val res = runCatching { project.extensions.getByType<Grgit>().head().id }
|
||||||
|
res.getOrDefault("")
|
||||||
|
.takeIf { it.length == 40 } ?: {
|
||||||
|
logger.error("Git commit hash not found", res.exceptionOrNull())
|
||||||
|
"unknown"
|
||||||
|
}()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
from(templateSource)
|
||||||
|
into(templateDest)
|
||||||
|
rename { "com/volmit/iris/$it" }
|
||||||
|
expand(inputs.properties)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.generateSentryBundleIdJava {
|
||||||
|
dependsOn(generateTemplates)
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.tasks.named("prepareKotlinBuildScriptModel") {
|
||||||
|
dependsOn(generateTemplates)
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets.main {
|
||||||
|
java.srcDir(generateTemplates.map { it.outputs })
|
||||||
}
|
}
|
||||||
@@ -715,7 +715,11 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
Iris.debug("Generator Config: " + w.toString());
|
Iris.debug("Generator Config: " + w.toString());
|
||||||
|
|
||||||
File ff = new File(w.worldFolder(), "iris/pack");
|
File ff = new File(w.worldFolder(), "iris/pack");
|
||||||
if (!ff.exists() || ff.listFiles().length == 0) {
|
var files = ff.listFiles();
|
||||||
|
if (files == null || files.length == 0)
|
||||||
|
IO.delete(ff);
|
||||||
|
|
||||||
|
if (!ff.exists()) {
|
||||||
ff.mkdirs();
|
ff.mkdirs();
|
||||||
service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w.worldFolder());
|
service(StudioSVC.class).installIntoWorld(getSender(), dim.getLoadKey(), w.worldFolder());
|
||||||
}
|
}
|
||||||
@@ -725,13 +729,13 @@ public class Iris extends VolmitPlugin implements Listener {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static IrisDimension loadDimension(@NonNull String worldName, @NonNull String id) {
|
public static IrisDimension loadDimension(@NonNull String worldName, @NonNull String id) {
|
||||||
var data = IrisData.get(new File(Bukkit.getWorldContainer(), String.join(File.separator, worldName, "iris", "pack")));
|
File pack = new File(Bukkit.getWorldContainer(), String.join(File.separator, worldName, "iris", "pack"));
|
||||||
var dimension = data.getDimensionLoader().load(id);
|
var dimension = pack.isDirectory() ? IrisData.get(pack).getDimensionLoader().load(id) : null;
|
||||||
if (dimension == null) dimension = IrisData.loadAnyDimension(id);
|
if (dimension == null) dimension = IrisData.loadAnyDimension(id, null);
|
||||||
if (dimension == null) {
|
if (dimension == null) {
|
||||||
Iris.warn("Unable to find dimension type " + id + " Looking for online packs...");
|
Iris.warn("Unable to find dimension type " + id + " Looking for online packs...");
|
||||||
Iris.service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, false);
|
Iris.service(StudioSVC.class).downloadSearch(new VolmitSender(Bukkit.getConsoleSender()), id, false);
|
||||||
dimension = IrisData.loadAnyDimension(id);
|
dimension = IrisData.loadAnyDimension(id, null);
|
||||||
|
|
||||||
if (dimension != null) {
|
if (dimension != null) {
|
||||||
Iris.info("Resolved missing dimension, proceeding.");
|
Iris.info("Resolved missing dimension, proceeding.");
|
||||||
|
|||||||
@@ -244,6 +244,7 @@ public class IrisSettings {
|
|||||||
public boolean preventLeafDecay = true;
|
public boolean preventLeafDecay = true;
|
||||||
public boolean useMulticore = false;
|
public boolean useMulticore = false;
|
||||||
public boolean offsetNoiseTypes = false;
|
public boolean offsetNoiseTypes = false;
|
||||||
|
public boolean earlyCustomBlocks = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ public class IrisWorlds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public KMap<String, String> getWorlds() {
|
public KMap<String, String> getWorlds() {
|
||||||
|
clean();
|
||||||
return readBukkitWorlds().put(worlds);
|
return readBukkitWorlds().put(worlds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +77,7 @@ public class IrisWorlds {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Stream<IrisDimension> getDimensions() {
|
public Stream<IrisDimension> getDimensions() {
|
||||||
return readBukkitWorlds()
|
return getWorlds()
|
||||||
.put(worlds)
|
|
||||||
.entrySet()
|
.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
.map(entry -> Iris.loadDimension(entry.getKey(), entry.getValue()))
|
.map(entry -> Iris.loadDimension(entry.getKey(), entry.getValue()))
|
||||||
|
|||||||
@@ -103,14 +103,14 @@ public class ServerConfigurator {
|
|||||||
return worlds;
|
return worlds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void installDataPacks(boolean fullInstall) {
|
public static boolean installDataPacks(boolean fullInstall) {
|
||||||
installDataPacks(DataVersion.getDefault(), fullInstall);
|
return installDataPacks(DataVersion.getDefault(), fullInstall);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void installDataPacks(IDataFixer fixer, boolean fullInstall) {
|
public static boolean installDataPacks(IDataFixer fixer, boolean fullInstall) {
|
||||||
if (fixer == null) {
|
if (fixer == null) {
|
||||||
Iris.error("Unable to install datapacks, fixer is null!");
|
Iris.error("Unable to install datapacks, fixer is null!");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
Iris.info("Checking Data Packs...");
|
Iris.info("Checking Data Packs...");
|
||||||
DimensionHeight height = new DimensionHeight(fixer);
|
DimensionHeight height = new DimensionHeight(fixer);
|
||||||
@@ -129,11 +129,10 @@ public class ServerConfigurator {
|
|||||||
IrisDimension.writeShared(folders, height);
|
IrisDimension.writeShared(folders, height);
|
||||||
Iris.info("Data Packs Setup!");
|
Iris.info("Data Packs Setup!");
|
||||||
|
|
||||||
if (fullInstall)
|
return fullInstall && verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall());
|
||||||
verifyDataPacksPost(IrisSettings.get().getAutoConfiguration().isAutoRestartOnCustomBiomeInstall());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void verifyDataPacksPost(boolean allowRestarting) {
|
private static boolean verifyDataPacksPost(boolean allowRestarting) {
|
||||||
try (Stream<IrisData> stream = allPacks()) {
|
try (Stream<IrisData> stream = allPacks()) {
|
||||||
boolean bad = stream
|
boolean bad = stream
|
||||||
.map(data -> {
|
.map(data -> {
|
||||||
@@ -148,7 +147,7 @@ public class ServerConfigurator {
|
|||||||
})
|
})
|
||||||
.toList()
|
.toList()
|
||||||
.contains(true);
|
.contains(true);
|
||||||
if (!bad) return;
|
if (!bad) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -172,6 +171,7 @@ public class ServerConfigurator {
|
|||||||
|
|
||||||
J.sleep(3000);
|
J.sleep(3000);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void restart() {
|
public static void restart() {
|
||||||
|
|||||||
@@ -18,19 +18,29 @@
|
|||||||
|
|
||||||
package com.volmit.iris.core.commands;
|
package com.volmit.iris.core.commands;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.ServerConfigurator;
|
import com.volmit.iris.core.ServerConfigurator;
|
||||||
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
|
import com.volmit.iris.core.nms.INMS;
|
||||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
import com.volmit.iris.core.service.IrisEngineSVC;
|
import com.volmit.iris.core.service.IrisEngineSVC;
|
||||||
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.engine.object.IrisDimension;
|
import com.volmit.iris.engine.object.IrisDimension;
|
||||||
|
import com.volmit.iris.engine.object.annotations.Snippet;
|
||||||
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.context.IrisContext;
|
import com.volmit.iris.util.context.IrisContext;
|
||||||
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
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.NullableDimensionHandler;
|
||||||
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.io.CountingDataInputStream;
|
import com.volmit.iris.util.io.CountingDataInputStream;
|
||||||
@@ -42,6 +52,7 @@ import com.volmit.iris.util.nbt.mca.MCAFile;
|
|||||||
import com.volmit.iris.util.nbt.mca.MCAUtil;
|
import com.volmit.iris.util.nbt.mca.MCAUtil;
|
||||||
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 lombok.SneakyThrows;
|
||||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||||
import net.jpountz.lz4.LZ4FrameInputStream;
|
import net.jpountz.lz4.LZ4FrameInputStream;
|
||||||
@@ -59,6 +70,7 @@ import java.util.*;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
import java.util.zip.GZIPOutputStream;
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
@@ -143,6 +155,130 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@Decree(description = "Generate Iris structures for all loaded datapack structures")
|
||||||
|
public void generateStructures(
|
||||||
|
@Param(description = "The pack to add the generated structures to", aliases = "pack", defaultValue = "null", customHandler = NullableDimensionHandler.class)
|
||||||
|
IrisDimension dimension,
|
||||||
|
@Param(description = "Ignore existing structures", defaultValue = "false")
|
||||||
|
boolean force
|
||||||
|
) {
|
||||||
|
var map = INMS.get().collectStructures();
|
||||||
|
if (map.isEmpty()) {
|
||||||
|
sender().sendMessage(C.IRIS + "No structures found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sender().sendMessage(C.IRIS + "Found " + map.size() + " structures");
|
||||||
|
|
||||||
|
final File dataDir;
|
||||||
|
final IrisData data;
|
||||||
|
final Set<String> existingStructures;
|
||||||
|
final Map<String, Set<String>> snippets;
|
||||||
|
final File dimensionFile;
|
||||||
|
final File structuresFolder;
|
||||||
|
final File snippetsFolder;
|
||||||
|
|
||||||
|
var dimensionObj = new JsonObject();
|
||||||
|
|
||||||
|
if (dimension == null) {
|
||||||
|
dataDir = Iris.instance.getDataFolder("structures");
|
||||||
|
IO.delete(dataDir);
|
||||||
|
data = IrisData.get(dataDir);
|
||||||
|
existingStructures = Set.of();
|
||||||
|
snippets = Map.of();
|
||||||
|
dimensionFile = new File(dataDir, "structures.json");
|
||||||
|
} else {
|
||||||
|
data = dimension.getLoader();
|
||||||
|
dataDir = data.getDataFolder();
|
||||||
|
existingStructures = new KSet<>(data.getJigsawStructureLoader().getPossibleKeys());
|
||||||
|
|
||||||
|
dimensionObj = data.getGson().fromJson(IO.readAll(dimension.getLoadFile()), JsonObject.class);
|
||||||
|
snippets = Optional.ofNullable(dimensionObj.getAsJsonArray("jigsawStructures"))
|
||||||
|
.map(array -> array.asList()
|
||||||
|
.stream()
|
||||||
|
.filter(JsonElement::isJsonPrimitive)
|
||||||
|
.collect(Collectors.toMap(element -> data.getGson()
|
||||||
|
.fromJson(element, IrisJigsawStructurePlacement.class)
|
||||||
|
.getStructure(),
|
||||||
|
element -> Set.of(element.getAsString()),
|
||||||
|
KSet::merge)))
|
||||||
|
.orElse(Map.of());
|
||||||
|
|
||||||
|
dimensionFile = dimension.getLoadFile();
|
||||||
|
}
|
||||||
|
structuresFolder = new File(dataDir, "jigsaw-structures");
|
||||||
|
snippetsFolder = new File(dataDir, "snippet" + "/" + IrisJigsawStructurePlacement.class.getAnnotation(Snippet.class).value());
|
||||||
|
|
||||||
|
var gson = data.getGson();
|
||||||
|
var jigsawStructures = Optional.ofNullable(dimensionObj.getAsJsonArray("jigsawStructures"))
|
||||||
|
.orElse(new JsonArray(map.size()));
|
||||||
|
|
||||||
|
map.forEach((key, placement) -> {
|
||||||
|
String loadKey = "datapack/" + key.namespace() + "/" + key.key();
|
||||||
|
if (existingStructures.contains(loadKey) && !force)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var structures = placement.structures();
|
||||||
|
var obj = placement.toJson(loadKey);
|
||||||
|
if (obj == null || structures.isEmpty()) {
|
||||||
|
sender().sendMessage(C.RED + "Failed to generate hook for " + key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File snippetFile = new File(snippetsFolder, loadKey + ".json");
|
||||||
|
try {
|
||||||
|
IO.writeAll(snippetFile, gson.toJson(obj));
|
||||||
|
} catch (IOException e) {
|
||||||
|
sender().sendMessage(C.RED + "Failed to generate snippet for " + key);
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> loadKeys = snippets.getOrDefault(loadKey, Set.of(loadKey));
|
||||||
|
jigsawStructures.asList().removeIf(e -> loadKeys.contains((e.isJsonObject() ? e.getAsJsonObject().get("structure") : e).getAsString()));
|
||||||
|
jigsawStructures.add("snippet/" + loadKey);
|
||||||
|
|
||||||
|
String structureKey;
|
||||||
|
if (structures.size() > 1) {
|
||||||
|
KList<String> common = new KList<>();
|
||||||
|
for (int i = 0; i < structures.size(); i++) {
|
||||||
|
var tags = structures.get(i).tags();
|
||||||
|
if (i == 0) common.addAll(tags);
|
||||||
|
else common.removeIf(tag -> !tags.contains(tag));
|
||||||
|
}
|
||||||
|
structureKey = common.isNotEmpty() ? "#" + common.getFirst() : structures.getFirst().key();
|
||||||
|
} else structureKey = structures.getFirst().key();
|
||||||
|
|
||||||
|
JsonArray array = new JsonArray();
|
||||||
|
if (structures.size() > 1) {
|
||||||
|
structures.stream()
|
||||||
|
.flatMap(structure -> {
|
||||||
|
String[] arr = new String[structure.weight()];
|
||||||
|
Arrays.fill(arr, structure.key());
|
||||||
|
return Arrays.stream(arr);
|
||||||
|
})
|
||||||
|
.forEach(array::add);
|
||||||
|
} else array.add(structureKey);
|
||||||
|
|
||||||
|
obj = new JsonObject();
|
||||||
|
obj.addProperty("structureKey", structureKey);
|
||||||
|
obj.add("datapackStructures", array);
|
||||||
|
|
||||||
|
File out = new File(structuresFolder, loadKey + ".json");
|
||||||
|
out.getParentFile().mkdirs();
|
||||||
|
try {
|
||||||
|
IO.writeAll(out, gson.toJson(obj));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dimensionObj.add("jigsawStructures", jigsawStructures);
|
||||||
|
IO.writeAll(dimensionFile, gson.toJson(dimensionObj));
|
||||||
|
|
||||||
|
data.hotloaded();
|
||||||
|
}
|
||||||
|
|
||||||
@Decree(description = "Test")
|
@Decree(description = "Test")
|
||||||
public void packBenchmark(
|
public void packBenchmark(
|
||||||
@Param(description = "The pack to bench", aliases = {"pack"}, defaultValue = "overworld")
|
@Param(description = "The pack to bench", aliases = {"pack"}, defaultValue = "overworld")
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class CommandJigsaw implements DecreeExecutor {
|
|||||||
IrisJigsawPiece piece
|
IrisJigsawPiece piece
|
||||||
) {
|
) {
|
||||||
File dest = piece.getLoadFile();
|
File dest = piece.getLoadFile();
|
||||||
new JigsawEditor(player(), piece, IrisData.loadAnyObject(piece.getObject()), dest);
|
new JigsawEditor(player(), piece, IrisData.loadAnyObject(piece.getObject(), data()), dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Decree(description = "Place a jigsaw structure")
|
@Decree(description = "Place a jigsaw structure")
|
||||||
@@ -78,7 +78,7 @@ public class CommandJigsaw implements DecreeExecutor {
|
|||||||
@Param(description = "The object to use for this piece", customHandler = ObjectHandler.class)
|
@Param(description = "The object to use for this piece", customHandler = ObjectHandler.class)
|
||||||
String object
|
String object
|
||||||
) {
|
) {
|
||||||
IrisObject o = IrisData.loadAnyObject(object);
|
IrisObject o = IrisData.loadAnyObject(object, data());
|
||||||
|
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
sender().sendMessage(C.RED + "Failed to find existing object");
|
sender().sendMessage(C.RED + "Failed to find existing object");
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ public class CommandObject implements DecreeExecutor {
|
|||||||
@Param(description = "The object to analyze", customHandler = ObjectHandler.class)
|
@Param(description = "The object to analyze", customHandler = ObjectHandler.class)
|
||||||
String object
|
String object
|
||||||
) {
|
) {
|
||||||
IrisObject o = IrisData.loadAnyObject(object);
|
IrisObject o = IrisData.loadAnyObject(object, data());
|
||||||
sender().sendMessage("Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD() + "");
|
sender().sendMessage("Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD() + "");
|
||||||
sender().sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(o.getBlocks().size()));
|
sender().sendMessage("Blocks Used: " + NumberFormat.getIntegerInstance().format(o.getBlocks().size()));
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ public class CommandObject implements DecreeExecutor {
|
|||||||
|
|
||||||
@Decree(description = "Shrink an object to its minimum size")
|
@Decree(description = "Shrink an object to its minimum size")
|
||||||
public void shrink(@Param(description = "The object to shrink", customHandler = ObjectHandler.class) String object) {
|
public void shrink(@Param(description = "The object to shrink", customHandler = ObjectHandler.class) String object) {
|
||||||
IrisObject o = IrisData.loadAnyObject(object);
|
IrisObject o = IrisData.loadAnyObject(object, data());
|
||||||
sender().sendMessage("Current Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD());
|
sender().sendMessage("Current Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD());
|
||||||
o.shrinkwrap();
|
o.shrinkwrap();
|
||||||
sender().sendMessage("New Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD());
|
sender().sendMessage("New Object Size: " + o.getW() + " * " + o.getH() + " * " + o.getD());
|
||||||
@@ -325,7 +325,7 @@ public class CommandObject implements DecreeExecutor {
|
|||||||
// @Param(description = "The scale interpolator to use", defaultValue = "none")
|
// @Param(description = "The scale interpolator to use", defaultValue = "none")
|
||||||
// IrisObjectPlacementScaleInterpolator interpolator
|
// IrisObjectPlacementScaleInterpolator interpolator
|
||||||
) {
|
) {
|
||||||
IrisObject o = IrisData.loadAnyObject(object);
|
IrisObject o = IrisData.loadAnyObject(object, data());
|
||||||
double maxScale = Double.max(10 - o.getBlocks().size() / 10000d, 1);
|
double maxScale = Double.max(10 - o.getBlocks().size() / 10000d, 1);
|
||||||
if (scale > maxScale) {
|
if (scale > maxScale) {
|
||||||
sender().sendMessage(C.YELLOW + "Indicated scale exceeds maximum. Downscaled to maximum: " + maxScale);
|
sender().sendMessage(C.YELLOW + "Indicated scale exceeds maximum. Downscaled to maximum: " + maxScale);
|
||||||
|
|||||||
@@ -171,9 +171,9 @@ public class CommandStudio implements DecreeExecutor {
|
|||||||
var loc = player().getLocation().clone();
|
var loc = player().getLocation().clone();
|
||||||
|
|
||||||
J.a(() -> {
|
J.a(() -> {
|
||||||
DecreeContext.touch(sender);
|
|
||||||
PlatformChunkGenerator plat = IrisToolbelt.access(world);
|
PlatformChunkGenerator plat = IrisToolbelt.access(world);
|
||||||
Engine engine = plat.getEngine();
|
Engine engine = plat.getEngine();
|
||||||
|
DecreeContext.touch(sender);
|
||||||
try (SyncExecutor executor = new SyncExecutor(20)) {
|
try (SyncExecutor executor = new SyncExecutor(20)) {
|
||||||
int x = loc.getBlockX() >> 4;
|
int x = loc.getBlockX() >> 4;
|
||||||
int z = loc.getBlockZ() >> 4;
|
int z = loc.getBlockZ() >> 4;
|
||||||
@@ -247,6 +247,8 @@ public class CommandStudio implements DecreeExecutor {
|
|||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
sender().sendMessage("Error while regenerating chunks");
|
sender().sendMessage("Error while regenerating chunks");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
DecreeContext.remove();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,10 @@ public class ItemAdderDataProvider extends ExternalDataProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
|
public void processUpdate(@NotNull Engine engine, @NotNull Block block, @NotNull Identifier blockId) {
|
||||||
CustomBlock.place(blockId.toString(), block.getLocation());
|
CustomBlock custom;
|
||||||
|
if ((custom = CustomBlock.place(blockId.toString(), block.getLocation())) == null)
|
||||||
|
return;
|
||||||
|
block.setBlockData(custom.getBaseBlockData(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,10 +5,14 @@ import com.volmit.iris.core.link.Identifier;
|
|||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import io.lumine.mythic.api.adapters.AbstractLocation;
|
import io.lumine.mythic.api.adapters.AbstractLocation;
|
||||||
import io.lumine.mythic.api.config.MythicLineConfig;
|
import io.lumine.mythic.api.config.MythicLineConfig;
|
||||||
|
import io.lumine.mythic.api.mobs.entities.SpawnReason;
|
||||||
import io.lumine.mythic.api.skills.conditions.ILocationCondition;
|
import io.lumine.mythic.api.skills.conditions.ILocationCondition;
|
||||||
|
import io.lumine.mythic.bukkit.BukkitAdapter;
|
||||||
import io.lumine.mythic.bukkit.MythicBukkit;
|
import io.lumine.mythic.bukkit.MythicBukkit;
|
||||||
import io.lumine.mythic.bukkit.adapters.BukkitWorld;
|
import io.lumine.mythic.bukkit.adapters.BukkitWorld;
|
||||||
import io.lumine.mythic.bukkit.events.MythicConditionLoadEvent;
|
import io.lumine.mythic.bukkit.events.MythicConditionLoadEvent;
|
||||||
|
import io.lumine.mythic.core.mobs.ActiveMob;
|
||||||
|
import io.lumine.mythic.core.mobs.MobStack;
|
||||||
import io.lumine.mythic.core.skills.SkillCondition;
|
import io.lumine.mythic.core.skills.SkillCondition;
|
||||||
import io.lumine.mythic.core.utils.annotations.MythicCondition;
|
import io.lumine.mythic.core.utils.annotations.MythicCondition;
|
||||||
import io.lumine.mythic.core.utils.annotations.MythicField;
|
import io.lumine.mythic.core.utils.annotations.MythicField;
|
||||||
@@ -17,10 +21,10 @@ import org.bukkit.entity.Entity;
|
|||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class MythicMobsDataProvider extends ExternalDataProvider {
|
public class MythicMobsDataProvider extends ExternalDataProvider {
|
||||||
public MythicMobsDataProvider() {
|
public MythicMobsDataProvider() {
|
||||||
@@ -33,18 +37,31 @@ public class MythicMobsDataProvider extends ExternalDataProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException {
|
public @Nullable Entity spawnMob(@NotNull Location location, @NotNull Identifier entityId) throws MissingResourceException {
|
||||||
var mm = MythicBukkit.inst().getMobManager().spawnMob(entityId.key(), location);
|
var mm = spawnMob(BukkitAdapter.adapt(location), entityId);
|
||||||
if (mm == null) throw new MissingResourceException("Failed to find mob!", entityId.namespace(), entityId.key());
|
return mm == null ? null : mm.getEntity().getBukkitEntity();
|
||||||
return mm.getEntity().getBukkitEntity();
|
}
|
||||||
|
|
||||||
|
private ActiveMob spawnMob(AbstractLocation location, Identifier entityId) throws MissingResourceException {
|
||||||
|
var manager = MythicBukkit.inst().getMobManager();
|
||||||
|
var mm = manager.getMythicMob(entityId.key()).orElse(null);
|
||||||
|
if (mm == null) {
|
||||||
|
var stack = manager.getMythicMobStack(entityId.key());
|
||||||
|
if (stack == null) throw new MissingResourceException("Failed to find Mob!", entityId.namespace(), entityId.key());
|
||||||
|
return stack.spawn(location, 1d, SpawnReason.OTHER, null);
|
||||||
|
}
|
||||||
|
return mm.spawn(location, 1d, SpawnReason.OTHER, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
|
public @NotNull Collection<@NotNull Identifier> getTypes(@NotNull DataType dataType) {
|
||||||
if (dataType != DataType.ENTITY) return List.of();
|
if (dataType != DataType.ENTITY) return List.of();
|
||||||
return MythicBukkit.inst()
|
var manager = MythicBukkit.inst().getMobManager();
|
||||||
.getMobManager()
|
return Stream.concat(manager.getMobNames().stream(),
|
||||||
.getMobNames()
|
manager.getMobStacks()
|
||||||
.stream()
|
.stream()
|
||||||
|
.map(MobStack::getName)
|
||||||
|
)
|
||||||
|
.distinct()
|
||||||
.map(name -> new Identifier("mythicmobs", name))
|
.map(name -> new Identifier("mythicmobs", name))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import com.volmit.iris.util.reflect.KeyedType;
|
|||||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
@@ -50,7 +51,7 @@ import java.io.IOException;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Function;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
||||||
@@ -99,6 +100,10 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
|||||||
return dataLoaders.computeIfAbsent(dataFolder, IrisData::new);
|
return dataLoaders.computeIfAbsent(dataFolder, IrisData::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Optional<IrisData> getLoaded(File dataFolder) {
|
||||||
|
return Optional.ofNullable(dataLoaders.get(dataFolder));
|
||||||
|
}
|
||||||
|
|
||||||
public static void dereference() {
|
public static void dereference() {
|
||||||
dataLoaders.v().forEach(IrisData::cleanupEngine);
|
dataLoaders.v().forEach(IrisData::cleanupEngine);
|
||||||
}
|
}
|
||||||
@@ -118,92 +123,100 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
|||||||
Iris.warn(" " + rl.getResourceTypeName() + " @ /" + rl.getFolderName() + ": Cache=" + rl.getLoadCache().getSize() + " Folders=" + rl.getFolders().size());
|
Iris.warn(" " + rl.getResourceTypeName() + " @ /" + rl.getFolderName() + ": Cache=" + rl.getLoadCache().getSize() + " Folders=" + rl.getFolders().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisObject loadAnyObject(String key) {
|
public static IrisObject loadAnyObject(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getObjectLoader().load(key, false));
|
return loadAny(IrisObject.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisMatterObject loadAnyMatter(String key) {
|
public static IrisMatterObject loadAnyMatter(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getMatterLoader().load(key, false));
|
return loadAny(IrisMatterObject.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisBiome loadAnyBiome(String key) {
|
public static IrisBiome loadAnyBiome(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getBiomeLoader().load(key, false));
|
return loadAny(IrisBiome.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisExpression loadAnyExpression(String key) {
|
public static IrisExpression loadAnyExpression(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getExpressionLoader().load(key, false));
|
return loadAny(IrisExpression.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisMod loadAnyMod(String key) {
|
public static IrisMod loadAnyMod(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getModLoader().load(key, false));
|
return loadAny(IrisMod.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisJigsawPiece loadAnyJigsawPiece(String key) {
|
public static IrisJigsawPiece loadAnyJigsawPiece(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getJigsawPieceLoader().load(key, false));
|
return loadAny(IrisJigsawPiece.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisJigsawPool loadAnyJigsawPool(String key) {
|
public static IrisJigsawPool loadAnyJigsawPool(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getJigsawPoolLoader().load(key, false));
|
return loadAny(IrisJigsawPool.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisEntity loadAnyEntity(String key) {
|
public static IrisEntity loadAnyEntity(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getEntityLoader().load(key, false));
|
return loadAny(IrisEntity.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisLootTable loadAnyLootTable(String key) {
|
public static IrisLootTable loadAnyLootTable(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getLootLoader().load(key, false));
|
return loadAny(IrisLootTable.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisBlockData loadAnyBlock(String key) {
|
public static IrisBlockData loadAnyBlock(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getBlockLoader().load(key, false));
|
return loadAny(IrisBlockData.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisSpawner loadAnySpaner(String key) {
|
public static IrisSpawner loadAnySpaner(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getSpawnerLoader().load(key, false));
|
return loadAny(IrisSpawner.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisScript loadAnyScript(String key) {
|
public static IrisScript loadAnyScript(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getScriptLoader().load(key, false));
|
return loadAny(IrisScript.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisRavine loadAnyRavine(String key) {
|
public static IrisRavine loadAnyRavine(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getRavineLoader().load(key, false));
|
return loadAny(IrisRavine.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisRegion loadAnyRegion(String key) {
|
public static IrisRegion loadAnyRegion(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getRegionLoader().load(key, false));
|
return loadAny(IrisRegion.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisMarker loadAnyMarker(String key) {
|
public static IrisMarker loadAnyMarker(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getMarkerLoader().load(key, false));
|
return loadAny(IrisMarker.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisCave loadAnyCave(String key) {
|
public static IrisCave loadAnyCave(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getCaveLoader().load(key, false));
|
return loadAny(IrisCave.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisImage loadAnyImage(String key) {
|
public static IrisImage loadAnyImage(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getImageLoader().load(key, false));
|
return loadAny(IrisImage.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisDimension loadAnyDimension(String key) {
|
public static IrisDimension loadAnyDimension(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getDimensionLoader().load(key, false));
|
return loadAny(IrisDimension.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisJigsawStructure loadAnyJigsawStructure(String key) {
|
public static IrisJigsawStructure loadAnyJigsawStructure(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getJigsawStructureLoader().load(key, false));
|
return loadAny(IrisJigsawStructure.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IrisGenerator loadAnyGenerator(String key) {
|
public static IrisGenerator loadAnyGenerator(String key, @Nullable IrisData nearest) {
|
||||||
return loadAny(key, (dm) -> dm.getGeneratorLoader().load(key, false));
|
return loadAny(IrisGenerator.class, key, nearest);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends IrisRegistrant> T loadAny(String key, Function<IrisData, T> v) {
|
public static <T extends IrisRegistrant> T loadAny(Class<T> type, String key, @Nullable IrisData nearest) {
|
||||||
try {
|
try {
|
||||||
|
if (nearest != null) {
|
||||||
|
T t = nearest.load(type, key, false);
|
||||||
|
if (t != null) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (File i : Objects.requireNonNull(Iris.instance.getDataFolder("packs").listFiles())) {
|
for (File i : Objects.requireNonNull(Iris.instance.getDataFolder("packs").listFiles())) {
|
||||||
if (i.isDirectory()) {
|
if (i.isDirectory()) {
|
||||||
IrisData dm = get(i);
|
IrisData dm = get(i);
|
||||||
T t = v.apply(dm);
|
if (dm == nearest) continue;
|
||||||
|
T t = dm.load(type, key, false);
|
||||||
|
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
return t;
|
return t;
|
||||||
@@ -218,6 +231,17 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <T extends IrisRegistrant> T load(Class<T> type, String key, boolean warn) {
|
||||||
|
var loader = getLoader(type);
|
||||||
|
if (loader == null) return null;
|
||||||
|
return loader.load(key, warn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T extends IrisRegistrant> ResourceLoader<T> getLoader(Class<T> type) {
|
||||||
|
return (ResourceLoader<T>) loaders.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
public ResourceLoader<?> getTypedLoaderFor(File f) {
|
public ResourceLoader<?> getTypedLoaderFor(File f) {
|
||||||
String[] k = f.getPath().split("\\Q" + File.separator + "\\E");
|
String[] k = f.getPath().split("\\Q" + File.separator + "\\E");
|
||||||
|
|
||||||
@@ -325,6 +349,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void hotloaded() {
|
public synchronized void hotloaded() {
|
||||||
|
closed = false;
|
||||||
environment.close();
|
environment.close();
|
||||||
possibleSnippets = new KMap<>();
|
possibleSnippets = new KMap<>();
|
||||||
builder = new GsonBuilder()
|
builder = new GsonBuilder()
|
||||||
@@ -425,6 +450,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String snippetType = typeToken.getRawType().getDeclaredAnnotation(Snippet.class).value();
|
String snippetType = typeToken.getRawType().getDeclaredAnnotation(Snippet.class).value();
|
||||||
|
String snippedBase = "snippet/" + snippetType + "/";
|
||||||
|
|
||||||
return new TypeAdapter<>() {
|
return new TypeAdapter<>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -438,10 +464,12 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
|||||||
|
|
||||||
if (reader.peek().equals(JsonToken.STRING)) {
|
if (reader.peek().equals(JsonToken.STRING)) {
|
||||||
String r = reader.nextString();
|
String r = reader.nextString();
|
||||||
|
if (!r.startsWith("snippet/"))
|
||||||
|
return null;
|
||||||
|
if (!r.startsWith(snippedBase))
|
||||||
|
r = snippedBase + r.substring(8);
|
||||||
|
|
||||||
if (r.startsWith("snippet/" + snippetType + "/")) {
|
|
||||||
File f = new File(getDataFolder(), r + ".json");
|
File f = new File(getDataFolder(), r + ".json");
|
||||||
|
|
||||||
if (f.exists()) {
|
if (f.exists()) {
|
||||||
try (JsonReader snippetReader = new JsonReader(new FileReader(f))){
|
try (JsonReader snippetReader = new JsonReader(new FileReader(f))){
|
||||||
return adapter.read(snippetReader);
|
return adapter.read(snippetReader);
|
||||||
@@ -451,7 +479,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
|||||||
} else {
|
} else {
|
||||||
Iris.error("Couldn't find snippet " + r + " in " + reader.getPath());
|
Iris.error("Couldn't find snippet " + r + " in " + reader.getPath());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -488,7 +515,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
|
|||||||
.map(s -> s.substring(absPath.length() + 1))
|
.map(s -> s.substring(absPath.length() + 1))
|
||||||
.map(s -> s.replace("\\", "/"))
|
.map(s -> s.replace("\\", "/"))
|
||||||
.map(s -> s.split("\\Q.\\E")[0])
|
.map(s -> s.split("\\Q.\\E")[0])
|
||||||
.forEach(s -> l.add("snippet/" + f + "/" + s));
|
.forEach(s -> l.add("snippet/" + s));
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import com.volmit.iris.util.collection.KList;
|
|||||||
import com.volmit.iris.util.json.JSONObject;
|
import com.volmit.iris.util.json.JSONObject;
|
||||||
import com.volmit.iris.util.plugin.VolmitSender;
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -39,6 +40,7 @@ public abstract class IrisRegistrant {
|
|||||||
@ArrayType(min = 1, type = String.class)
|
@ArrayType(min = 1, type = String.class)
|
||||||
private KList<String> preprocessors = new KList<>();
|
private KList<String> preprocessors = new KList<>();
|
||||||
|
|
||||||
|
@EqualsAndHashCode.Exclude
|
||||||
private transient IrisData loader;
|
private transient IrisData loader;
|
||||||
|
|
||||||
private transient String loadKey;
|
private transient String loadKey;
|
||||||
|
|||||||
@@ -18,9 +18,13 @@
|
|||||||
|
|
||||||
package com.volmit.iris.core.nms;
|
package com.volmit.iris.core.nms;
|
||||||
|
|
||||||
|
import com.volmit.iris.core.link.Identifier;
|
||||||
|
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||||
import com.volmit.iris.core.link.FoliaWorldsLink;
|
import com.volmit.iris.core.link.FoliaWorldsLink;
|
||||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
import com.volmit.iris.core.nms.container.BlockProperty;
|
import com.volmit.iris.core.nms.container.BlockProperty;
|
||||||
|
import com.volmit.iris.core.nms.container.Pair;
|
||||||
|
import com.volmit.iris.core.nms.container.StructurePlacement;
|
||||||
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.platform.PlatformChunkGenerator;
|
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||||
@@ -147,4 +151,8 @@ public interface INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KMap<Material, List<BlockProperty>> getBlockProperties();
|
KMap<Material, List<BlockProperty>> getBlockProperties();
|
||||||
|
|
||||||
|
void placeStructures(Chunk chunk);
|
||||||
|
|
||||||
|
KMap<Identifier, StructurePlacement> collectStructures();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package com.volmit.iris.core.nms.container;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement.SpreadType;
|
||||||
|
import lombok.*;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import org.apache.commons.math3.fraction.Fraction;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@SuperBuilder
|
||||||
|
@Accessors(fluent = true, chain = true)
|
||||||
|
public abstract class StructurePlacement {
|
||||||
|
private final int salt;
|
||||||
|
private final float frequency;
|
||||||
|
private final List<Structure> structures;
|
||||||
|
|
||||||
|
public abstract JsonObject toJson(String structure);
|
||||||
|
|
||||||
|
protected JsonObject createBase(String structure) {
|
||||||
|
JsonObject object = new JsonObject();
|
||||||
|
object.addProperty("structure", structure);
|
||||||
|
object.addProperty("salt", salt);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int frequencyToSpacing() {
|
||||||
|
var frac = new Fraction(Math.max(Math.min(frequency, 1), 0.000000001f));
|
||||||
|
return (int) Math.round(Math.sqrt((double) frac.getDenominator() / frac.getNumerator()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Accessors(chain = true, fluent = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@SuperBuilder
|
||||||
|
public static class RandomSpread extends StructurePlacement {
|
||||||
|
private final int spacing;
|
||||||
|
private final int separation;
|
||||||
|
private final SpreadType spreadType;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonObject toJson(String structure) {
|
||||||
|
JsonObject object = createBase(structure);
|
||||||
|
object.addProperty("spacing", Math.max(spacing, frequencyToSpacing()));
|
||||||
|
object.addProperty("separation", separation);
|
||||||
|
object.addProperty("spreadType", spreadType.name());
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@SuperBuilder
|
||||||
|
public static class ConcentricRings extends StructurePlacement {
|
||||||
|
private final int distance;
|
||||||
|
private final int spread;
|
||||||
|
private final int count;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonObject toJson(String structure) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Structure(
|
||||||
|
int weight,
|
||||||
|
String key,
|
||||||
|
List<String> tags
|
||||||
|
) {
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return weight > 0 && key != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,10 +19,13 @@
|
|||||||
package com.volmit.iris.core.nms.v1X;
|
package com.volmit.iris.core.nms.v1X;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.link.Identifier;
|
||||||
import com.volmit.iris.core.nms.INMSBinding;
|
import com.volmit.iris.core.nms.INMSBinding;
|
||||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
import com.volmit.iris.core.nms.container.BlockProperty;
|
import com.volmit.iris.core.nms.container.BlockProperty;
|
||||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
|
import com.volmit.iris.core.nms.container.Pair;
|
||||||
|
import com.volmit.iris.core.nms.container.StructurePlacement;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
@@ -135,6 +138,16 @@ public class NMSBinding1X implements INMSBinding {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void placeStructures(Chunk chunk) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KMap<Identifier, StructurePlacement> collectStructures() {
|
||||||
|
return new KMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag serializeEntity(Entity location) {
|
public CompoundTag serializeEntity(Entity location) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ public class IrisProject {
|
|||||||
|
|
||||||
public void openVSCode(VolmitSender sender) {
|
public void openVSCode(VolmitSender sender) {
|
||||||
|
|
||||||
IrisDimension d = IrisData.loadAnyDimension(getName());
|
IrisDimension d = IrisData.loadAnyDimension(getName(), null);
|
||||||
J.attemptAsync(() ->
|
J.attemptAsync(() ->
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -221,7 +221,7 @@ public class IrisProject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
J.a(() -> {
|
J.a(() -> {
|
||||||
IrisDimension d = IrisData.loadAnyDimension(getName());
|
IrisDimension d = IrisData.loadAnyDimension(getName(), null);
|
||||||
if (d == null) {
|
if (d == null) {
|
||||||
sender.sendMessage("Can't find dimension: " + getName());
|
sender.sendMessage("Can't find dimension: " + getName());
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -22,33 +22,39 @@ import com.volmit.iris.Iris;
|
|||||||
import com.volmit.iris.core.IrisSettings;
|
import com.volmit.iris.core.IrisSettings;
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
|
||||||
import com.volmit.iris.util.board.BoardManager;
|
import com.volmit.iris.util.board.BoardManager;
|
||||||
import com.volmit.iris.util.board.BoardProvider;
|
import com.volmit.iris.util.board.BoardProvider;
|
||||||
import com.volmit.iris.util.board.BoardSettings;
|
import com.volmit.iris.util.board.BoardSettings;
|
||||||
import com.volmit.iris.util.board.ScoreDirection;
|
import com.volmit.iris.util.board.ScoreDirection;
|
||||||
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.format.C;
|
||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
import com.volmit.iris.util.plugin.IrisService;
|
import com.volmit.iris.util.plugin.IrisService;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class BoardSVC implements IrisService, BoardProvider {
|
public class BoardSVC implements IrisService, BoardProvider {
|
||||||
private final KMap<Player, PlayerBoard> boards = new KMap<>();
|
private final KMap<Player, PlayerBoard> boards = new KMap<>();
|
||||||
private com.volmit.iris.util.board.BoardManager manager;
|
private ScheduledExecutorService executor;
|
||||||
|
private BoardManager manager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
J.ar(this::tick, 20);
|
executor = Executors.newScheduledThreadPool(0, Thread.ofVirtual().factory());
|
||||||
manager = new BoardManager(Iris.instance, BoardSettings.builder()
|
manager = new BoardManager(Iris.instance, BoardSettings.builder()
|
||||||
.boardProvider(this)
|
.boardProvider(this)
|
||||||
.scoreDirection(ScoreDirection.DOWN)
|
.scoreDirection(ScoreDirection.DOWN)
|
||||||
@@ -57,6 +63,7 @@ public class BoardSVC implements IrisService, BoardProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
|
executor.shutdownNow();
|
||||||
manager.onDisable();
|
manager.onDisable();
|
||||||
boards.clear();
|
boards.clear();
|
||||||
}
|
}
|
||||||
@@ -71,14 +78,22 @@ public class BoardSVC implements IrisService, BoardProvider {
|
|||||||
J.s(() -> updatePlayer(e.getPlayer()));
|
J.s(() -> updatePlayer(e.getPlayer()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void on(PlayerQuitEvent e) {
|
||||||
|
remove(e.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
public void updatePlayer(Player p) {
|
public void updatePlayer(Player p) {
|
||||||
if (IrisToolbelt.isIrisStudioWorld(p.getWorld())) {
|
if (IrisToolbelt.isIrisStudioWorld(p.getWorld())) {
|
||||||
manager.remove(p);
|
manager.remove(p);
|
||||||
manager.setup(p);
|
manager.setup(p);
|
||||||
} else {
|
} else remove(p);
|
||||||
manager.remove(p);
|
|
||||||
boards.remove(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void remove(Player player) {
|
||||||
|
manager.remove(player);
|
||||||
|
var board = boards.remove(player);
|
||||||
|
if (board != null) board.task.cancel(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -86,52 +101,55 @@ public class BoardSVC implements IrisService, BoardProvider {
|
|||||||
return C.GREEN + "Iris";
|
return C.GREEN + "Iris";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick() {
|
@Override
|
||||||
|
public List<String> getLines(Player player) {
|
||||||
|
return boards.computeIfAbsent(player, PlayerBoard::new).lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PlayerBoard {
|
||||||
|
private final Player player;
|
||||||
|
private final ScheduledFuture<?> task;
|
||||||
|
private volatile List<String> lines;
|
||||||
|
|
||||||
|
public PlayerBoard(Player player) {
|
||||||
|
this.player = player;
|
||||||
|
this.lines = new ArrayList<>();
|
||||||
|
this.task = executor.scheduleAtFixedRate(this::tick, 0, 1, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tick() {
|
||||||
if (!Iris.service(StudioSVC.class).isProjectOpen()) {
|
if (!Iris.service(StudioSVC.class).isProjectOpen()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boards.forEach((k, v) -> v.update());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> getLines(Player player) {
|
|
||||||
PlayerBoard pb = boards.computeIfAbsent(player, PlayerBoard::new);
|
|
||||||
synchronized (pb.lines) {
|
|
||||||
return pb.lines;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public static class PlayerBoard {
|
|
||||||
private final Player player;
|
|
||||||
private final CopyOnWriteArrayList<String> lines;
|
|
||||||
|
|
||||||
public PlayerBoard(Player player) {
|
|
||||||
this.player = player;
|
|
||||||
this.lines = new CopyOnWriteArrayList<>();
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update() {
|
public void update() {
|
||||||
synchronized (lines) {
|
final World world = player.getWorld();
|
||||||
lines.clear();
|
final Location loc = player.getLocation();
|
||||||
|
|
||||||
if (!IrisToolbelt.isIrisStudioWorld(player.getWorld())) {
|
final var access = IrisToolbelt.access(world);
|
||||||
return;
|
if (access == null) return;
|
||||||
}
|
|
||||||
|
|
||||||
Engine engine = IrisToolbelt.access(player.getWorld()).getEngine();
|
final var engine = access.getEngine();
|
||||||
int x = player.getLocation().getBlockX();
|
if (engine == null) return;
|
||||||
int y = player.getLocation().getBlockY() - player.getWorld().getMinHeight();
|
|
||||||
int z = player.getLocation().getBlockZ();
|
|
||||||
|
|
||||||
if(IrisSettings.get().getGeneral().debug){
|
int x = loc.getBlockX();
|
||||||
|
int y = loc.getBlockY() - world.getMinHeight();
|
||||||
|
int z = loc.getBlockZ();
|
||||||
|
|
||||||
|
List<String> lines = new ArrayList<>(this.lines.size());
|
||||||
lines.add("&7&m ");
|
lines.add("&7&m ");
|
||||||
lines.add(C.GREEN + "Speed" + C.GRAY + ": " + Form.f(engine.getGeneratedPerSecond(), 0) + "/s " + Form.duration(1000D / engine.getGeneratedPerSecond(), 0));
|
lines.add(C.GREEN + "Speed" + C.GRAY + ": " + Form.f(engine.getGeneratedPerSecond(), 0) + "/s " + Form.duration(1000D / engine.getGeneratedPerSecond(), 0));
|
||||||
lines.add(C.AQUA + "Cache" + C.GRAY + ": " + Form.f(IrisData.cacheSize()));
|
lines.add(C.AQUA + "Cache" + C.GRAY + ": " + Form.f(IrisData.cacheSize()));
|
||||||
lines.add(C.AQUA + "Mantle" + C.GRAY + ": " + engine.getMantle().getLoadedRegionCount());
|
lines.add(C.AQUA + "Mantle" + C.GRAY + ": " + engine.getMantle().getLoadedRegionCount());
|
||||||
|
|
||||||
|
if (IrisSettings.get().getGeneral().debug) {
|
||||||
lines.add(C.LIGHT_PURPLE + "Carving" + C.GRAY + ": " + engine.getMantle().isCarved(x,y,z));
|
lines.add(C.LIGHT_PURPLE + "Carving" + C.GRAY + ": " + engine.getMantle().isCarved(x,y,z));
|
||||||
|
}
|
||||||
|
|
||||||
lines.add("&7&m ");
|
lines.add("&7&m ");
|
||||||
lines.add(C.AQUA + "Region" + C.GRAY + ": " + engine.getRegion(x, z).getName());
|
lines.add(C.AQUA + "Region" + C.GRAY + ": " + engine.getRegion(x, z).getName());
|
||||||
lines.add(C.AQUA + "Biome" + C.GRAY + ": " + engine.getBiomeOrMantle(x, y, z).getName());
|
lines.add(C.AQUA + "Biome" + C.GRAY + ": " + engine.getBiomeOrMantle(x, y, z).getName());
|
||||||
@@ -139,20 +157,7 @@ public class BoardSVC implements IrisService, BoardProvider {
|
|||||||
lines.add(C.AQUA + "Slope" + C.GRAY + ": " + Form.f(engine.getComplex().getSlopeStream().get(x, z), 2));
|
lines.add(C.AQUA + "Slope" + C.GRAY + ": " + Form.f(engine.getComplex().getSlopeStream().get(x, z), 2));
|
||||||
lines.add(C.AQUA + "BUD/s" + C.GRAY + ": " + Form.f(engine.getBlockUpdatesPerSecond()));
|
lines.add(C.AQUA + "BUD/s" + C.GRAY + ": " + Form.f(engine.getBlockUpdatesPerSecond()));
|
||||||
lines.add("&7&m ");
|
lines.add("&7&m ");
|
||||||
} else {
|
this.lines = lines;
|
||||||
lines.add("&7&m ");
|
|
||||||
lines.add(C.GREEN + "Speed" + C.GRAY + ": " + Form.f(engine.getGeneratedPerSecond(), 0) + "/s " + Form.duration(1000D / engine.getGeneratedPerSecond(), 0));
|
|
||||||
lines.add(C.AQUA + "Cache" + C.GRAY + ": " + Form.f(IrisData.cacheSize()));
|
|
||||||
lines.add(C.AQUA + "Mantle" + C.GRAY + ": " + engine.getMantle().getLoadedRegionCount());
|
|
||||||
lines.add("&7&m ");
|
|
||||||
lines.add(C.AQUA + "Region" + C.GRAY + ": " + engine.getRegion(x, z).getName());
|
|
||||||
lines.add(C.AQUA + "Biome" + C.GRAY + ": " + engine.getBiomeOrMantle(x, y, z).getName());
|
|
||||||
lines.add(C.AQUA + "Height" + C.GRAY + ": " + Math.round(engine.getHeight(x, z)));
|
|
||||||
lines.add(C.AQUA + "Slope" + C.GRAY + ": " + Form.f(engine.getComplex().getSlopeStream().get(x, z), 2));
|
|
||||||
lines.add(C.AQUA + "BUD/s" + C.GRAY + ": " + Form.f(engine.getBlockUpdatesPerSecond()));
|
|
||||||
lines.add("&7&m ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.volmit.iris.core.commands.CommandIris;
|
|||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
|
import com.volmit.iris.util.decree.DecreeContext;
|
||||||
import com.volmit.iris.util.decree.DecreeSystem;
|
import com.volmit.iris.util.decree.DecreeSystem;
|
||||||
import com.volmit.iris.util.decree.virtual.VirtualDecreeCommand;
|
import com.volmit.iris.util.decree.virtual.VirtualDecreeCommand;
|
||||||
import com.volmit.iris.util.format.C;
|
import com.volmit.iris.util.format.C;
|
||||||
@@ -44,7 +45,14 @@ public class CommandSVC implements IrisService, DecreeSystem {
|
|||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
Iris.instance.getCommand("iris").setExecutor(this);
|
Iris.instance.getCommand("iris").setExecutor(this);
|
||||||
J.a(() -> getRoot().cacheAll());
|
J.a(() -> {
|
||||||
|
DecreeContext.touch(Iris.getSender());
|
||||||
|
try {
|
||||||
|
getRoot().cacheAll();
|
||||||
|
} finally {
|
||||||
|
DecreeContext.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -88,16 +88,18 @@ public class StudioSVC implements IrisService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IrisDimension installIntoWorld(VolmitSender sender, String type, File folder) {
|
public IrisDimension installIntoWorld(VolmitSender sender, String type, File folder) {
|
||||||
|
return installInto(sender, type, new File(folder, "iris/pack"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IrisDimension installInto(VolmitSender sender, String type, File folder) {
|
||||||
sender.sendMessage("Looking for Package: " + type);
|
sender.sendMessage("Looking for Package: " + type);
|
||||||
File iris = new File(folder, "iris");
|
IrisDimension dim = IrisData.loadAnyDimension(type, null);
|
||||||
File irispack = new File(folder, "iris/pack");
|
|
||||||
IrisDimension dim = IrisData.loadAnyDimension(type);
|
|
||||||
|
|
||||||
if (dim == null) {
|
if (dim == null) {
|
||||||
for (File i : getWorkspaceFolder().listFiles()) {
|
for (File i : getWorkspaceFolder().listFiles()) {
|
||||||
if (i.isFile() && i.getName().equals(type + ".iris")) {
|
if (i.isFile() && i.getName().equals(type + ".iris")) {
|
||||||
sender.sendMessage("Found " + type + ".iris in " + WORKSPACE_NAME + " folder");
|
sender.sendMessage("Found " + type + ".iris in " + WORKSPACE_NAME + " folder");
|
||||||
ZipUtil.unpack(i, irispack);
|
ZipUtil.unpack(i, folder);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,29 +108,29 @@ public class StudioSVC implements IrisService {
|
|||||||
File f = new IrisProject(new File(getWorkspaceFolder(), type)).getPath();
|
File f = new IrisProject(new File(getWorkspaceFolder(), type)).getPath();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FileUtils.copyDirectory(f, irispack);
|
FileUtils.copyDirectory(f, folder);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File dimf = new File(irispack, "dimensions/" + type + ".json");
|
File dimensionFile = new File(folder, "dimensions/" + type + ".json");
|
||||||
|
|
||||||
if (!dimf.exists() || !dimf.isFile()) {
|
if (!dimensionFile.exists() || !dimensionFile.isFile()) {
|
||||||
downloadSearch(sender, type, false);
|
downloadSearch(sender, type, false);
|
||||||
File downloaded = getWorkspaceFolder(type);
|
File downloaded = getWorkspaceFolder(type);
|
||||||
|
|
||||||
for (File i : downloaded.listFiles()) {
|
for (File i : downloaded.listFiles()) {
|
||||||
if (i.isFile()) {
|
if (i.isFile()) {
|
||||||
try {
|
try {
|
||||||
FileUtils.copyFile(i, new File(irispack, i.getName()));
|
FileUtils.copyFile(i, new File(folder, i.getName()));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
FileUtils.copyDirectory(i, new File(irispack, i.getName()));
|
FileUtils.copyDirectory(i, new File(folder, i.getName()));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
@@ -139,12 +141,13 @@ public class StudioSVC implements IrisService {
|
|||||||
IO.delete(downloaded);
|
IO.delete(downloaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dimf.exists() || !dimf.isFile()) {
|
if (!dimensionFile.exists() || !dimensionFile.isFile()) {
|
||||||
sender.sendMessage("Can't find the " + dimf.getName() + " in the dimensions folder of this pack! Failed!");
|
sender.sendMessage("Can't find the " + dimensionFile.getName() + " in the dimensions folder of this pack! Failed!");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
IrisData dm = IrisData.get(irispack);
|
IrisData dm = IrisData.get(folder);
|
||||||
|
dm.hotloaded();
|
||||||
dim = dm.getDimensionLoader().load(type);
|
dim = dm.getDimensionLoader().load(type);
|
||||||
|
|
||||||
if (dim == null) {
|
if (dim == null) {
|
||||||
@@ -261,6 +264,7 @@ public class StudioSVC implements IrisService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IrisDimension d = data.getDimensionLoader().load(dimensions[0]);
|
IrisDimension d = data.getDimensionLoader().load(dimensions[0]);
|
||||||
|
data.close();
|
||||||
|
|
||||||
if (d == null) {
|
if (d == null) {
|
||||||
sender.sendMessage("Invalid dimension (folder) in dimensions folder");
|
sender.sendMessage("Invalid dimension (folder) in dimensions folder");
|
||||||
@@ -275,7 +279,7 @@ public class StudioSVC implements IrisService {
|
|||||||
IO.delete(packEntry);
|
IO.delete(packEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IrisData.loadAnyDimension(key) != null) {
|
if (IrisData.loadAnyDimension(key, null) != null) {
|
||||||
sender.sendMessage("Another dimension in the packs folder is already using the key " + key + " IMPORT FAILED!");
|
sender.sendMessage("Another dimension in the packs folder is already using the key " + key + " IMPORT FAILED!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -294,6 +298,8 @@ public class StudioSVC implements IrisService {
|
|||||||
packEntry.mkdirs();
|
packEntry.mkdirs();
|
||||||
ZipUtil.unpack(cp, packEntry);
|
ZipUtil.unpack(cp, packEntry);
|
||||||
}
|
}
|
||||||
|
IrisData.getLoaded(packEntry)
|
||||||
|
.ifPresent(IrisData::hotloaded);
|
||||||
|
|
||||||
sender.sendMessage("Successfully Aquired " + d.getName());
|
sender.sendMessage("Successfully Aquired " + d.getName());
|
||||||
ServerConfigurator.installDataPacks(true);
|
ServerConfigurator.installDataPacks(true);
|
||||||
|
|||||||
@@ -135,12 +135,14 @@ public class IrisCreator {
|
|||||||
.seed(seed)
|
.seed(seed)
|
||||||
.studio(studio)
|
.studio(studio)
|
||||||
.create();
|
.create();
|
||||||
ServerConfigurator.installDataPacks(false);
|
if (ServerConfigurator.installDataPacks(true)) {
|
||||||
|
throw new IrisException("Datapacks were missing!");
|
||||||
|
}
|
||||||
|
|
||||||
PlatformChunkGenerator access = (PlatformChunkGenerator) wc.generator();
|
PlatformChunkGenerator access = (PlatformChunkGenerator) wc.generator();
|
||||||
if (access == null) throw new IrisException("Access is null. Something bad happened.");
|
if (access == null) throw new IrisException("Access is null. Something bad happened.");
|
||||||
|
|
||||||
AtomicBoolean failed = new AtomicBoolean(false);
|
AtomicBoolean done = new AtomicBoolean(false);
|
||||||
J.a(() -> {
|
J.a(() -> {
|
||||||
IntSupplier g = () -> {
|
IntSupplier g = () -> {
|
||||||
if (access.getEngine() == null) {
|
if (access.getEngine() == null) {
|
||||||
@@ -150,19 +152,13 @@ public class IrisCreator {
|
|||||||
};
|
};
|
||||||
if(!benchmark) {
|
if(!benchmark) {
|
||||||
int req = access.getSpawnChunks().join();
|
int req = access.getSpawnChunks().join();
|
||||||
|
for (int c = 0; c < req && !done.get(); c = g.getAsInt()) {
|
||||||
while (g.getAsInt() < req) {
|
double v = (double) c / req;
|
||||||
if (failed.get()) {
|
|
||||||
sender.sendMessage(C.RED + "Failed to create world!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
double v = (double) g.getAsInt() / (double) req;
|
|
||||||
if (sender.isPlayer()) {
|
if (sender.isPlayer()) {
|
||||||
sender.sendProgress(v, "Generating");
|
sender.sendProgress(v, "Generating");
|
||||||
J.sleep(16);
|
J.sleep(16);
|
||||||
} else {
|
} else {
|
||||||
sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - g.getAsInt()) + " Left)")));
|
sender.sendMessage(C.WHITE + "Generating " + Form.pc(v) + ((C.GRAY + " (" + (req - c) + " Left)")));
|
||||||
J.sleep(1000);
|
J.sleep(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,10 +172,12 @@ public class IrisCreator {
|
|||||||
.thenCompose(Function.identity())
|
.thenCompose(Function.identity())
|
||||||
.get();
|
.get();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
failed.set(true);
|
done.set(true);
|
||||||
throw new IrisException("Failed to create world!", e);
|
throw new IrisException("Failed to create world!", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done.set(true);
|
||||||
|
|
||||||
if (sender.isPlayer() && !benchmark) {
|
if (sender.isPlayer() && !benchmark) {
|
||||||
Iris.platform.getChunkAtAsync(world, 0, 0, true, true)
|
Iris.platform.getChunkAtAsync(world, 0, 0, true, true)
|
||||||
.thenApply(Objects::requireNonNull)
|
.thenApply(Objects::requireNonNull)
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class IrisWorldCreator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public WorldCreator create() {
|
public WorldCreator create() {
|
||||||
IrisDimension dim = IrisData.loadAnyDimension(dimensionName);
|
IrisDimension dim = IrisData.loadAnyDimension(dimensionName, null);
|
||||||
|
|
||||||
IrisWorld w = IrisWorld.builder()
|
IrisWorld w = IrisWorld.builder()
|
||||||
.name(name)
|
.name(name)
|
||||||
@@ -80,13 +80,13 @@ public class IrisWorldCreator {
|
|||||||
|
|
||||||
|
|
||||||
return new WorldCreator(name)
|
return new WorldCreator(name)
|
||||||
.environment(findEnvironment())
|
.environment(w.environment())
|
||||||
.generateStructures(true)
|
.generateStructures(true)
|
||||||
.generator(g).seed(seed);
|
.generator(g).seed(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private World.Environment findEnvironment() {
|
private World.Environment findEnvironment() {
|
||||||
IrisDimension dim = IrisData.loadAnyDimension(dimensionName);
|
IrisDimension dim = IrisData.loadAnyDimension(dimensionName, null);
|
||||||
if (dim == null || dim.getEnvironment() == null) {
|
if (dim == null || dim.getEnvironment() == null) {
|
||||||
return World.Environment.NORMAL;
|
return World.Environment.NORMAL;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ package com.volmit.iris.engine;
|
|||||||
|
|
||||||
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.link.Identifier;
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
|
import com.volmit.iris.core.service.ExternalDataSVC;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.engine.framework.EngineAssignedWorldManager;
|
import com.volmit.iris.engine.framework.EngineAssignedWorldManager;
|
||||||
import com.volmit.iris.engine.object.*;
|
import com.volmit.iris.engine.object.*;
|
||||||
@@ -426,18 +428,35 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var ref = new WeakReference<>(e.getWorld());
|
var ref = new WeakReference<>(e.getWorld());
|
||||||
int x = e.getX(), z = e.getZ();
|
int cX = e.getX(), cZ = e.getZ();
|
||||||
J.s(() -> {
|
J.s(() -> {
|
||||||
World world = ref.get();
|
World world = ref.get();
|
||||||
if (world == null || !world.isChunkLoaded(x, z))
|
if (world == null || !world.isChunkLoaded(cX, cZ))
|
||||||
return;
|
return;
|
||||||
energy += 0.3;
|
energy += 0.3;
|
||||||
fixEnergy();
|
fixEnergy();
|
||||||
getEngine().cleanupMantleChunk(x, z);
|
getEngine().cleanupMantleChunk(cX, cZ);
|
||||||
}, IrisSettings.get().getPerformance().mantleCleanupDelay);
|
}, IrisSettings.get().getPerformance().mantleCleanupDelay);
|
||||||
|
|
||||||
if (generated) {
|
if (generated) {
|
||||||
//INMS.get().injectBiomesFromMantle(e, getMantle());
|
//INMS.get().injectBiomesFromMantle(e, getMantle());
|
||||||
|
|
||||||
|
if (!IrisSettings.get().getGenerator().earlyCustomBlocks) return;
|
||||||
|
e.addPluginChunkTicket(Iris.instance);
|
||||||
|
J.s(() -> {
|
||||||
|
var chunk = getMantle().getChunk(e).use();
|
||||||
|
int minY = getTarget().getWorld().minHeight();
|
||||||
|
try {
|
||||||
|
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, () -> {
|
||||||
|
chunk.iterate(Identifier.class, (x, y, z, v) -> {
|
||||||
|
Iris.service(ExternalDataSVC.class).processUpdate(getEngine(), e.getBlock(x & 15, y + minY, z & 15), v);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
chunk.release();
|
||||||
|
e.removePluginChunkTicket(Iris.instance);
|
||||||
|
}
|
||||||
|
}, RNG.r.i(20, 60));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -295,20 +295,20 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
try {
|
try {
|
||||||
Semaphore semaphore = new Semaphore(3);
|
Semaphore semaphore = new Semaphore(3);
|
||||||
chunk.raiseFlag(MantleFlag.ETCHED, () -> {
|
chunk.raiseFlag(MantleFlag.ETCHED, () -> {
|
||||||
chunk.raiseFlag(MantleFlag.TILE, run(semaphore, () -> {
|
chunk.raiseFlagUnchecked(MantleFlag.TILE, run(semaphore, () -> {
|
||||||
chunk.iterate(TileWrapper.class, (x, y, z, v) -> {
|
chunk.iterate(TileWrapper.class, (x, y, z, v) -> {
|
||||||
Block block = c.getBlock(x & 15, y + getWorld().minHeight(), z & 15);
|
Block block = c.getBlock(x & 15, y + getWorld().minHeight(), z & 15);
|
||||||
if (!TileData.setTileState(block, v.getData()))
|
if (!TileData.setTileState(block, v.getData()))
|
||||||
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", block.getX(), block.getY(), block.getZ(), block.getType().getKey(), v.getData().getMaterial().getKey());
|
Iris.warn("Failed to set tile entity data at [%d %d %d | %s] for tile %s!", block.getX(), block.getY(), block.getZ(), block.getType().getKey(), v.getData().getMaterial().getKey());
|
||||||
});
|
});
|
||||||
}, c, 1));
|
}, c, 1));
|
||||||
chunk.raiseFlag(MantleFlag.CUSTOM, run(semaphore, () -> {
|
chunk.raiseFlagUnchecked(MantleFlag.CUSTOM, run(semaphore, () -> {
|
||||||
chunk.iterate(Identifier.class, (x, y, z, v) -> {
|
chunk.iterate(Identifier.class, (x, y, z, v) -> {
|
||||||
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
|
Iris.service(ExternalDataSVC.class).processUpdate(this, c.getBlock(x & 15, y + getWorld().minHeight(), z & 15), v);
|
||||||
});
|
});
|
||||||
}, c, 1));
|
}, c, 1));
|
||||||
|
|
||||||
chunk.raiseFlag(MantleFlag.UPDATE, run(semaphore, () -> {
|
chunk.raiseFlagUnchecked(MantleFlag.UPDATE, run(semaphore, () -> {
|
||||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||||
int[][] grid = new int[16][16];
|
int[][] grid = new int[16][16];
|
||||||
for (int x = 0; x < 16; x++) {
|
for (int x = 0; x < 16; x++) {
|
||||||
@@ -863,7 +863,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
default void gotoBiome(IrisBiome biome, Player player, boolean teleport) {
|
default void gotoBiome(IrisBiome biome, Player player, boolean teleport) {
|
||||||
Set<String> regionKeys = getDimension()
|
Set<String> regionKeys = getDimension()
|
||||||
.getAllRegions(this).stream()
|
.getAllRegions(this).stream()
|
||||||
.filter((i) -> i.getAllBiomes(this).contains(biome))
|
.filter((i) -> i.getAllBiomeIds().contains(biome.getLoadKey()))
|
||||||
.map(IrisRegistrant::getLoadKey)
|
.map(IrisRegistrant::getLoadKey)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
Locator<IrisBiome> lb = Locator.surfaceBiome(biome.getLoadKey());
|
Locator<IrisBiome> lb = Locator.surfaceBiome(biome.getLoadKey());
|
||||||
@@ -959,7 +959,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
}
|
}
|
||||||
|
|
||||||
default void gotoRegion(IrisRegion r, Player player, boolean teleport) {
|
default void gotoRegion(IrisRegion r, Player player, boolean teleport) {
|
||||||
if (!getDimension().getAllRegions(this).contains(r)) {
|
if (!getDimension().getRegions().contains(r.getLoadKey())) {
|
||||||
player.sendMessage(C.RED + r.getName() + " is not defined in the dimension!");
|
player.sendMessage(C.RED + r.getName() + " is not defined in the dimension!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ public class MantleJigsawComponent extends IrisMantleComponent {
|
|||||||
|
|
||||||
@BlockCoordinates
|
@BlockCoordinates
|
||||||
private boolean place(MantleWriter writer, IrisPosition position, IrisJigsawStructure structure, RNG rng, boolean forcePlace) {
|
private boolean place(MantleWriter writer, IrisPosition position, IrisJigsawStructure structure, RNG rng, boolean forcePlace) {
|
||||||
|
if (structure == null || structure.getDatapackStructures().isNotEmpty()) return false;
|
||||||
return new PlannedStructure(structure, position, rng, forcePlace).place(writer, getMantle(), writer.getEngine());
|
return new PlannedStructure(structure, position, rng, forcePlace).place(writer, getMantle(), writer.getEngine());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package com.volmit.iris.engine.modifier;
|
|||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.engine.framework.EngineAssignedModifier;
|
import com.volmit.iris.engine.framework.EngineAssignedModifier;
|
||||||
import com.volmit.iris.engine.object.IrisBiome;
|
import com.volmit.iris.engine.object.IrisBiome;
|
||||||
|
import com.volmit.iris.engine.object.IrisSlopeClip;
|
||||||
import com.volmit.iris.util.context.ChunkContext;
|
import com.volmit.iris.util.context.ChunkContext;
|
||||||
import com.volmit.iris.util.data.B;
|
import com.volmit.iris.util.data.B;
|
||||||
import com.volmit.iris.util.hunk.Hunk;
|
import com.volmit.iris.util.hunk.Hunk;
|
||||||
@@ -174,7 +175,8 @@ public class IrisPostModifier extends EngineAssignedModifier<BlockData> {
|
|||||||
|| (hd == h + 1 && isSolidNonSlab(x, hd, z - 1, currentPostX, currentPostZ, currentData)))
|
|| (hd == h + 1 && isSolidNonSlab(x, hd, z - 1, currentPostX, currentPostZ, currentData)))
|
||||||
//@done
|
//@done
|
||||||
{
|
{
|
||||||
BlockData d = biome.getSlab().get(rng, x, h, z, getData());
|
IrisSlopeClip sc = biome.getSlab().getSlopeCondition();
|
||||||
|
BlockData d = sc.isValid(getComplex().getSlopeStream().get(x, z)) ? biome.getSlab().get(rng, x, h, z, getData()) : null;
|
||||||
|
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
boolean cancel = B.isAir(d);
|
boolean cancel = B.isAir(d);
|
||||||
|
|||||||
@@ -355,7 +355,7 @@ public class IrisDimension extends IrisRegistrant {
|
|||||||
KList<IrisRegion> r = new KList<>();
|
KList<IrisRegion> r = new KList<>();
|
||||||
|
|
||||||
for (String i : getRegions()) {
|
for (String i : getRegions()) {
|
||||||
r.add(IrisData.loadAnyRegion(i));
|
r.add(IrisData.loadAnyRegion(i, getLoader()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import com.volmit.iris.core.loader.IrisRegistrant;
|
|||||||
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.engine.object.annotations.functions.StructureKeyFunction;
|
import com.volmit.iris.engine.object.annotations.functions.StructureKeyFunction;
|
||||||
|
import com.volmit.iris.engine.object.annotations.functions.StructureKeyOrTagFunction;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.json.JSONObject;
|
import com.volmit.iris.util.json.JSONObject;
|
||||||
import com.volmit.iris.util.plugin.VolmitSender;
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
@@ -40,6 +41,11 @@ import lombok.experimental.Accessors;
|
|||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class IrisJigsawStructure extends IrisRegistrant {
|
public class IrisJigsawStructure extends IrisRegistrant {
|
||||||
|
@RegistryListFunction(StructureKeyFunction.class)
|
||||||
|
@ArrayType(min = 1, type = String.class)
|
||||||
|
@Desc("The datapack structures. Randomply chooses a structure to place\nIgnores every other setting")
|
||||||
|
private KList<String> datapackStructures = new KList<>();
|
||||||
|
|
||||||
@RegistryListResource(IrisJigsawPiece.class)
|
@RegistryListResource(IrisJigsawPiece.class)
|
||||||
@Required
|
@Required
|
||||||
@ArrayType(min = 1, type = String.class)
|
@ArrayType(min = 1, type = String.class)
|
||||||
@@ -70,7 +76,7 @@ public class IrisJigsawStructure extends IrisRegistrant {
|
|||||||
@Desc("Set to true to prevent rotating the initial structure piece")
|
@Desc("Set to true to prevent rotating the initial structure piece")
|
||||||
private boolean disableInitialRotation = false;
|
private boolean disableInitialRotation = false;
|
||||||
|
|
||||||
@RegistryListFunction(StructureKeyFunction.class)
|
@RegistryListFunction(StructureKeyOrTagFunction.class)
|
||||||
@Desc("The minecraft key to use when creating treasure maps")
|
@Desc("The minecraft key to use when creating treasure maps")
|
||||||
private String structureKey = null;
|
private String structureKey = null;
|
||||||
|
|
||||||
@@ -117,6 +123,10 @@ public class IrisJigsawStructure extends IrisRegistrant {
|
|||||||
|
|
||||||
public int getMaxDimension() {
|
public int getMaxDimension() {
|
||||||
return maxDimension.aquire(() -> {
|
return maxDimension.aquire(() -> {
|
||||||
|
if (datapackStructures.isNotEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (useMaxPieceSizeForParallaxRadius) {
|
if (useMaxPieceSizeForParallaxRadius) {
|
||||||
int max = 0;
|
int max = 0;
|
||||||
KList<String> pools = new KList<>();
|
KList<String> pools = new KList<>();
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ public class IrisRegion extends IrisRegistrant implements IRare {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
IrisBiome biome = IrisData.loadAnyBiome(i);
|
IrisBiome biome = IrisData.loadAnyBiome(i, getLoader());
|
||||||
|
|
||||||
names.remove(i);
|
names.remove(i);
|
||||||
if (biome == null) {
|
if (biome == null) {
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
import com.volmit.iris.engine.framework.EngineAssignedComponent;
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import com.volmit.iris.util.documentation.ChunkCoordinates;
|
||||||
|
import com.volmit.iris.util.math.Position2;
|
||||||
|
import com.volmit.iris.util.math.RNG;
|
||||||
|
import com.volmit.iris.util.noise.CNG;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.BiPredicate;
|
||||||
|
|
||||||
|
public class IrisStructurePopulator extends EngineAssignedComponent {
|
||||||
|
private final CNG cng;
|
||||||
|
private final long mantle;
|
||||||
|
private final long jigsaw;
|
||||||
|
|
||||||
|
public IrisStructurePopulator(Engine engine) {
|
||||||
|
super(engine, "Datapack Structures");
|
||||||
|
mantle = engine.getSeedManager().getMantle();
|
||||||
|
jigsaw = engine.getSeedManager().getJigsaw();
|
||||||
|
cng = NoiseStyle.STATIC.create(new RNG(jigsaw));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ChunkCoordinates
|
||||||
|
public void populateStructures(int x, int z, BiPredicate<String, Boolean> placer) {
|
||||||
|
int bX = x << 4, bZ = z << 4;
|
||||||
|
var dimension = getDimension();
|
||||||
|
var region = getEngine().getRegion(bX + 8, bZ + 8);
|
||||||
|
var biome = getEngine().getSurfaceBiome(bX + 8, bZ + 8);
|
||||||
|
var loader = getData().getJigsawStructureLoader();
|
||||||
|
|
||||||
|
long seed = cng.fit(Integer.MIN_VALUE, Integer.MAX_VALUE, x, z);
|
||||||
|
if (dimension.getStronghold() != null) {
|
||||||
|
var list = getDimension().getStrongholds(mantle);
|
||||||
|
if (list != null && list.contains(new Position2(bX, bZ))) {
|
||||||
|
place(placer, loader.load(dimension.getStronghold()), new RNG(seed), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean placed = place(placer, biome.getJigsawStructures(), seed, x, z);
|
||||||
|
if (!placed) placed = place(placer, region.getJigsawStructures(), seed, x, z);
|
||||||
|
if (!placed) place(placer, dimension.getJigsawStructures(), seed, x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean place(BiPredicate<String, Boolean> placer, KList<IrisJigsawStructurePlacement> placements, long seed, int x, int z) {
|
||||||
|
var placement = pick(placements, seed, x, z);
|
||||||
|
if (placement == null) return false;
|
||||||
|
return place(placer, getData().getJigsawStructureLoader().load(placement.getStructure()), new RNG(seed), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@ChunkCoordinates
|
||||||
|
private IrisJigsawStructurePlacement pick(List<IrisJigsawStructurePlacement> structures, long seed, int x, int z) {
|
||||||
|
return IRare.pick(structures.stream()
|
||||||
|
.filter(p -> p.shouldPlace(getData(), getDimension().getJigsawStructureDivisor(), jigsaw, x, z))
|
||||||
|
.toList(), new RNG(seed).nextDouble());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ChunkCoordinates
|
||||||
|
private boolean place(BiPredicate<String, Boolean> placer, IrisJigsawStructure structure, RNG rng, boolean ignoreBiomes) {
|
||||||
|
if (structure == null || structure.getDatapackStructures().isEmpty()) return false;
|
||||||
|
var keys = structure.getDatapackStructures().shuffleCopy(rng);
|
||||||
|
while (keys.isNotEmpty()) {
|
||||||
|
String key = keys.removeFirst();
|
||||||
|
if (key != null && placer.test(key, ignoreBiomes || structure.isForcePlace()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,6 @@ public class StructureKeyFunction implements ListFunction<KList<String>> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KList<String> apply(IrisData irisData) {
|
public KList<String> apply(IrisData irisData) {
|
||||||
return INMS.get().getStructureKeys();
|
return INMS.get().getStructureKeys().removeWhere(t -> t.startsWith("#"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.volmit.iris.engine.object.annotations.functions;
|
||||||
|
|
||||||
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
|
import com.volmit.iris.core.nms.INMS;
|
||||||
|
import com.volmit.iris.engine.framework.ListFunction;
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
|
||||||
|
public class StructureKeyOrTagFunction implements ListFunction<KList<String>> {
|
||||||
|
@Override
|
||||||
|
public String key() {
|
||||||
|
return "structure-key-or-tag";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String fancyName() {
|
||||||
|
return "Structure Key or Tag";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KList<String> apply(IrisData irisData) {
|
||||||
|
return INMS.get().getStructureKeys();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -169,15 +169,12 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
|
|
||||||
if (dimension == null) {
|
if (dimension == null) {
|
||||||
Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey);
|
Iris.error("Oh No! There's no pack in " + data.getDataFolder().getPath() + " or... there's no dimension for the key " + dimensionKey);
|
||||||
IrisDimension test = IrisData.loadAnyDimension(dimensionKey);
|
IrisDimension test = IrisData.loadAnyDimension(dimensionKey, null);
|
||||||
|
|
||||||
if (test != null) {
|
if (test != null) {
|
||||||
Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " ");
|
Iris.warn("Looks like " + dimensionKey + " exists in " + test.getLoadFile().getPath() + " ");
|
||||||
Iris.service(StudioSVC.class).installIntoWorld(Iris.getSender(), dimensionKey, dataLocation.getParentFile().getParentFile());
|
test = Iris.service(StudioSVC.class).installInto(Iris.getSender(), dimensionKey, dataLocation);
|
||||||
Iris.warn("Attempted to install into " + data.getDataFolder().getPath());
|
Iris.warn("Attempted to install into " + data.getDataFolder().getPath());
|
||||||
data.dump();
|
|
||||||
data.clearLists();
|
|
||||||
test = data.getDimensionLoader().load(dimensionKey);
|
|
||||||
|
|
||||||
if (test != null) {
|
if (test != null) {
|
||||||
Iris.success("Woo! Patched the Engine!");
|
Iris.success("Woo! Patched the Engine!");
|
||||||
@@ -240,11 +237,12 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
}
|
}
|
||||||
}, syncExecutor));
|
}, syncExecutor));
|
||||||
}
|
}
|
||||||
|
futures.add(CompletableFuture.runAsync(() -> INMS.get().placeStructures(c), syncExecutor));
|
||||||
|
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
|
||||||
.thenRunAsync(() -> {
|
.thenRunAsync(() -> {
|
||||||
c.removePluginChunkTicket(Iris.instance);
|
c.removePluginChunkTicket(Iris.instance);
|
||||||
c.unload();
|
engine.getWorldManager().onChunkLoad(c, true);
|
||||||
}, syncExecutor)
|
}, syncExecutor)
|
||||||
.get();
|
.get();
|
||||||
Iris.debug("Regenerated " + x + " " + z);
|
Iris.debug("Regenerated " + x + " " + z);
|
||||||
@@ -356,16 +354,16 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun
|
|||||||
@Override
|
@Override
|
||||||
public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) {
|
public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) {
|
||||||
try {
|
try {
|
||||||
getEngine(world);
|
Engine engine = getEngine(world);
|
||||||
computeStudioGenerator();
|
computeStudioGenerator();
|
||||||
TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage());
|
TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage());
|
||||||
this.world.bind(world);
|
this.world.bind(world);
|
||||||
if (studioGenerator != null) {
|
if (studioGenerator != null) {
|
||||||
studioGenerator.generateChunk(getEngine(), tc, x, z);
|
studioGenerator.generateChunk(engine, tc, x, z);
|
||||||
} else {
|
} else {
|
||||||
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
|
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
|
||||||
BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
|
BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
|
||||||
getEngine().generate(x << 4, z << 4, blocks, biomes, IrisSettings.get().getGenerator().useMulticore);
|
engine.generate(x << 4, z << 4, blocks, biomes, IrisSettings.get().getGenerator().useMulticore);
|
||||||
blocks.apply();
|
blocks.apply();
|
||||||
biomes.apply();
|
biomes.apply();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,15 +23,11 @@ import lombok.NonNull;
|
|||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.scoreboard.DisplaySlot;
|
import org.bukkit.scoreboard.*;
|
||||||
import org.bukkit.scoreboard.Objective;
|
|
||||||
import org.bukkit.scoreboard.Scoreboard;
|
|
||||||
import org.bukkit.scoreboard.Team;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.UnaryOperator;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,7 +38,7 @@ public class Board {
|
|||||||
|
|
||||||
private static final String[] CACHED_ENTRIES = new String[C.values().length];
|
private static final String[] CACHED_ENTRIES = new String[C.values().length];
|
||||||
|
|
||||||
private static final Function<String, String> APPLY_COLOR_TRANSLATION = s -> C.translateAlternateColorCodes('&', s);
|
private static final UnaryOperator<String> APPLY_COLOR_TRANSLATION = s -> C.translateAlternateColorCodes('&', s);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
IntStream.range(0, 15).forEach(i -> CACHED_ENTRIES[i] = C.values()[i].toString() + C.RESET);
|
IntStream.range(0, 15).forEach(i -> CACHED_ENTRIES[i] = C.values()[i].toString() + C.RESET);
|
||||||
@@ -54,13 +50,14 @@ public class Board {
|
|||||||
private BoardSettings boardSettings;
|
private BoardSettings boardSettings;
|
||||||
private boolean ready;
|
private boolean ready;
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public Board(@NonNull final Player player, final BoardSettings boardSettings) {
|
public Board(@NonNull final Player player, final BoardSettings boardSettings) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.boardSettings = boardSettings;
|
this.boardSettings = boardSettings;
|
||||||
this.objective = this.getScoreboard().getObjective("board") == null ? this.getScoreboard().registerNewObjective("board", "dummy") : this.getScoreboard().getObjective("board");
|
var obj = getScoreboard().getObjective("board");
|
||||||
|
this.objective = obj == null ? this.getScoreboard().registerNewObjective("board", Criteria.DUMMY, "Iris") : obj;
|
||||||
this.objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
this.objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
||||||
Team team = this.getScoreboard().getTeam("board") == null ? this.getScoreboard().registerNewTeam("board") : this.getScoreboard().getTeam("board");
|
Team team = getScoreboard().getTeam("board");
|
||||||
|
team = team == null ? getScoreboard().registerNewTeam("board") : team;
|
||||||
team.setAllowFriendlyFire(true);
|
team.setAllowFriendlyFire(true);
|
||||||
team.setCanSeeFriendlyInvisibles(false);
|
team.setCanSeeFriendlyInvisibles(false);
|
||||||
team.setPrefix("");
|
team.setPrefix("");
|
||||||
@@ -94,7 +91,8 @@ public class Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Getting their Scoreboard display from the Scoreboard Provider.
|
// Getting their Scoreboard display from the Scoreboard Provider.
|
||||||
final List<String> entries = boardSettings.getBoardProvider().getLines(player).stream().map(APPLY_COLOR_TRANSLATION).collect(Collectors.toList());
|
final List<String> entries = boardSettings.getBoardProvider().getLines(player);
|
||||||
|
entries.replaceAll(APPLY_COLOR_TRANSLATION);
|
||||||
|
|
||||||
if (boardSettings.getScoreDirection() == ScoreDirection.UP) {
|
if (boardSettings.getScoreDirection() == ScoreDirection.UP) {
|
||||||
Collections.reverse(entries);
|
Collections.reverse(entries);
|
||||||
|
|||||||
@@ -37,6 +37,12 @@ public class BoardUpdateTask implements Runnable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
boardManager.getScoreboards().entrySet().stream().filter(entrySet -> PLAYER_IS_ONLINE.test(entrySet.getKey())).forEach(entrySet -> entrySet.getValue().update());
|
for (var entry : boardManager.getScoreboards().entrySet()) {
|
||||||
|
if (!PLAYER_IS_ONLINE.test(entry.getKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.getValue().update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.AbstractSet;
|
import java.util.AbstractSet;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@@ -30,13 +31,15 @@ public class KSet<T> extends AbstractSet<T> implements Serializable {
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private final ConcurrentHashMap<T, Boolean> map;
|
private final ConcurrentHashMap<T, Boolean> map;
|
||||||
|
|
||||||
public KSet() {
|
public KSet(Collection<? extends T> c) {
|
||||||
map = new ConcurrentHashMap<>();
|
this(c.size());
|
||||||
|
addAll(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
public KSet(Collection<? extends T> c) {
|
@SafeVarargs
|
||||||
this();
|
public KSet(T... values) {
|
||||||
addAll(c);
|
this(values.length);
|
||||||
|
addAll(Arrays.asList(values));
|
||||||
}
|
}
|
||||||
|
|
||||||
public KSet(int initialCapacity, float loadFactor) {
|
public KSet(int initialCapacity, float loadFactor) {
|
||||||
@@ -47,6 +50,13 @@ public class KSet<T> extends AbstractSet<T> implements Serializable {
|
|||||||
map = new ConcurrentHashMap<>(initialCapacity);
|
map = new ConcurrentHashMap<>(initialCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> KSet<T> merge(Collection<? extends T> first, Collection<? extends T> second) {
|
||||||
|
var set = new KSet<T>();
|
||||||
|
set.addAll(first);
|
||||||
|
set.addAll(second);
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return map.size();
|
return map.size();
|
||||||
|
|||||||
@@ -498,7 +498,7 @@ public class B {
|
|||||||
if (!ix.startsWith("minecraft:") && ix.contains(":")) {
|
if (!ix.startsWith("minecraft:") && ix.contains(":")) {
|
||||||
Identifier key = Identifier.fromString(ix);
|
Identifier key = Identifier.fromString(ix);
|
||||||
Optional<BlockData> bd = Iris.service(ExternalDataSVC.class).getBlockData(key);
|
Optional<BlockData> bd = Iris.service(ExternalDataSVC.class).getBlockData(key);
|
||||||
Iris.info("Loading block data " + key);
|
Iris.debug("Loading block data " + key);
|
||||||
if (bd.isPresent())
|
if (bd.isPresent())
|
||||||
bx = bd.get();
|
bx = bd.get();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,29 +18,20 @@
|
|||||||
|
|
||||||
package com.volmit.iris.util.decree;
|
package com.volmit.iris.util.decree;
|
||||||
|
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.plugin.VolmitSender;
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
|
||||||
|
|
||||||
public class DecreeContext {
|
public class DecreeContext {
|
||||||
private static final ChronoLatch cl = new ChronoLatch(60000);
|
private static final ThreadLocal<VolmitSender> context = new ThreadLocal<>();
|
||||||
private static final KMap<Thread, VolmitSender> context = new KMap<>();
|
|
||||||
|
|
||||||
public static VolmitSender get() {
|
public static VolmitSender get() {
|
||||||
return context.get(Thread.currentThread());
|
return context.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void touch(VolmitSender c) {
|
public static void touch(VolmitSender c) {
|
||||||
synchronized (context) {
|
context.set(c);
|
||||||
context.put(Thread.currentThread(), c);
|
}
|
||||||
|
|
||||||
if (cl.flip()) {
|
public static void remove() {
|
||||||
for (Thread i : context.k()) {
|
context.remove();
|
||||||
if (!i.isAlive()) {
|
|
||||||
context.remove(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package com.volmit.iris.util.decree;
|
package com.volmit.iris.util.decree;
|
||||||
|
|
||||||
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
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.platform.PlatformChunkGenerator;
|
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||||
@@ -34,6 +35,14 @@ public interface DecreeExecutor {
|
|||||||
return sender().player();
|
return sender().player();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default IrisData data() {
|
||||||
|
var access = access();
|
||||||
|
if (access != null) {
|
||||||
|
return access.getData();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
default Engine engine() {
|
default Engine engine() {
|
||||||
if (sender().isPlayer() && IrisToolbelt.access(sender().player().getWorld()) != null) {
|
if (sender().isPlayer() && IrisToolbelt.access(sender().player().getWorld()) != null) {
|
||||||
PlatformChunkGenerator gen = IrisToolbelt.access(sender().player().getWorld());
|
PlatformChunkGenerator gen = IrisToolbelt.access(sender().player().getWorld());
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
|||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
public interface DecreeParameterHandler<T> {
|
public interface DecreeParameterHandler<T> extends DecreeExecutor {
|
||||||
/**
|
/**
|
||||||
* Should return the possible values for this type
|
* Should return the possible values for this type
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -133,12 +133,18 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter {
|
|||||||
|
|
||||||
default boolean call(VolmitSender sender, String[] args) {
|
default boolean call(VolmitSender sender, String[] args) {
|
||||||
DecreeContext.touch(sender);
|
DecreeContext.touch(sender);
|
||||||
|
try {
|
||||||
return getRoot().invoke(sender, enhanceArgs(args));
|
return getRoot().invoke(sender, enhanceArgs(args));
|
||||||
|
} finally {
|
||||||
|
DecreeContext.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
default List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
|
default List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
|
||||||
|
DecreeContext.touch(new VolmitSender(sender));
|
||||||
|
try {
|
||||||
KList<String> enhanced = new KList<>(args);
|
KList<String> enhanced = new KList<>(args);
|
||||||
KList<String> v = getRoot().tabComplete(enhanced, enhanced.toString(" "));
|
KList<String> v = getRoot().tabComplete(enhanced, enhanced.toString(" "));
|
||||||
v.removeDuplicates();
|
v.removeDuplicates();
|
||||||
@@ -150,6 +156,9 @@ public interface DecreeSystem extends CommandExecutor, TabCompleter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
|
} finally {
|
||||||
|
DecreeContext.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,63 +18,12 @@
|
|||||||
|
|
||||||
package com.volmit.iris.util.decree.handlers;
|
package com.volmit.iris.util.decree.handlers;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
|
||||||
import com.volmit.iris.engine.object.IrisBiome;
|
import com.volmit.iris.engine.object.IrisBiome;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.decree.DecreeParameterHandler;
|
|
||||||
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
|
||||||
|
|
||||||
import java.io.File;
|
public class BiomeHandler extends RegistrantHandler<IrisBiome> {
|
||||||
import java.util.stream.Collectors;
|
public BiomeHandler() {
|
||||||
|
super(IrisBiome.class, true);
|
||||||
public class BiomeHandler implements DecreeParameterHandler<IrisBiome> {
|
|
||||||
@Override
|
|
||||||
public KList<IrisBiome> getPossibilities() {
|
|
||||||
KMap<String, IrisBiome> p = new KMap<>();
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
|
||||||
if (i.isDirectory()) {
|
|
||||||
IrisData data = IrisData.get(i);
|
|
||||||
for (IrisBiome j : data.getBiomeLoader().loadAll(data.getBiomeLoader().getPossibleKeys())) {
|
|
||||||
p.putIfAbsent(j.getLoadKey(), j);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.v();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(IrisBiome dim) {
|
|
||||||
return dim.getLoadKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IrisBiome parse(String in, boolean force) throws DecreeParsingException {
|
|
||||||
if (in.equals("null")) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
KList<IrisBiome> options = getPossibilities(in);
|
|
||||||
|
|
||||||
if (options.isEmpty()) {
|
|
||||||
throw new DecreeParsingException("Unable to find Biome \"" + in + "\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
throw new DecreeParsingException("Unable to filter which Biome \"" + in + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> type) {
|
|
||||||
return type.equals(IrisBiome.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,62 +18,12 @@
|
|||||||
|
|
||||||
package com.volmit.iris.util.decree.handlers;
|
package com.volmit.iris.util.decree.handlers;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
|
||||||
import com.volmit.iris.engine.object.IrisCave;
|
import com.volmit.iris.engine.object.IrisCave;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.decree.DecreeParameterHandler;
|
|
||||||
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
|
||||||
|
|
||||||
import java.io.File;
|
public class CaveHandler extends RegistrantHandler<IrisCave> {
|
||||||
import java.util.stream.Collectors;
|
public CaveHandler() {
|
||||||
|
super(IrisCave.class, true);
|
||||||
public class CaveHandler implements DecreeParameterHandler<IrisCave> {
|
|
||||||
@Override
|
|
||||||
public KList<IrisCave> getPossibilities() {
|
|
||||||
KMap<String, IrisCave> p = new KMap<>();
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
|
||||||
if (i.isDirectory()) {
|
|
||||||
IrisData data = IrisData.get(i);
|
|
||||||
for (IrisCave j : data.getCaveLoader().loadAll(data.getCaveLoader().getPossibleKeys())) {
|
|
||||||
p.putIfAbsent(j.getLoadKey(), j);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.v();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(IrisCave dim) {
|
|
||||||
return dim.getLoadKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IrisCave parse(String in, boolean force) throws DecreeParsingException {
|
|
||||||
if (in.equals("null")) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
KList<IrisCave> options = getPossibilities(in);
|
|
||||||
|
|
||||||
if (options.isEmpty()) {
|
|
||||||
throw new DecreeParsingException("Unable to find Cave \"" + in + "\"");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
throw new DecreeParsingException("Unable to filter which Cave\"" + in + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> type) {
|
|
||||||
return type.equals(IrisCave.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,65 +18,22 @@
|
|||||||
|
|
||||||
package com.volmit.iris.util.decree.handlers;
|
package com.volmit.iris.util.decree.handlers;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.IrisSettings;
|
import com.volmit.iris.core.IrisSettings;
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
|
||||||
import com.volmit.iris.engine.object.IrisDimension;
|
import com.volmit.iris.engine.object.IrisDimension;
|
||||||
import com.volmit.iris.util.collection.KList;
|
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.decree.DecreeParameterHandler;
|
|
||||||
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
||||||
|
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
|
||||||
|
|
||||||
import java.io.File;
|
public class DimensionHandler extends RegistrantHandler<IrisDimension> {
|
||||||
|
public DimensionHandler() {
|
||||||
public class DimensionHandler implements DecreeParameterHandler<IrisDimension> {
|
super(IrisDimension.class, false);
|
||||||
@Override
|
|
||||||
public KList<IrisDimension> getPossibilities() {
|
|
||||||
KMap<String, IrisDimension> p = new KMap<>();
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
|
||||||
if (i.isDirectory()) {
|
|
||||||
IrisData data = IrisData.get(i);
|
|
||||||
for (IrisDimension j : data.getDimensionLoader().loadAll(data.getDimensionLoader().getPossibleKeys())) {
|
|
||||||
p.putIfAbsent(j.getLoadKey(), j);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.v();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(IrisDimension dim) {
|
|
||||||
return dim.getLoadKey();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IrisDimension parse(String in, boolean force) throws DecreeParsingException {
|
public IrisDimension parse(String in, boolean force) throws DecreeParsingException {
|
||||||
|
|
||||||
if (in.equalsIgnoreCase("default")) {
|
if (in.equalsIgnoreCase("default")) {
|
||||||
return parse(IrisSettings.get().getGenerator().getDefaultWorldType());
|
return parse(IrisSettings.get().getGenerator().getDefaultWorldType());
|
||||||
}
|
}
|
||||||
|
return super.parse(in, force);
|
||||||
KList<IrisDimension> options = getPossibilities(in);
|
|
||||||
|
|
||||||
|
|
||||||
if (options.isEmpty()) {
|
|
||||||
throw new DecreeParsingException("Unable to find Dimension \"" + in + "\"");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).toList().get(0);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
throw new DecreeParsingException("Unable to filter which Dimension \"" + in + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> type) {
|
|
||||||
return type.equals(IrisDimension.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,84 +18,13 @@
|
|||||||
|
|
||||||
package com.volmit.iris.util.decree.handlers;
|
package com.volmit.iris.util.decree.handlers;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
|
||||||
import com.volmit.iris.engine.object.IrisEntity;
|
import com.volmit.iris.engine.object.IrisEntity;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.decree.DecreeParameterHandler;
|
|
||||||
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
|
||||||
|
|
||||||
import java.io.File;
|
public class EntityHandler extends RegistrantHandler<IrisEntity> {
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class EntityHandler implements DecreeParameterHandler<IrisEntity> {
|
public EntityHandler() {
|
||||||
|
super(IrisEntity.class, false);
|
||||||
/**
|
|
||||||
* Should return the possible values for this type
|
|
||||||
*
|
|
||||||
* @return Possibilities for this type.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public KList<IrisEntity> getPossibilities() {
|
|
||||||
KMap<String, IrisEntity> p = new KMap<>();
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
|
||||||
if (i.isDirectory()) {
|
|
||||||
IrisData data = IrisData.get(i);
|
|
||||||
for (IrisEntity j : data.getEntityLoader().loadAll(data.getEntityLoader().getPossibleKeys())) {
|
|
||||||
p.putIfAbsent(j.getLoadKey(), j);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.v();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converting the type back to a string (inverse of the {@link #parse(String) parse} method)
|
|
||||||
*
|
|
||||||
* @param entity The input of the designated type to convert to a String
|
|
||||||
* @return The resulting string
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString(IrisEntity entity) {
|
|
||||||
return entity.getLoadKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should parse a String into the designated type
|
|
||||||
*
|
|
||||||
* @param in The string to parse
|
|
||||||
* @return The value extracted from the string, of the designated type
|
|
||||||
* @throws DecreeParsingException Thrown when the parsing fails (ex: "oop" translated to an integer throws this)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public IrisEntity parse(String in, boolean force) throws DecreeParsingException {
|
|
||||||
KList<IrisEntity> options = getPossibilities(in);
|
|
||||||
|
|
||||||
if (options.isEmpty()) {
|
|
||||||
throw new DecreeParsingException("Unable to find Entity \"" + in + "\"");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
throw new DecreeParsingException("Unable to filter which Entity \"" + in + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether a certain type is supported by this handler<br>
|
|
||||||
*
|
|
||||||
* @param type The type to check
|
|
||||||
* @return True if supported, false if not
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> type) {
|
|
||||||
return type.equals(IrisEntity.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,59 +18,12 @@
|
|||||||
|
|
||||||
package com.volmit.iris.util.decree.handlers;
|
package com.volmit.iris.util.decree.handlers;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
|
||||||
import com.volmit.iris.engine.object.IrisGenerator;
|
import com.volmit.iris.engine.object.IrisGenerator;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.decree.DecreeParameterHandler;
|
|
||||||
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
|
||||||
|
|
||||||
import java.io.File;
|
public class GeneratorHandler extends RegistrantHandler<IrisGenerator> {
|
||||||
import java.util.stream.Collectors;
|
public GeneratorHandler() {
|
||||||
|
super(IrisGenerator.class, false);
|
||||||
public class GeneratorHandler implements DecreeParameterHandler<IrisGenerator> {
|
|
||||||
@Override
|
|
||||||
public KList<IrisGenerator> getPossibilities() {
|
|
||||||
KMap<String, IrisGenerator> p = new KMap<>();
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
|
||||||
if (i.isDirectory()) {
|
|
||||||
IrisData data = IrisData.get(i);
|
|
||||||
for (IrisGenerator j : data.getGeneratorLoader().loadAll(data.getGeneratorLoader().getPossibleKeys())) {
|
|
||||||
p.putIfAbsent(j.getLoadKey(), j);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.v();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(IrisGenerator gen) {
|
|
||||||
return gen.getLoadKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IrisGenerator parse(String in, boolean force) throws DecreeParsingException {
|
|
||||||
KList<IrisGenerator> options = getPossibilities(in);
|
|
||||||
|
|
||||||
if (options.isEmpty()) {
|
|
||||||
throw new DecreeParsingException("Unable to find Generator \"" + in + "\"");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
throw new DecreeParsingException("Unable to filter which Generator \"" + in + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> type) {
|
|
||||||
return type.equals(IrisGenerator.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,62 +18,12 @@
|
|||||||
|
|
||||||
package com.volmit.iris.util.decree.handlers;
|
package com.volmit.iris.util.decree.handlers;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
|
||||||
import com.volmit.iris.engine.object.IrisJigsawPiece;
|
import com.volmit.iris.engine.object.IrisJigsawPiece;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.decree.DecreeParameterHandler;
|
|
||||||
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
|
||||||
|
|
||||||
import java.io.File;
|
public class JigsawPieceHandler extends RegistrantHandler<IrisJigsawPiece> {
|
||||||
import java.util.stream.Collectors;
|
public JigsawPieceHandler() {
|
||||||
|
super(IrisJigsawPiece.class, true);
|
||||||
public class JigsawPieceHandler implements DecreeParameterHandler<IrisJigsawPiece> {
|
|
||||||
@Override
|
|
||||||
public KList<IrisJigsawPiece> getPossibilities() {
|
|
||||||
KMap<String, IrisJigsawPiece> p = new KMap<>();
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
|
||||||
if (i.isDirectory()) {
|
|
||||||
IrisData data = IrisData.get(i);
|
|
||||||
for (IrisJigsawPiece j : data.getJigsawPieceLoader().loadAll(data.getJigsawPieceLoader().getPossibleKeys())) {
|
|
||||||
p.putIfAbsent(j.getLoadKey(), j);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.v();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(IrisJigsawPiece dim) {
|
|
||||||
return dim.getLoadKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IrisJigsawPiece parse(String in, boolean force) throws DecreeParsingException {
|
|
||||||
if (in.equals("null")) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
KList<IrisJigsawPiece> options = getPossibilities(in);
|
|
||||||
|
|
||||||
if (options.isEmpty()) {
|
|
||||||
throw new DecreeParsingException("Unable to find Jigsaw Piece \"" + in + "\"");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
throw new DecreeParsingException("Unable to filter which Jigsaw Piece \"" + in + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> type) {
|
|
||||||
return type.equals(IrisJigsawPiece.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,62 +18,12 @@
|
|||||||
|
|
||||||
package com.volmit.iris.util.decree.handlers;
|
package com.volmit.iris.util.decree.handlers;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
|
||||||
import com.volmit.iris.engine.object.IrisJigsawPool;
|
import com.volmit.iris.engine.object.IrisJigsawPool;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.decree.DecreeParameterHandler;
|
|
||||||
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
|
||||||
|
|
||||||
import java.io.File;
|
public class JigsawPoolHandler extends RegistrantHandler<IrisJigsawPool> {
|
||||||
import java.util.stream.Collectors;
|
public JigsawPoolHandler() {
|
||||||
|
super(IrisJigsawPool.class, true);
|
||||||
public class JigsawPoolHandler implements DecreeParameterHandler<IrisJigsawPool> {
|
|
||||||
@Override
|
|
||||||
public KList<IrisJigsawPool> getPossibilities() {
|
|
||||||
KMap<String, IrisJigsawPool> p = new KMap<>();
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
|
||||||
if (i.isDirectory()) {
|
|
||||||
IrisData data = IrisData.get(i);
|
|
||||||
for (IrisJigsawPool j : data.getJigsawPoolLoader().loadAll(data.getJigsawPoolLoader().getPossibleKeys())) {
|
|
||||||
p.putIfAbsent(j.getLoadKey(), j);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.v();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(IrisJigsawPool dim) {
|
|
||||||
return dim.getLoadKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IrisJigsawPool parse(String in, boolean force) throws DecreeParsingException {
|
|
||||||
if (in.equals("null")) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
KList<IrisJigsawPool> options = getPossibilities(in);
|
|
||||||
|
|
||||||
if (options.isEmpty()) {
|
|
||||||
throw new DecreeParsingException("Unable to find Jigsaw Pool \"" + in + "\"");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
throw new DecreeParsingException("Unable to filter which Jigsaw Pool \"" + in + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> type) {
|
|
||||||
return type.equals(IrisJigsawPool.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,62 +18,12 @@
|
|||||||
|
|
||||||
package com.volmit.iris.util.decree.handlers;
|
package com.volmit.iris.util.decree.handlers;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.decree.DecreeParameterHandler;
|
|
||||||
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
|
||||||
|
|
||||||
import java.io.File;
|
public class JigsawStructureHandler extends RegistrantHandler<IrisJigsawStructure> {
|
||||||
import java.util.stream.Collectors;
|
public JigsawStructureHandler() {
|
||||||
|
super(IrisJigsawStructure.class, true);
|
||||||
public class JigsawStructureHandler implements DecreeParameterHandler<IrisJigsawStructure> {
|
|
||||||
@Override
|
|
||||||
public KList<IrisJigsawStructure> getPossibilities() {
|
|
||||||
KMap<String, IrisJigsawStructure> p = new KMap<>();
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
|
||||||
if (i.isDirectory()) {
|
|
||||||
IrisData data = IrisData.get(i);
|
|
||||||
for (IrisJigsawStructure j : data.getJigsawStructureLoader().loadAll(data.getJigsawStructureLoader().getPossibleKeys())) {
|
|
||||||
p.putIfAbsent(j.getLoadKey(), j);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.v();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(IrisJigsawStructure dim) {
|
|
||||||
return dim.getLoadKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IrisJigsawStructure parse(String in, boolean force) throws DecreeParsingException {
|
|
||||||
if (in.equals("null")) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
KList<IrisJigsawStructure> options = getPossibilities(in);
|
|
||||||
|
|
||||||
if (options.isEmpty()) {
|
|
||||||
throw new DecreeParsingException("Unable to find Jigsaw Structure \"" + in + "\"");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
throw new DecreeParsingException("Unable to filter which Jigsaw Structure \"" + in + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> type) {
|
|
||||||
return type.equals(IrisJigsawStructure.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,62 +18,12 @@
|
|||||||
|
|
||||||
package com.volmit.iris.util.decree.handlers;
|
package com.volmit.iris.util.decree.handlers;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
|
||||||
import com.volmit.iris.engine.object.IrisRegion;
|
import com.volmit.iris.engine.object.IrisRegion;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.decree.DecreeParameterHandler;
|
|
||||||
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
|
||||||
|
|
||||||
import java.io.File;
|
public class RegionHandler extends RegistrantHandler<IrisRegion> {
|
||||||
import java.util.stream.Collectors;
|
public RegionHandler() {
|
||||||
|
super(IrisRegion.class, true);
|
||||||
public class RegionHandler implements DecreeParameterHandler<IrisRegion> {
|
|
||||||
@Override
|
|
||||||
public KList<IrisRegion> getPossibilities() {
|
|
||||||
KMap<String, IrisRegion> p = new KMap<>();
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
|
||||||
if (i.isDirectory()) {
|
|
||||||
IrisData data = IrisData.get(i);
|
|
||||||
for (IrisRegion j : data.getRegionLoader().loadAll(data.getRegionLoader().getPossibleKeys())) {
|
|
||||||
p.putIfAbsent(j.getLoadKey(), j);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.v();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(IrisRegion dim) {
|
|
||||||
return dim.getLoadKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IrisRegion parse(String in, boolean force) throws DecreeParsingException {
|
|
||||||
if (in.equals("null")) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
KList<IrisRegion> options = getPossibilities(in);
|
|
||||||
|
|
||||||
if (options.isEmpty()) {
|
|
||||||
throw new DecreeParsingException("Unable to find Region \"" + in + "\"");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
throw new DecreeParsingException("Unable to filter which Region \"" + in + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> type) {
|
|
||||||
return type.equals(IrisRegion.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -18,59 +18,12 @@
|
|||||||
|
|
||||||
package com.volmit.iris.util.decree.handlers;
|
package com.volmit.iris.util.decree.handlers;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
|
||||||
import com.volmit.iris.engine.object.IrisScript;
|
import com.volmit.iris.engine.object.IrisScript;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.decree.specialhandlers.RegistrantHandler;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.decree.DecreeParameterHandler;
|
|
||||||
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
|
||||||
|
|
||||||
import java.io.File;
|
public class ScriptHandler extends RegistrantHandler<IrisScript> {
|
||||||
import java.util.stream.Collectors;
|
public ScriptHandler() {
|
||||||
|
super(IrisScript.class, false);
|
||||||
public class ScriptHandler implements DecreeParameterHandler<IrisScript> {
|
|
||||||
@Override
|
|
||||||
public KList<IrisScript> getPossibilities() {
|
|
||||||
KMap<String, IrisScript> p = new KMap<>();
|
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
|
||||||
if (i.isDirectory()) {
|
|
||||||
IrisData data = IrisData.get(i);
|
|
||||||
for (IrisScript j : data.getScriptLoader().loadAll(data.getScriptLoader().getPossibleKeys())) {
|
|
||||||
p.putIfAbsent(j.getLoadKey(), j);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.v();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(IrisScript script) {
|
|
||||||
return script.getLoadKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IrisScript parse(String in, boolean force) throws DecreeParsingException {
|
|
||||||
KList<IrisScript> options = getPossibilities(in);
|
|
||||||
|
|
||||||
if (options.isEmpty()) {
|
|
||||||
throw new DecreeParsingException("Unable to find Script \"" + in + "\"");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return options.stream().filter((i) -> toString(i).equalsIgnoreCase(in)).collect(Collectors.toList()).get(0);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
throw new DecreeParsingException("Unable to filter which Script \"" + in + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> type) {
|
|
||||||
return type.equals(IrisScript.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -16,28 +16,27 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.volmit.iris.engine.object;
|
package com.volmit.iris.util.decree.specialhandlers;
|
||||||
|
|
||||||
import com.volmit.iris.engine.object.annotations.*;
|
import com.volmit.iris.core.IrisSettings;
|
||||||
import lombok.AllArgsConstructor;
|
import com.volmit.iris.engine.object.IrisDimension;
|
||||||
import lombok.Data;
|
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
@Snippet("jigsaw-placer")
|
public class NullableDimensionHandler extends RegistrantHandler<IrisDimension> {
|
||||||
@Accessors(chain = true)
|
public NullableDimensionHandler() {
|
||||||
@NoArgsConstructor
|
super(IrisDimension.class, true);
|
||||||
@AllArgsConstructor
|
}
|
||||||
@Desc("Represents a jigsaw placement")
|
|
||||||
@Data
|
|
||||||
public class IrisJigsawPlacement {
|
|
||||||
@RegistryListResource(IrisJigsawStructure.class)
|
|
||||||
@Required
|
|
||||||
@Desc("The jigsaw structure to use")
|
|
||||||
private String structure = "";
|
|
||||||
|
|
||||||
@Required
|
@Override
|
||||||
@MinNumber(1)
|
public IrisDimension parse(String in, boolean force) throws DecreeParsingException {
|
||||||
@Desc("The rarity for this jigsaw structure to place on a per chunk basis")
|
if (in.equalsIgnoreCase("default")) {
|
||||||
private int rarity = 29;
|
return parse(IrisSettings.get().getGenerator().getDefaultWorldType());
|
||||||
|
}
|
||||||
|
return super.parse(in, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRandomDefault() {
|
||||||
|
return "dimension";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -31,11 +31,15 @@ public class ObjectHandler implements DecreeParameterHandler<String> {
|
|||||||
@Override
|
@Override
|
||||||
public KList<String> getPossibilities() {
|
public KList<String> getPossibilities() {
|
||||||
KList<String> p = new KList<>();
|
KList<String> p = new KList<>();
|
||||||
|
IrisData data = data();
|
||||||
|
if (data != null) {
|
||||||
|
return new KList<>(data.getObjectLoader().getPossibleKeys());
|
||||||
|
}
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
||||||
if (i.isDirectory()) {
|
if (i.isDirectory()) {
|
||||||
IrisData data = IrisData.get(i);
|
data = IrisData.get(i);
|
||||||
p.add(data.getObjectLoader().getPossibleKeys());
|
p.add(data.getObjectLoader().getPossibleKeys());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package com.volmit.iris.util.decree.specialhandlers;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
|
import com.volmit.iris.core.loader.IrisRegistrant;
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import com.volmit.iris.util.decree.DecreeParameterHandler;
|
||||||
|
import com.volmit.iris.util.decree.exceptions.DecreeParsingException;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public abstract class RegistrantHandler<T extends IrisRegistrant> implements DecreeParameterHandler<T> {
|
||||||
|
private final Class<T> type;
|
||||||
|
private final String name;
|
||||||
|
private final boolean nullable;
|
||||||
|
|
||||||
|
public RegistrantHandler(Class<T> type, boolean nullable) {
|
||||||
|
this.type = type;
|
||||||
|
this.name = type.getSimpleName().replaceFirst("Iris", "");
|
||||||
|
this.nullable = nullable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KList<T> getPossibilities() {
|
||||||
|
KList<T> p = new KList<>();
|
||||||
|
Set<String> known = new HashSet<>();
|
||||||
|
IrisData data = data();
|
||||||
|
if (data != null) {
|
||||||
|
for (T j : data.getLoader(type).loadAll(data.getLoader(type).getPossibleKeys())) {
|
||||||
|
known.add(j.getLoadKey());
|
||||||
|
p.add(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
for (File i : Iris.instance.getDataFolder("packs").listFiles()) {
|
||||||
|
if (i.isDirectory()) {
|
||||||
|
data = IrisData.get(i);
|
||||||
|
for (T j : data.getLoader(type).loadAll(data.getLoader(type).getPossibleKeys())) {
|
||||||
|
if (known.add(j.getLoadKey()))
|
||||||
|
p.add(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(T t) {
|
||||||
|
return t != null ? t.getLoadKey() : "null";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T parse(String in, boolean force) throws DecreeParsingException {
|
||||||
|
if (in.equals("null") && nullable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
KList<T> options = getPossibilities(in);
|
||||||
|
if (options.isEmpty()) {
|
||||||
|
throw new DecreeParsingException("Unable to find " + name + " \"" + in + "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
return options.stream()
|
||||||
|
.filter((i) -> toString(i).equalsIgnoreCase(in))
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(() -> new DecreeParsingException("Unable to filter which " + name + " \"" + in + "\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(Class<?> type) {
|
||||||
|
return type.equals(this.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -478,14 +478,17 @@ public class VirtualDecreeCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DecreeContext.touch(sender);
|
DecreeContext.touch(sender);
|
||||||
Runnable rx = () -> {
|
|
||||||
try {
|
try {
|
||||||
|
Runnable rx = () -> {
|
||||||
DecreeContext.touch(sender);
|
DecreeContext.touch(sender);
|
||||||
|
try {
|
||||||
getNode().getMethod().setAccessible(true);
|
getNode().getMethod().setAccessible(true);
|
||||||
getNode().getMethod().invoke(getNode().getInstance(), params);
|
getNode().getMethod().invoke(getNode().getInstance(), params);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw new RuntimeException("Failed to execute <INSERT REAL NODE HERE>"); // TODO:
|
throw new RuntimeException("Failed to execute <INSERT REAL NODE HERE>"); // TODO:
|
||||||
|
} finally {
|
||||||
|
DecreeContext.remove();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -494,6 +497,9 @@ public class VirtualDecreeCommand {
|
|||||||
} else {
|
} else {
|
||||||
rx.run();
|
rx.run();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
DecreeContext.remove();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,6 +179,8 @@ public class IO {
|
|||||||
JsonElement json;
|
JsonElement json;
|
||||||
try (FileReader reader = new FileReader(file)) {
|
try (FileReader reader = new FileReader(file)) {
|
||||||
json = JsonParser.parseReader(reader);
|
json = JsonParser.parseReader(reader);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new IOException("Failed to read json file " + file, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
var queue = new LinkedList<JsonElement>();
|
var queue = new LinkedList<JsonElement>();
|
||||||
@@ -1705,6 +1707,7 @@ public class IO {
|
|||||||
action.accept(out);
|
action.accept(out);
|
||||||
}
|
}
|
||||||
Files.copy(temp.toPath(), Channels.newOutputStream(target));
|
Files.copy(temp.toPath(), Channels.newOutputStream(target));
|
||||||
|
target.truncate(temp.length());
|
||||||
} finally {
|
} finally {
|
||||||
temp.delete();
|
temp.delete();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ public class ReactiveFolder {
|
|||||||
|
|
||||||
if (checkCycle % 3 == 0 ? fw.checkModified() : fw.checkModifiedFast()) {
|
if (checkCycle % 3 == 0 ? fw.checkModified() : fw.checkModifiedFast()) {
|
||||||
for (File i : fw.getCreated()) {
|
for (File i : fw.getCreated()) {
|
||||||
if (i.getName().endsWith(".iob") || i.getName().endsWith(".json") || i.getName().endsWith(".js")) {
|
if (i.getName().endsWith(".iob") || i.getName().endsWith(".json") || i.getName().endsWith(".kts")) {
|
||||||
if (i.getPath().contains(".iris")) {
|
if (i.getPath().contains(".iris") || i.getName().endsWith(".gradle.kts")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,11 +58,11 @@ public class ReactiveFolder {
|
|||||||
|
|
||||||
if (!modified) {
|
if (!modified) {
|
||||||
for (File i : fw.getChanged()) {
|
for (File i : fw.getChanged()) {
|
||||||
if (i.getPath().contains(".iris")) {
|
if (i.getPath().contains(".iris") || i.getName().endsWith(".gradle.kts")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i.getName().endsWith(".iob") || i.getName().endsWith(".json") || i.getName().endsWith(".js")) {
|
if (i.getName().endsWith(".iob") || i.getName().endsWith(".json") || i.getName().endsWith(".kts")) {
|
||||||
modified = true;
|
modified = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -71,11 +71,11 @@ public class ReactiveFolder {
|
|||||||
|
|
||||||
if (!modified) {
|
if (!modified) {
|
||||||
for (File i : fw.getDeleted()) {
|
for (File i : fw.getDeleted()) {
|
||||||
if (i.getPath().contains(".iris")) {
|
if (i.getPath().contains(".iris") || i.getName().endsWith(".gradle.kts")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i.getName().endsWith(".iob") || i.getName().endsWith(".json") || i.getName().endsWith(".js")) {
|
if (i.getName().endsWith(".iob") || i.getName().endsWith(".json") || i.getName().endsWith(".kts")) {
|
||||||
modified = true;
|
modified = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,6 +181,11 @@ public class MantleChunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void raiseFlagUnchecked(MantleFlag flag, Runnable r) {
|
||||||
|
if (closed.get()) throw new IllegalStateException("Chunk is closed!");
|
||||||
|
if (flags.compareAndSet(flag.ordinal(), false, true)) r.run();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isFlagged(MantleFlag flag) {
|
public boolean isFlagged(MantleFlag flag) {
|
||||||
return flags.get(flag.ordinal());
|
return flags.get(flag.ordinal());
|
||||||
}
|
}
|
||||||
@@ -266,7 +271,7 @@ public class MantleChunk {
|
|||||||
dos.writeByte(x);
|
dos.writeByte(x);
|
||||||
dos.writeByte(z);
|
dos.writeByte(z);
|
||||||
dos.writeByte(sections.length());
|
dos.writeByte(sections.length());
|
||||||
Varint.writeUnsignedVarInt(Math.ceilDiv(flags.length(), Byte.SIZE), dos);
|
Varint.writeUnsignedVarInt(flags.length(), dos);
|
||||||
|
|
||||||
int count = flags.length();
|
int count = flags.length();
|
||||||
for (int i = 0; i < count;) {
|
for (int i = 0; i < count;) {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.volmit.iris.util.misc;
|
package com.volmit.iris.util.misc;
|
||||||
|
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
import com.volmit.iris.BuildConstants;
|
||||||
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.nms.INMS;
|
import com.volmit.iris.core.nms.INMS;
|
||||||
@@ -19,19 +21,12 @@ import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
|||||||
import net.kyori.adventure.text.serializer.ComponentSerializer;
|
import net.kyori.adventure.text.serializer.ComponentSerializer;
|
||||||
import org.bstats.bukkit.Metrics;
|
import org.bstats.bukkit.Metrics;
|
||||||
import org.bstats.charts.DrilldownPie;
|
import org.bstats.charts.DrilldownPie;
|
||||||
import org.bstats.charts.SimplePie;
|
|
||||||
import org.bstats.charts.SingleLineChart;
|
import org.bstats.charts.SingleLineChart;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import oshi.SystemInfo;
|
|
||||||
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.text.NumberFormat;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -47,8 +42,6 @@ public class Bindings {
|
|||||||
if (settings.disableAutoReporting || Sentry.isEnabled() || Boolean.getBoolean("iris.suppressReporting")) return;
|
if (settings.disableAutoReporting || Sentry.isEnabled() || Boolean.getBoolean("iris.suppressReporting")) return;
|
||||||
Iris.info("Enabling Sentry for anonymous error reporting. You can disable this in the settings.");
|
Iris.info("Enabling Sentry for anonymous error reporting. You can disable this in the settings.");
|
||||||
Iris.info("Your server ID is: " + ServerID.ID);
|
Iris.info("Your server ID is: " + ServerID.ID);
|
||||||
var resource = Iris.instance.getResource("plugin.yml");
|
|
||||||
YamlConfiguration desc = resource != null ? YamlConfiguration.loadConfiguration(new InputStreamReader(resource)) : new YamlConfiguration();
|
|
||||||
|
|
||||||
Sentry.init(options -> {
|
Sentry.init(options -> {
|
||||||
options.setDsn("http://4cdbb9ac953306529947f4ca1e8e6b26@sentry.volmit.com:8080/2");
|
options.setDsn("http://4cdbb9ac953306529947f4ca1e8e6b26@sentry.volmit.com:8080/2");
|
||||||
@@ -60,7 +53,7 @@ public class Bindings {
|
|||||||
options.setAttachServerName(false);
|
options.setAttachServerName(false);
|
||||||
options.setEnableUncaughtExceptionHandler(false);
|
options.setEnableUncaughtExceptionHandler(false);
|
||||||
options.setRelease(Iris.instance.getDescription().getVersion());
|
options.setRelease(Iris.instance.getDescription().getVersion());
|
||||||
options.setEnvironment(desc.getString("environment", "production"));
|
options.setEnvironment(BuildConstants.ENVIRONMENT);
|
||||||
options.setBeforeSend((event, hint) -> {
|
options.setBeforeSend((event, hint) -> {
|
||||||
if (suppress(event.getThrowable())) return null;
|
if (suppress(event.getThrowable())) return null;
|
||||||
event.setTag("iris.safeguard", IrisSafeguard.mode());
|
event.setTag("iris.safeguard", IrisSafeguard.mode());
|
||||||
@@ -77,12 +70,14 @@ public class Bindings {
|
|||||||
scope.setTag("server", Bukkit.getVersion());
|
scope.setTag("server", Bukkit.getVersion());
|
||||||
scope.setTag("server.type", Bukkit.getName());
|
scope.setTag("server.type", Bukkit.getName());
|
||||||
scope.setTag("server.api", Bukkit.getBukkitVersion());
|
scope.setTag("server.api", Bukkit.getBukkitVersion());
|
||||||
scope.setTag("iris.commit", desc.getString("commit", "unknown"));
|
scope.setTag("iris.commit", BuildConstants.COMMIT);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean suppress(Throwable e) {
|
private static boolean suppress(Throwable e) {
|
||||||
return (e instanceof IllegalStateException ex && "zip file closed".equals(ex.getMessage())) || e instanceof JSONException;
|
return (e instanceof IllegalStateException ex && "zip file closed".equals(ex.getMessage()))
|
||||||
|
|| e instanceof JSONException
|
||||||
|
|| e instanceof JsonSyntaxException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -99,6 +94,7 @@ public class Bindings {
|
|||||||
.map(IrisToolbelt::access)
|
.map(IrisToolbelt::access)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.map(PlatformChunkGenerator::getEngine)
|
.map(PlatformChunkGenerator::getEngine)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toMap(engine -> engine.getDimension().getLoadKey(), engine -> {
|
.collect(Collectors.toMap(engine -> engine.getDimension().getLoadKey(), engine -> {
|
||||||
var hash32 = engine.getHash32().getNow(null);
|
var hash32 = engine.getHash32().getNow(null);
|
||||||
if (hash32 == null) return Map.of();
|
if (hash32 == null) return Map.of();
|
||||||
@@ -111,23 +107,7 @@ public class Bindings {
|
|||||||
b.forEach((k, v) -> merged.merge(k, v, Integer::sum));
|
b.forEach((k, v) -> merged.merge(k, v, Integer::sum));
|
||||||
return merged;
|
return merged;
|
||||||
}))));
|
}))));
|
||||||
|
metrics.addCustomChart(new DrilldownPie("environment", () -> Map.of(BuildConstants.ENVIRONMENT, Map.of(BuildConstants.COMMIT, 1))));
|
||||||
|
|
||||||
var info = new SystemInfo().getHardware();
|
|
||||||
var cpu = info.getProcessor().getProcessorIdentifier();
|
|
||||||
var mem = info.getMemory();
|
|
||||||
metrics.addCustomChart(new SimplePie("cpu_model", cpu::getName));
|
|
||||||
|
|
||||||
var nf = NumberFormat.getInstance(Locale.ENGLISH);
|
|
||||||
nf.setMinimumFractionDigits(0);
|
|
||||||
nf.setMaximumFractionDigits(2);
|
|
||||||
nf.setRoundingMode(RoundingMode.HALF_UP);
|
|
||||||
|
|
||||||
metrics.addCustomChart(new DrilldownPie("memory", () -> {
|
|
||||||
double total = mem.getTotal() * 1E-9;
|
|
||||||
double alloc = Math.min(total, Runtime.getRuntime().maxMemory() * 1E-9);
|
|
||||||
return Map.of(nf.format(alloc), Map.of(nf.format(total), 1));
|
|
||||||
}));
|
|
||||||
|
|
||||||
plugin.postShutdown(metrics::shutdown);
|
plugin.postShutdown(metrics::shutdown);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ load: STARTUP
|
|||||||
authors: [ cyberpwn, NextdoorPsycho, Vatuu ]
|
authors: [ cyberpwn, NextdoorPsycho, Vatuu ]
|
||||||
website: volmit.com
|
website: volmit.com
|
||||||
description: More than a Dimension!
|
description: More than a Dimension!
|
||||||
environment: '${environment}'
|
|
||||||
commit: '${commit}'
|
|
||||||
commands:
|
commands:
|
||||||
iris:
|
iris:
|
||||||
aliases: [ ir, irs ]
|
aliases: [ ir, irs ]
|
||||||
|
|||||||
7
core/src/main/templates/BuildConstants.java
Normal file
7
core/src/main/templates/BuildConstants.java
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package com.volmit.iris;
|
||||||
|
|
||||||
|
// The constants are replaced before compilation
|
||||||
|
public interface BuildConstants {
|
||||||
|
String ENVIRONMENT = "${environment}";
|
||||||
|
String COMMIT = "${commit}";
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ sentry = "8.14.0" # https://github.com/getsentry/sentry-java
|
|||||||
commons-io = "2.19.0" # https://central.sonatype.com/artifact/commons-io/commons-io
|
commons-io = "2.19.0" # https://central.sonatype.com/artifact/commons-io/commons-io
|
||||||
commons-lang = "2.6" # https://central.sonatype.com/artifact/commons-lang/commons-lang
|
commons-lang = "2.6" # https://central.sonatype.com/artifact/commons-lang/commons-lang
|
||||||
commons-lang3 = "3.17.0" # https://central.sonatype.com/artifact/org.apache.commons/commons-lang3
|
commons-lang3 = "3.17.0" # https://central.sonatype.com/artifact/org.apache.commons/commons-lang3
|
||||||
|
commons-math3 = "3.6.1"
|
||||||
oshi = "6.8.2" # https://central.sonatype.com/artifact/com.github.oshi/oshi-core
|
oshi = "6.8.2" # https://central.sonatype.com/artifact/com.github.oshi/oshi-core
|
||||||
fastutil = "8.5.16" # https://central.sonatype.com/artifact/it.unimi.dsi/fastutil
|
fastutil = "8.5.16" # https://central.sonatype.com/artifact/it.unimi.dsi/fastutil
|
||||||
lz4 = "1.8.0" # https://central.sonatype.com/artifact/org.lz4/lz4-java
|
lz4 = "1.8.0" # https://central.sonatype.com/artifact/org.lz4/lz4-java
|
||||||
@@ -78,6 +79,7 @@ sentry = { module = "io.sentry:sentry", version.ref = "sentry" }
|
|||||||
commons-io = { module = "commons-io:commons-io", version.ref = "commons-io" }
|
commons-io = { module = "commons-io:commons-io", version.ref = "commons-io" }
|
||||||
commons-lang = { module = "commons-lang:commons-lang", version.ref = "commons-lang" }
|
commons-lang = { module = "commons-lang:commons-lang", version.ref = "commons-lang" }
|
||||||
commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "commons-lang3" }
|
commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "commons-lang3" }
|
||||||
|
commons-math3 = { module = "org.apache.commons:commons-math3", version.ref = "commons-math3" }
|
||||||
oshi = { module = "com.github.oshi:oshi-core", version.ref = "oshi" }
|
oshi = { module = "com.github.oshi:oshi-core", version.ref = "oshi" }
|
||||||
lz4 = { module = "org.lz4:lz4-java", version.ref = "lz4" }
|
lz4 = { module = "org.lz4:lz4-java", version.ref = "lz4" }
|
||||||
fastutil = { module = "it.unimi.dsi:fastutil", version.ref = "fastutil" }
|
fastutil = { module = "it.unimi.dsi:fastutil", version.ref = "fastutil" }
|
||||||
|
|||||||
@@ -8,16 +8,18 @@ import com.volmit.iris.engine.framework.ResultLocator;
|
|||||||
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
|
import com.volmit.iris.engine.object.IrisStructurePopulator;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
import com.volmit.iris.util.reflect.WrappedField;
|
import com.volmit.iris.util.reflect.WrappedField;
|
||||||
import net.minecraft.core.BlockPos;
|
import com.volmit.iris.util.reflect.WrappedReturningMethod;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.CrashReport;
|
||||||
import net.minecraft.core.HolderSet;
|
import net.minecraft.CrashReportCategory;
|
||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.ReportedException;
|
||||||
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -27,45 +29,55 @@ import net.minecraft.tags.StructureTags;
|
|||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.util.random.WeightedRandomList;
|
import net.minecraft.util.random.WeightedRandomList;
|
||||||
import net.minecraft.world.entity.MobCategory;
|
import net.minecraft.world.entity.MobCategory;
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
import net.minecraft.world.level.*;
|
||||||
import net.minecraft.world.level.NoiseColumn;
|
|
||||||
import net.minecraft.world.level.StructureManager;
|
|
||||||
import net.minecraft.world.level.WorldGenLevel;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.biome.BiomeManager;
|
import net.minecraft.world.level.biome.BiomeManager;
|
||||||
import net.minecraft.world.level.biome.BiomeSource;
|
import net.minecraft.world.level.biome.BiomeSource;
|
||||||
import net.minecraft.world.level.biome.MobSpawnSettings;
|
import net.minecraft.world.level.biome.MobSpawnSettings;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
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.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||||
import net.minecraft.world.level.levelgen.GenerationStep;
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.*;
|
||||||
import net.minecraft.world.level.levelgen.RandomState;
|
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.generator.CustomChunkGenerator;
|
import org.bukkit.craftbukkit.v1_20_R1.generator.CustomChunkGenerator;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R1.generator.structure.CraftStructure;
|
||||||
|
import org.bukkit.event.world.AsyncStructureSpawnEvent;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class IrisChunkGenerator extends CustomChunkGenerator {
|
public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||||
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
||||||
|
private static final WrappedReturningMethod<Heightmap, Object> SET_HEIGHT;
|
||||||
private final ChunkGenerator delegate;
|
private final ChunkGenerator delegate;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
||||||
|
private final IrisStructurePopulator populator;
|
||||||
|
|
||||||
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
||||||
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
|
this.populator = new IrisStructurePopulator(engine);
|
||||||
var dimension = engine.getDimension();
|
var dimension = engine.getDimension();
|
||||||
|
|
||||||
KSet<IrisJigsawStructure> placements = new KSet<>();
|
KSet<IrisJigsawStructure> placements = new KSet<>();
|
||||||
@@ -182,8 +194,58 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
|
public void createStructures(RegistryAccess registryAccess, ChunkGeneratorStructureState structureState, StructureManager structureManager, ChunkAccess access, StructureTemplateManager templateManager) {
|
||||||
delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
var chunkPos = access.getPos();
|
||||||
|
var sectionPos = SectionPos.bottomOf(access);
|
||||||
|
var registry = registryAccess.registryOrThrow(Registries.STRUCTURE);
|
||||||
|
populator.populateStructures(chunkPos.x, chunkPos.z, (key, ignoreBiomes) -> {
|
||||||
|
var loc = ResourceLocation.tryParse(key);
|
||||||
|
if (loc == null) return false;
|
||||||
|
var structure = registry.getOptional(loc).orElse(null);
|
||||||
|
if (structure == null) return false;
|
||||||
|
var biomes = structure.biomes();
|
||||||
|
|
||||||
|
var start = structure.generate(
|
||||||
|
registryAccess,
|
||||||
|
this,
|
||||||
|
biomeSource,
|
||||||
|
structureState.randomState(),
|
||||||
|
templateManager,
|
||||||
|
structureState.getLevelSeed(),
|
||||||
|
chunkPos,
|
||||||
|
fetchReferences(structureManager, access, sectionPos, structure),
|
||||||
|
access,
|
||||||
|
(biome) -> ignoreBiomes || biomes.contains(biome)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!start.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BoundingBox box = start.getBoundingBox();
|
||||||
|
AsyncStructureSpawnEvent event = new AsyncStructureSpawnEvent(
|
||||||
|
structureManager.level.getMinecraftWorld().getWorld(),
|
||||||
|
CraftStructure.minecraftToBukkit(structure, registryAccess),
|
||||||
|
new org.bukkit.util.BoundingBox(
|
||||||
|
box.minX(),
|
||||||
|
box.minY(),
|
||||||
|
box.minZ(),
|
||||||
|
box.maxX(),
|
||||||
|
box.maxY(),
|
||||||
|
box.maxZ()
|
||||||
|
), chunkPos.x, chunkPos.z);
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
structureManager.setStartForStructure(sectionPos, structure, start, access);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int fetchReferences(StructureManager structureManager, ChunkAccess access, SectionPos sectionPos, Structure structure) {
|
||||||
|
StructureStart structurestart = structureManager.getStartForStructure(sectionPos, structure, access);
|
||||||
|
return structurestart != null ? structurestart.getReferences() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -201,11 +263,6 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess);
|
return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
|
||||||
return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
||||||
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
||||||
@@ -213,7 +270,75 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
||||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
|
applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
||||||
|
addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
||||||
|
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addVanillaDecorations(WorldGenLevel level, ChunkAccess chunkAccess, StructureManager structureManager) {
|
||||||
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SectionPos sectionPos = SectionPos.of(chunkAccess.getPos(), level.getMinSection());
|
||||||
|
BlockPos blockPos = sectionPos.origin();
|
||||||
|
WorldgenRandom random = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||||
|
long i = random.setDecorationSeed(level.getSeed(), blockPos.getX(), blockPos.getZ());
|
||||||
|
var structures = level.registryAccess().registryOrThrow(Registries.STRUCTURE);
|
||||||
|
var list = structures.stream()
|
||||||
|
.sorted(Comparator.comparingInt(s -> s.step().ordinal()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
var surface = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE_WG);
|
||||||
|
var ocean = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.OCEAN_FLOOR_WG);
|
||||||
|
var motion = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING);
|
||||||
|
var motionNoLeaves = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES);
|
||||||
|
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
int wX = x + blockPos.getX();
|
||||||
|
int wZ = z + blockPos.getZ();
|
||||||
|
|
||||||
|
int noAir = engine.getHeight(wX, wZ, false) + engine.getMinHeight() + 1;
|
||||||
|
int noFluid = engine.getHeight(wX, wZ, true) + engine.getMinHeight() + 1;
|
||||||
|
SET_HEIGHT.invoke(ocean, x, z, Math.min(noFluid, ocean.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(surface, x, z, Math.min(noAir, surface.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motion, x, z, Math.min(noAir, motion.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motionNoLeaves, x, z, Math.min(noAir, motionNoLeaves.getFirstAvailable(x, z)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < list.size(); j++) {
|
||||||
|
Structure structure = list.get(j);
|
||||||
|
random.setFeatureSeed(i, j, structure.step().ordinal());
|
||||||
|
Supplier<String> supplier = () -> structures.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
|
||||||
|
|
||||||
|
try {
|
||||||
|
level.setCurrentlyGenerating(supplier);
|
||||||
|
structureManager.startsForStructure(sectionPos, structure).forEach((start) -> start.placeInChunk(level, structureManager, this, random, getWritableArea(chunkAccess), chunkAccess.getPos()));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
CrashReport crashReport = CrashReport.forThrowable(exception, "Feature placement");
|
||||||
|
CrashReportCategory category = crashReport.addCategory("Feature");
|
||||||
|
category.setDetail("Description", supplier::get);
|
||||||
|
throw new ReportedException(crashReport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Heightmap.primeHeightmaps(chunkAccess, ChunkStatus.POST_FEATURES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BoundingBox getWritableArea(ChunkAccess ichunkaccess) {
|
||||||
|
ChunkPos chunkPos = ichunkaccess.getPos();
|
||||||
|
int minX = chunkPos.getMinBlockX();
|
||||||
|
int minZ = chunkPos.getMinBlockZ();
|
||||||
|
LevelHeightAccessor heightAccessor = ichunkaccess.getHeightAccessorForGeneration();
|
||||||
|
int minY = heightAccessor.getMinBuildHeight() + 1;
|
||||||
|
int maxY = heightAccessor.getMaxBuildHeight() - 1;
|
||||||
|
return new BoundingBox(minX, minY, minZ, minX + 15, maxY, minZ + 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -236,9 +361,22 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.getGenDepth();
|
return delegate.getGenDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
|
return levelheightaccessor.getMinBuildHeight() + engine.getHeight(i, j, !heightmap_type.isOpaque().test(Blocks.WATER.defaultBlockState())) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
|
int block = engine.getHeight(i, j, true);
|
||||||
|
int water = engine.getHeight(i, j, false);
|
||||||
|
BlockState[] column = new BlockState[levelheightaccessor.getHeight()];
|
||||||
|
for (int k = 0; k < column.length; k++) {
|
||||||
|
if (k <= block) column[k] = Blocks.STONE.defaultBlockState();
|
||||||
|
else if (k <= water) column[k] = Blocks.WATER.defaultBlockState();
|
||||||
|
else column[k] = Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
return new NoiseColumn(levelheightaccessor.getMinBuildHeight(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -251,7 +389,21 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
if (biomeSource == null)
|
if (biomeSource == null)
|
||||||
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
||||||
|
|
||||||
|
Method setHeight = null;
|
||||||
|
for (Method method : Heightmap.class.getDeclaredMethods()) {
|
||||||
|
var types = method.getParameterTypes();
|
||||||
|
if (types.length != 3 || !Arrays.equals(types, new Class<?>[]{int.class, int.class, int.class})
|
||||||
|
|| !method.getReturnType().equals(void.class))
|
||||||
|
continue;
|
||||||
|
setHeight = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (setHeight == null)
|
||||||
|
throw new RuntimeException("Could not find setHeight method in Heightmap!");
|
||||||
|
|
||||||
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
||||||
|
SET_HEIGHT = new WrappedReturningMethod<>(Heightmap.class, setHeight.getName(), setHeight.getParameterTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
||||||
|
|||||||
@@ -3,11 +3,14 @@ package com.volmit.iris.core.nms.v1_20_R1;
|
|||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.link.Identifier;
|
||||||
import com.volmit.iris.core.nms.INMSBinding;
|
import com.volmit.iris.core.nms.INMSBinding;
|
||||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
|
import com.volmit.iris.core.nms.container.StructurePlacement;
|
||||||
import com.volmit.iris.core.nms.container.BlockProperty;
|
import com.volmit.iris.core.nms.container.BlockProperty;
|
||||||
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.IrisJigsawStructurePlacement;
|
||||||
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||||
import com.volmit.iris.util.agent.Agent;
|
import com.volmit.iris.util.agent.Agent;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
@@ -58,6 +61,8 @@ import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
|||||||
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
||||||
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;
|
||||||
@@ -78,7 +83,6 @@ import org.bukkit.inventory.ItemStack;
|
|||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@@ -89,6 +93,7 @@ import java.util.List;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
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.stream.Collectors;
|
||||||
|
|
||||||
public class NMSBinding implements INMSBinding {
|
public class NMSBinding implements INMSBinding {
|
||||||
|
|
||||||
@@ -703,6 +708,71 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void placeStructures(Chunk chunk) {
|
||||||
|
var craft = ((CraftChunk) chunk);
|
||||||
|
var level = craft.getCraftWorld().getHandle();
|
||||||
|
var access = ((CraftChunk) chunk).getHandle(ChunkStatus.FULL);
|
||||||
|
level.getChunkSource().getGenerator().applyBiomeDecoration(level, access, level.structureManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KMap<Identifier, StructurePlacement> collectStructures() {
|
||||||
|
var structureSets = registry().registryOrThrow(Registries.STRUCTURE_SET);
|
||||||
|
var structurePlacements = registry().registryOrThrow(Registries.STRUCTURE_PLACEMENT);
|
||||||
|
return structureSets.registryKeySet()
|
||||||
|
.stream()
|
||||||
|
.map(structureSets::getHolder)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.map(holder -> {
|
||||||
|
var set = holder.value();
|
||||||
|
var placement = set.placement();
|
||||||
|
var key = holder.key().location();
|
||||||
|
StructurePlacement.StructurePlacementBuilder<?, ?> builder;
|
||||||
|
if (placement instanceof RandomSpreadStructurePlacement random) {
|
||||||
|
builder = StructurePlacement.RandomSpread.builder()
|
||||||
|
.separation(random.separation())
|
||||||
|
.spacing(random.spacing())
|
||||||
|
.spreadType(switch (random.spreadType()) {
|
||||||
|
case LINEAR -> IrisJigsawStructurePlacement.SpreadType.LINEAR;
|
||||||
|
case TRIANGULAR -> IrisJigsawStructurePlacement.SpreadType.TRIANGULAR;
|
||||||
|
});
|
||||||
|
} else if (placement instanceof ConcentricRingsStructurePlacement rings) {
|
||||||
|
builder = StructurePlacement.ConcentricRings.builder()
|
||||||
|
.distance(rings.distance())
|
||||||
|
.spread(rings.spread())
|
||||||
|
.count(rings.count());
|
||||||
|
} else {
|
||||||
|
Iris.warn("Unsupported structure placement for set " + key + " with type " + structurePlacements.getKey(placement.type()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new com.volmit.iris.core.nms.container.Pair<>(new Identifier(key.getNamespace(), key.getPath()), builder
|
||||||
|
.salt(placement.salt)
|
||||||
|
.frequency(placement.frequency)
|
||||||
|
.structures(set.structures()
|
||||||
|
.stream()
|
||||||
|
.map(entry -> new StructurePlacement.Structure(
|
||||||
|
entry.weight(),
|
||||||
|
entry.structure()
|
||||||
|
.unwrapKey()
|
||||||
|
.map(ResourceKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.orElse(null),
|
||||||
|
entry.structure().tags()
|
||||||
|
.map(TagKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.toList()
|
||||||
|
))
|
||||||
|
.filter(StructurePlacement.Structure::isValid)
|
||||||
|
.toList())
|
||||||
|
.build());
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toMap(com.volmit.iris.core.nms.container.Pair::getA, com.volmit.iris.core.nms.container.Pair::getB, (a, b) -> a, KMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
||||||
if (!(raw instanceof PlatformChunkGenerator gen))
|
if (!(raw instanceof PlatformChunkGenerator gen))
|
||||||
throw new IllegalStateException("Generator is not platform chunk generator!");
|
throw new IllegalStateException("Generator is not platform chunk generator!");
|
||||||
|
|||||||
@@ -8,16 +8,18 @@ import com.volmit.iris.engine.framework.ResultLocator;
|
|||||||
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
|
import com.volmit.iris.engine.object.IrisStructurePopulator;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
import com.volmit.iris.util.reflect.WrappedField;
|
import com.volmit.iris.util.reflect.WrappedField;
|
||||||
import net.minecraft.core.BlockPos;
|
import com.volmit.iris.util.reflect.WrappedReturningMethod;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.CrashReport;
|
||||||
import net.minecraft.core.HolderSet;
|
import net.minecraft.CrashReportCategory;
|
||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.ReportedException;
|
||||||
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -27,45 +29,55 @@ import net.minecraft.tags.StructureTags;
|
|||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.util.random.WeightedRandomList;
|
import net.minecraft.util.random.WeightedRandomList;
|
||||||
import net.minecraft.world.entity.MobCategory;
|
import net.minecraft.world.entity.MobCategory;
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
import net.minecraft.world.level.*;
|
||||||
import net.minecraft.world.level.NoiseColumn;
|
|
||||||
import net.minecraft.world.level.StructureManager;
|
|
||||||
import net.minecraft.world.level.WorldGenLevel;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.biome.BiomeManager;
|
import net.minecraft.world.level.biome.BiomeManager;
|
||||||
import net.minecraft.world.level.biome.BiomeSource;
|
import net.minecraft.world.level.biome.BiomeSource;
|
||||||
import net.minecraft.world.level.biome.MobSpawnSettings;
|
import net.minecraft.world.level.biome.MobSpawnSettings;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
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.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||||
import net.minecraft.world.level.levelgen.GenerationStep;
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.*;
|
||||||
import net.minecraft.world.level.levelgen.RandomState;
|
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
|
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.generator.CustomChunkGenerator;
|
import org.bukkit.craftbukkit.v1_20_R2.generator.CustomChunkGenerator;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R2.generator.structure.CraftStructure;
|
||||||
|
import org.bukkit.event.world.AsyncStructureSpawnEvent;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class IrisChunkGenerator extends CustomChunkGenerator {
|
public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||||
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
||||||
|
private static final WrappedReturningMethod<Heightmap, Object> SET_HEIGHT;
|
||||||
private final ChunkGenerator delegate;
|
private final ChunkGenerator delegate;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
||||||
|
private final IrisStructurePopulator populator;
|
||||||
|
|
||||||
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
||||||
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
|
this.populator = new IrisStructurePopulator(engine);
|
||||||
var dimension = engine.getDimension();
|
var dimension = engine.getDimension();
|
||||||
|
|
||||||
KSet<IrisJigsawStructure> placements = new KSet<>();
|
KSet<IrisJigsawStructure> placements = new KSet<>();
|
||||||
@@ -182,8 +194,58 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
|
public void createStructures(RegistryAccess registryAccess, ChunkGeneratorStructureState structureState, StructureManager structureManager, ChunkAccess access, StructureTemplateManager templateManager) {
|
||||||
delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
var chunkPos = access.getPos();
|
||||||
|
var sectionPos = SectionPos.bottomOf(access);
|
||||||
|
var registry = registryAccess.registryOrThrow(Registries.STRUCTURE);
|
||||||
|
populator.populateStructures(chunkPos.x, chunkPos.z, (key, ignoreBiomes) -> {
|
||||||
|
var loc = ResourceLocation.tryParse(key);
|
||||||
|
if (loc == null) return false;
|
||||||
|
var structure = registry.getOptional(loc).orElse(null);
|
||||||
|
if (structure == null) return false;
|
||||||
|
var biomes = structure.biomes();
|
||||||
|
|
||||||
|
var start = structure.generate(
|
||||||
|
registryAccess,
|
||||||
|
this,
|
||||||
|
biomeSource,
|
||||||
|
structureState.randomState(),
|
||||||
|
templateManager,
|
||||||
|
structureState.getLevelSeed(),
|
||||||
|
chunkPos,
|
||||||
|
fetchReferences(structureManager, access, sectionPos, structure),
|
||||||
|
access,
|
||||||
|
(biome) -> ignoreBiomes || biomes.contains(biome)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!start.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BoundingBox box = start.getBoundingBox();
|
||||||
|
AsyncStructureSpawnEvent event = new AsyncStructureSpawnEvent(
|
||||||
|
structureManager.level.getMinecraftWorld().getWorld(),
|
||||||
|
CraftStructure.minecraftToBukkit(structure, registryAccess),
|
||||||
|
new org.bukkit.util.BoundingBox(
|
||||||
|
box.minX(),
|
||||||
|
box.minY(),
|
||||||
|
box.minZ(),
|
||||||
|
box.maxX(),
|
||||||
|
box.maxY(),
|
||||||
|
box.maxZ()
|
||||||
|
), chunkPos.x, chunkPos.z);
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
structureManager.setStartForStructure(sectionPos, structure, start, access);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int fetchReferences(StructureManager structureManager, ChunkAccess access, SectionPos sectionPos, Structure structure) {
|
||||||
|
StructureStart structurestart = structureManager.getStartForStructure(sectionPos, structure, access);
|
||||||
|
return structurestart != null ? structurestart.getReferences() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -201,11 +263,6 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess);
|
return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
|
||||||
return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
||||||
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
||||||
@@ -213,7 +270,75 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
||||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
|
applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
||||||
|
addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
||||||
|
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addVanillaDecorations(WorldGenLevel level, ChunkAccess chunkAccess, StructureManager structureManager) {
|
||||||
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SectionPos sectionPos = SectionPos.of(chunkAccess.getPos(), level.getMinSection());
|
||||||
|
BlockPos blockPos = sectionPos.origin();
|
||||||
|
WorldgenRandom random = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||||
|
long i = random.setDecorationSeed(level.getSeed(), blockPos.getX(), blockPos.getZ());
|
||||||
|
var structures = level.registryAccess().registryOrThrow(Registries.STRUCTURE);
|
||||||
|
var list = structures.stream()
|
||||||
|
.sorted(Comparator.comparingInt(s -> s.step().ordinal()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
var surface = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE_WG);
|
||||||
|
var ocean = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.OCEAN_FLOOR_WG);
|
||||||
|
var motion = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING);
|
||||||
|
var motionNoLeaves = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES);
|
||||||
|
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
int wX = x + blockPos.getX();
|
||||||
|
int wZ = z + blockPos.getZ();
|
||||||
|
|
||||||
|
int noAir = engine.getHeight(wX, wZ, false) + engine.getMinHeight() + 1;
|
||||||
|
int noFluid = engine.getHeight(wX, wZ, true) + engine.getMinHeight() + 1;
|
||||||
|
SET_HEIGHT.invoke(ocean, x, z, Math.min(noFluid, ocean.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(surface, x, z, Math.min(noAir, surface.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motion, x, z, Math.min(noAir, motion.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motionNoLeaves, x, z, Math.min(noAir, motionNoLeaves.getFirstAvailable(x, z)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < list.size(); j++) {
|
||||||
|
Structure structure = list.get(j);
|
||||||
|
random.setFeatureSeed(i, j, structure.step().ordinal());
|
||||||
|
Supplier<String> supplier = () -> structures.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
|
||||||
|
|
||||||
|
try {
|
||||||
|
level.setCurrentlyGenerating(supplier);
|
||||||
|
structureManager.startsForStructure(sectionPos, structure).forEach((start) -> start.placeInChunk(level, structureManager, this, random, getWritableArea(chunkAccess), chunkAccess.getPos()));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
CrashReport crashReport = CrashReport.forThrowable(exception, "Feature placement");
|
||||||
|
CrashReportCategory category = crashReport.addCategory("Feature");
|
||||||
|
category.setDetail("Description", supplier::get);
|
||||||
|
throw new ReportedException(crashReport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Heightmap.primeHeightmaps(chunkAccess, ChunkStatus.POST_FEATURES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BoundingBox getWritableArea(ChunkAccess ichunkaccess) {
|
||||||
|
ChunkPos chunkPos = ichunkaccess.getPos();
|
||||||
|
int minX = chunkPos.getMinBlockX();
|
||||||
|
int minZ = chunkPos.getMinBlockZ();
|
||||||
|
LevelHeightAccessor heightAccessor = ichunkaccess.getHeightAccessorForGeneration();
|
||||||
|
int minY = heightAccessor.getMinBuildHeight() + 1;
|
||||||
|
int maxY = heightAccessor.getMaxBuildHeight() - 1;
|
||||||
|
return new BoundingBox(minX, minY, minZ, minX + 15, maxY, minZ + 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -236,9 +361,22 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.getGenDepth();
|
return delegate.getGenDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
|
return levelheightaccessor.getMinBuildHeight() + engine.getHeight(i, j, !heightmap_type.isOpaque().test(Blocks.WATER.defaultBlockState())) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
|
int block = engine.getHeight(i, j, true);
|
||||||
|
int water = engine.getHeight(i, j, false);
|
||||||
|
BlockState[] column = new BlockState[levelheightaccessor.getHeight()];
|
||||||
|
for (int k = 0; k < column.length; k++) {
|
||||||
|
if (k <= block) column[k] = Blocks.STONE.defaultBlockState();
|
||||||
|
else if (k <= water) column[k] = Blocks.WATER.defaultBlockState();
|
||||||
|
else column[k] = Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
return new NoiseColumn(levelheightaccessor.getMinBuildHeight(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -251,7 +389,21 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
if (biomeSource == null)
|
if (biomeSource == null)
|
||||||
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
||||||
|
|
||||||
|
Method setHeight = null;
|
||||||
|
for (Method method : Heightmap.class.getDeclaredMethods()) {
|
||||||
|
var types = method.getParameterTypes();
|
||||||
|
if (types.length != 3 || !Arrays.equals(types, new Class<?>[]{int.class, int.class, int.class})
|
||||||
|
|| !method.getReturnType().equals(void.class))
|
||||||
|
continue;
|
||||||
|
setHeight = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (setHeight == null)
|
||||||
|
throw new RuntimeException("Could not find setHeight method in Heightmap!");
|
||||||
|
|
||||||
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
||||||
|
SET_HEIGHT = new WrappedReturningMethod<>(Heightmap.class, setHeight.getName(), setHeight.getParameterTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
||||||
|
|||||||
@@ -1,9 +1,26 @@
|
|||||||
package com.volmit.iris.core.nms.v1_20_R2;
|
package com.volmit.iris.core.nms.v1_20_R2;
|
||||||
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
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.mojang.serialization.Lifecycle;
|
||||||
|
import com.volmit.iris.core.link.Identifier;
|
||||||
|
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
import com.volmit.iris.core.nms.container.BlockProperty;
|
import com.volmit.iris.core.nms.container.BlockProperty;
|
||||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||||
@@ -21,6 +38,8 @@ import com.volmit.iris.util.matter.MatterBiomeInject;
|
|||||||
import com.volmit.iris.util.nbt.mca.NBTWorld;
|
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 com.volmit.iris.core.nms.container.StructurePlacement;
|
||||||
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
@@ -58,6 +77,8 @@ import net.minecraft.world.level.dimension.LevelStem;
|
|||||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
@@ -707,6 +728,71 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void placeStructures(Chunk chunk) {
|
||||||
|
var craft = ((CraftChunk) chunk);
|
||||||
|
var level = craft.getCraftWorld().getHandle();
|
||||||
|
var access = ((CraftChunk) chunk).getHandle(ChunkStatus.FULL);
|
||||||
|
level.getChunkSource().getGenerator().applyBiomeDecoration(level, access, level.structureManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KMap<Identifier, StructurePlacement> collectStructures() {
|
||||||
|
var structureSets = registry().registryOrThrow(Registries.STRUCTURE_SET);
|
||||||
|
var structurePlacements = registry().registryOrThrow(Registries.STRUCTURE_PLACEMENT);
|
||||||
|
return structureSets.registryKeySet()
|
||||||
|
.stream()
|
||||||
|
.map(structureSets::getHolder)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.map(holder -> {
|
||||||
|
var set = holder.value();
|
||||||
|
var placement = set.placement();
|
||||||
|
var key = holder.key().location();
|
||||||
|
StructurePlacement.StructurePlacementBuilder<?, ?> builder;
|
||||||
|
if (placement instanceof RandomSpreadStructurePlacement random) {
|
||||||
|
builder = StructurePlacement.RandomSpread.builder()
|
||||||
|
.separation(random.separation())
|
||||||
|
.spacing(random.spacing())
|
||||||
|
.spreadType(switch (random.spreadType()) {
|
||||||
|
case LINEAR -> IrisJigsawStructurePlacement.SpreadType.LINEAR;
|
||||||
|
case TRIANGULAR -> IrisJigsawStructurePlacement.SpreadType.TRIANGULAR;
|
||||||
|
});
|
||||||
|
} else if (placement instanceof ConcentricRingsStructurePlacement rings) {
|
||||||
|
builder = StructurePlacement.ConcentricRings.builder()
|
||||||
|
.distance(rings.distance())
|
||||||
|
.spread(rings.spread())
|
||||||
|
.count(rings.count());
|
||||||
|
} else {
|
||||||
|
Iris.warn("Unsupported structure placement for set " + key + " with type " + structurePlacements.getKey(placement.type()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new com.volmit.iris.core.nms.container.Pair<>(new Identifier(key.getNamespace(), key.getPath()), builder
|
||||||
|
.salt(placement.salt)
|
||||||
|
.frequency(placement.frequency)
|
||||||
|
.structures(set.structures()
|
||||||
|
.stream()
|
||||||
|
.map(entry -> new StructurePlacement.Structure(
|
||||||
|
entry.weight(),
|
||||||
|
entry.structure()
|
||||||
|
.unwrapKey()
|
||||||
|
.map(ResourceKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.orElse(null),
|
||||||
|
entry.structure().tags()
|
||||||
|
.map(TagKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.toList()
|
||||||
|
))
|
||||||
|
.filter(StructurePlacement.Structure::isValid)
|
||||||
|
.toList())
|
||||||
|
.build());
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toMap(com.volmit.iris.core.nms.container.Pair::getA, com.volmit.iris.core.nms.container.Pair::getB, (a, b) -> a, KMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
||||||
if (!(raw instanceof PlatformChunkGenerator gen))
|
if (!(raw instanceof PlatformChunkGenerator gen))
|
||||||
throw new IllegalStateException("Generator is not platform chunk generator!");
|
throw new IllegalStateException("Generator is not platform chunk generator!");
|
||||||
|
|||||||
@@ -8,16 +8,18 @@ import com.volmit.iris.engine.framework.ResultLocator;
|
|||||||
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
|
import com.volmit.iris.engine.object.IrisStructurePopulator;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
import com.volmit.iris.util.reflect.WrappedField;
|
import com.volmit.iris.util.reflect.WrappedField;
|
||||||
import net.minecraft.core.BlockPos;
|
import com.volmit.iris.util.reflect.WrappedReturningMethod;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.CrashReport;
|
||||||
import net.minecraft.core.HolderSet;
|
import net.minecraft.CrashReportCategory;
|
||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.ReportedException;
|
||||||
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -27,45 +29,55 @@ import net.minecraft.tags.StructureTags;
|
|||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.util.random.WeightedRandomList;
|
import net.minecraft.util.random.WeightedRandomList;
|
||||||
import net.minecraft.world.entity.MobCategory;
|
import net.minecraft.world.entity.MobCategory;
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
import net.minecraft.world.level.*;
|
||||||
import net.minecraft.world.level.NoiseColumn;
|
|
||||||
import net.minecraft.world.level.StructureManager;
|
|
||||||
import net.minecraft.world.level.WorldGenLevel;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.biome.BiomeManager;
|
import net.minecraft.world.level.biome.BiomeManager;
|
||||||
import net.minecraft.world.level.biome.BiomeSource;
|
import net.minecraft.world.level.biome.BiomeSource;
|
||||||
import net.minecraft.world.level.biome.MobSpawnSettings;
|
import net.minecraft.world.level.biome.MobSpawnSettings;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
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.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||||
import net.minecraft.world.level.levelgen.GenerationStep;
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.*;
|
||||||
import net.minecraft.world.level.levelgen.RandomState;
|
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator;
|
import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R3.generator.structure.CraftStructure;
|
||||||
|
import org.bukkit.event.world.AsyncStructureSpawnEvent;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class IrisChunkGenerator extends CustomChunkGenerator {
|
public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||||
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
||||||
|
private static final WrappedReturningMethod<Heightmap, Object> SET_HEIGHT;
|
||||||
private final ChunkGenerator delegate;
|
private final ChunkGenerator delegate;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
||||||
|
private final IrisStructurePopulator populator;
|
||||||
|
|
||||||
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
||||||
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
|
this.populator = new IrisStructurePopulator(engine);
|
||||||
var dimension = engine.getDimension();
|
var dimension = engine.getDimension();
|
||||||
|
|
||||||
KSet<IrisJigsawStructure> placements = new KSet<>();
|
KSet<IrisJigsawStructure> placements = new KSet<>();
|
||||||
@@ -182,8 +194,58 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
|
public void createStructures(RegistryAccess registryAccess, ChunkGeneratorStructureState structureState, StructureManager structureManager, ChunkAccess access, StructureTemplateManager templateManager) {
|
||||||
delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
var chunkPos = access.getPos();
|
||||||
|
var sectionPos = SectionPos.bottomOf(access);
|
||||||
|
var registry = registryAccess.registryOrThrow(Registries.STRUCTURE);
|
||||||
|
populator.populateStructures(chunkPos.x, chunkPos.z, (key, ignoreBiomes) -> {
|
||||||
|
var loc = ResourceLocation.tryParse(key);
|
||||||
|
if (loc == null) return false;
|
||||||
|
var structure = registry.getOptional(loc).orElse(null);
|
||||||
|
if (structure == null) return false;
|
||||||
|
var biomes = structure.biomes();
|
||||||
|
|
||||||
|
var start = structure.generate(
|
||||||
|
registryAccess,
|
||||||
|
this,
|
||||||
|
biomeSource,
|
||||||
|
structureState.randomState(),
|
||||||
|
templateManager,
|
||||||
|
structureState.getLevelSeed(),
|
||||||
|
chunkPos,
|
||||||
|
fetchReferences(structureManager, access, sectionPos, structure),
|
||||||
|
access,
|
||||||
|
(biome) -> ignoreBiomes || biomes.contains(biome)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!start.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BoundingBox box = start.getBoundingBox();
|
||||||
|
AsyncStructureSpawnEvent event = new AsyncStructureSpawnEvent(
|
||||||
|
structureManager.level.getMinecraftWorld().getWorld(),
|
||||||
|
CraftStructure.minecraftToBukkit(structure),
|
||||||
|
new org.bukkit.util.BoundingBox(
|
||||||
|
box.minX(),
|
||||||
|
box.minY(),
|
||||||
|
box.minZ(),
|
||||||
|
box.maxX(),
|
||||||
|
box.maxY(),
|
||||||
|
box.maxZ()
|
||||||
|
), chunkPos.x, chunkPos.z);
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
structureManager.setStartForStructure(sectionPos, structure, start, access);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int fetchReferences(StructureManager structureManager, ChunkAccess access, SectionPos sectionPos, Structure structure) {
|
||||||
|
StructureStart structurestart = structureManager.getStartForStructure(sectionPos, structure, access);
|
||||||
|
return structurestart != null ? structurestart.getReferences() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -201,11 +263,6 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess);
|
return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
|
||||||
return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
||||||
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
||||||
@@ -213,7 +270,75 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
||||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
|
applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
||||||
|
addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
||||||
|
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addVanillaDecorations(WorldGenLevel level, ChunkAccess chunkAccess, StructureManager structureManager) {
|
||||||
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SectionPos sectionPos = SectionPos.of(chunkAccess.getPos(), level.getMinSection());
|
||||||
|
BlockPos blockPos = sectionPos.origin();
|
||||||
|
WorldgenRandom random = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||||
|
long i = random.setDecorationSeed(level.getSeed(), blockPos.getX(), blockPos.getZ());
|
||||||
|
var structures = level.registryAccess().registryOrThrow(Registries.STRUCTURE);
|
||||||
|
var list = structures.stream()
|
||||||
|
.sorted(Comparator.comparingInt(s -> s.step().ordinal()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
var surface = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE_WG);
|
||||||
|
var ocean = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.OCEAN_FLOOR_WG);
|
||||||
|
var motion = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING);
|
||||||
|
var motionNoLeaves = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES);
|
||||||
|
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
int wX = x + blockPos.getX();
|
||||||
|
int wZ = z + blockPos.getZ();
|
||||||
|
|
||||||
|
int noAir = engine.getHeight(wX, wZ, false) + engine.getMinHeight() + 1;
|
||||||
|
int noFluid = engine.getHeight(wX, wZ, true) + engine.getMinHeight() + 1;
|
||||||
|
SET_HEIGHT.invoke(ocean, x, z, Math.min(noFluid, ocean.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(surface, x, z, Math.min(noAir, surface.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motion, x, z, Math.min(noAir, motion.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motionNoLeaves, x, z, Math.min(noAir, motionNoLeaves.getFirstAvailable(x, z)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < list.size(); j++) {
|
||||||
|
Structure structure = list.get(j);
|
||||||
|
random.setFeatureSeed(i, j, structure.step().ordinal());
|
||||||
|
Supplier<String> supplier = () -> structures.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
|
||||||
|
|
||||||
|
try {
|
||||||
|
level.setCurrentlyGenerating(supplier);
|
||||||
|
structureManager.startsForStructure(sectionPos, structure).forEach((start) -> start.placeInChunk(level, structureManager, this, random, getWritableArea(chunkAccess), chunkAccess.getPos()));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
CrashReport crashReport = CrashReport.forThrowable(exception, "Feature placement");
|
||||||
|
CrashReportCategory category = crashReport.addCategory("Feature");
|
||||||
|
category.setDetail("Description", supplier::get);
|
||||||
|
throw new ReportedException(crashReport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Heightmap.primeHeightmaps(chunkAccess, ChunkStatus.POST_FEATURES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BoundingBox getWritableArea(ChunkAccess ichunkaccess) {
|
||||||
|
ChunkPos chunkPos = ichunkaccess.getPos();
|
||||||
|
int minX = chunkPos.getMinBlockX();
|
||||||
|
int minZ = chunkPos.getMinBlockZ();
|
||||||
|
LevelHeightAccessor heightAccessor = ichunkaccess.getHeightAccessorForGeneration();
|
||||||
|
int minY = heightAccessor.getMinBuildHeight() + 1;
|
||||||
|
int maxY = heightAccessor.getMaxBuildHeight() - 1;
|
||||||
|
return new BoundingBox(minX, minY, minZ, minX + 15, maxY, minZ + 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -236,9 +361,22 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.getGenDepth();
|
return delegate.getGenDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
|
return levelheightaccessor.getMinBuildHeight() + engine.getHeight(i, j, !heightmap_type.isOpaque().test(Blocks.WATER.defaultBlockState())) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
|
int block = engine.getHeight(i, j, true);
|
||||||
|
int water = engine.getHeight(i, j, false);
|
||||||
|
BlockState[] column = new BlockState[levelheightaccessor.getHeight()];
|
||||||
|
for (int k = 0; k < column.length; k++) {
|
||||||
|
if (k <= block) column[k] = Blocks.STONE.defaultBlockState();
|
||||||
|
else if (k <= water) column[k] = Blocks.WATER.defaultBlockState();
|
||||||
|
else column[k] = Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
return new NoiseColumn(levelheightaccessor.getMinBuildHeight(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -251,7 +389,21 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
if (biomeSource == null)
|
if (biomeSource == null)
|
||||||
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
||||||
|
|
||||||
|
Method setHeight = null;
|
||||||
|
for (Method method : Heightmap.class.getDeclaredMethods()) {
|
||||||
|
var types = method.getParameterTypes();
|
||||||
|
if (types.length != 3 || !Arrays.equals(types, new Class<?>[]{int.class, int.class, int.class})
|
||||||
|
|| !method.getReturnType().equals(void.class))
|
||||||
|
continue;
|
||||||
|
setHeight = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (setHeight == null)
|
||||||
|
throw new RuntimeException("Could not find setHeight method in Heightmap!");
|
||||||
|
|
||||||
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
||||||
|
SET_HEIGHT = new WrappedReturningMethod<>(Heightmap.class, setHeight.getName(), setHeight.getParameterTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
||||||
|
|||||||
@@ -1,9 +1,26 @@
|
|||||||
package com.volmit.iris.core.nms.v1_20_R3;
|
package com.volmit.iris.core.nms.v1_20_R3;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.nms.INMSBinding;
|
import com.volmit.iris.core.nms.INMSBinding;
|
||||||
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
import com.volmit.iris.core.link.Identifier;
|
||||||
|
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
import com.volmit.iris.core.nms.container.BlockProperty;
|
import com.volmit.iris.core.nms.container.BlockProperty;
|
||||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||||
@@ -21,6 +38,8 @@ import com.volmit.iris.util.matter.MatterBiomeInject;
|
|||||||
import com.volmit.iris.util.nbt.mca.NBTWorld;
|
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 com.volmit.iris.core.nms.container.StructurePlacement;
|
||||||
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
@@ -58,6 +77,8 @@ import net.minecraft.world.level.dimension.LevelStem;
|
|||||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
@@ -708,6 +729,71 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void placeStructures(Chunk chunk) {
|
||||||
|
var craft = ((CraftChunk) chunk);
|
||||||
|
var level = craft.getCraftWorld().getHandle();
|
||||||
|
var access = ((CraftChunk) chunk).getHandle(ChunkStatus.FULL);
|
||||||
|
level.getChunkSource().getGenerator().applyBiomeDecoration(level, access, level.structureManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KMap<Identifier, StructurePlacement> collectStructures() {
|
||||||
|
var structureSets = registry().registryOrThrow(Registries.STRUCTURE_SET);
|
||||||
|
var structurePlacements = registry().registryOrThrow(Registries.STRUCTURE_PLACEMENT);
|
||||||
|
return structureSets.registryKeySet()
|
||||||
|
.stream()
|
||||||
|
.map(structureSets::getHolder)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.map(holder -> {
|
||||||
|
var set = holder.value();
|
||||||
|
var placement = set.placement();
|
||||||
|
var key = holder.key().location();
|
||||||
|
StructurePlacement.StructurePlacementBuilder<?, ?> builder;
|
||||||
|
if (placement instanceof RandomSpreadStructurePlacement random) {
|
||||||
|
builder = StructurePlacement.RandomSpread.builder()
|
||||||
|
.separation(random.separation())
|
||||||
|
.spacing(random.spacing())
|
||||||
|
.spreadType(switch (random.spreadType()) {
|
||||||
|
case LINEAR -> IrisJigsawStructurePlacement.SpreadType.LINEAR;
|
||||||
|
case TRIANGULAR -> IrisJigsawStructurePlacement.SpreadType.TRIANGULAR;
|
||||||
|
});
|
||||||
|
} else if (placement instanceof ConcentricRingsStructurePlacement rings) {
|
||||||
|
builder = StructurePlacement.ConcentricRings.builder()
|
||||||
|
.distance(rings.distance())
|
||||||
|
.spread(rings.spread())
|
||||||
|
.count(rings.count());
|
||||||
|
} else {
|
||||||
|
Iris.warn("Unsupported structure placement for set " + key + " with type " + structurePlacements.getKey(placement.type()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new com.volmit.iris.core.nms.container.Pair<>(new Identifier(key.getNamespace(), key.getPath()), builder
|
||||||
|
.salt(placement.salt)
|
||||||
|
.frequency(placement.frequency)
|
||||||
|
.structures(set.structures()
|
||||||
|
.stream()
|
||||||
|
.map(entry -> new StructurePlacement.Structure(
|
||||||
|
entry.weight(),
|
||||||
|
entry.structure()
|
||||||
|
.unwrapKey()
|
||||||
|
.map(ResourceKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.orElse(null),
|
||||||
|
entry.structure().tags()
|
||||||
|
.map(TagKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.toList()
|
||||||
|
))
|
||||||
|
.filter(StructurePlacement.Structure::isValid)
|
||||||
|
.toList())
|
||||||
|
.build());
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toMap(com.volmit.iris.core.nms.container.Pair::getA, com.volmit.iris.core.nms.container.Pair::getB, (a, b) -> a, KMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
||||||
if (!(raw instanceof PlatformChunkGenerator gen))
|
if (!(raw instanceof PlatformChunkGenerator gen))
|
||||||
throw new IllegalStateException("Generator is not platform chunk generator!");
|
throw new IllegalStateException("Generator is not platform chunk generator!");
|
||||||
|
|||||||
@@ -8,16 +8,18 @@ import com.volmit.iris.engine.framework.ResultLocator;
|
|||||||
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
|
import com.volmit.iris.engine.object.IrisStructurePopulator;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
import com.volmit.iris.util.reflect.WrappedField;
|
import com.volmit.iris.util.reflect.WrappedField;
|
||||||
import net.minecraft.core.BlockPos;
|
import com.volmit.iris.util.reflect.WrappedReturningMethod;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.CrashReport;
|
||||||
import net.minecraft.core.HolderSet;
|
import net.minecraft.CrashReportCategory;
|
||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.ReportedException;
|
||||||
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -27,43 +29,53 @@ import net.minecraft.tags.StructureTags;
|
|||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.util.random.WeightedRandomList;
|
import net.minecraft.util.random.WeightedRandomList;
|
||||||
import net.minecraft.world.entity.MobCategory;
|
import net.minecraft.world.entity.MobCategory;
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
import net.minecraft.world.level.*;
|
||||||
import net.minecraft.world.level.NoiseColumn;
|
|
||||||
import net.minecraft.world.level.StructureManager;
|
|
||||||
import net.minecraft.world.level.WorldGenLevel;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.biome.BiomeManager;
|
import net.minecraft.world.level.biome.BiomeManager;
|
||||||
import net.minecraft.world.level.biome.BiomeSource;
|
import net.minecraft.world.level.biome.BiomeSource;
|
||||||
import net.minecraft.world.level.biome.MobSpawnSettings;
|
import net.minecraft.world.level.biome.MobSpawnSettings;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
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.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||||
import net.minecraft.world.level.levelgen.GenerationStep;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.*;
|
||||||
import net.minecraft.world.level.levelgen.RandomState;
|
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_20_R4.CraftWorld;
|
import org.bukkit.craftbukkit.v1_20_R4.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_20_R4.generator.CustomChunkGenerator;
|
import org.bukkit.craftbukkit.v1_20_R4.generator.CustomChunkGenerator;
|
||||||
|
import org.bukkit.craftbukkit.v1_20_R4.generator.structure.CraftStructure;
|
||||||
|
import org.bukkit.event.world.AsyncStructureSpawnEvent;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class IrisChunkGenerator extends CustomChunkGenerator {
|
public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||||
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
||||||
|
private static final WrappedReturningMethod<Heightmap, Object> SET_HEIGHT;
|
||||||
private final ChunkGenerator delegate;
|
private final ChunkGenerator delegate;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
||||||
|
private final IrisStructurePopulator populator;
|
||||||
|
|
||||||
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
||||||
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
|
this.populator = new IrisStructurePopulator(engine);
|
||||||
var dimension = engine.getDimension();
|
var dimension = engine.getDimension();
|
||||||
|
|
||||||
KSet<IrisJigsawStructure> placements = new KSet<>();
|
KSet<IrisJigsawStructure> placements = new KSet<>();
|
||||||
@@ -180,8 +192,59 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
|
public void createStructures(RegistryAccess registryAccess, ChunkGeneratorStructureState structureState, StructureManager structureManager, ChunkAccess access, StructureTemplateManager templateManager) {
|
||||||
delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
var chunkPos = access.getPos();
|
||||||
|
var sectionPos = SectionPos.bottomOf(access);
|
||||||
|
var registry = registryAccess.registryOrThrow(Registries.STRUCTURE);
|
||||||
|
populator.populateStructures(chunkPos.x, chunkPos.z, (key, ignoreBiomes) -> {
|
||||||
|
var loc = ResourceLocation.tryParse(key);
|
||||||
|
if (loc == null) return false;
|
||||||
|
var holder = registry.getHolder(loc).orElse(null);
|
||||||
|
if (holder == null) return false;
|
||||||
|
var structure = holder.value();
|
||||||
|
var biomes = structure.biomes();
|
||||||
|
|
||||||
|
var start = structure.generate(
|
||||||
|
registryAccess,
|
||||||
|
this,
|
||||||
|
biomeSource,
|
||||||
|
structureState.randomState(),
|
||||||
|
templateManager,
|
||||||
|
structureState.getLevelSeed(),
|
||||||
|
chunkPos,
|
||||||
|
fetchReferences(structureManager, access, sectionPos, structure),
|
||||||
|
access,
|
||||||
|
(biome) -> ignoreBiomes || biomes.contains(biome)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!start.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BoundingBox box = start.getBoundingBox();
|
||||||
|
AsyncStructureSpawnEvent event = new AsyncStructureSpawnEvent(
|
||||||
|
structureManager.level.getMinecraftWorld().getWorld(),
|
||||||
|
CraftStructure.minecraftToBukkit(structure),
|
||||||
|
new org.bukkit.util.BoundingBox(
|
||||||
|
box.minX(),
|
||||||
|
box.minY(),
|
||||||
|
box.minZ(),
|
||||||
|
box.maxX(),
|
||||||
|
box.maxY(),
|
||||||
|
box.maxZ()
|
||||||
|
), chunkPos.x, chunkPos.z);
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
structureManager.setStartForStructure(sectionPos, structure, start, access);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int fetchReferences(StructureManager structureManager, ChunkAccess access, SectionPos sectionPos, Structure structure) {
|
||||||
|
StructureStart structurestart = structureManager.getStartForStructure(sectionPos, structure, access);
|
||||||
|
return structurestart != null ? structurestart.getReferences() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -199,11 +262,6 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess);
|
return delegate.fillFromNoise(executor, blender, randomstate, structuremanager, ichunkaccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
|
||||||
return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
||||||
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
||||||
@@ -211,7 +269,75 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
||||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
|
applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
||||||
|
addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
||||||
|
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addVanillaDecorations(WorldGenLevel level, ChunkAccess chunkAccess, StructureManager structureManager) {
|
||||||
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SectionPos sectionPos = SectionPos.of(chunkAccess.getPos(), level.getMinSection());
|
||||||
|
BlockPos blockPos = sectionPos.origin();
|
||||||
|
WorldgenRandom random = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||||
|
long i = random.setDecorationSeed(level.getSeed(), blockPos.getX(), blockPos.getZ());
|
||||||
|
var structures = level.registryAccess().registryOrThrow(Registries.STRUCTURE);
|
||||||
|
var list = structures.stream()
|
||||||
|
.sorted(Comparator.comparingInt(s -> s.step().ordinal()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
var surface = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE_WG);
|
||||||
|
var ocean = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.OCEAN_FLOOR_WG);
|
||||||
|
var motion = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING);
|
||||||
|
var motionNoLeaves = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES);
|
||||||
|
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
int wX = x + blockPos.getX();
|
||||||
|
int wZ = z + blockPos.getZ();
|
||||||
|
|
||||||
|
int noAir = engine.getHeight(wX, wZ, false) + engine.getMinHeight() + 1;
|
||||||
|
int noFluid = engine.getHeight(wX, wZ, true) + engine.getMinHeight() + 1;
|
||||||
|
SET_HEIGHT.invoke(ocean, x, z, Math.min(noFluid, ocean.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(surface, x, z, Math.min(noAir, surface.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motion, x, z, Math.min(noAir, motion.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motionNoLeaves, x, z, Math.min(noAir, motionNoLeaves.getFirstAvailable(x, z)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < list.size(); j++) {
|
||||||
|
Structure structure = list.get(j);
|
||||||
|
random.setFeatureSeed(i, j, structure.step().ordinal());
|
||||||
|
Supplier<String> supplier = () -> structures.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
|
||||||
|
|
||||||
|
try {
|
||||||
|
level.setCurrentlyGenerating(supplier);
|
||||||
|
structureManager.startsForStructure(sectionPos, structure).forEach((start) -> start.placeInChunk(level, structureManager, this, random, getWritableArea(chunkAccess), chunkAccess.getPos()));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
CrashReport crashReport = CrashReport.forThrowable(exception, "Feature placement");
|
||||||
|
CrashReportCategory category = crashReport.addCategory("Feature");
|
||||||
|
category.setDetail("Description", supplier::get);
|
||||||
|
throw new ReportedException(crashReport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Heightmap.primeHeightmaps(chunkAccess, ChunkStatus.POST_FEATURES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BoundingBox getWritableArea(ChunkAccess ichunkaccess) {
|
||||||
|
ChunkPos chunkPos = ichunkaccess.getPos();
|
||||||
|
int minX = chunkPos.getMinBlockX();
|
||||||
|
int minZ = chunkPos.getMinBlockZ();
|
||||||
|
LevelHeightAccessor heightAccessor = ichunkaccess.getHeightAccessorForGeneration();
|
||||||
|
int minY = heightAccessor.getMinBuildHeight() + 1;
|
||||||
|
int maxY = heightAccessor.getMaxBuildHeight() - 1;
|
||||||
|
return new BoundingBox(minX, minY, minZ, minX + 15, maxY, minZ + 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -234,9 +360,22 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.getGenDepth();
|
return delegate.getGenDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
|
return levelheightaccessor.getMinBuildHeight() + engine.getHeight(i, j, !heightmap_type.isOpaque().test(Blocks.WATER.defaultBlockState())) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
|
int block = engine.getHeight(i, j, true);
|
||||||
|
int water = engine.getHeight(i, j, false);
|
||||||
|
BlockState[] column = new BlockState[levelheightaccessor.getHeight()];
|
||||||
|
for (int k = 0; k < column.length; k++) {
|
||||||
|
if (k <= block) column[k] = Blocks.STONE.defaultBlockState();
|
||||||
|
else if (k <= water) column[k] = Blocks.WATER.defaultBlockState();
|
||||||
|
else column[k] = Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
return new NoiseColumn(levelheightaccessor.getMinBuildHeight(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -249,7 +388,21 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
if (biomeSource == null)
|
if (biomeSource == null)
|
||||||
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
||||||
|
|
||||||
|
Method setHeight = null;
|
||||||
|
for (Method method : Heightmap.class.getDeclaredMethods()) {
|
||||||
|
var types = method.getParameterTypes();
|
||||||
|
if (types.length != 3 || !Arrays.equals(types, new Class<?>[]{int.class, int.class, int.class})
|
||||||
|
|| !method.getReturnType().equals(void.class))
|
||||||
|
continue;
|
||||||
|
setHeight = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (setHeight == null)
|
||||||
|
throw new RuntimeException("Could not find setHeight method in Heightmap!");
|
||||||
|
|
||||||
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
||||||
|
SET_HEIGHT = new WrappedReturningMethod<>(Heightmap.class, setHeight.getName(), setHeight.getParameterTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
||||||
|
|||||||
@@ -1,11 +1,25 @@
|
|||||||
package com.volmit.iris.core.nms.v1_20_R4;
|
package com.volmit.iris.core.nms.v1_20_R4;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.nms.INMSBinding;
|
import com.volmit.iris.core.nms.INMSBinding;
|
||||||
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
import com.volmit.iris.core.link.Identifier;
|
||||||
|
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
import com.volmit.iris.core.nms.container.BlockProperty;
|
import com.volmit.iris.core.nms.container.BlockProperty;
|
||||||
|
import com.volmit.iris.core.nms.container.StructurePlacement;
|
||||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
@@ -21,6 +35,7 @@ import com.volmit.iris.util.math.Vector3d;
|
|||||||
import com.volmit.iris.util.matter.MatterBiomeInject;
|
import com.volmit.iris.util.matter.MatterBiomeInject;
|
||||||
import com.volmit.iris.util.nbt.mca.NBTWorld;
|
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.engine.object.IrisJigsawStructurePlacement;
|
||||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import net.bytebuddy.ByteBuddy;
|
import net.bytebuddy.ByteBuddy;
|
||||||
@@ -58,6 +73,8 @@ import net.minecraft.world.level.dimension.LevelStem;
|
|||||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
@@ -725,6 +742,71 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void placeStructures(Chunk chunk) {
|
||||||
|
var craft = ((CraftChunk) chunk);
|
||||||
|
var level = craft.getCraftWorld().getHandle();
|
||||||
|
var access = ((CraftChunk) chunk).getHandle(ChunkStatus.FULL);
|
||||||
|
level.getChunkSource().getGenerator().applyBiomeDecoration(level, access, level.structureManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KMap<Identifier, StructurePlacement> collectStructures() {
|
||||||
|
var structureSets = registry().registryOrThrow(Registries.STRUCTURE_SET);
|
||||||
|
var structurePlacements = registry().registryOrThrow(Registries.STRUCTURE_PLACEMENT);
|
||||||
|
return structureSets.keySet()
|
||||||
|
.stream()
|
||||||
|
.map(structureSets::getHolder)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.map(holder -> {
|
||||||
|
var set = holder.value();
|
||||||
|
var placement = set.placement();
|
||||||
|
var key = holder.key().location();
|
||||||
|
StructurePlacement.StructurePlacementBuilder<?, ?> builder;
|
||||||
|
if (placement instanceof RandomSpreadStructurePlacement random) {
|
||||||
|
builder = StructurePlacement.RandomSpread.builder()
|
||||||
|
.separation(random.separation())
|
||||||
|
.spacing(random.spacing())
|
||||||
|
.spreadType(switch (random.spreadType()) {
|
||||||
|
case LINEAR -> IrisJigsawStructurePlacement.SpreadType.LINEAR;
|
||||||
|
case TRIANGULAR -> IrisJigsawStructurePlacement.SpreadType.TRIANGULAR;
|
||||||
|
});
|
||||||
|
} else if (placement instanceof ConcentricRingsStructurePlacement rings) {
|
||||||
|
builder = StructurePlacement.ConcentricRings.builder()
|
||||||
|
.distance(rings.distance())
|
||||||
|
.spread(rings.spread())
|
||||||
|
.count(rings.count());
|
||||||
|
} else {
|
||||||
|
Iris.warn("Unsupported structure placement for set " + key + " with type " + structurePlacements.getKey(placement.type()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new com.volmit.iris.core.nms.container.Pair<>(new Identifier(key.getNamespace(), key.getPath()), builder
|
||||||
|
.salt(placement.salt)
|
||||||
|
.frequency(placement.frequency)
|
||||||
|
.structures(set.structures()
|
||||||
|
.stream()
|
||||||
|
.map(entry -> new StructurePlacement.Structure(
|
||||||
|
entry.weight(),
|
||||||
|
entry.structure()
|
||||||
|
.unwrapKey()
|
||||||
|
.map(ResourceKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.orElse(null),
|
||||||
|
entry.structure().tags()
|
||||||
|
.map(TagKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.toList()
|
||||||
|
))
|
||||||
|
.filter(StructurePlacement.Structure::isValid)
|
||||||
|
.toList())
|
||||||
|
.build());
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toMap(com.volmit.iris.core.nms.container.Pair::getA, com.volmit.iris.core.nms.container.Pair::getB, (a, b) -> a, KMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
||||||
if (!(raw instanceof PlatformChunkGenerator gen))
|
if (!(raw instanceof PlatformChunkGenerator gen))
|
||||||
throw new IllegalStateException("Generator is not platform chunk generator!");
|
throw new IllegalStateException("Generator is not platform chunk generator!");
|
||||||
|
|||||||
@@ -8,16 +8,18 @@ import com.volmit.iris.engine.framework.ResultLocator;
|
|||||||
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
|
import com.volmit.iris.engine.object.IrisStructurePopulator;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
import com.volmit.iris.util.reflect.WrappedField;
|
import com.volmit.iris.util.reflect.WrappedField;
|
||||||
import net.minecraft.core.BlockPos;
|
import com.volmit.iris.util.reflect.WrappedReturningMethod;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.CrashReport;
|
||||||
import net.minecraft.core.HolderSet;
|
import net.minecraft.CrashReportCategory;
|
||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.ReportedException;
|
||||||
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -27,44 +29,54 @@ import net.minecraft.tags.StructureTags;
|
|||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.util.random.WeightedRandomList;
|
import net.minecraft.util.random.WeightedRandomList;
|
||||||
import net.minecraft.world.entity.MobCategory;
|
import net.minecraft.world.entity.MobCategory;
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
import net.minecraft.world.level.*;
|
||||||
import net.minecraft.world.level.NoiseColumn;
|
|
||||||
import net.minecraft.world.level.StructureManager;
|
|
||||||
import net.minecraft.world.level.WorldGenLevel;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.biome.BiomeManager;
|
import net.minecraft.world.level.biome.BiomeManager;
|
||||||
import net.minecraft.world.level.biome.BiomeSource;
|
import net.minecraft.world.level.biome.BiomeSource;
|
||||||
import net.minecraft.world.level.biome.MobSpawnSettings;
|
import net.minecraft.world.level.biome.MobSpawnSettings;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
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.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||||
import net.minecraft.world.level.levelgen.GenerationStep;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.levelgen.*;
|
||||||
import net.minecraft.world.level.levelgen.RandomState;
|
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_21_R1.CraftWorld;
|
import org.bukkit.craftbukkit.v1_21_R1.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_21_R1.generator.CustomChunkGenerator;
|
import org.bukkit.craftbukkit.v1_21_R1.generator.CustomChunkGenerator;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_R1.generator.structure.CraftStructure;
|
||||||
|
import org.bukkit.event.world.AsyncStructureSpawnEvent;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class IrisChunkGenerator extends CustomChunkGenerator {
|
public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||||
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
||||||
|
private static final WrappedReturningMethod<Heightmap, Object> SET_HEIGHT;
|
||||||
private final ChunkGenerator delegate;
|
private final ChunkGenerator delegate;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
||||||
|
private final IrisStructurePopulator populator;
|
||||||
|
|
||||||
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
||||||
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
|
this.populator = new IrisStructurePopulator(engine);
|
||||||
var dimension = engine.getDimension();
|
var dimension = engine.getDimension();
|
||||||
|
|
||||||
KSet<IrisJigsawStructure> placements = new KSet<>();
|
KSet<IrisJigsawStructure> placements = new KSet<>();
|
||||||
@@ -181,8 +193,59 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
|
public void createStructures(RegistryAccess registryAccess, ChunkGeneratorStructureState structureState, StructureManager structureManager, ChunkAccess access, StructureTemplateManager templateManager) {
|
||||||
delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
var chunkPos = access.getPos();
|
||||||
|
var sectionPos = SectionPos.bottomOf(access);
|
||||||
|
var registry = registryAccess.registryOrThrow(Registries.STRUCTURE);
|
||||||
|
populator.populateStructures(chunkPos.x, chunkPos.z, (key, ignoreBiomes) -> {
|
||||||
|
var loc = ResourceLocation.tryParse(key);
|
||||||
|
if (loc == null) return false;
|
||||||
|
var holder = registry.getHolder(loc).orElse(null);
|
||||||
|
if (holder == null) return false;
|
||||||
|
var structure = holder.value();
|
||||||
|
var biomes = structure.biomes();
|
||||||
|
|
||||||
|
var start = structure.generate(
|
||||||
|
registryAccess,
|
||||||
|
this,
|
||||||
|
biomeSource,
|
||||||
|
structureState.randomState(),
|
||||||
|
templateManager,
|
||||||
|
structureState.getLevelSeed(),
|
||||||
|
chunkPos,
|
||||||
|
fetchReferences(structureManager, access, sectionPos, structure),
|
||||||
|
access,
|
||||||
|
(biome) -> ignoreBiomes || biomes.contains(biome)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!start.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BoundingBox box = start.getBoundingBox();
|
||||||
|
AsyncStructureSpawnEvent event = new AsyncStructureSpawnEvent(
|
||||||
|
structureManager.level.getMinecraftWorld().getWorld(),
|
||||||
|
CraftStructure.minecraftToBukkit(structure),
|
||||||
|
new org.bukkit.util.BoundingBox(
|
||||||
|
box.minX(),
|
||||||
|
box.minY(),
|
||||||
|
box.minZ(),
|
||||||
|
box.maxX(),
|
||||||
|
box.maxY(),
|
||||||
|
box.maxZ()
|
||||||
|
), chunkPos.x, chunkPos.z);
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
structureManager.setStartForStructure(sectionPos, structure, start, access);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int fetchReferences(StructureManager structureManager, ChunkAccess access, SectionPos sectionPos, Structure structure) {
|
||||||
|
StructureStart structurestart = structureManager.getStartForStructure(sectionPos, structure, access);
|
||||||
|
return structurestart != null ? structurestart.getReferences() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -200,11 +263,6 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.fillFromNoise(blender, randomstate, structuremanager, ichunkaccess);
|
return delegate.fillFromNoise(blender, randomstate, structuremanager, ichunkaccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
|
||||||
return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
||||||
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
||||||
@@ -212,7 +270,75 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
||||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
|
applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
||||||
|
addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
||||||
|
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addVanillaDecorations(WorldGenLevel level, ChunkAccess chunkAccess, StructureManager structureManager) {
|
||||||
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SectionPos sectionPos = SectionPos.of(chunkAccess.getPos(), level.getMinSection());
|
||||||
|
BlockPos blockPos = sectionPos.origin();
|
||||||
|
WorldgenRandom random = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||||
|
long i = random.setDecorationSeed(level.getSeed(), blockPos.getX(), blockPos.getZ());
|
||||||
|
var structures = level.registryAccess().registryOrThrow(Registries.STRUCTURE);
|
||||||
|
var list = structures.stream()
|
||||||
|
.sorted(Comparator.comparingInt(s -> s.step().ordinal()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
var surface = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE_WG);
|
||||||
|
var ocean = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.OCEAN_FLOOR_WG);
|
||||||
|
var motion = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING);
|
||||||
|
var motionNoLeaves = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES);
|
||||||
|
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
int wX = x + blockPos.getX();
|
||||||
|
int wZ = z + blockPos.getZ();
|
||||||
|
|
||||||
|
int noAir = engine.getHeight(wX, wZ, false) + engine.getMinHeight() + 1;
|
||||||
|
int noFluid = engine.getHeight(wX, wZ, true) + engine.getMinHeight() + 1;
|
||||||
|
SET_HEIGHT.invoke(ocean, x, z, Math.min(noFluid, ocean.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(surface, x, z, Math.min(noAir, surface.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motion, x, z, Math.min(noAir, motion.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motionNoLeaves, x, z, Math.min(noAir, motionNoLeaves.getFirstAvailable(x, z)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < list.size(); j++) {
|
||||||
|
Structure structure = list.get(j);
|
||||||
|
random.setFeatureSeed(i, j, structure.step().ordinal());
|
||||||
|
Supplier<String> supplier = () -> structures.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
|
||||||
|
|
||||||
|
try {
|
||||||
|
level.setCurrentlyGenerating(supplier);
|
||||||
|
structureManager.startsForStructure(sectionPos, structure).forEach((start) -> start.placeInChunk(level, structureManager, this, random, getWritableArea(chunkAccess), chunkAccess.getPos()));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
CrashReport crashReport = CrashReport.forThrowable(exception, "Feature placement");
|
||||||
|
CrashReportCategory category = crashReport.addCategory("Feature");
|
||||||
|
category.setDetail("Description", supplier::get);
|
||||||
|
throw new ReportedException(crashReport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Heightmap.primeHeightmaps(chunkAccess, ChunkStatus.FINAL_HEIGHTMAPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BoundingBox getWritableArea(ChunkAccess ichunkaccess) {
|
||||||
|
ChunkPos chunkPos = ichunkaccess.getPos();
|
||||||
|
int minX = chunkPos.getMinBlockX();
|
||||||
|
int minZ = chunkPos.getMinBlockZ();
|
||||||
|
LevelHeightAccessor heightAccessor = ichunkaccess.getHeightAccessorForGeneration();
|
||||||
|
int minY = heightAccessor.getMinBuildHeight() + 1;
|
||||||
|
int maxY = heightAccessor.getMaxBuildHeight() - 1;
|
||||||
|
return new BoundingBox(minX, minY, minZ, minX + 15, maxY, minZ + 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -235,9 +361,22 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.getGenDepth();
|
return delegate.getGenDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
|
return levelheightaccessor.getMinBuildHeight() + engine.getHeight(i, j, !heightmap_type.isOpaque().test(Blocks.WATER.defaultBlockState())) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
|
int block = engine.getHeight(i, j, true);
|
||||||
|
int water = engine.getHeight(i, j, false);
|
||||||
|
BlockState[] column = new BlockState[levelheightaccessor.getHeight()];
|
||||||
|
for (int k = 0; k < column.length; k++) {
|
||||||
|
if (k <= block) column[k] = Blocks.STONE.defaultBlockState();
|
||||||
|
else if (k <= water) column[k] = Blocks.WATER.defaultBlockState();
|
||||||
|
else column[k] = Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
return new NoiseColumn(levelheightaccessor.getMinBuildHeight(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -250,7 +389,21 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
if (biomeSource == null)
|
if (biomeSource == null)
|
||||||
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
||||||
|
|
||||||
|
Method setHeight = null;
|
||||||
|
for (Method method : Heightmap.class.getDeclaredMethods()) {
|
||||||
|
var types = method.getParameterTypes();
|
||||||
|
if (types.length != 3 || !Arrays.equals(types, new Class<?>[]{int.class, int.class, int.class})
|
||||||
|
|| !method.getReturnType().equals(void.class))
|
||||||
|
continue;
|
||||||
|
setHeight = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (setHeight == null)
|
||||||
|
throw new RuntimeException("Could not find setHeight method in Heightmap!");
|
||||||
|
|
||||||
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
||||||
|
SET_HEIGHT = new WrappedReturningMethod<>(Heightmap.class, setHeight.getName(), setHeight.getParameterTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
||||||
|
|||||||
@@ -1,12 +1,31 @@
|
|||||||
package com.volmit.iris.core.nms.v1_21_R1;
|
package com.volmit.iris.core.nms.v1_21_R1;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
import com.volmit.iris.core.link.Identifier;
|
||||||
|
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||||
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.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
import com.volmit.iris.core.nms.container.BlockProperty;
|
import com.volmit.iris.core.nms.container.BlockProperty;
|
||||||
|
import com.volmit.iris.core.nms.container.StructurePlacement;
|
||||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
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.platform.PlatformChunkGenerator;
|
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||||
@@ -63,6 +82,8 @@ import net.minecraft.world.level.dimension.LevelStem;
|
|||||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
@@ -737,6 +758,71 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void placeStructures(Chunk chunk) {
|
||||||
|
var craft = ((CraftChunk) chunk);
|
||||||
|
var level = craft.getCraftWorld().getHandle();
|
||||||
|
var access = ((CraftChunk) chunk).getHandle(ChunkStatus.FULL);
|
||||||
|
level.getChunkSource().getGenerator().applyBiomeDecoration(level, access, level.structureManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KMap<Identifier, StructurePlacement> collectStructures() {
|
||||||
|
var structureSets = registry().registryOrThrow(Registries.STRUCTURE_SET);
|
||||||
|
var structurePlacements = registry().registryOrThrow(Registries.STRUCTURE_PLACEMENT);
|
||||||
|
return structureSets.keySet()
|
||||||
|
.stream()
|
||||||
|
.map(structureSets::getHolder)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.map(holder -> {
|
||||||
|
var set = holder.value();
|
||||||
|
var placement = set.placement();
|
||||||
|
var key = holder.key().location();
|
||||||
|
StructurePlacement.StructurePlacementBuilder<?, ?> builder;
|
||||||
|
if (placement instanceof RandomSpreadStructurePlacement random) {
|
||||||
|
builder = StructurePlacement.RandomSpread.builder()
|
||||||
|
.separation(random.separation())
|
||||||
|
.spacing(random.spacing())
|
||||||
|
.spreadType(switch (random.spreadType()) {
|
||||||
|
case LINEAR -> IrisJigsawStructurePlacement.SpreadType.LINEAR;
|
||||||
|
case TRIANGULAR -> IrisJigsawStructurePlacement.SpreadType.TRIANGULAR;
|
||||||
|
});
|
||||||
|
} else if (placement instanceof ConcentricRingsStructurePlacement rings) {
|
||||||
|
builder = StructurePlacement.ConcentricRings.builder()
|
||||||
|
.distance(rings.distance())
|
||||||
|
.spread(rings.spread())
|
||||||
|
.count(rings.count());
|
||||||
|
} else {
|
||||||
|
Iris.warn("Unsupported structure placement for set " + key + " with type " + structurePlacements.getKey(placement.type()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new com.volmit.iris.core.nms.container.Pair<>(new Identifier(key.getNamespace(), key.getPath()), builder
|
||||||
|
.salt(placement.salt)
|
||||||
|
.frequency(placement.frequency)
|
||||||
|
.structures(set.structures()
|
||||||
|
.stream()
|
||||||
|
.map(entry -> new StructurePlacement.Structure(
|
||||||
|
entry.weight(),
|
||||||
|
entry.structure()
|
||||||
|
.unwrapKey()
|
||||||
|
.map(ResourceKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.orElse(null),
|
||||||
|
entry.structure().tags()
|
||||||
|
.map(TagKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.toList()
|
||||||
|
))
|
||||||
|
.filter(StructurePlacement.Structure::isValid)
|
||||||
|
.toList())
|
||||||
|
.build());
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toMap(com.volmit.iris.core.nms.container.Pair::getA, com.volmit.iris.core.nms.container.Pair::getB, (a, b) -> a, KMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
||||||
if (!(raw instanceof PlatformChunkGenerator gen))
|
if (!(raw instanceof PlatformChunkGenerator gen))
|
||||||
throw new IllegalStateException("Generator is not platform chunk generator!");
|
throw new IllegalStateException("Generator is not platform chunk generator!");
|
||||||
|
|||||||
@@ -8,16 +8,18 @@ import com.volmit.iris.engine.framework.ResultLocator;
|
|||||||
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
|
import com.volmit.iris.engine.object.IrisStructurePopulator;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
import com.volmit.iris.util.reflect.WrappedField;
|
import com.volmit.iris.util.reflect.WrappedField;
|
||||||
import net.minecraft.core.BlockPos;
|
import com.volmit.iris.util.reflect.WrappedReturningMethod;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.CrashReport;
|
||||||
import net.minecraft.core.HolderSet;
|
import net.minecraft.CrashReportCategory;
|
||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.ReportedException;
|
||||||
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -27,43 +29,54 @@ import net.minecraft.tags.StructureTags;
|
|||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.util.random.WeightedRandomList;
|
import net.minecraft.util.random.WeightedRandomList;
|
||||||
import net.minecraft.world.entity.MobCategory;
|
import net.minecraft.world.entity.MobCategory;
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
import net.minecraft.world.level.*;
|
||||||
import net.minecraft.world.level.NoiseColumn;
|
|
||||||
import net.minecraft.world.level.StructureManager;
|
|
||||||
import net.minecraft.world.level.WorldGenLevel;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.biome.BiomeManager;
|
import net.minecraft.world.level.biome.BiomeManager;
|
||||||
import net.minecraft.world.level.biome.BiomeSource;
|
import net.minecraft.world.level.biome.BiomeSource;
|
||||||
import net.minecraft.world.level.biome.MobSpawnSettings;
|
import net.minecraft.world.level.biome.MobSpawnSettings;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
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.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.levelgen.RandomState;
|
import net.minecraft.world.level.levelgen.*;
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_21_R2.CraftWorld;
|
import org.bukkit.craftbukkit.v1_21_R2.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_21_R2.generator.CustomChunkGenerator;
|
import org.bukkit.craftbukkit.v1_21_R2.generator.CustomChunkGenerator;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_R2.generator.structure.CraftStructure;
|
||||||
|
import org.bukkit.event.world.AsyncStructureSpawnEvent;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class IrisChunkGenerator extends CustomChunkGenerator {
|
public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||||
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
||||||
|
private static final WrappedReturningMethod<Heightmap, Object> SET_HEIGHT;
|
||||||
private final ChunkGenerator delegate;
|
private final ChunkGenerator delegate;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
||||||
|
private final IrisStructurePopulator populator;
|
||||||
|
|
||||||
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
||||||
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
|
this.populator = new IrisStructurePopulator(engine);
|
||||||
var dimension = engine.getDimension();
|
var dimension = engine.getDimension();
|
||||||
|
|
||||||
KSet<IrisJigsawStructure> placements = new KSet<>();
|
KSet<IrisJigsawStructure> placements = new KSet<>();
|
||||||
@@ -180,8 +193,59 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
|
public void createStructures(RegistryAccess registryAccess, ChunkGeneratorStructureState structureState, StructureManager structureManager, ChunkAccess access, StructureTemplateManager templateManager) {
|
||||||
delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
var chunkPos = access.getPos();
|
||||||
|
var sectionPos = SectionPos.bottomOf(access);
|
||||||
|
var registry = registryAccess.lookupOrThrow(Registries.STRUCTURE);
|
||||||
|
populator.populateStructures(chunkPos.x, chunkPos.z, (key, ignoreBiomes) -> {
|
||||||
|
var loc = ResourceLocation.tryParse(key);
|
||||||
|
if (loc == null) return false;
|
||||||
|
var holder = registry.get(loc).orElse(null);
|
||||||
|
if (holder == null) return false;
|
||||||
|
var structure = holder.value();
|
||||||
|
var biomes = structure.biomes();
|
||||||
|
|
||||||
|
var start = structure.generate(
|
||||||
|
registryAccess,
|
||||||
|
this,
|
||||||
|
biomeSource,
|
||||||
|
structureState.randomState(),
|
||||||
|
templateManager,
|
||||||
|
structureState.getLevelSeed(),
|
||||||
|
chunkPos,
|
||||||
|
fetchReferences(structureManager, access, sectionPos, structure),
|
||||||
|
access,
|
||||||
|
(biome) -> ignoreBiomes || biomes.contains(biome)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!start.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BoundingBox box = start.getBoundingBox();
|
||||||
|
AsyncStructureSpawnEvent event = new AsyncStructureSpawnEvent(
|
||||||
|
structureManager.level.getMinecraftWorld().getWorld(),
|
||||||
|
CraftStructure.minecraftToBukkit(structure),
|
||||||
|
new org.bukkit.util.BoundingBox(
|
||||||
|
box.minX(),
|
||||||
|
box.minY(),
|
||||||
|
box.minZ(),
|
||||||
|
box.maxX(),
|
||||||
|
box.maxY(),
|
||||||
|
box.maxZ()
|
||||||
|
), chunkPos.x, chunkPos.z);
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
structureManager.setStartForStructure(sectionPos, structure, start, access);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int fetchReferences(StructureManager structureManager, ChunkAccess access, SectionPos sectionPos, Structure structure) {
|
||||||
|
StructureStart structurestart = structureManager.getStartForStructure(sectionPos, structure, access);
|
||||||
|
return structurestart != null ? structurestart.getReferences() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -199,11 +263,6 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.fillFromNoise(blender, randomstate, structuremanager, ichunkaccess);
|
return delegate.fillFromNoise(blender, randomstate, structuremanager, ichunkaccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
|
||||||
return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
||||||
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
||||||
@@ -211,7 +270,75 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
||||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
|
applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
||||||
|
addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
||||||
|
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addVanillaDecorations(WorldGenLevel level, ChunkAccess chunkAccess, StructureManager structureManager) {
|
||||||
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SectionPos sectionPos = SectionPos.of(chunkAccess.getPos(), level.getMinSectionY());
|
||||||
|
BlockPos blockPos = sectionPos.origin();
|
||||||
|
WorldgenRandom random = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||||
|
long i = random.setDecorationSeed(level.getSeed(), blockPos.getX(), blockPos.getZ());
|
||||||
|
var structures = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||||
|
var list = structures.stream()
|
||||||
|
.sorted(Comparator.comparingInt(s -> s.step().ordinal()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
var surface = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE_WG);
|
||||||
|
var ocean = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.OCEAN_FLOOR_WG);
|
||||||
|
var motion = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING);
|
||||||
|
var motionNoLeaves = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES);
|
||||||
|
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
int wX = x + blockPos.getX();
|
||||||
|
int wZ = z + blockPos.getZ();
|
||||||
|
|
||||||
|
int noAir = engine.getHeight(wX, wZ, false) + engine.getMinHeight() + 1;
|
||||||
|
int noFluid = engine.getHeight(wX, wZ, true) + engine.getMinHeight() + 1;
|
||||||
|
SET_HEIGHT.invoke(ocean, x, z, Math.min(noFluid, ocean.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(surface, x, z, Math.min(noAir, surface.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motion, x, z, Math.min(noAir, motion.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motionNoLeaves, x, z, Math.min(noAir, motionNoLeaves.getFirstAvailable(x, z)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < list.size(); j++) {
|
||||||
|
Structure structure = list.get(j);
|
||||||
|
random.setFeatureSeed(i, j, structure.step().ordinal());
|
||||||
|
Supplier<String> supplier = () -> structures.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
|
||||||
|
|
||||||
|
try {
|
||||||
|
level.setCurrentlyGenerating(supplier);
|
||||||
|
structureManager.startsForStructure(sectionPos, structure).forEach((start) -> start.placeInChunk(level, structureManager, this, random, getWritableArea(chunkAccess), chunkAccess.getPos()));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
CrashReport crashReport = CrashReport.forThrowable(exception, "Feature placement");
|
||||||
|
CrashReportCategory category = crashReport.addCategory("Feature");
|
||||||
|
category.setDetail("Description", supplier::get);
|
||||||
|
throw new ReportedException(crashReport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Heightmap.primeHeightmaps(chunkAccess, ChunkStatus.FINAL_HEIGHTMAPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BoundingBox getWritableArea(ChunkAccess ichunkaccess) {
|
||||||
|
ChunkPos chunkPos = ichunkaccess.getPos();
|
||||||
|
int minX = chunkPos.getMinBlockX();
|
||||||
|
int minZ = chunkPos.getMinBlockZ();
|
||||||
|
LevelHeightAccessor heightAccessor = ichunkaccess.getHeightAccessorForGeneration();
|
||||||
|
int minY = heightAccessor.getMinY() + 1;
|
||||||
|
int maxY = heightAccessor.getMaxY();
|
||||||
|
return new BoundingBox(minX, minY, minZ, minX + 15, maxY, minZ + 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -234,9 +361,22 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.getGenDepth();
|
return delegate.getGenDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
|
return levelheightaccessor.getMinY() + engine.getHeight(i, j, !heightmap_type.isOpaque().test(Blocks.WATER.defaultBlockState())) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
|
int block = engine.getHeight(i, j, true);
|
||||||
|
int water = engine.getHeight(i, j, false);
|
||||||
|
BlockState[] column = new BlockState[levelheightaccessor.getHeight()];
|
||||||
|
for (int k = 0; k < column.length; k++) {
|
||||||
|
if (k <= block) column[k] = Blocks.STONE.defaultBlockState();
|
||||||
|
else if (k <= water) column[k] = Blocks.WATER.defaultBlockState();
|
||||||
|
else column[k] = Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
return new NoiseColumn(levelheightaccessor.getMinY(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -249,7 +389,21 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
if (biomeSource == null)
|
if (biomeSource == null)
|
||||||
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
||||||
|
|
||||||
|
Method setHeight = null;
|
||||||
|
for (Method method : Heightmap.class.getDeclaredMethods()) {
|
||||||
|
var types = method.getParameterTypes();
|
||||||
|
if (types.length != 3 || !Arrays.equals(types, new Class<?>[]{int.class, int.class, int.class})
|
||||||
|
|| !method.getReturnType().equals(void.class))
|
||||||
|
continue;
|
||||||
|
setHeight = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (setHeight == null)
|
||||||
|
throw new RuntimeException("Could not find setHeight method in Heightmap!");
|
||||||
|
|
||||||
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
||||||
|
SET_HEIGHT = new WrappedReturningMethod<>(Heightmap.class, setHeight.getName(), setHeight.getParameterTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
||||||
|
|||||||
@@ -1,9 +1,24 @@
|
|||||||
package com.volmit.iris.core.nms.v1_21_R2;
|
package com.volmit.iris.core.nms.v1_21_R2;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
import com.volmit.iris.core.link.Identifier;
|
||||||
|
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
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.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
|
import com.volmit.iris.core.nms.container.Pair;
|
||||||
|
import com.volmit.iris.core.nms.container.StructurePlacement;
|
||||||
import com.volmit.iris.core.nms.container.BlockProperty;
|
import com.volmit.iris.core.nms.container.BlockProperty;
|
||||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||||
@@ -21,6 +36,7 @@ import com.volmit.iris.util.matter.MatterBiomeInject;
|
|||||||
import com.volmit.iris.util.nbt.mca.NBTWorld;
|
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 com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.shorts.ShortList;
|
import it.unimi.dsi.fastutil.shorts.ShortList;
|
||||||
@@ -60,6 +76,8 @@ import net.minecraft.world.level.dimension.LevelStem;
|
|||||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
@@ -734,6 +752,71 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void placeStructures(Chunk chunk) {
|
||||||
|
var craft = ((CraftChunk) chunk);
|
||||||
|
var level = craft.getCraftWorld().getHandle();
|
||||||
|
var access = ((CraftChunk) chunk).getHandle(ChunkStatus.FULL);
|
||||||
|
level.getChunkSource().getGenerator().applyBiomeDecoration(level, access, level.structureManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KMap<Identifier, StructurePlacement> collectStructures() {
|
||||||
|
var structureSets = registry().lookupOrThrow(Registries.STRUCTURE_SET);
|
||||||
|
var structurePlacements = registry().lookupOrThrow(Registries.STRUCTURE_PLACEMENT);
|
||||||
|
return structureSets.keySet()
|
||||||
|
.stream()
|
||||||
|
.map(structureSets::get)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.map(holder -> {
|
||||||
|
var set = holder.value();
|
||||||
|
var placement = set.placement();
|
||||||
|
var key = holder.key().location();
|
||||||
|
StructurePlacement.StructurePlacementBuilder<?, ?> builder;
|
||||||
|
if (placement instanceof RandomSpreadStructurePlacement random) {
|
||||||
|
builder = StructurePlacement.RandomSpread.builder()
|
||||||
|
.separation(random.separation())
|
||||||
|
.spacing(random.spacing())
|
||||||
|
.spreadType(switch (random.spreadType()) {
|
||||||
|
case LINEAR -> IrisJigsawStructurePlacement.SpreadType.LINEAR;
|
||||||
|
case TRIANGULAR -> IrisJigsawStructurePlacement.SpreadType.TRIANGULAR;
|
||||||
|
});
|
||||||
|
} else if (placement instanceof ConcentricRingsStructurePlacement rings) {
|
||||||
|
builder = StructurePlacement.ConcentricRings.builder()
|
||||||
|
.distance(rings.distance())
|
||||||
|
.spread(rings.spread())
|
||||||
|
.count(rings.count());
|
||||||
|
} else {
|
||||||
|
Iris.warn("Unsupported structure placement for set " + key + " with type " + structurePlacements.getKey(placement.type()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Pair<>(new Identifier(key.getNamespace(), key.getPath()), builder
|
||||||
|
.salt(placement.salt)
|
||||||
|
.frequency(placement.frequency)
|
||||||
|
.structures(set.structures()
|
||||||
|
.stream()
|
||||||
|
.map(entry -> new StructurePlacement.Structure(
|
||||||
|
entry.weight(),
|
||||||
|
entry.structure()
|
||||||
|
.unwrapKey()
|
||||||
|
.map(ResourceKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.orElse(null),
|
||||||
|
entry.structure().tags()
|
||||||
|
.map(TagKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.toList()
|
||||||
|
))
|
||||||
|
.filter(StructurePlacement.Structure::isValid)
|
||||||
|
.toList())
|
||||||
|
.build());
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toMap(Pair::getA, Pair::getB, (a, b) -> a, KMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
||||||
if (!(raw instanceof PlatformChunkGenerator gen))
|
if (!(raw instanceof PlatformChunkGenerator gen))
|
||||||
throw new IllegalStateException("Generator is not platform chunk generator!");
|
throw new IllegalStateException("Generator is not platform chunk generator!");
|
||||||
|
|||||||
@@ -8,12 +8,17 @@ import com.volmit.iris.engine.framework.ResultLocator;
|
|||||||
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
|
import com.volmit.iris.engine.object.IrisStructurePopulator;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
import com.volmit.iris.util.reflect.WrappedField;
|
import com.volmit.iris.util.reflect.WrappedField;
|
||||||
|
import com.volmit.iris.util.reflect.WrappedReturningMethod;
|
||||||
|
import net.minecraft.CrashReport;
|
||||||
|
import net.minecraft.CrashReportCategory;
|
||||||
|
import net.minecraft.ReportedException;
|
||||||
import net.minecraft.core.*;
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
@@ -26,38 +31,49 @@ import net.minecraft.util.random.WeightedRandomList;
|
|||||||
import net.minecraft.world.entity.MobCategory;
|
import net.minecraft.world.entity.MobCategory;
|
||||||
import net.minecraft.world.level.*;
|
import net.minecraft.world.level.*;
|
||||||
import net.minecraft.world.level.biome.*;
|
import net.minecraft.world.level.biome.*;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
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.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.levelgen.RandomState;
|
import net.minecraft.world.level.levelgen.*;
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.BuiltinStructures;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
import net.minecraft.world.level.levelgen.structure.StructureSet;
|
import net.minecraft.world.level.levelgen.structure.StructureSet;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_21_R3.CraftWorld;
|
import org.bukkit.craftbukkit.v1_21_R3.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_21_R3.generator.CustomChunkGenerator;
|
import org.bukkit.craftbukkit.v1_21_R3.generator.CustomChunkGenerator;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_R3.generator.structure.CraftStructure;
|
||||||
|
import org.bukkit.event.world.AsyncStructureSpawnEvent;
|
||||||
import org.spigotmc.SpigotWorldConfig;
|
import org.spigotmc.SpigotWorldConfig;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.List;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Objects;
|
import java.util.*;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class IrisChunkGenerator extends CustomChunkGenerator {
|
public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||||
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
||||||
|
private static final WrappedReturningMethod<Heightmap, Object> SET_HEIGHT;
|
||||||
private final ChunkGenerator delegate;
|
private final ChunkGenerator delegate;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
||||||
|
private final IrisStructurePopulator populator;
|
||||||
|
|
||||||
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
||||||
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
|
this.populator = new IrisStructurePopulator(engine);
|
||||||
var dimension = engine.getDimension();
|
var dimension = engine.getDimension();
|
||||||
|
|
||||||
KSet<IrisJigsawStructure> placements = new KSet<>();
|
KSet<IrisJigsawStructure> placements = new KSet<>();
|
||||||
@@ -174,8 +190,61 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager, ResourceKey<Level> resourcekey) {
|
public void createStructures(RegistryAccess registryAccess, ChunkGeneratorStructureState structureState, StructureManager structureManager, ChunkAccess access, StructureTemplateManager templateManager, ResourceKey<Level> levelKey) {
|
||||||
delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager, resourcekey);
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
var chunkPos = access.getPos();
|
||||||
|
var sectionPos = SectionPos.bottomOf(access);
|
||||||
|
var registry = registryAccess.lookupOrThrow(Registries.STRUCTURE);
|
||||||
|
populator.populateStructures(chunkPos.x, chunkPos.z, (key, ignoreBiomes) -> {
|
||||||
|
var loc = ResourceLocation.tryParse(key);
|
||||||
|
if (loc == null) return false;
|
||||||
|
var holder = registry.get(loc).orElse(null);
|
||||||
|
if (holder == null) return false;
|
||||||
|
var structure = holder.value();
|
||||||
|
var biomes = structure.biomes();
|
||||||
|
|
||||||
|
var start = structure.generate(
|
||||||
|
holder,
|
||||||
|
levelKey,
|
||||||
|
registryAccess,
|
||||||
|
this,
|
||||||
|
biomeSource,
|
||||||
|
structureState.randomState(),
|
||||||
|
templateManager,
|
||||||
|
structureState.getLevelSeed(),
|
||||||
|
chunkPos,
|
||||||
|
fetchReferences(structureManager, access, sectionPos, structure),
|
||||||
|
access,
|
||||||
|
biome -> ignoreBiomes || biomes.contains(biome)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!start.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BoundingBox box = start.getBoundingBox();
|
||||||
|
AsyncStructureSpawnEvent event = new AsyncStructureSpawnEvent(
|
||||||
|
structureManager.level.getMinecraftWorld().getWorld(),
|
||||||
|
CraftStructure.minecraftToBukkit(structure),
|
||||||
|
new org.bukkit.util.BoundingBox(
|
||||||
|
box.minX(),
|
||||||
|
box.minY(),
|
||||||
|
box.minZ(),
|
||||||
|
box.maxX(),
|
||||||
|
box.maxY(),
|
||||||
|
box.maxZ()
|
||||||
|
), chunkPos.x, chunkPos.z);
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
structureManager.setStartForStructure(sectionPos, structure, start, access);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int fetchReferences(StructureManager structureManager, ChunkAccess access, SectionPos sectionPos, Structure structure) {
|
||||||
|
StructureStart structurestart = structureManager.getStartForStructure(sectionPos, structure, access);
|
||||||
|
return structurestart != null ? structurestart.getReferences() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -208,11 +277,6 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.fillFromNoise(blender, randomstate, structuremanager, ichunkaccess);
|
return delegate.fillFromNoise(blender, randomstate, structuremanager, ichunkaccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
|
||||||
return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
||||||
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
||||||
@@ -220,7 +284,7 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
||||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
|
applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -230,22 +294,70 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
||||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, vanilla);
|
addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
||||||
|
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getFirstFreeHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
public void addVanillaDecorations(WorldGenLevel level, ChunkAccess chunkAccess, StructureManager structureManager) {
|
||||||
return delegate.getFirstFreeHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SectionPos sectionPos = SectionPos.of(chunkAccess.getPos(), level.getMinSectionY());
|
||||||
|
BlockPos blockPos = sectionPos.origin();
|
||||||
|
WorldgenRandom random = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||||
|
long i = random.setDecorationSeed(level.getSeed(), blockPos.getX(), blockPos.getZ());
|
||||||
|
var structures = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||||
|
var list = structures.stream()
|
||||||
|
.sorted(Comparator.comparingInt(s -> s.step().ordinal()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
var surface = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE_WG);
|
||||||
|
var ocean = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.OCEAN_FLOOR_WG);
|
||||||
|
var motion = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING);
|
||||||
|
var motionNoLeaves = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES);
|
||||||
|
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
int wX = x + blockPos.getX();
|
||||||
|
int wZ = z + blockPos.getZ();
|
||||||
|
|
||||||
|
int noAir = engine.getHeight(wX, wZ, false) + engine.getMinHeight() + 1;
|
||||||
|
int noFluid = engine.getHeight(wX, wZ, true) + engine.getMinHeight() + 1;
|
||||||
|
SET_HEIGHT.invoke(ocean, x, z, Math.min(noFluid, ocean.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(surface, x, z, Math.min(noAir, surface.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motion, x, z, Math.min(noAir, motion.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motionNoLeaves, x, z, Math.min(noAir, motionNoLeaves.getFirstAvailable(x, z)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
for (int j = 0; j < list.size(); j++) {
|
||||||
public int getFirstOccupiedHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
Structure structure = list.get(j);
|
||||||
return delegate.getFirstOccupiedHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
random.setFeatureSeed(i, j, structure.step().ordinal());
|
||||||
|
Supplier<String> supplier = () -> structures.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
|
||||||
|
|
||||||
|
try {
|
||||||
|
level.setCurrentlyGenerating(supplier);
|
||||||
|
structureManager.startsForStructure(sectionPos, structure).forEach((start) -> start.placeInChunk(level, structureManager, this, random, getWritableArea(chunkAccess), chunkAccess.getPos()));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
CrashReport crashReport = CrashReport.forThrowable(exception, "Feature placement");
|
||||||
|
CrashReportCategory category = crashReport.addCategory("Feature");
|
||||||
|
category.setDetail("Description", supplier::get);
|
||||||
|
throw new ReportedException(crashReport);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
Heightmap.primeHeightmaps(chunkAccess, ChunkStatus.FINAL_HEIGHTMAPS);
|
||||||
public void addVanillaDecorations(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
}
|
||||||
delegate.addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
|
||||||
|
private static BoundingBox getWritableArea(ChunkAccess ichunkaccess) {
|
||||||
|
ChunkPos chunkPos = ichunkaccess.getPos();
|
||||||
|
int minX = chunkPos.getMinBlockX();
|
||||||
|
int minZ = chunkPos.getMinBlockZ();
|
||||||
|
LevelHeightAccessor heightAccessor = ichunkaccess.getHeightAccessorForGeneration();
|
||||||
|
int minY = heightAccessor.getMinY() + 1;
|
||||||
|
int maxY = heightAccessor.getMaxY();
|
||||||
|
return new BoundingBox(minX, minY, minZ, minX + 15, maxY, minZ + 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -263,9 +375,22 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.getGenDepth();
|
return delegate.getGenDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
|
return levelheightaccessor.getMinY() + engine.getHeight(i, j, !heightmap_type.isOpaque().test(Blocks.WATER.defaultBlockState())) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
|
int block = engine.getHeight(i, j, true);
|
||||||
|
int water = engine.getHeight(i, j, false);
|
||||||
|
BlockState[] column = new BlockState[levelheightaccessor.getHeight()];
|
||||||
|
for (int k = 0; k < column.length; k++) {
|
||||||
|
if (k <= block) column[k] = Blocks.STONE.defaultBlockState();
|
||||||
|
else if (k <= water) column[k] = Blocks.WATER.defaultBlockState();
|
||||||
|
else column[k] = Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
return new NoiseColumn(levelheightaccessor.getMinY(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -294,7 +419,21 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
if (biomeSource == null)
|
if (biomeSource == null)
|
||||||
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
||||||
|
|
||||||
|
Method setHeight = null;
|
||||||
|
for (Method method : Heightmap.class.getDeclaredMethods()) {
|
||||||
|
var types = method.getParameterTypes();
|
||||||
|
if (types.length != 3 || !Arrays.equals(types, new Class<?>[]{int.class, int.class, int.class})
|
||||||
|
|| !method.getReturnType().equals(void.class))
|
||||||
|
continue;
|
||||||
|
setHeight = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (setHeight == null)
|
||||||
|
throw new RuntimeException("Could not find setHeight method in Heightmap!");
|
||||||
|
|
||||||
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
||||||
|
SET_HEIGHT = new WrappedReturningMethod<>(Heightmap.class, setHeight.getName(), setHeight.getParameterTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
||||||
|
|||||||
@@ -2,12 +2,17 @@ package com.volmit.iris.core.nms.v1_21_R3;
|
|||||||
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.link.Identifier;
|
||||||
import com.volmit.iris.core.nms.INMSBinding;
|
import com.volmit.iris.core.nms.INMSBinding;
|
||||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
|
import com.volmit.iris.core.nms.container.Pair;
|
||||||
|
import com.volmit.iris.core.nms.container.StructurePlacement;
|
||||||
import com.volmit.iris.core.nms.container.BlockProperty;
|
import com.volmit.iris.core.nms.container.BlockProperty;
|
||||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
||||||
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||||
import com.volmit.iris.util.agent.Agent;
|
import com.volmit.iris.util.agent.Agent;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
@@ -60,6 +65,9 @@ import net.minecraft.world.level.dimension.LevelStem;
|
|||||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.StructureSet;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
@@ -88,10 +96,16 @@ import java.lang.reflect.InvocationTargetException;
|
|||||||
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.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
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.locks.ReentrantLock;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
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<>();
|
||||||
@@ -178,14 +192,14 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Contract(value = "null, _, _ -> null", pure = true)
|
@Contract(value = "null, _, _ -> null", pure = true)
|
||||||
private Object convertFromTag(net.minecraft.nbt.Tag tag, int depth, int maxDepth) {
|
private Object convertFromTag(Tag tag, int depth, int maxDepth) {
|
||||||
if (tag == null || depth > maxDepth) return null;
|
if (tag == null || depth > maxDepth) return null;
|
||||||
return switch (tag) {
|
return switch (tag) {
|
||||||
case CollectionTag<?> collection -> {
|
case CollectionTag<?> collection -> {
|
||||||
KList<Object> list = new KList<>();
|
KList<Object> list = new KList<>();
|
||||||
|
|
||||||
for (Object i : collection) {
|
for (Object i : collection) {
|
||||||
if (i instanceof net.minecraft.nbt.Tag t)
|
if (i instanceof Tag t)
|
||||||
list.add(convertFromTag(t, depth + 1, maxDepth));
|
list.add(convertFromTag(t, depth + 1, maxDepth));
|
||||||
else list.add(i);
|
else list.add(i);
|
||||||
}
|
}
|
||||||
@@ -242,7 +256,7 @@ public class NMSBinding implements INMSBinding {
|
|||||||
yield tag;
|
yield tag;
|
||||||
}
|
}
|
||||||
case List<?> list -> {
|
case List<?> list -> {
|
||||||
var tag = new net.minecraft.nbt.ListTag();
|
var tag = new ListTag();
|
||||||
for (var i : list) {
|
for (var i : list) {
|
||||||
tag.add(convertToTag(i, depth + 1, maxDepth));
|
tag.add(convertToTag(i, depth + 1, maxDepth));
|
||||||
}
|
}
|
||||||
@@ -496,13 +510,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 = net.minecraft.core.IdMapper.class.getDeclaredField("tToId");
|
Field cf = IdMapper.class.getDeclaredField("tToId");
|
||||||
Field df = net.minecraft.core.IdMapper.class.getDeclaredField("idToT");
|
Field df = IdMapper.class.getDeclaredField("idToT");
|
||||||
Field bf = net.minecraft.core.IdMapper.class.getDeclaredField("nextId");
|
Field bf = IdMapper.class.getDeclaredField("nextId");
|
||||||
cf.setAccessible(true);
|
cf.setAccessible(true);
|
||||||
df.setAccessible(true);
|
df.setAccessible(true);
|
||||||
bf.setAccessible(true);
|
bf.setAccessible(true);
|
||||||
net.minecraft.core.IdMapper<BlockState> blockData = Block.BLOCK_STATE_REGISTRY;
|
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);
|
||||||
@@ -600,7 +614,7 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public java.awt.Color getBiomeColor(Location location, BiomeColor type) {
|
public Color getBiomeColor(Location location, BiomeColor type) {
|
||||||
LevelReader reader = ((CraftWorld) location.getWorld()).getHandle();
|
LevelReader reader = ((CraftWorld) location.getWorld()).getHandle();
|
||||||
var holder = reader.getBiome(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()));
|
var holder = reader.getBiome(new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()));
|
||||||
var biome = holder.value();
|
var biome = holder.value();
|
||||||
@@ -733,6 +747,71 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void placeStructures(Chunk chunk) {
|
||||||
|
var craft = ((CraftChunk) chunk);
|
||||||
|
var level = craft.getCraftWorld().getHandle();
|
||||||
|
var access = ((CraftChunk) chunk).getHandle(ChunkStatus.FULL);
|
||||||
|
level.getChunkSource().getGenerator().applyBiomeDecoration(level, access, level.structureManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KMap<Identifier, StructurePlacement> collectStructures() {
|
||||||
|
var structureSets = registry().lookupOrThrow(Registries.STRUCTURE_SET);
|
||||||
|
var structurePlacements = registry().lookupOrThrow(Registries.STRUCTURE_PLACEMENT);
|
||||||
|
return structureSets.keySet()
|
||||||
|
.stream()
|
||||||
|
.map(structureSets::get)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.map(holder -> {
|
||||||
|
var set = holder.value();
|
||||||
|
var placement = set.placement();
|
||||||
|
var key = holder.key().location();
|
||||||
|
StructurePlacement.StructurePlacementBuilder<?, ?> builder;
|
||||||
|
if (placement instanceof RandomSpreadStructurePlacement random) {
|
||||||
|
builder = StructurePlacement.RandomSpread.builder()
|
||||||
|
.separation(random.separation())
|
||||||
|
.spacing(random.spacing())
|
||||||
|
.spreadType(switch (random.spreadType()) {
|
||||||
|
case LINEAR -> IrisJigsawStructurePlacement.SpreadType.LINEAR;
|
||||||
|
case TRIANGULAR -> IrisJigsawStructurePlacement.SpreadType.TRIANGULAR;
|
||||||
|
});
|
||||||
|
} else if (placement instanceof ConcentricRingsStructurePlacement rings) {
|
||||||
|
builder = StructurePlacement.ConcentricRings.builder()
|
||||||
|
.distance(rings.distance())
|
||||||
|
.spread(rings.spread())
|
||||||
|
.count(rings.count());
|
||||||
|
} else {
|
||||||
|
Iris.warn("Unsupported structure placement for set " + key + " with type " + structurePlacements.getKey(placement.type()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Pair<>(new Identifier(key.getNamespace(), key.getPath()), builder
|
||||||
|
.salt(placement.salt)
|
||||||
|
.frequency(placement.frequency)
|
||||||
|
.structures(set.structures()
|
||||||
|
.stream()
|
||||||
|
.map(entry -> new StructurePlacement.Structure(
|
||||||
|
entry.weight(),
|
||||||
|
entry.structure()
|
||||||
|
.unwrapKey()
|
||||||
|
.map(ResourceKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.orElse(null),
|
||||||
|
entry.structure().tags()
|
||||||
|
.map(TagKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.toList()
|
||||||
|
))
|
||||||
|
.filter(StructurePlacement.Structure::isValid)
|
||||||
|
.toList())
|
||||||
|
.build());
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toMap(Pair::getA, Pair::getB, (a,b) -> a, KMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
||||||
if (!(raw instanceof PlatformChunkGenerator gen))
|
if (!(raw instanceof PlatformChunkGenerator gen))
|
||||||
throw new IllegalStateException("Generator is not platform chunk generator!");
|
throw new IllegalStateException("Generator is not platform chunk generator!");
|
||||||
|
|||||||
@@ -8,12 +8,17 @@ import com.volmit.iris.engine.framework.ResultLocator;
|
|||||||
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
|
import com.volmit.iris.engine.object.IrisStructurePopulator;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
import com.volmit.iris.util.reflect.WrappedField;
|
import com.volmit.iris.util.reflect.WrappedField;
|
||||||
|
import com.volmit.iris.util.reflect.WrappedReturningMethod;
|
||||||
|
import net.minecraft.CrashReport;
|
||||||
|
import net.minecraft.CrashReportCategory;
|
||||||
|
import net.minecraft.ReportedException;
|
||||||
import net.minecraft.core.*;
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
@@ -26,38 +31,48 @@ import net.minecraft.util.random.WeightedList;
|
|||||||
import net.minecraft.world.entity.MobCategory;
|
import net.minecraft.world.entity.MobCategory;
|
||||||
import net.minecraft.world.level.*;
|
import net.minecraft.world.level.*;
|
||||||
import net.minecraft.world.level.biome.*;
|
import net.minecraft.world.level.biome.*;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
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.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.levelgen.RandomState;
|
import net.minecraft.world.level.levelgen.*;
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
import net.minecraft.world.level.levelgen.structure.StructureSet;
|
import net.minecraft.world.level.levelgen.structure.StructureSet;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_21_R4.CraftWorld;
|
import org.bukkit.craftbukkit.v1_21_R4.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_21_R4.generator.CustomChunkGenerator;
|
import org.bukkit.craftbukkit.v1_21_R4.generator.CustomChunkGenerator;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_R4.generator.structure.CraftStructure;
|
||||||
|
import org.bukkit.event.world.AsyncStructureSpawnEvent;
|
||||||
import org.spigotmc.SpigotWorldConfig;
|
import org.spigotmc.SpigotWorldConfig;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.List;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Objects;
|
import java.util.*;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class IrisChunkGenerator extends CustomChunkGenerator {
|
public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||||
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
||||||
|
private static final WrappedReturningMethod<Heightmap, Object> SET_HEIGHT;
|
||||||
private final ChunkGenerator delegate;
|
private final ChunkGenerator delegate;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
||||||
|
private final IrisStructurePopulator populator;
|
||||||
|
|
||||||
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
||||||
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
|
this.populator = new IrisStructurePopulator(engine);
|
||||||
var dimension = engine.getDimension();
|
var dimension = engine.getDimension();
|
||||||
|
|
||||||
KSet<IrisJigsawStructure> placements = new KSet<>();
|
KSet<IrisJigsawStructure> placements = new KSet<>();
|
||||||
@@ -174,8 +189,61 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager, ResourceKey<Level> resourcekey) {
|
public void createStructures(RegistryAccess registryAccess, ChunkGeneratorStructureState structureState, StructureManager structureManager, ChunkAccess access, StructureTemplateManager templateManager, ResourceKey<Level> levelKey) {
|
||||||
delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager, resourcekey);
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
var chunkPos = access.getPos();
|
||||||
|
var sectionPos = SectionPos.bottomOf(access);
|
||||||
|
var registry = registryAccess.lookupOrThrow(Registries.STRUCTURE);
|
||||||
|
populator.populateStructures(chunkPos.x, chunkPos.z, (key, ignoreBiomes) -> {
|
||||||
|
var loc = ResourceLocation.tryParse(key);
|
||||||
|
if (loc == null) return false;
|
||||||
|
var holder = registry.get(loc).orElse(null);
|
||||||
|
if (holder == null) return false;
|
||||||
|
var structure = holder.value();
|
||||||
|
var biomes = structure.biomes();
|
||||||
|
|
||||||
|
var start = structure.generate(
|
||||||
|
holder,
|
||||||
|
levelKey,
|
||||||
|
registryAccess,
|
||||||
|
this,
|
||||||
|
biomeSource,
|
||||||
|
structureState.randomState(),
|
||||||
|
templateManager,
|
||||||
|
structureState.getLevelSeed(),
|
||||||
|
chunkPos,
|
||||||
|
fetchReferences(structureManager, access, sectionPos, structure),
|
||||||
|
access,
|
||||||
|
biome -> ignoreBiomes || biomes.contains(biome)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!start.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BoundingBox box = start.getBoundingBox();
|
||||||
|
AsyncStructureSpawnEvent event = new AsyncStructureSpawnEvent(
|
||||||
|
structureManager.level.getMinecraftWorld().getWorld(),
|
||||||
|
CraftStructure.minecraftToBukkit(structure),
|
||||||
|
new org.bukkit.util.BoundingBox(
|
||||||
|
box.minX(),
|
||||||
|
box.minY(),
|
||||||
|
box.minZ(),
|
||||||
|
box.maxX(),
|
||||||
|
box.maxY(),
|
||||||
|
box.maxZ()
|
||||||
|
), chunkPos.x, chunkPos.z);
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
structureManager.setStartForStructure(sectionPos, structure, start, access);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int fetchReferences(StructureManager structureManager, ChunkAccess access, SectionPos sectionPos, Structure structure) {
|
||||||
|
StructureStart structurestart = structureManager.getStartForStructure(sectionPos, structure, access);
|
||||||
|
return structurestart != null ? structurestart.getReferences() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -208,11 +276,6 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.fillFromNoise(blender, randomstate, structuremanager, ichunkaccess);
|
return delegate.fillFromNoise(blender, randomstate, structuremanager, ichunkaccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
|
||||||
return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeightedList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
public WeightedList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
||||||
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
||||||
@@ -220,7 +283,7 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
||||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
|
applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -230,22 +293,70 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
||||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, vanilla);
|
addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
||||||
|
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getFirstFreeHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
public void addVanillaDecorations(WorldGenLevel level, ChunkAccess chunkAccess, StructureManager structureManager) {
|
||||||
return delegate.getFirstFreeHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SectionPos sectionPos = SectionPos.of(chunkAccess.getPos(), level.getMinSectionY());
|
||||||
|
BlockPos blockPos = sectionPos.origin();
|
||||||
|
WorldgenRandom random = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||||
|
long i = random.setDecorationSeed(level.getSeed(), blockPos.getX(), blockPos.getZ());
|
||||||
|
var structures = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||||
|
var list = structures.stream()
|
||||||
|
.sorted(Comparator.comparingInt(s -> s.step().ordinal()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
var surface = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE_WG);
|
||||||
|
var ocean = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.OCEAN_FLOOR_WG);
|
||||||
|
var motion = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING);
|
||||||
|
var motionNoLeaves = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES);
|
||||||
|
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
int wX = x + blockPos.getX();
|
||||||
|
int wZ = z + blockPos.getZ();
|
||||||
|
|
||||||
|
int noAir = engine.getHeight(wX, wZ, false) + engine.getMinHeight() + 1;
|
||||||
|
int noFluid = engine.getHeight(wX, wZ, true) + engine.getMinHeight() + 1;
|
||||||
|
SET_HEIGHT.invoke(ocean, x, z, Math.min(noFluid, ocean.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(surface, x, z, Math.min(noAir, surface.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motion, x, z, Math.min(noAir, motion.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motionNoLeaves, x, z, Math.min(noAir, motionNoLeaves.getFirstAvailable(x, z)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
for (int j = 0; j < list.size(); j++) {
|
||||||
public int getFirstOccupiedHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
Structure structure = list.get(j);
|
||||||
return delegate.getFirstOccupiedHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
random.setFeatureSeed(i, j, structure.step().ordinal());
|
||||||
|
Supplier<String> supplier = () -> structures.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
|
||||||
|
|
||||||
|
try {
|
||||||
|
level.setCurrentlyGenerating(supplier);
|
||||||
|
structureManager.startsForStructure(sectionPos, structure).forEach((start) -> start.placeInChunk(level, structureManager, this, random, getWritableArea(chunkAccess), chunkAccess.getPos()));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
CrashReport crashReport = CrashReport.forThrowable(exception, "Feature placement");
|
||||||
|
CrashReportCategory category = crashReport.addCategory("Feature");
|
||||||
|
category.setDetail("Description", supplier::get);
|
||||||
|
throw new ReportedException(crashReport);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
Heightmap.primeHeightmaps(chunkAccess, ChunkStatus.FINAL_HEIGHTMAPS);
|
||||||
public void addVanillaDecorations(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
}
|
||||||
delegate.addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
|
||||||
|
private static BoundingBox getWritableArea(ChunkAccess ichunkaccess) {
|
||||||
|
ChunkPos chunkPos = ichunkaccess.getPos();
|
||||||
|
int minX = chunkPos.getMinBlockX();
|
||||||
|
int minZ = chunkPos.getMinBlockZ();
|
||||||
|
LevelHeightAccessor heightAccessor = ichunkaccess.getHeightAccessorForGeneration();
|
||||||
|
int minY = heightAccessor.getMinY() + 1;
|
||||||
|
int maxY = heightAccessor.getMaxY();
|
||||||
|
return new BoundingBox(minX, minY, minZ, minX + 15, maxY, minZ + 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -263,9 +374,22 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.getGenDepth();
|
return delegate.getGenDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
|
return levelheightaccessor.getMinY() + engine.getHeight(i, j, !heightmap_type.isOpaque().test(Blocks.WATER.defaultBlockState())) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
|
int block = engine.getHeight(i, j, true);
|
||||||
|
int water = engine.getHeight(i, j, false);
|
||||||
|
BlockState[] column = new BlockState[levelheightaccessor.getHeight()];
|
||||||
|
for (int k = 0; k < column.length; k++) {
|
||||||
|
if (k <= block) column[k] = Blocks.STONE.defaultBlockState();
|
||||||
|
else if (k <= water) column[k] = Blocks.WATER.defaultBlockState();
|
||||||
|
else column[k] = Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
return new NoiseColumn(levelheightaccessor.getMinY(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -294,7 +418,21 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
if (biomeSource == null)
|
if (biomeSource == null)
|
||||||
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
||||||
|
|
||||||
|
Method setHeight = null;
|
||||||
|
for (Method method : Heightmap.class.getDeclaredMethods()) {
|
||||||
|
var types = method.getParameterTypes();
|
||||||
|
if (types.length != 3 || !Arrays.equals(types, new Class<?>[]{int.class, int.class, int.class})
|
||||||
|
|| !method.getReturnType().equals(void.class))
|
||||||
|
continue;
|
||||||
|
setHeight = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (setHeight == null)
|
||||||
|
throw new RuntimeException("Could not find setHeight method in Heightmap!");
|
||||||
|
|
||||||
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
||||||
|
SET_HEIGHT = new WrappedReturningMethod<>(Heightmap.class, setHeight.getName(), setHeight.getParameterTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ package com.volmit.iris.core.nms.v1_21_R4;
|
|||||||
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.link.Identifier;
|
||||||
import com.volmit.iris.core.nms.INMSBinding;
|
import com.volmit.iris.core.nms.INMSBinding;
|
||||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
|
import com.volmit.iris.core.nms.container.Pair;
|
||||||
|
import com.volmit.iris.core.nms.container.StructurePlacement;
|
||||||
import com.volmit.iris.core.nms.container.BlockProperty;
|
import com.volmit.iris.core.nms.container.BlockProperty;
|
||||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||||
import com.volmit.iris.util.agent.Agent;
|
import com.volmit.iris.util.agent.Agent;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
@@ -60,6 +64,8 @@ import net.minecraft.world.level.dimension.LevelStem;
|
|||||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
@@ -92,6 +98,7 @@ import java.util.List;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
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.stream.Collectors;
|
||||||
|
|
||||||
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<>();
|
||||||
@@ -733,6 +740,71 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void placeStructures(Chunk chunk) {
|
||||||
|
var craft = ((CraftChunk) chunk);
|
||||||
|
var level = craft.getCraftWorld().getHandle();
|
||||||
|
var access = ((CraftChunk) chunk).getHandle(ChunkStatus.FULL);
|
||||||
|
level.getChunkSource().getGenerator().applyBiomeDecoration(level, access, level.structureManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KMap<Identifier, StructurePlacement> collectStructures() {
|
||||||
|
var structureSets = registry().lookupOrThrow(Registries.STRUCTURE_SET);
|
||||||
|
var structurePlacements = registry().lookupOrThrow(Registries.STRUCTURE_PLACEMENT);
|
||||||
|
return structureSets.keySet()
|
||||||
|
.stream()
|
||||||
|
.map(structureSets::get)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.map(holder -> {
|
||||||
|
var set = holder.value();
|
||||||
|
var placement = set.placement();
|
||||||
|
var key = holder.key().location();
|
||||||
|
StructurePlacement.StructurePlacementBuilder<?, ?> builder;
|
||||||
|
if (placement instanceof RandomSpreadStructurePlacement random) {
|
||||||
|
builder = StructurePlacement.RandomSpread.builder()
|
||||||
|
.separation(random.separation())
|
||||||
|
.spacing(random.spacing())
|
||||||
|
.spreadType(switch (random.spreadType()) {
|
||||||
|
case LINEAR -> IrisJigsawStructurePlacement.SpreadType.LINEAR;
|
||||||
|
case TRIANGULAR -> IrisJigsawStructurePlacement.SpreadType.TRIANGULAR;
|
||||||
|
});
|
||||||
|
} else if (placement instanceof ConcentricRingsStructurePlacement rings) {
|
||||||
|
builder = StructurePlacement.ConcentricRings.builder()
|
||||||
|
.distance(rings.distance())
|
||||||
|
.spread(rings.spread())
|
||||||
|
.count(rings.count());
|
||||||
|
} else {
|
||||||
|
Iris.warn("Unsupported structure placement for set " + key + " with type " + structurePlacements.getKey(placement.type()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Pair<>(new Identifier(key.getNamespace(), key.getPath()), builder
|
||||||
|
.salt(placement.salt)
|
||||||
|
.frequency(placement.frequency)
|
||||||
|
.structures(set.structures()
|
||||||
|
.stream()
|
||||||
|
.map(entry -> new StructurePlacement.Structure(
|
||||||
|
entry.weight(),
|
||||||
|
entry.structure()
|
||||||
|
.unwrapKey()
|
||||||
|
.map(ResourceKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.orElse(null),
|
||||||
|
entry.structure().tags()
|
||||||
|
.map(TagKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.toList()
|
||||||
|
))
|
||||||
|
.filter(StructurePlacement.Structure::isValid)
|
||||||
|
.toList())
|
||||||
|
.build());
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toMap(Pair::getA, Pair::getB, (a, b) -> a, KMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
||||||
if (!(raw instanceof PlatformChunkGenerator gen))
|
if (!(raw instanceof PlatformChunkGenerator gen))
|
||||||
throw new IllegalStateException("Generator is not platform chunk generator!");
|
throw new IllegalStateException("Generator is not platform chunk generator!");
|
||||||
|
|||||||
@@ -8,12 +8,17 @@ import com.volmit.iris.engine.framework.ResultLocator;
|
|||||||
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
import com.volmit.iris.engine.framework.WrongEngineBroException;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
import com.volmit.iris.engine.object.IrisJigsawStructure;
|
||||||
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
|
import com.volmit.iris.engine.object.IrisStructurePopulator;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.collection.KSet;
|
import com.volmit.iris.util.collection.KSet;
|
||||||
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
import com.volmit.iris.util.mantle.flag.MantleFlag;
|
||||||
import com.volmit.iris.util.math.Position2;
|
import com.volmit.iris.util.math.Position2;
|
||||||
import com.volmit.iris.util.reflect.WrappedField;
|
import com.volmit.iris.util.reflect.WrappedField;
|
||||||
|
import com.volmit.iris.util.reflect.WrappedReturningMethod;
|
||||||
|
import net.minecraft.CrashReport;
|
||||||
|
import net.minecraft.CrashReportCategory;
|
||||||
|
import net.minecraft.ReportedException;
|
||||||
import net.minecraft.core.*;
|
import net.minecraft.core.*;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
@@ -26,38 +31,48 @@ import net.minecraft.util.random.WeightedList;
|
|||||||
import net.minecraft.world.entity.MobCategory;
|
import net.minecraft.world.entity.MobCategory;
|
||||||
import net.minecraft.world.level.*;
|
import net.minecraft.world.level.*;
|
||||||
import net.minecraft.world.level.biome.*;
|
import net.minecraft.world.level.biome.*;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
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.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.levelgen.RandomState;
|
import net.minecraft.world.level.levelgen.*;
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
||||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||||
import net.minecraft.world.level.levelgen.structure.StructureSet;
|
import net.minecraft.world.level.levelgen.structure.StructureSet;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_21_R5.CraftWorld;
|
import org.bukkit.craftbukkit.v1_21_R5.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_21_R5.generator.CustomChunkGenerator;
|
import org.bukkit.craftbukkit.v1_21_R5.generator.CustomChunkGenerator;
|
||||||
|
import org.bukkit.craftbukkit.v1_21_R5.generator.structure.CraftStructure;
|
||||||
|
import org.bukkit.event.world.AsyncStructureSpawnEvent;
|
||||||
import org.spigotmc.SpigotWorldConfig;
|
import org.spigotmc.SpigotWorldConfig;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.List;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Objects;
|
import java.util.*;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class IrisChunkGenerator extends CustomChunkGenerator {
|
public class IrisChunkGenerator extends CustomChunkGenerator {
|
||||||
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
private static final WrappedField<ChunkGenerator, BiomeSource> BIOME_SOURCE;
|
||||||
|
private static final WrappedReturningMethod<Heightmap, Object> SET_HEIGHT;
|
||||||
private final ChunkGenerator delegate;
|
private final ChunkGenerator delegate;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
private final KMap<ResourceKey<Structure>, KSet<String>> structures = new KMap<>();
|
||||||
|
private final IrisStructurePopulator populator;
|
||||||
|
|
||||||
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
|
||||||
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
super(((CraftWorld) world).getHandle(), edit(delegate, new CustomBiomeSource(seed, engine, world)), null);
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
|
this.populator = new IrisStructurePopulator(engine);
|
||||||
var dimension = engine.getDimension();
|
var dimension = engine.getDimension();
|
||||||
|
|
||||||
KSet<IrisJigsawStructure> placements = new KSet<>();
|
KSet<IrisJigsawStructure> placements = new KSet<>();
|
||||||
@@ -174,8 +189,61 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager, ResourceKey<Level> resourcekey) {
|
public void createStructures(RegistryAccess registryAccess, ChunkGeneratorStructureState structureState, StructureManager structureManager, ChunkAccess access, StructureTemplateManager templateManager, ResourceKey<Level> levelKey) {
|
||||||
delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager, resourcekey);
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
var chunkPos = access.getPos();
|
||||||
|
var sectionPos = SectionPos.bottomOf(access);
|
||||||
|
var registry = registryAccess.lookupOrThrow(Registries.STRUCTURE);
|
||||||
|
populator.populateStructures(chunkPos.x, chunkPos.z, (key, ignoreBiomes) -> {
|
||||||
|
var loc = ResourceLocation.tryParse(key);
|
||||||
|
if (loc == null) return false;
|
||||||
|
var holder = registry.get(loc).orElse(null);
|
||||||
|
if (holder == null) return false;
|
||||||
|
var structure = holder.value();
|
||||||
|
var biomes = structure.biomes();
|
||||||
|
|
||||||
|
var start = structure.generate(
|
||||||
|
holder,
|
||||||
|
levelKey,
|
||||||
|
registryAccess,
|
||||||
|
this,
|
||||||
|
biomeSource,
|
||||||
|
structureState.randomState(),
|
||||||
|
templateManager,
|
||||||
|
structureState.getLevelSeed(),
|
||||||
|
chunkPos,
|
||||||
|
fetchReferences(structureManager, access, sectionPos, structure),
|
||||||
|
access,
|
||||||
|
biome -> ignoreBiomes || biomes.contains(biome)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!start.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BoundingBox box = start.getBoundingBox();
|
||||||
|
AsyncStructureSpawnEvent event = new AsyncStructureSpawnEvent(
|
||||||
|
structureManager.level.getMinecraftWorld().getWorld(),
|
||||||
|
CraftStructure.minecraftToBukkit(structure),
|
||||||
|
new org.bukkit.util.BoundingBox(
|
||||||
|
box.minX(),
|
||||||
|
box.minY(),
|
||||||
|
box.minZ(),
|
||||||
|
box.maxX(),
|
||||||
|
box.maxY(),
|
||||||
|
box.maxZ()
|
||||||
|
), chunkPos.x, chunkPos.z);
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
structureManager.setStartForStructure(sectionPos, structure, start, access);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int fetchReferences(StructureManager structureManager, ChunkAccess access, SectionPos sectionPos, Structure structure) {
|
||||||
|
StructureStart structurestart = structureManager.getStartForStructure(sectionPos, structure, access);
|
||||||
|
return structurestart != null ? structurestart.getReferences() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -208,11 +276,6 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.fillFromNoise(blender, randomstate, structuremanager, ichunkaccess);
|
return delegate.fillFromNoise(blender, randomstate, structuremanager, ichunkaccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
|
||||||
return delegate.getBaseHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WeightedList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
public WeightedList<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
|
||||||
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
|
||||||
@@ -220,7 +283,7 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
||||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
|
applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -230,22 +293,70 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager, boolean vanilla) {
|
||||||
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, vanilla);
|
addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
||||||
|
delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getFirstFreeHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
public void addVanillaDecorations(WorldGenLevel level, ChunkAccess chunkAccess, StructureManager structureManager) {
|
||||||
return delegate.getFirstFreeHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
if (!structureManager.shouldGenerateStructures())
|
||||||
|
return;
|
||||||
|
|
||||||
|
SectionPos sectionPos = SectionPos.of(chunkAccess.getPos(), level.getMinSectionY());
|
||||||
|
BlockPos blockPos = sectionPos.origin();
|
||||||
|
WorldgenRandom random = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||||
|
long i = random.setDecorationSeed(level.getSeed(), blockPos.getX(), blockPos.getZ());
|
||||||
|
var structures = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||||
|
var list = structures.stream()
|
||||||
|
.sorted(Comparator.comparingInt(s -> s.step().ordinal()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
var surface = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE_WG);
|
||||||
|
var ocean = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.OCEAN_FLOOR_WG);
|
||||||
|
var motion = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING);
|
||||||
|
var motionNoLeaves = chunkAccess.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES);
|
||||||
|
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
int wX = x + blockPos.getX();
|
||||||
|
int wZ = z + blockPos.getZ();
|
||||||
|
|
||||||
|
int noAir = engine.getHeight(wX, wZ, false) + engine.getMinHeight() + 1;
|
||||||
|
int noFluid = engine.getHeight(wX, wZ, true) + engine.getMinHeight() + 1;
|
||||||
|
SET_HEIGHT.invoke(ocean, x, z, Math.min(noFluid, ocean.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(surface, x, z, Math.min(noAir, surface.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motion, x, z, Math.min(noAir, motion.getFirstAvailable(x, z)));
|
||||||
|
SET_HEIGHT.invoke(motionNoLeaves, x, z, Math.min(noAir, motionNoLeaves.getFirstAvailable(x, z)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
for (int j = 0; j < list.size(); j++) {
|
||||||
public int getFirstOccupiedHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
Structure structure = list.get(j);
|
||||||
return delegate.getFirstOccupiedHeight(i, j, heightmap_type, levelheightaccessor, randomstate);
|
random.setFeatureSeed(i, j, structure.step().ordinal());
|
||||||
|
Supplier<String> supplier = () -> structures.getResourceKey(structure).map(Object::toString).orElseGet(structure::toString);
|
||||||
|
|
||||||
|
try {
|
||||||
|
level.setCurrentlyGenerating(supplier);
|
||||||
|
structureManager.startsForStructure(sectionPos, structure).forEach((start) -> start.placeInChunk(level, structureManager, this, random, getWritableArea(chunkAccess), chunkAccess.getPos()));
|
||||||
|
} catch (Exception exception) {
|
||||||
|
CrashReport crashReport = CrashReport.forThrowable(exception, "Feature placement");
|
||||||
|
CrashReportCategory category = crashReport.addCategory("Feature");
|
||||||
|
category.setDetail("Description", supplier::get);
|
||||||
|
throw new ReportedException(crashReport);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
Heightmap.primeHeightmaps(chunkAccess, ChunkStatus.FINAL_HEIGHTMAPS);
|
||||||
public void addVanillaDecorations(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
|
}
|
||||||
delegate.addVanillaDecorations(generatoraccessseed, ichunkaccess, structuremanager);
|
|
||||||
|
private static BoundingBox getWritableArea(ChunkAccess ichunkaccess) {
|
||||||
|
ChunkPos chunkPos = ichunkaccess.getPos();
|
||||||
|
int minX = chunkPos.getMinBlockX();
|
||||||
|
int minZ = chunkPos.getMinBlockZ();
|
||||||
|
LevelHeightAccessor heightAccessor = ichunkaccess.getHeightAccessorForGeneration();
|
||||||
|
int minY = heightAccessor.getMinY() + 1;
|
||||||
|
int maxY = heightAccessor.getMaxY();
|
||||||
|
return new BoundingBox(minX, minY, minZ, minX + 15, maxY, minZ + 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -263,9 +374,22 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
return delegate.getGenDepth();
|
return delegate.getGenDepth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBaseHeight(int i, int j, Heightmap.Types heightmap_type, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
|
return levelheightaccessor.getMinY() + engine.getHeight(i, j, !heightmap_type.isOpaque().test(Blocks.WATER.defaultBlockState())) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
|
||||||
return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
|
int block = engine.getHeight(i, j, true);
|
||||||
|
int water = engine.getHeight(i, j, false);
|
||||||
|
BlockState[] column = new BlockState[levelheightaccessor.getHeight()];
|
||||||
|
for (int k = 0; k < column.length; k++) {
|
||||||
|
if (k <= block) column[k] = Blocks.STONE.defaultBlockState();
|
||||||
|
else if (k <= water) column[k] = Blocks.WATER.defaultBlockState();
|
||||||
|
else column[k] = Blocks.AIR.defaultBlockState();
|
||||||
|
}
|
||||||
|
return new NoiseColumn(levelheightaccessor.getMinY(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -294,7 +418,21 @@ public class IrisChunkGenerator extends CustomChunkGenerator {
|
|||||||
}
|
}
|
||||||
if (biomeSource == null)
|
if (biomeSource == null)
|
||||||
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
throw new RuntimeException("Could not find biomeSource field in ChunkGenerator!");
|
||||||
|
|
||||||
|
Method setHeight = null;
|
||||||
|
for (Method method : Heightmap.class.getDeclaredMethods()) {
|
||||||
|
var types = method.getParameterTypes();
|
||||||
|
if (types.length != 3 || !Arrays.equals(types, new Class<?>[]{int.class, int.class, int.class})
|
||||||
|
|| !method.getReturnType().equals(void.class))
|
||||||
|
continue;
|
||||||
|
setHeight = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (setHeight == null)
|
||||||
|
throw new RuntimeException("Could not find setHeight method in Heightmap!");
|
||||||
|
|
||||||
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
BIOME_SOURCE = new WrappedField<>(ChunkGenerator.class, biomeSource.getName());
|
||||||
|
SET_HEIGHT = new WrappedReturningMethod<>(Heightmap.class, setHeight.getName(), setHeight.getParameterTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
private static ChunkGenerator edit(ChunkGenerator generator, BiomeSource source) {
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ package com.volmit.iris.core.nms.v1_21_R5;
|
|||||||
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.link.Identifier;
|
||||||
import com.volmit.iris.core.nms.INMSBinding;
|
import com.volmit.iris.core.nms.INMSBinding;
|
||||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
|
import com.volmit.iris.core.nms.container.Pair;
|
||||||
|
import com.volmit.iris.core.nms.container.StructurePlacement;
|
||||||
import com.volmit.iris.core.nms.container.BlockProperty;
|
import com.volmit.iris.core.nms.container.BlockProperty;
|
||||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
|
||||||
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
||||||
import com.volmit.iris.util.agent.Agent;
|
import com.volmit.iris.util.agent.Agent;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
@@ -60,6 +64,8 @@ import net.minecraft.world.level.dimension.LevelStem;
|
|||||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
import net.minecraft.world.level.levelgen.flat.FlatLayerInfo;
|
||||||
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
|
||||||
|
import net.minecraft.world.level.levelgen.structure.placement.RandomSpreadStructurePlacement;
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
@@ -92,6 +98,7 @@ import java.util.List;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
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.stream.Collectors;
|
||||||
|
|
||||||
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<>();
|
||||||
@@ -733,6 +740,71 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
return new BlockProperty(property.getName(), property.getValueClass(), state.getValue(property), property.getPossibleValues(), property::getName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void placeStructures(Chunk chunk) {
|
||||||
|
var craft = ((CraftChunk) chunk);
|
||||||
|
var level = craft.getCraftWorld().getHandle();
|
||||||
|
var access = ((CraftChunk) chunk).getHandle(ChunkStatus.FULL);
|
||||||
|
level.getChunkSource().getGenerator().applyBiomeDecoration(level, access, level.structureManager());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KMap<Identifier, StructurePlacement> collectStructures() {
|
||||||
|
var structureSets = registry().lookupOrThrow(Registries.STRUCTURE_SET);
|
||||||
|
var structurePlacements = registry().lookupOrThrow(Registries.STRUCTURE_PLACEMENT);
|
||||||
|
return structureSets.keySet()
|
||||||
|
.stream()
|
||||||
|
.map(structureSets::get)
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.map(holder -> {
|
||||||
|
var set = holder.value();
|
||||||
|
var placement = set.placement();
|
||||||
|
var key = holder.key().location();
|
||||||
|
StructurePlacement.StructurePlacementBuilder<?, ?> builder;
|
||||||
|
if (placement instanceof RandomSpreadStructurePlacement random) {
|
||||||
|
builder = StructurePlacement.RandomSpread.builder()
|
||||||
|
.separation(random.separation())
|
||||||
|
.spacing(random.spacing())
|
||||||
|
.spreadType(switch (random.spreadType()) {
|
||||||
|
case LINEAR -> IrisJigsawStructurePlacement.SpreadType.LINEAR;
|
||||||
|
case TRIANGULAR -> IrisJigsawStructurePlacement.SpreadType.TRIANGULAR;
|
||||||
|
});
|
||||||
|
} else if (placement instanceof ConcentricRingsStructurePlacement rings) {
|
||||||
|
builder = StructurePlacement.ConcentricRings.builder()
|
||||||
|
.distance(rings.distance())
|
||||||
|
.spread(rings.spread())
|
||||||
|
.count(rings.count());
|
||||||
|
} else {
|
||||||
|
Iris.warn("Unsupported structure placement for set " + key + " with type " + structurePlacements.getKey(placement.type()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Pair<>(new Identifier(key.getNamespace(), key.getPath()), builder
|
||||||
|
.salt(placement.salt)
|
||||||
|
.frequency(placement.frequency)
|
||||||
|
.structures(set.structures()
|
||||||
|
.stream()
|
||||||
|
.map(entry -> new StructurePlacement.Structure(
|
||||||
|
entry.weight(),
|
||||||
|
entry.structure()
|
||||||
|
.unwrapKey()
|
||||||
|
.map(ResourceKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.orElse(null),
|
||||||
|
entry.structure().tags()
|
||||||
|
.map(TagKey::location)
|
||||||
|
.map(ResourceLocation::toString)
|
||||||
|
.toList()
|
||||||
|
))
|
||||||
|
.filter(StructurePlacement.Structure::isValid)
|
||||||
|
.toList())
|
||||||
|
.build());
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toMap(Pair::getA, Pair::getB, (a, b) -> a, KMap::new));
|
||||||
|
}
|
||||||
|
|
||||||
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
public LevelStem levelStem(RegistryAccess access, ChunkGenerator raw) {
|
||||||
if (!(raw instanceof PlatformChunkGenerator gen))
|
if (!(raw instanceof PlatformChunkGenerator gen))
|
||||||
throw new IllegalStateException("Generator is not platform chunk generator!");
|
throw new IllegalStateException("Generator is not platform chunk generator!");
|
||||||
|
|||||||
Reference in New Issue
Block a user