diff --git a/build.gradle b/build.gradle
index 209907647..cc985d606 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,10 +16,6 @@
* along with this program. If not, see .
*/
-import java.util.function.Consumer
-
-
-
buildscript() {
repositories {
maven { url 'https://jitpack.io'}
@@ -36,7 +32,7 @@ plugins {
id "de.undercouch.download" version "5.0.1"
}
-version '4.0-1.19.2-1.21'
+version '4.0-1.19.2-1.21.1'
// ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED
// ======================== WINDOWS =============================
diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java
index ad6f8ae3f..f1d51edde 100644
--- a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java
+++ b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java
@@ -36,6 +36,7 @@ import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.mantle.TectonicPlate;
import com.volmit.iris.util.nbt.mca.MCAFile;
import com.volmit.iris.util.nbt.mca.MCAUtil;
+import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
@@ -50,6 +51,7 @@ import java.io.*;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@@ -169,6 +171,23 @@ public class CommandDeveloper implements DecreeExecutor {
}
+ @Decree
+ public void objects(@Param(defaultValue = "overworld") IrisDimension dimension) {
+ var loader = dimension.getLoader().getObjectLoader();
+ var sender = sender();
+ var keys = loader.getPossibleKeys();
+ var burst = MultiBurst.burst.burst(keys.length);
+ AtomicInteger failed = new AtomicInteger();
+ for (String key : keys) {
+ burst.queue(() -> {
+ if (loader.load(key) == null)
+ failed.incrementAndGet();
+ });
+ }
+ burst.complete();
+ sender.sendMessage(C.RED + "Failed to load " + failed.get() + " of " + keys.length + " objects");
+ }
+
@Decree(description = "Test", aliases = {"ip"})
public void network() {
try {
diff --git a/core/src/main/java/com/volmit/iris/core/loader/ObjectResourceLoader.java b/core/src/main/java/com/volmit/iris/core/loader/ObjectResourceLoader.java
index 9b473c666..3c6f6ee06 100644
--- a/core/src/main/java/com/volmit/iris/core/loader/ObjectResourceLoader.java
+++ b/core/src/main/java/com/volmit/iris/core/loader/ObjectResourceLoader.java
@@ -50,10 +50,10 @@ public class ObjectResourceLoader extends ResourceLoader {
try {
PrecisionStopwatch p = PrecisionStopwatch.start();
IrisObject t = new IrisObject(0, 0, 0);
- t.read(j);
t.setLoadKey(name);
t.setLoader(manager);
t.setLoadFile(j);
+ t.read(j);
logLoad(j, t);
tlt.addAndGet(p.getMilliseconds());
return t;
diff --git a/core/src/main/java/com/volmit/iris/core/nms/INMS.java b/core/src/main/java/com/volmit/iris/core/nms/INMS.java
index fd713f637..a5deaf7ab 100644
--- a/core/src/main/java/com/volmit/iris/core/nms/INMS.java
+++ b/core/src/main/java/com/volmit/iris/core/nms/INMS.java
@@ -29,7 +29,8 @@ public class INMS {
private static final Map REVISION = Map.of(
"1.20.5", "v1_20_R4",
"1.20.6", "v1_20_R4",
- "1.21", "v1_21_R1"
+ "1.21", "v1_21_R1",
+ "1.21.1", "v1_21_R1"
);
//@done
private static final INMSBinding binding = bind();
diff --git a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java
index b50b14c54..c5802717d 100644
--- a/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java
+++ b/core/src/main/java/com/volmit/iris/core/nms/INMSBinding.java
@@ -38,6 +38,7 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator;
+import org.bukkit.generator.structure.Structure;
import org.bukkit.inventory.ItemStack;
import java.io.File;
@@ -110,8 +111,6 @@ public interface INMSBinding {
ItemStack applyCustomNbt(ItemStack itemStack, KMap customNbt) throws IllegalArgumentException;
- void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos);
-
void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException;
Vector3d getBoundingbox(org.bukkit.entity.EntityType entity);
@@ -141,4 +140,6 @@ public interface INMSBinding {
}
IPackRepository getPackRepository();
+
+ KList getStructureKeys();
}
diff --git a/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java b/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java
index de6477aba..873e169a2 100644
--- a/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java
+++ b/core/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java
@@ -39,10 +39,7 @@ import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
import net.bytebuddy.matcher.ElementMatchers;
-import org.bukkit.Chunk;
-import org.bukkit.Location;
-import org.bukkit.Material;
-import org.bukkit.World;
+import org.bukkit.*;
import org.bukkit.WorldCreator;
import org.bukkit.block.Biome;
import org.bukkit.entity.Dolphin;
@@ -50,9 +47,10 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.ChunkGenerator;
+import org.bukkit.generator.structure.Structure;
import org.bukkit.inventory.ItemStack;
-import java.awt.*;
+import java.awt.Color;
import java.io.File;
public class NMSBinding1X implements INMSBinding {
@@ -104,11 +102,6 @@ public class NMSBinding1X implements INMSBinding {
return itemStack;
}
- @Override
- public void setTreasurePos(Dolphin dolphin, BlockPos pos) {
-
- }
-
@Override
public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
@@ -143,6 +136,15 @@ public class NMSBinding1X implements INMSBinding {
return Color.GREEN;
}
+ @Override
+ public KList getStructureKeys() {
+ var list = Registry.STRUCTURE.stream()
+ .map(Structure::getKey)
+ .map(NamespacedKey::toString)
+ .toList();
+ return new KList<>(list);
+ }
+
@Override
public CompoundTag serializeEntity(Entity location) {
return null;
diff --git a/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java b/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java
index a4ce69d18..eda3029c2 100644
--- a/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java
+++ b/core/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java
@@ -177,7 +177,7 @@ public class IrisPregenerator {
// updater.start();
// }
} else {
- IrisPackBenchmarking.instance.finishedBenchmark(chunksPerSecondHistory);
+ IrisPackBenchmarking.getInstance().finishedBenchmark(chunksPerSecondHistory);
}
}
diff --git a/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java b/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java
index d18b08840..32659705c 100644
--- a/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java
+++ b/core/src/main/java/com/volmit/iris/core/project/SchemaBuilder.java
@@ -22,6 +22,7 @@ import com.volmit.iris.Iris;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.loader.IrisRegistrant;
import com.volmit.iris.core.loader.ResourceLoader;
+import com.volmit.iris.engine.framework.ListFunction;
import com.volmit.iris.engine.object.annotations.*;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
@@ -309,6 +310,24 @@ public class SchemaBuilder {
fancyType = "Enchantment Type";
prop.put("$ref", "#/definitions/" + key);
description.add(SYMBOL_TYPE__N + " Must be a valid Enchantment Type (use ctrl+space for auto complete!)");
+ } else if (k.isAnnotationPresent(RegistryListFunction.class)) {
+ var functionClass = k.getDeclaredAnnotation(RegistryListFunction.class).value();
+ try {
+ var instance = functionClass.getDeclaredConstructor().newInstance();
+ String key = instance.key();
+ fancyType = instance.fancyName();
+
+ if (!definitions.containsKey(key)) {
+ JSONObject j = new JSONObject();
+ j.put("enum", instance.apply(data));
+ definitions.put(key, j);
+ }
+
+ prop.put("$ref", "#/definitions/" + key);
+ description.add(SYMBOL_TYPE__N + " Must be a valid " + fancyType + " (use ctrl+space for auto complete!)");
+ } catch (Throwable e) {
+ Iris.error("Could not execute apply method in " + functionClass.getName());
+ }
} else if (k.getType().equals(PotionEffectType.class)) {
String key = "enum-potion-effect-type";
diff --git a/core/src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java b/core/src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java
index c4fac6a38..63c86e7ff 100644
--- a/core/src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java
+++ b/core/src/main/java/com/volmit/iris/core/safeguard/UtilsSFG.java
@@ -55,7 +55,7 @@ public class UtilsSFG {
}
if (ServerBootSFG.unsuportedversion) {
Iris.safeguard(C.RED + "Server Version");
- Iris.safeguard(C.RED + "- Iris only supports 1.19.2 > 1.20.6");
+ Iris.safeguard(C.RED + "- Iris only supports 1.19.2 > 1.21.1");
}
if (!ServerBootSFG.passedserversoftware) {
Iris.safeguard(C.YELLOW + "Unsupported Server Software");
diff --git a/core/src/main/java/com/volmit/iris/core/service/DolphinSVC.java b/core/src/main/java/com/volmit/iris/core/service/DolphinSVC.java
index 2b87684a9..e69de29bb 100644
--- a/core/src/main/java/com/volmit/iris/core/service/DolphinSVC.java
+++ b/core/src/main/java/com/volmit/iris/core/service/DolphinSVC.java
@@ -1,93 +0,0 @@
-/*
- * Iris is a World Generator for Minecraft Bukkit Servers
- * Copyright (c) 2024 Arcane Arts (Volmit Software)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package com.volmit.iris.core.service;
-
-import com.volmit.iris.core.nms.INMS;
-import com.volmit.iris.core.nms.container.BlockPos;
-import com.volmit.iris.core.tools.IrisToolbelt;
-import com.volmit.iris.engine.framework.Engine;
-import com.volmit.iris.util.documentation.ChunkCoordinates;
-import com.volmit.iris.util.function.Consumer4;
-import com.volmit.iris.util.math.Spiraler;
-import com.volmit.iris.util.matter.MatterStructurePOI;
-import com.volmit.iris.util.plugin.IrisService;
-import org.bukkit.Material;
-import org.bukkit.Sound;
-import org.bukkit.SoundCategory;
-import org.bukkit.entity.Dolphin;
-import org.bukkit.entity.EntityType;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.player.PlayerInteractEntityEvent;
-import org.bukkit.generator.structure.StructureType;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-public class DolphinSVC implements IrisService {
-
- @Override
- public void onEnable() {
-
- }
-
- @Override
- public void onDisable() {
-
- }
-
- @EventHandler
- public void on(PlayerInteractEntityEvent event) {
- if (!IrisToolbelt.isIrisWorld(event.getPlayer().getWorld())) {
- return;
- }
-
- Material hand = event.getPlayer().getInventory().getItem(event.getHand()).getType();
- if (event.getRightClicked().getType().equals(EntityType.DOLPHIN) && (hand.equals(Material.TROPICAL_FISH) || hand.equals(Material.PUFFERFISH) || hand.equals(Material.COD) || hand.equals(Material.SALMON))) {
- Engine e = IrisToolbelt.access(event.getPlayer().getWorld()).getEngine();
- searchNearestTreasure(e, event.getPlayer().getLocation().getBlockX() >> 4, event.getPlayer().getLocation().getBlockZ() >> 4, e.getMantle().getRadius() - 1, StructureType.BURIED_TREASURE, (x, y, z, p) -> {
- event.setCancelled(true);
- Dolphin d = (Dolphin) event.getRightClicked();
- INMS.get().setTreasurePos(d, new BlockPos(x, y, z));
- d.getWorld().playSound(d, Sound.ENTITY_DOLPHIN_EAT, SoundCategory.NEUTRAL, 1, 1);
- });
-
- }
- }
-
- @ChunkCoordinates
- public void findTreasure(Engine engine, int chunkX, int chunkY, StructureType type, Consumer4 consumer) {
- AtomicReference ref = new AtomicReference<>();
- engine.getMantle().getMantle().iterateChunk(chunkX, chunkY, MatterStructurePOI.class, ref.get() == null ? (x, y, z, d) -> {
- if (d.getType().equals(type.getKey().getKey())) {
- ref.set(d);
- consumer.accept(x, y, z, d);
- }
- } : (x, y, z, d) -> {
- });
- }
-
- @ChunkCoordinates
- public void searchNearestTreasure(Engine engine, int chunkX, int chunkY, int radius, StructureType type, Consumer4 consumer) {
- AtomicReference ref = new AtomicReference<>();
- new Spiraler(radius * 2, radius * 2, (x, z) -> findTreasure(engine, x, z, type, ref.get() == null ? (i, d, g, a) -> {
- ref.set(a);
- consumer.accept(i, d, g, a);
- } : (i, d, g, a) -> {
- })).setOffset(chunkX, chunkY).drain();
- }
-}
diff --git a/core/src/main/java/com/volmit/iris/core/service/VillageSVC.java b/core/src/main/java/com/volmit/iris/core/service/VillageSVC.java
index 14d6af3f7..e69de29bb 100644
--- a/core/src/main/java/com/volmit/iris/core/service/VillageSVC.java
+++ b/core/src/main/java/com/volmit/iris/core/service/VillageSVC.java
@@ -1,127 +0,0 @@
-/*
- * Iris is a World Generator for Minecraft Bukkit Servers
- * Copyright (c) 2024 Arcane Arts (Volmit Software)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package com.volmit.iris.core.service;
-
-import com.volmit.iris.Iris;
-import com.volmit.iris.core.IrisSettings;
-import com.volmit.iris.core.tools.IrisToolbelt;
-import com.volmit.iris.engine.object.IrisDimension;
-import com.volmit.iris.util.format.C;
-import com.volmit.iris.util.plugin.IrisService;
-import com.volmit.iris.util.plugin.VolmitSender;
-import org.bukkit.Location;
-import org.bukkit.entity.Player;
-import org.bukkit.entity.Villager;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.entity.VillagerCareerChangeEvent;
-
-import java.util.List;
-
-public class VillageSVC implements IrisService {
- @Override
- public void onEnable() {
-
- }
-
- @Override
- public void onDisable() {
-
- }
-
- @EventHandler
- public void on(VillagerCareerChangeEvent event) {
-
- if (!IrisToolbelt.isIrisWorld(event.getEntity().getWorld())) {
- return;
- }
-
- IrisDimension dim = IrisToolbelt.access(event.getEntity().getWorld())
- .getEngine().getDimension();
-
- if (!dim.isRemoveCartographersDueToCrash()) {
- return;
- }
-
- if (event.getProfession().equals(Villager.Profession.CARTOGRAPHER)) {
- event.setCancelled(true);
-
- Location eventLocation = event.getEntity().getLocation();
-
- int radius = dim.getNotifyPlayersOfCartographerCancelledRadius();
-
- if (radius == -1) {
- return;
- }
-
- List playersInWorld = event.getEntity().getWorld().getPlayers();
-
- String message = C.GOLD + IrisSettings.get().getGeneral().cartographerMessage;
-
- Iris.info("Cancelled Cartographer Villager to prevent server crash at " + eventLocation + "!");
-
- if (radius == -2) {
- playersInWorld.stream().map(VolmitSender::new).forEach(v -> v.sendMessage(message));
- } else {
- playersInWorld.forEach(p -> {
- if (p.getLocation().distance(eventLocation) < radius) {
- new VolmitSender(p).sendMessage(message);
- }
- });
- }
-
- }
- }
-
- /*
- * Replace or disable villager trade add event to prevent explorer map
- */
- /* Removed due to MC breaking stuff again. This event is now called after the cartographer maps are made,
- so it can fuck right off.
- @EventHandler
- public void on(VillagerAcquireTradeEvent event) {
- if(!IrisToolbelt.isIrisWorld((event.getEntity().getWorld()))) {
- return;
- }
-
- // Iris.info("Trade event: type " + event.getRecipe().getResult().getType() + " / meta " + event.getRecipe().getResult().getItemMeta() + " / data " + event.getRecipe().getResult().getData());
- if(!event.getRecipe().getResult().getType().equals(Material.FILLED_MAP)) {
- return;
- }
-
- IrisVillagerOverride override = IrisToolbelt.access(event.getEntity().getWorld()).getEngine()
- .getDimension().getPatchCartographers();
-
- if(override.isDisableTrade()) {
- event.setCancelled(true);
- Iris.debug("Cancelled cartographer trade @ " + event.getEntity().getLocation());
- return;
- }
-
- if(override.getValidItems() == null) {
- event.setCancelled(true);
- Iris.debug("Cancelled cartographer trade because no override items are valid @ " + event.getEntity().getLocation());
- return;
- }
-
- IrisVillagerTrade trade = override.getValidItems().getRandom();
- event.setRecipe(trade.convert());
- Iris.debug("Overrode cartographer trade with: " + trade + " to prevent allowing cartography map trades");
- }
- */
-}
diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java
index 1dffbfbfb..557b9ad58 100644
--- a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java
+++ b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java
@@ -299,39 +299,44 @@ public class IrisEngine implements Engine {
@Override
public IrisEngineData getEngineData() {
- var ret = engineData.aquire(() -> {
+ return engineData.aquire(() -> {
//TODO: Method this file
File f = new File(getWorld().worldFolder(), "iris/engine-data/" + getDimension().getLoadKey() + ".json");
+ IrisEngineData data = null;
- if (!f.exists()) {
+ if (f.exists()) {
try {
- f.getParentFile().mkdirs();
- IrisEngineData data = new IrisEngineData();
- data.getStatistics().setIrisCreationVersion(Iris.instance.getIrisVersion());
- data.getStatistics().setMCVersion(Iris.instance.getMCVersion());
- data.getStatistics().setIrisToUpgradedVersion(Iris.instance.getIrisVersion());
- if (data.getStatistics().getIrisCreationVersion() == -1 || data.getStatistics().getMCVersion() == -1) {
- Iris.error("Failed to setup Engine Data!");
+ data = new Gson().fromJson(IO.readAll(f), IrisEngineData.class);
+ if (data == null) {
+ Iris.error("Failed to read Engine Data! Corrupted File? recreating...");
}
- IO.writeAll(f, new Gson().toJson(data));
} catch (IOException e) {
e.printStackTrace();
}
}
- try {
- return new Gson().fromJson(IO.readAll(f), IrisEngineData.class);
- } catch (Throwable e) {
- e.printStackTrace();
+ if (data == null) {
+ data = new IrisEngineData();
+ data.getStatistics().setIrisCreationVersion(Iris.instance.getIrisVersion());
+ data.getStatistics().setMCVersion(Iris.instance.getMCVersion());
+ data.getStatistics().setIrisToUpgradedVersion(Iris.instance.getIrisVersion());
+ if (data.getStatistics().getIrisCreationVersion() == -1 || data.getStatistics().getMCVersion() == -1) {
+ Iris.error("Failed to setup Engine Data!");
+ }
+
+ if (f.getParentFile().exists() || f.getParentFile().mkdirs()) {
+ try {
+ IO.writeAll(f, new Gson().toJson(data));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ Iris.error("Failed to setup Engine Data!");
+ }
}
- return new IrisEngineData();
+ return data;
});
- if (ret == null) {
- Iris.error("Failed to load Engine Data! (How did this happen?)");
- return new IrisEngineData();
- }
- return ret;
}
@Override
diff --git a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java
index 2541ba332..eb03244f8 100644
--- a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java
+++ b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java
@@ -76,6 +76,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
private final ChronoLatch ecl;
private final ChronoLatch cln;
private final ChronoLatch chunkUpdater;
+ private final ChronoLatch chunkDiscovery;
private double energy = 25;
private int entityCount = 0;
private long charge = 0;
@@ -92,12 +93,14 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
clw = null;
looper = null;
chunkUpdater = null;
+ chunkDiscovery = null;
id = -1;
}
public IrisWorldManager(Engine engine) {
super(engine);
chunkUpdater = new ChronoLatch(3000);
+ chunkDiscovery = new ChronoLatch(5000);
cln = new ChronoLatch(60000);
cl = new ChronoLatch(3000);
ecl = new ChronoLatch(250);
@@ -128,6 +131,10 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
updateChunks();
}
+ if (chunkDiscovery.flip()) {
+ discoverChunks();
+ }
+
if (getDimension().isInfiniteEnergy()) {
energy += 1000;
@@ -174,6 +181,19 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
looper.start();
}
+ private void discoverChunks() {
+ var mantle = getEngine().getMantle().getMantle();
+ for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
+ int r = 1;
+
+ for (int x = -r; x <= r; x++) {
+ for (int z = -r; z <= r; z++) {
+ mantle.getChunk(i.getLocation().getChunk()).flag(MantleFlag.DISCOVERED, true);
+ }
+ }
+ }
+ }
+
private void updateChunks() {
for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
int r = 1;
diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java
index 977c7e2d5..aafc2e3c2 100644
--- a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java
+++ b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java
@@ -840,7 +840,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
default void gotoJigsaw(IrisJigsawStructure s, Player player, boolean teleport) {
if (s.getLoadKey().equals(getDimension().getStronghold())) {
- KList p = getDimension().getStrongholds(getSeedManager().getSpawn());
+ KList p = getDimension().getStrongholds(getSeedManager().getMantle());
if (p.isEmpty()) {
player.sendMessage(C.GOLD + "No strongholds in world.");
diff --git a/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java b/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java
index 03db13e3c..6830222e0 100644
--- a/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java
+++ b/core/src/main/java/com/volmit/iris/engine/framework/EngineAssignedWorldManager.java
@@ -110,7 +110,7 @@ public abstract class EngineAssignedWorldManager extends EngineAssignedComponent
return;
}
- KList positions = getEngine().getDimension().getStrongholds(getEngine().getSeedManager().getSpawn());
+ KList positions = getEngine().getDimension().getStrongholds(getEngine().getSeedManager().getMantle());
if (positions.isEmpty()) {
return;
}
diff --git a/core/src/main/java/com/volmit/iris/engine/framework/ListFunction.java b/core/src/main/java/com/volmit/iris/engine/framework/ListFunction.java
new file mode 100644
index 000000000..2d2c8bfdb
--- /dev/null
+++ b/core/src/main/java/com/volmit/iris/engine/framework/ListFunction.java
@@ -0,0 +1,8 @@
+package com.volmit.iris.engine.framework;
+
+import java.util.function.Function;
+
+public interface ListFunction extends Function {
+ String key();
+ String fancyName();
+}
diff --git a/core/src/main/java/com/volmit/iris/engine/framework/ResultLocator.java b/core/src/main/java/com/volmit/iris/engine/framework/ResultLocator.java
new file mode 100644
index 000000000..93d698347
--- /dev/null
+++ b/core/src/main/java/com/volmit/iris/engine/framework/ResultLocator.java
@@ -0,0 +1,121 @@
+package com.volmit.iris.engine.framework;
+
+import com.volmit.iris.core.IrisSettings;
+import com.volmit.iris.engine.object.IrisJigsawStructure;
+import com.volmit.iris.engine.object.IrisObject;
+import com.volmit.iris.util.collection.KList;
+import com.volmit.iris.util.math.Position2;
+import com.volmit.iris.util.math.Spiraler;
+import com.volmit.iris.util.parallel.BurstExecutor;
+import com.volmit.iris.util.parallel.MultiBurst;
+import com.volmit.iris.util.scheduling.PrecisionStopwatch;
+import org.apache.commons.lang3.function.TriFunction;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
+
+@FunctionalInterface
+public interface ResultLocator {
+ static void cancelSearch() {
+ if (LocatorCanceller.cancel != null) {
+ LocatorCanceller.cancel.run();
+ LocatorCanceller.cancel = null;
+ }
+ }
+
+ static ResultLocator locateStructure(Collection keys) {
+ return (e, pos) -> {
+ var structure = e.getStructureAt(pos.getX(), pos.getZ());
+ return structure != null && keys.contains(structure.getLoadKey()) ? structure : null;
+ };
+ }
+
+ static ResultLocator locateObject(Collection keys) {
+ return (e, pos) -> {
+ Set objects = e.getObjectsAt(pos.getX(), pos.getZ());
+ for (String object : objects) {
+ if (!keys.contains(object)) continue;
+ return e.getData().getObjectLoader().load(object);
+ }
+ return null;
+ };
+ }
+
+ T find(Engine e, Position2 chunkPos);
+
+ default ResultLocator then(TriFunction filter) {
+ return (e, pos) -> {
+ var t = find(e, pos);
+ return t != null ? filter.apply(e, pos, t) : null;
+ };
+ }
+
+ default Future> find(Engine engine, Position2 pos, long timeout, Consumer checks, boolean cancelable) throws WrongEngineBroException {
+ if (engine.isClosed()) {
+ throw new WrongEngineBroException();
+ }
+
+ cancelSearch();
+
+ return MultiBurst.burst.completeValue(() -> {
+ int tc = IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism()) * 17;
+ MultiBurst burst = MultiBurst.burst;
+ AtomicBoolean found = new AtomicBoolean(false);
+ AtomicReference> foundObj = new AtomicReference<>();
+ Position2 cursor = pos;
+ AtomicInteger searched = new AtomicInteger();
+ AtomicBoolean stop = new AtomicBoolean(false);
+ PrecisionStopwatch px = PrecisionStopwatch.start();
+ if (cancelable) LocatorCanceller.cancel = () -> stop.set(true);
+ AtomicReference next = new AtomicReference<>(cursor);
+ Spiraler s = new Spiraler(100000, 100000, (x, z) -> next.set(new Position2(x, z)));
+ s.setOffset(cursor.getX(), cursor.getZ());
+ s.next();
+ while (!found.get() && !stop.get() && px.getMilliseconds() < timeout) {
+ BurstExecutor e = burst.burst(tc);
+
+ for (int i = 0; i < tc; i++) {
+ Position2 p = next.get();
+ s.next();
+ e.queue(() -> {
+ var o = find(engine, p);
+ if (o != null) {
+ if (foundObj.get() == null) {
+ foundObj.set(new Result<>(o, p));
+ }
+
+ found.set(true);
+ }
+ searched.incrementAndGet();
+ });
+ }
+
+ e.complete();
+ checks.accept(searched.get());
+ }
+
+ LocatorCanceller.cancel = null;
+
+ if (found.get() && foundObj.get() != null) {
+ return foundObj.get();
+ }
+
+ return null;
+ });
+ }
+
+ record Result(T obj, Position2 pos) {
+ public int getBlockX() {
+ return (pos.getX() << 4) + 8;
+ }
+
+ public int getBlockZ() {
+ return (pos.getZ() << 4) + 8;
+ }
+ }
+}
diff --git a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java
index f642d5a5b..ae6c95518 100644
--- a/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java
+++ b/core/src/main/java/com/volmit/iris/engine/mantle/EngineMantle.java
@@ -107,7 +107,7 @@ public interface EngineMantle extends IObjectPlacer {
@Override
default void setTile(int x, int y, int z, TileData d) {
- getMantle().set(x, y, z, d);
+ getMantle().set(x, y, z, new TileWrapper(d));
}
@Override
diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java b/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java
index d54b75b0f..568bfcf26 100644
--- a/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java
+++ b/core/src/main/java/com/volmit/iris/engine/object/IrisBlockData.java
@@ -62,6 +62,8 @@ public class IrisBlockData extends IrisRegistrant {
private IrisBlockData backup = null;
@Desc("Optional properties for this block data such as 'waterlogged': true")
private KMap data = new KMap<>();
+ @Desc("Optional tile data for this block data")
+ private KMap tileData = new KMap<>();
public IrisBlockData(String b) {
this.block = b;
@@ -200,9 +202,9 @@ public class IrisBlockData extends IrisRegistrant {
public TileData tryGetTile(IrisData data) {
//TODO Do like a registry thing with the tile data registry. Also update the parsing of data to include **block** entities.
var type = getBlockData(data).getMaterial();
- if (!INMS.get().hasTile(type))
+ if (!INMS.get().hasTile(type) || tileData == null || tileData.isEmpty())
return null;
- return new TileData().setMaterial(type).setProperties(this.data);
+ return new TileData(type, this.tileData);
}
private String keyify(String dat) {
diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java b/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java
index 28f64ca9f..eff9fc558 100644
--- a/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java
+++ b/core/src/main/java/com/volmit/iris/engine/object/IrisDimension.java
@@ -219,10 +219,8 @@ public class IrisDimension extends IrisRegistrant {
private IrisMaterialPalette rockPalette = new IrisMaterialPalette().qclear().qadd("stone");
@Desc("The palette of blocks for 'water'")
private IrisMaterialPalette fluidPalette = new IrisMaterialPalette().qclear().qadd("water");
- @Desc("Remove cartographers so they do not crash the server (Iris worlds only)")
- private boolean removeCartographersDueToCrash = true;
- @Desc("Notify players of cancelled cartographer villager in this radius in blocks (set to -1 to disable, -2 for everyone)")
- private int notifyPlayersOfCartographerCancelledRadius = 30;
+ @Desc("Prevent cartographers to generate explorer maps (Iris worlds only)\nONLY TOUCH IF YOUR SERVER CRASHES WHILE GENERATING EXPLORER MAPS")
+ private boolean disableExplorerMaps = false;
@Desc("Collection of ores to be generated")
@ArrayType(type = IrisOreGenerator.class, min = 1)
private KList ores = new KList<>();
diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructure.java b/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructure.java
index fcbe5d7a5..5e7357d35 100644
--- a/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructure.java
+++ b/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructure.java
@@ -69,6 +69,10 @@ public class IrisJigsawStructure extends IrisRegistrant {
@Desc("Set to true to prevent rotating the initial structure piece")
private boolean disableInitialRotation = false;
+ @RegistryListFunction(StructureKeyFunction.class)
+ @Desc("The minecraft key to use when creating treasure maps")
+ private String structureKey = null;
+
private transient AtomicCache maxDimension = new AtomicCache<>();
private void loadPool(String p, KList pools, KList pieces) {
diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructurePlacement.java b/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructurePlacement.java
index 9fe58ad54..05483f0bb 100644
--- a/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructurePlacement.java
+++ b/core/src/main/java/com/volmit/iris/engine/object/IrisJigsawStructurePlacement.java
@@ -64,7 +64,7 @@ public class IrisJigsawStructurePlacement implements IRare {
private int separation = -1;
@Desc("The method used to spread the structure")
- private SpreadType spreadType = SpreadType.TRIANGULAR;
+ private SpreadType spreadType = SpreadType.LINEAR;
@ArrayType(type = IrisJigsawMinDistance.class)
@Desc("List of minimum distances to check for")
diff --git a/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java b/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java
index 50eee93ee..dddd36228 100644
--- a/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java
+++ b/core/src/main/java/com/volmit/iris/engine/object/IrisObject.java
@@ -385,14 +385,14 @@ public class IrisObject extends IrisRegistrant {
}
public void read(File file) throws IOException {
- FileInputStream fin = new FileInputStream(file);
+ var fin = new BufferedInputStream(new FileInputStream(file));
try {
read(fin);
fin.close();
} catch (Throwable e) {
Iris.reportError(e);
fin.close();
- fin = new FileInputStream(file);
+ fin = new BufferedInputStream(new FileInputStream(file));
readLegacy(fin);
fin.close();
}
diff --git a/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java b/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java
new file mode 100644
index 000000000..ac8728ebe
--- /dev/null
+++ b/core/src/main/java/com/volmit/iris/engine/object/LegacyTileData.java
@@ -0,0 +1,151 @@
+package com.volmit.iris.engine.object;
+
+import com.volmit.iris.util.collection.KList;
+import com.volmit.iris.util.scheduling.J;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.apache.commons.io.function.IOFunction;
+import org.bukkit.DyeColor;
+import org.bukkit.block.*;
+import org.bukkit.block.banner.Pattern;
+import org.bukkit.block.banner.PatternType;
+import org.bukkit.entity.EntityType;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Map;
+
+@ToString
+@EqualsAndHashCode(callSuper = false)
+public class LegacyTileData extends TileData {
+ private static final Map> legacy = Map.of(
+ 0, SignHandler::new,
+ 1, SpawnerHandler::new,
+ 2, BannerHandler::new);
+ private final int id;
+ private final Handler handler;
+
+ public LegacyTileData(DataInputStream in) throws IOException {
+ id = in.readShort();
+ var factory = legacy.get(id);
+ if (factory == null)
+ throw new IOException("Unknown tile type: " + id);
+ handler = factory.apply(in);
+ }
+
+ @Override
+ public void toBukkit(Block block) {
+ J.s(() -> handler.toBukkit(block));
+ }
+
+ @Override
+ public void toBinary(DataOutputStream out) throws IOException {
+ out.writeShort(id);
+ handler.toBinary(out);
+ }
+
+ @Override
+ public TileData clone() {
+ return this;
+ }
+
+ private interface Handler {
+ void toBinary(DataOutputStream out) throws IOException;
+ void toBukkit(Block block);
+ }
+
+ @ToString
+ @EqualsAndHashCode
+ private static class SignHandler implements Handler {
+ private final String line1;
+ private final String line2;
+ private final String line3;
+ private final String line4;
+ private final DyeColor dyeColor;
+
+ private SignHandler(DataInputStream in) throws IOException {
+ line1 = in.readUTF();
+ line2 = in.readUTF();
+ line3 = in.readUTF();
+ line4 = in.readUTF();
+ dyeColor = DyeColor.values()[in.readByte()];
+ }
+
+ @Override
+ public void toBinary(DataOutputStream out) throws IOException {
+ out.writeUTF(line1);
+ out.writeUTF(line2);
+ out.writeUTF(line3);
+ out.writeUTF(line4);
+ out.writeByte(dyeColor.ordinal());
+ }
+
+ @Override
+ public void toBukkit(Block block) {
+ Sign sign = (Sign) block.getState();
+ sign.setLine(0, line1);
+ sign.setLine(1, line2);
+ sign.setLine(2, line3);
+ sign.setLine(3, line4);
+ sign.setColor(dyeColor);
+ sign.update();
+ }
+ }
+ @ToString
+ @EqualsAndHashCode
+ private static class SpawnerHandler implements Handler {
+ private final EntityType type;
+
+ private SpawnerHandler(DataInputStream in) throws IOException {
+ type = EntityType.values()[in.readShort()];
+ }
+
+ @Override
+ public void toBinary(DataOutputStream out) throws IOException {
+ out.writeShort(type.ordinal());
+ }
+
+ @Override
+ public void toBukkit(Block block) {
+ CreatureSpawner spawner = (CreatureSpawner) block.getState();
+ spawner.setSpawnedType(type);
+ spawner.update();
+ }
+ }
+ @ToString
+ @EqualsAndHashCode
+ private static class BannerHandler implements Handler {
+ private final KList patterns;
+ private final DyeColor baseColor;
+
+ private BannerHandler(DataInputStream in) throws IOException {
+ baseColor = DyeColor.values()[in.readByte()];
+ patterns = new KList<>();
+ int listSize = in.readByte();
+ for (int i = 0; i < listSize; i++) {
+ DyeColor color = DyeColor.values()[in.readByte()];
+ PatternType pattern = PatternType.values()[in.readByte()];
+ patterns.add(new Pattern(color, pattern));
+ }
+ }
+
+ @Override
+ public void toBinary(DataOutputStream out) throws IOException {
+ out.writeByte(baseColor.ordinal());
+ out.writeByte(patterns.size());
+ for (Pattern i : patterns) {
+ out.writeByte(i.getColor().ordinal());
+ out.writeByte(i.getPattern().ordinal());
+ }
+ }
+
+ @Override
+ public void toBukkit(Block block) {
+ Banner banner = (Banner) block.getState();
+ banner.setBaseColor(baseColor);
+ banner.setPatterns(patterns);
+ banner.update();
+ }
+ }
+}
diff --git a/core/src/main/java/com/volmit/iris/engine/object/TileData.java b/core/src/main/java/com/volmit/iris/engine/object/TileData.java
index d4119d940..a0c6961af 100644
--- a/core/src/main/java/com/volmit/iris/engine/object/TileData.java
+++ b/core/src/main/java/com/volmit/iris/engine/object/TileData.java
@@ -23,11 +23,9 @@ import com.google.gson.GsonBuilder;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.util.collection.KMap;
-import lombok.Data;
-import lombok.experimental.Accessors;
+import lombok.*;
import org.bukkit.Material;
import org.bukkit.block.Block;
-import org.bukkit.block.BlockState;
import org.bukkit.block.TileState;
import org.bukkit.block.data.BlockData;
@@ -35,14 +33,19 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
-@Data
@SuppressWarnings("ALL")
-@Accessors(chain = true)
+@Getter
+@ToString
+@EqualsAndHashCode
+@AllArgsConstructor
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class TileData implements Cloneable {
private static final Gson gson = new GsonBuilder().disableHtmlEscaping().setLenient().create();
- private Material material = null;
- private KMap properties = new KMap<>();
+ @NonNull
+ private Material material;
+ @NonNull
+ private KMap properties;
public static boolean setTileState(Block block, TileData data) {
if (block.getState() instanceof TileState && data.isApplicable(block.getBlockData()))
@@ -57,10 +60,19 @@ public class TileData implements Cloneable {
}
public static TileData read(DataInputStream in) throws IOException {
- TileData d = new TileData();
- d.material = Material.matchMaterial(in.readUTF());
- d.properties = gson.fromJson(in.readUTF(), KMap.class);
- return d;
+ if (!in.markSupported())
+ throw new IOException("Mark not supported");
+ in.mark(Integer.MAX_VALUE);
+ try {
+ return new TileData(
+ Material.matchMaterial(in.readUTF()),
+ gson.fromJson(in.readUTF(), KMap.class));
+ } catch (Throwable e) {
+ in.reset();
+ return new LegacyTileData(in);
+ } finally {
+ in.mark(0);
+ }
}
public boolean isApplicable(BlockData data) {
diff --git a/core/src/main/java/com/volmit/iris/engine/object/annotations/RegistryListFunction.java b/core/src/main/java/com/volmit/iris/engine/object/annotations/RegistryListFunction.java
new file mode 100644
index 000000000..e437ebfae
--- /dev/null
+++ b/core/src/main/java/com/volmit/iris/engine/object/annotations/RegistryListFunction.java
@@ -0,0 +1,17 @@
+package com.volmit.iris.engine.object.annotations;
+
+import com.volmit.iris.core.loader.IrisData;
+import com.volmit.iris.engine.framework.ListFunction;
+import com.volmit.iris.util.collection.KList;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Retention(RUNTIME)
+@Target({PARAMETER, TYPE, FIELD})
+public @interface RegistryListFunction {
+ Class extends ListFunction>> value();
+}
diff --git a/core/src/main/java/com/volmit/iris/engine/object/annotations/StructureKeyFunction.java b/core/src/main/java/com/volmit/iris/engine/object/annotations/StructureKeyFunction.java
new file mode 100644
index 000000000..5ab656cc8
--- /dev/null
+++ b/core/src/main/java/com/volmit/iris/engine/object/annotations/StructureKeyFunction.java
@@ -0,0 +1,23 @@
+package com.volmit.iris.engine.object.annotations;
+
+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 StructureKeyFunction implements ListFunction> {
+ @Override
+ public String key() {
+ return "structure-key";
+ }
+
+ @Override
+ public String fancyName() {
+ return "Structure Key";
+ }
+
+ @Override
+ public KList apply(IrisData irisData) {
+ return INMS.get().getStructureKeys();
+ }
+}
diff --git a/core/src/main/java/com/volmit/iris/util/mantle/MantleFlag.java b/core/src/main/java/com/volmit/iris/util/mantle/MantleFlag.java
index 8df7190e5..66be64a9a 100644
--- a/core/src/main/java/com/volmit/iris/util/mantle/MantleFlag.java
+++ b/core/src/main/java/com/volmit/iris/util/mantle/MantleFlag.java
@@ -35,7 +35,8 @@ public enum MantleFlag {
ETCHED,
TILE,
CUSTOM,
- CUSTOM_ACTIVE;
+ CUSTOM_ACTIVE,
+ DISCOVERED;
static StateList getStateList() {
return new StateList(MantleFlag.values());
diff --git a/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java b/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java
index eab4780b8..a32645115 100644
--- a/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java
+++ b/core/src/main/java/com/volmit/iris/util/mantle/TectonicPlate.java
@@ -84,10 +84,10 @@ public class TectonicPlate {
DataInputStream din;
if (file.getName().endsWith("ttp.lz4b")) {
LZ4BlockInputStream lz4 = new LZ4BlockInputStream(fin);
- din = new DataInputStream(lz4);
+ din = new DataInputStream(new BufferedInputStream(lz4));
} else {
GZIPInputStream gzi = new GZIPInputStream(fin);
- din = new DataInputStream(gzi);
+ din = new DataInputStream(new BufferedInputStream(gzi));
}
TectonicPlate p = new TectonicPlate(worldHeight, din);
din.close();
diff --git a/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java b/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java
index e69de29bb..0fa14eab6 100644
--- a/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java
+++ b/core/src/main/java/com/volmit/iris/util/matter/TileWrapper.java
@@ -0,0 +1,27 @@
+/*
+ * Iris is a World Generator for Minecraft Bukkit Servers
+ * Copyright (c) 2024 Arcane Arts (Volmit Software)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package com.volmit.iris.util.matter;
+
+import com.volmit.iris.engine.object.TileData;
+import lombok.Data;
+
+@Data
+public class TileWrapper {
+ private final TileData data;
+}
diff --git a/core/src/main/java/com/volmit/iris/util/matter/WorldMatter.java b/core/src/main/java/com/volmit/iris/util/matter/WorldMatter.java
index 3c2126c1d..829c0b3b4 100644
--- a/core/src/main/java/com/volmit/iris/util/matter/WorldMatter.java
+++ b/core/src/main/java/com/volmit/iris/util/matter/WorldMatter.java
@@ -34,8 +34,8 @@ public class WorldMatter {
matter.slice(MatterEntityGroup.class).writeInto(at);
}
- if (matter.hasSlice(TileData.class)) {
- matter.slice(TileData.class).writeInto(at);
+ if (matter.hasSlice(TileWrapper.class)) {
+ matter.slice(TileWrapper.class).writeInto(at);
}
}
@@ -46,7 +46,7 @@ public class WorldMatter {
s.getHeader().setAuthor(author);
s.slice(BlockData.class).readFrom(c.getLowerNE());
s.slice(MatterEntityGroup.class).readFrom(c.getLowerNE());
- s.slice(TileData.class).readFrom(c.getLowerNE());
+ s.slice(TileWrapper.class).readFrom(c.getLowerNE());
s.trimSlices();
return s;
diff --git a/core/src/main/java/com/volmit/iris/util/matter/slices/TileMatter.java b/core/src/main/java/com/volmit/iris/util/matter/slices/TileMatter.java
index 008901590..7a51e6d60 100644
--- a/core/src/main/java/com/volmit/iris/util/matter/slices/TileMatter.java
+++ b/core/src/main/java/com/volmit/iris/util/matter/slices/TileMatter.java
@@ -21,6 +21,7 @@ package com.volmit.iris.util.matter.slices;
import com.volmit.iris.engine.object.TileData;
import com.volmit.iris.util.data.palette.Palette;
import com.volmit.iris.util.matter.Sliced;
+import com.volmit.iris.util.matter.TileWrapper;
import org.bukkit.Location;
import org.bukkit.World;
@@ -30,28 +31,28 @@ import java.io.IOException;
@SuppressWarnings("rawtypes")
@Sliced
-public class TileMatter extends RawMatter {
+public class TileMatter extends RawMatter {
public TileMatter() {
this(1, 1, 1);
}
public TileMatter(int width, int height, int depth) {
- super(width, height, depth, TileData.class);
- registerWriter(World.class, (w, d, x, y, z) -> TileData.setTileState(w.getBlockAt(new Location(w, x, y, z)), d));
- registerReader(World.class, (w, x, y, z) -> TileData.getTileState(w.getBlockAt(new Location(w, x, y, z))));
+ super(width, height, depth, TileWrapper.class);
+ registerWriter(World.class, (w, d, x, y, z) -> TileData.setTileState(w.getBlockAt(new Location(w, x, y, z)), d.getData()));
+ registerReader(World.class, (w, x, y, z) -> new TileWrapper(TileData.getTileState(w.getBlockAt(new Location(w, x, y, z)))));
}
@Override
- public Palette getGlobalPalette() {
+ public Palette getGlobalPalette() {
return null;
}
- public void writeNode(TileData b, DataOutputStream dos) throws IOException {
- b.toBinary(dos);
+ public void writeNode(TileWrapper b, DataOutputStream dos) throws IOException {
+ b.getData().toBinary(dos);
}
- public TileData readNode(DataInputStream din) throws IOException {
- return TileData.read(din);
+ public TileWrapper readNode(DataInputStream din) throws IOException {
+ return new TileWrapper(TileData.read(din));
}
}
diff --git a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/IrisChunkGenerator.java b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/IrisChunkGenerator.java
new file mode 100644
index 000000000..040d588df
--- /dev/null
+++ b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/IrisChunkGenerator.java
@@ -0,0 +1,236 @@
+package com.volmit.iris.core.nms.v1_19_R1;
+
+import com.mojang.datafixers.util.Pair;
+import com.mojang.serialization.Codec;
+import com.volmit.iris.Iris;
+import com.volmit.iris.engine.framework.Engine;
+import com.volmit.iris.engine.framework.ResultLocator;
+import com.volmit.iris.engine.framework.WrongEngineBroException;
+import com.volmit.iris.engine.object.IrisJigsawStructure;
+import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
+import com.volmit.iris.util.collection.KList;
+import com.volmit.iris.util.collection.KMap;
+import com.volmit.iris.util.collection.KSet;
+import com.volmit.iris.util.mantle.MantleFlag;
+import com.volmit.iris.util.math.Position2;
+import net.minecraft.core.*;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.WorldGenRegion;
+import net.minecraft.tags.TagKey;
+import net.minecraft.util.random.WeightedRandomList;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.LevelHeightAccessor;
+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.BiomeManager;
+import net.minecraft.world.level.biome.BiomeSource;
+import net.minecraft.world.level.biome.MobSpawnSettings;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkGenerator;
+import net.minecraft.world.level.levelgen.GenerationStep;
+import net.minecraft.world.level.levelgen.Heightmap;
+import net.minecraft.world.level.levelgen.RandomState;
+import net.minecraft.world.level.levelgen.blending.Blender;
+import net.minecraft.world.level.levelgen.structure.Structure;
+import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
+import org.bukkit.World;
+import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_19_R1.generator.CustomChunkGenerator;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+
+public class IrisChunkGenerator extends CustomChunkGenerator {
+ private final ChunkGenerator delegate;
+ private final Engine engine;
+ private final BiomeSource biomeSource;
+ private final KMap, KSet> structures = new KMap<>();
+
+ public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
+ super(((CraftWorld) world).getHandle(), delegate, null);
+ this.delegate = delegate;
+ this.engine = engine;
+ this.biomeSource = new CustomBiomeSource(seed, engine, world);
+ var dimension = engine.getDimension();
+
+ KSet placements = new KSet<>();
+ addAll(dimension.getJigsawStructures(), placements);
+ for (var region : dimension.getAllRegions(engine)) {
+ addAll(region.getJigsawStructures(), placements);
+ for (var biome : region.getAllBiomes(engine))
+ addAll(biome.getJigsawStructures(), placements);
+ }
+ var stronghold = dimension.getStronghold();
+ if (stronghold != null)
+ placements.add(engine.getData().getJigsawStructureLoader().load(stronghold));
+ placements.removeIf(Objects::isNull);
+
+ var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registry.STRUCTURE_REGISTRY).orElseThrow();
+ for (var s : placements) {
+ try {
+ String raw = s.getStructureKey();
+ if (raw == null) continue;
+ boolean tag = raw.startsWith("#");
+ if (tag) raw = raw.substring(1);
+
+ var location = new ResourceLocation(raw);
+ if (!tag) {
+ structures.computeIfAbsent(ResourceKey.create(Registry.STRUCTURE_REGISTRY, location), k -> new KSet<>()).add(s.getLoadKey());
+ continue;
+ }
+
+ var key = TagKey.create(Registry.STRUCTURE_REGISTRY, location);
+ var set = registry.getTag(key).orElse(null);
+ if (set == null) {
+ Iris.error("Could not find structure tag: " + raw);
+ continue;
+ }
+ for (var holder : set) {
+ var resourceKey = holder.unwrapKey().orElse(null);
+ if (resourceKey == null) continue;
+ structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey());
+ }
+ } catch (Throwable e) {
+ Iris.error("Failed to load structure: " + s.getLoadKey());
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void addAll(KList placements, KSet structures) {
+ if (placements == null) return;
+ placements.stream()
+ .map(IrisJigsawStructurePlacement::getStructure)
+ .map(engine.getData().getJigsawStructureLoader()::load)
+ .filter(Objects::nonNull)
+ .forEach(structures::add);
+ }
+
+ @Override
+ public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) {
+ if (engine.getDimension().isDisableExplorerMaps())
+ return null;
+
+ KMap> structures = new KMap<>();
+ for (var holder : holders) {
+ if (holder == null) continue;
+ var key = holder.unwrapKey().orElse(null);
+ var set = this.structures.get(key);
+ if (set == null) continue;
+ for (var structure : set) {
+ structures.put(structure, holder);
+ }
+ }
+ if (structures.isEmpty())
+ return null;
+
+ var locator = ResultLocator.locateStructure(structures.keySet())
+ .then((e, p , s) -> structures.get(s.getLoadKey()));
+ if (findUnexplored)
+ locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s);
+
+ try {
+ var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get();
+ if (result == null) return null;
+ var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ());
+ return Pair.of(blockPos, result.obj());
+ } catch (WrongEngineBroException | ExecutionException | InterruptedException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected Codec extends ChunkGenerator> codec() {
+ return Codec.unit(null);
+ }
+
+ @Override
+ public ChunkGenerator getDelegate() {
+ if (delegate instanceof CustomChunkGenerator chunkGenerator)
+ return chunkGenerator.getDelegate();
+ return delegate;
+ }
+
+ @Override
+ public BiomeSource getBiomeSource() {
+ return biomeSource;
+ }
+
+ @Override
+ public int getMinY() {
+ return delegate.getMinY();
+ }
+
+ @Override
+ public int getSeaLevel() {
+ return delegate.getSeaLevel();
+ }
+
+ @Override
+ public void createStructures(RegistryAccess iregistrycustom, RandomState randomstate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager, long i) {
+ delegate.createStructures(iregistrycustom, randomstate, structuremanager, ichunkaccess, structuretemplatemanager, i);
+ }
+
+ @Override
+ public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) {
+ delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess);
+ }
+
+ @Override
+ public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) {
+ delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features);
+ }
+
+ @Override
+ public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess 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
+ public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
+ return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
+ }
+
+ @Override
+ public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
+ delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
+ }
+
+ @Override
+ public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) {
+ delegate.addDebugScreenInfo(list, randomstate, blockposition);
+ }
+
+ @Override
+ public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) {
+ delegate.spawnOriginalMobs(regionlimitedworldaccess);
+ }
+
+ @Override
+ public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) {
+ return delegate.getSpawnHeight(levelheightaccessor);
+ }
+
+ @Override
+ public int getGenDepth() {
+ return delegate.getGenDepth();
+ }
+
+ @Override
+ public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
+ return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
+ }
+}
diff --git a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java
index c0fc93aa9..bd0e98299 100644
--- a/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java
+++ b/nms/v1_19_R1/src/main/java/com/volmit/iris/core/nms/v1_19_R1/NMSBinding.java
@@ -34,6 +34,7 @@ import java.util.logging.Logger;
import java.util.stream.Collectors;
import com.google.gson.JsonNull;
+import com.mojang.datafixers.util.Pair;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.util.scheduling.J;
import net.minecraft.nbt.*;
@@ -41,6 +42,7 @@ import net.minecraft.nbt.Tag;
import net.minecraft.server.commands.data.BlockDataAccessor;
import com.volmit.iris.core.nms.container.IPackRepository;
import com.volmit.iris.util.io.IO;
+import net.minecraft.tags.TagKey;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.EntityBlock;
import com.google.common.base.Preconditions;
@@ -594,23 +596,9 @@ public class NMSBinding implements INMSBinding {
}
}
- public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) {
- CraftDolphin cd = (CraftDolphin)dolphin;
- cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
- cd.getHandle().setGotFish(true);
- }
-
- public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
- ServerLevel serverLevel = ((CraftWorld)world).getHandle();
- Class> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass();
- Field biomeSource = getField(clazz, BiomeSource.class);
- biomeSource.setAccessible(true);
- Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
- unsafeField.setAccessible(true);
- Unsafe unsafe = (Unsafe)unsafeField.get(null);
- CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world);
- unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource);
- biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource);
+ public void inject(long seed, Engine engine, World world) {
+ var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
+ chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
}
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
@@ -865,6 +853,23 @@ public class NMSBinding implements INMSBinding {
return new Color(rgba, true);
}
+ @Override
+ public KList getStructureKeys() {
+ KList keys = new KList<>();
+
+ var registry = registry().registry(Registry.STRUCTURE_REGISTRY).orElse(null);
+ if (registry == null) return keys;
+ registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add);
+ registry.getTags()
+ .map(Pair::getFirst)
+ .map(TagKey::location)
+ .map(ResourceLocation::toString)
+ .map(s -> "#" + s)
+ .forEach(keys::add);
+
+ return keys;
+ }
+
private static Field getField(Class> clazz, Class> fieldType) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
diff --git a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/IrisChunkGenerator.java b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/IrisChunkGenerator.java
new file mode 100644
index 000000000..9bb31ef8c
--- /dev/null
+++ b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/IrisChunkGenerator.java
@@ -0,0 +1,241 @@
+package com.volmit.iris.core.nms.v1_19_R2;
+
+import com.mojang.datafixers.util.Pair;
+import com.mojang.serialization.Codec;
+import com.volmit.iris.Iris;
+import com.volmit.iris.engine.framework.Engine;
+import com.volmit.iris.engine.framework.ResultLocator;
+import com.volmit.iris.engine.framework.WrongEngineBroException;
+import com.volmit.iris.engine.object.IrisJigsawStructure;
+import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
+import com.volmit.iris.util.collection.KList;
+import com.volmit.iris.util.collection.KMap;
+import com.volmit.iris.util.collection.KSet;
+import com.volmit.iris.util.mantle.MantleFlag;
+import com.volmit.iris.util.math.Position2;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Holder;
+import net.minecraft.core.HolderSet;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.WorldGenRegion;
+import net.minecraft.tags.TagKey;
+import net.minecraft.util.random.WeightedRandomList;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.LevelHeightAccessor;
+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.BiomeManager;
+import net.minecraft.world.level.biome.BiomeSource;
+import net.minecraft.world.level.biome.MobSpawnSettings;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkGenerator;
+import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
+import net.minecraft.world.level.levelgen.GenerationStep;
+import net.minecraft.world.level.levelgen.Heightmap;
+import net.minecraft.world.level.levelgen.RandomState;
+import net.minecraft.world.level.levelgen.blending.Blender;
+import net.minecraft.world.level.levelgen.structure.Structure;
+import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
+import org.bukkit.World;
+import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
+import org.bukkit.craftbukkit.v1_19_R2.generator.CustomChunkGenerator;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+
+public class IrisChunkGenerator extends CustomChunkGenerator {
+ private final ChunkGenerator delegate;
+ private final Engine engine;
+ private final BiomeSource biomeSource;
+ private final KMap, KSet> structures = new KMap<>();
+
+ public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
+ super(((CraftWorld) world).getHandle(), delegate, null);
+ this.delegate = delegate;
+ this.engine = engine;
+ this.biomeSource = new CustomBiomeSource(seed, engine, world);
+ var dimension = engine.getDimension();
+
+ KSet placements = new KSet<>();
+ addAll(dimension.getJigsawStructures(), placements);
+ for (var region : dimension.getAllRegions(engine)) {
+ addAll(region.getJigsawStructures(), placements);
+ for (var biome : region.getAllBiomes(engine))
+ addAll(biome.getJigsawStructures(), placements);
+ }
+ var stronghold = dimension.getStronghold();
+ if (stronghold != null)
+ placements.add(engine.getData().getJigsawStructureLoader().load(stronghold));
+ placements.removeIf(Objects::isNull);
+
+ var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow();
+ for (var s : placements) {
+ try {
+ String raw = s.getStructureKey();
+ if (raw == null) continue;
+ boolean tag = raw.startsWith("#");
+ if (tag) raw = raw.substring(1);
+
+ var location = new ResourceLocation(raw);
+ if (!tag) {
+ structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey());
+ continue;
+ }
+
+ var key = TagKey.create(Registries.STRUCTURE, location);
+ var set = registry.getTag(key).orElse(null);
+ if (set == null) {
+ Iris.error("Could not find structure tag: " + raw);
+ continue;
+ }
+ for (var holder : set) {
+ var resourceKey = holder.unwrapKey().orElse(null);
+ if (resourceKey == null) continue;
+ structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey());
+ }
+ } catch (Throwable e) {
+ Iris.error("Failed to load structure: " + s.getLoadKey());
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void addAll(KList placements, KSet structures) {
+ if (placements == null) return;
+ placements.stream()
+ .map(IrisJigsawStructurePlacement::getStructure)
+ .map(engine.getData().getJigsawStructureLoader()::load)
+ .filter(Objects::nonNull)
+ .forEach(structures::add);
+ }
+
+ @Override
+ public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) {
+ if (engine.getDimension().isDisableExplorerMaps())
+ return null;
+
+ KMap> structures = new KMap<>();
+ for (var holder : holders) {
+ if (holder == null) continue;
+ var key = holder.unwrapKey().orElse(null);
+ var set = this.structures.get(key);
+ if (set == null) continue;
+ for (var structure : set) {
+ structures.put(structure, holder);
+ }
+ }
+ if (structures.isEmpty())
+ return null;
+
+ var locator = ResultLocator.locateStructure(structures.keySet())
+ .then((e, p , s) -> structures.get(s.getLoadKey()));
+ if (findUnexplored)
+ locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s);
+
+ try {
+ var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get();
+ if (result == null) return null;
+ var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ());
+ return Pair.of(blockPos, result.obj());
+ } catch (WrongEngineBroException | ExecutionException | InterruptedException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected Codec extends ChunkGenerator> codec() {
+ return Codec.unit(null);
+ }
+
+ @Override
+ public ChunkGenerator getDelegate() {
+ if (delegate instanceof CustomChunkGenerator chunkGenerator)
+ return chunkGenerator.getDelegate();
+ return delegate;
+ }
+
+ @Override
+ public BiomeSource getBiomeSource() {
+ return biomeSource;
+ }
+
+ @Override
+ public int getMinY() {
+ return delegate.getMinY();
+ }
+
+ @Override
+ public int getSeaLevel() {
+ return delegate.getSeaLevel();
+ }
+
+ @Override
+ public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
+ delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
+ }
+
+ @Override
+ public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) {
+ delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess);
+ }
+
+ @Override
+ public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) {
+ delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features);
+ }
+
+ @Override
+ public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess 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
+ public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
+ return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
+ }
+
+ @Override
+ public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
+ delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
+ }
+
+ @Override
+ public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) {
+ delegate.addDebugScreenInfo(list, randomstate, blockposition);
+ }
+
+ @Override
+ public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) {
+ delegate.spawnOriginalMobs(regionlimitedworldaccess);
+ }
+
+ @Override
+ public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) {
+ return delegate.getSpawnHeight(levelheightaccessor);
+ }
+
+ @Override
+ public int getGenDepth() {
+ return delegate.getGenDepth();
+ }
+
+ @Override
+ public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
+ return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
+ }
+}
diff --git a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java
index 776790845..a3a0ceb21 100644
--- a/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java
+++ b/nms/v1_19_R2/src/main/java/com/volmit/iris/core/nms/v1_19_R2/NMSBinding.java
@@ -35,6 +35,7 @@ import java.util.logging.Logger;
import java.util.stream.Collectors;
import com.google.gson.JsonNull;
+import com.mojang.datafixers.util.Pair;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.IPackRepository;
import com.volmit.iris.util.io.IO;
@@ -42,6 +43,7 @@ import com.volmit.iris.util.scheduling.J;
import net.minecraft.nbt.*;
import net.minecraft.nbt.Tag;
import net.minecraft.server.commands.data.BlockDataAccessor;
+import net.minecraft.tags.TagKey;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.EntityBlock;
import com.google.common.base.Preconditions;
@@ -596,23 +598,9 @@ public class NMSBinding implements INMSBinding {
}
}
- public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) {
- CraftDolphin cd = (CraftDolphin)dolphin;
- cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
- cd.getHandle().setGotFish(true);
- }
-
- public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
- ServerLevel serverLevel = ((CraftWorld)world).getHandle();
- Class> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass();
- Field biomeSource = getField(clazz, BiomeSource.class);
- biomeSource.setAccessible(true);
- Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
- unsafeField.setAccessible(true);
- Unsafe unsafe = (Unsafe)unsafeField.get(null);
- CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world);
- unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource);
- biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource);
+ public void inject(long seed, Engine engine, World world) {
+ var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
+ chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
}
@@ -802,6 +790,23 @@ public class NMSBinding implements INMSBinding {
return new Color(rgba, true);
}
+ @Override
+ public KList getStructureKeys() {
+ KList keys = new KList<>();
+
+ var registry = registry().registry(Registries.STRUCTURE).orElse(null);
+ if (registry == null) return keys;
+ registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add);
+ registry.getTags()
+ .map(Pair::getFirst)
+ .map(TagKey::location)
+ .map(ResourceLocation::toString)
+ .map(s -> "#" + s)
+ .forEach(keys::add);
+
+ return keys;
+ }
+
private static Field getField(Class> clazz, Class> fieldType) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
diff --git a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/IrisChunkGenerator.java b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/IrisChunkGenerator.java
new file mode 100644
index 000000000..358ef9829
--- /dev/null
+++ b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/IrisChunkGenerator.java
@@ -0,0 +1,241 @@
+package com.volmit.iris.core.nms.v1_19_R3;
+
+import com.mojang.datafixers.util.Pair;
+import com.mojang.serialization.Codec;
+import com.volmit.iris.Iris;
+import com.volmit.iris.engine.framework.Engine;
+import com.volmit.iris.engine.framework.ResultLocator;
+import com.volmit.iris.engine.framework.WrongEngineBroException;
+import com.volmit.iris.engine.object.IrisJigsawStructure;
+import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
+import com.volmit.iris.util.collection.KList;
+import com.volmit.iris.util.collection.KMap;
+import com.volmit.iris.util.collection.KSet;
+import com.volmit.iris.util.mantle.MantleFlag;
+import com.volmit.iris.util.math.Position2;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Holder;
+import net.minecraft.core.HolderSet;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.WorldGenRegion;
+import net.minecraft.tags.TagKey;
+import net.minecraft.util.random.WeightedRandomList;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.LevelHeightAccessor;
+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.BiomeManager;
+import net.minecraft.world.level.biome.BiomeSource;
+import net.minecraft.world.level.biome.MobSpawnSettings;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkGenerator;
+import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
+import net.minecraft.world.level.levelgen.GenerationStep;
+import net.minecraft.world.level.levelgen.Heightmap;
+import net.minecraft.world.level.levelgen.RandomState;
+import net.minecraft.world.level.levelgen.blending.Blender;
+import net.minecraft.world.level.levelgen.structure.Structure;
+import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
+import org.bukkit.World;
+import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
+import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+
+public class IrisChunkGenerator extends CustomChunkGenerator {
+ private final ChunkGenerator delegate;
+ private final Engine engine;
+ private final BiomeSource biomeSource;
+ private final KMap, KSet> structures = new KMap<>();
+
+ public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
+ super(((CraftWorld) world).getHandle(), delegate, null);
+ this.delegate = delegate;
+ this.engine = engine;
+ this.biomeSource = new CustomBiomeSource(seed, engine, world);
+ var dimension = engine.getDimension();
+
+ KSet placements = new KSet<>();
+ addAll(dimension.getJigsawStructures(), placements);
+ for (var region : dimension.getAllRegions(engine)) {
+ addAll(region.getJigsawStructures(), placements);
+ for (var biome : region.getAllBiomes(engine))
+ addAll(biome.getJigsawStructures(), placements);
+ }
+ var stronghold = dimension.getStronghold();
+ if (stronghold != null)
+ placements.add(engine.getData().getJigsawStructureLoader().load(stronghold));
+ placements.removeIf(Objects::isNull);
+
+ var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow();
+ for (var s : placements) {
+ try {
+ String raw = s.getStructureKey();
+ if (raw == null) continue;
+ boolean tag = raw.startsWith("#");
+ if (tag) raw = raw.substring(1);
+
+ var location = new ResourceLocation(raw);
+ if (!tag) {
+ structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey());
+ continue;
+ }
+
+ var key = TagKey.create(Registries.STRUCTURE, location);
+ var set = registry.getTag(key).orElse(null);
+ if (set == null) {
+ Iris.error("Could not find structure tag: " + raw);
+ continue;
+ }
+ for (var holder : set) {
+ var resourceKey = holder.unwrapKey().orElse(null);
+ if (resourceKey == null) continue;
+ structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey());
+ }
+ } catch (Throwable e) {
+ Iris.error("Failed to load structure: " + s.getLoadKey());
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void addAll(KList placements, KSet structures) {
+ if (placements == null) return;
+ placements.stream()
+ .map(IrisJigsawStructurePlacement::getStructure)
+ .map(engine.getData().getJigsawStructureLoader()::load)
+ .filter(Objects::nonNull)
+ .forEach(structures::add);
+ }
+
+ @Override
+ public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) {
+ if (engine.getDimension().isDisableExplorerMaps())
+ return null;
+
+ KMap> structures = new KMap<>();
+ for (var holder : holders) {
+ if (holder == null) continue;
+ var key = holder.unwrapKey().orElse(null);
+ var set = this.structures.get(key);
+ if (set == null) continue;
+ for (var structure : set) {
+ structures.put(structure, holder);
+ }
+ }
+ if (structures.isEmpty())
+ return null;
+
+ var locator = ResultLocator.locateStructure(structures.keySet())
+ .then((e, p , s) -> structures.get(s.getLoadKey()));
+ if (findUnexplored)
+ locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s);
+
+ try {
+ var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get();
+ if (result == null) return null;
+ var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ());
+ return Pair.of(blockPos, result.obj());
+ } catch (WrongEngineBroException | ExecutionException | InterruptedException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected Codec extends ChunkGenerator> codec() {
+ return Codec.unit(null);
+ }
+
+ @Override
+ public ChunkGenerator getDelegate() {
+ if (delegate instanceof CustomChunkGenerator chunkGenerator)
+ return chunkGenerator.getDelegate();
+ return delegate;
+ }
+
+ @Override
+ public BiomeSource getBiomeSource() {
+ return biomeSource;
+ }
+
+ @Override
+ public int getMinY() {
+ return delegate.getMinY();
+ }
+
+ @Override
+ public int getSeaLevel() {
+ return delegate.getSeaLevel();
+ }
+
+ @Override
+ public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
+ delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
+ }
+
+ @Override
+ public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) {
+ delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess);
+ }
+
+ @Override
+ public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) {
+ delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features);
+ }
+
+ @Override
+ public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess 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
+ public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
+ return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
+ }
+
+ @Override
+ public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
+ delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
+ }
+
+ @Override
+ public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) {
+ delegate.addDebugScreenInfo(list, randomstate, blockposition);
+ }
+
+ @Override
+ public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) {
+ delegate.spawnOriginalMobs(regionlimitedworldaccess);
+ }
+
+ @Override
+ public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) {
+ return delegate.getSpawnHeight(levelheightaccessor);
+ }
+
+ @Override
+ public int getGenDepth() {
+ return delegate.getGenDepth();
+ }
+
+ @Override
+ public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
+ return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
+ }
+}
diff --git a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java
index fca8f5290..7626ea853 100644
--- a/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java
+++ b/nms/v1_19_R3/src/main/java/com/volmit/iris/core/nms/v1_19_R3/NMSBinding.java
@@ -34,6 +34,7 @@ import java.util.logging.Logger;
import java.util.stream.Collectors;
import com.google.gson.JsonNull;
+import com.mojang.datafixers.util.Pair;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.util.scheduling.J;
import net.minecraft.nbt.*;
@@ -41,6 +42,7 @@ import net.minecraft.nbt.Tag;
import net.minecraft.server.commands.data.BlockDataAccessor;
import com.volmit.iris.core.nms.container.IPackRepository;
import com.volmit.iris.util.io.IO;
+import net.minecraft.tags.TagKey;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.EntityBlock;
import com.google.common.base.Preconditions;
@@ -603,17 +605,9 @@ public class NMSBinding implements INMSBinding {
cd.getHandle().setGotFish(true);
}
- public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
- ServerLevel serverLevel = ((CraftWorld)world).getHandle();
- Class> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass();
- Field biomeSource = getField(clazz, BiomeSource.class);
- biomeSource.setAccessible(true);
- Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
- unsafeField.setAccessible(true);
- Unsafe unsafe = (Unsafe)unsafeField.get(null);
- CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world);
- unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource);
- biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource);
+ public void inject(long seed, Engine engine, World world) {
+ var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
+ chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
}
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
@@ -805,6 +799,23 @@ public class NMSBinding implements INMSBinding {
return new Color(rgba, true);
}
+ @Override
+ public KList getStructureKeys() {
+ KList keys = new KList<>();
+
+ var registry = registry().registry(Registries.STRUCTURE).orElse(null);
+ if (registry == null) return keys;
+ registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add);
+ registry.getTags()
+ .map(Pair::getFirst)
+ .map(TagKey::location)
+ .map(ResourceLocation::toString)
+ .map(s -> "#" + s)
+ .forEach(keys::add);
+
+ return keys;
+ }
+
private static Field getField(Class> clazz, Class> fieldType) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
diff --git a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/IrisChunkGenerator.java b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/IrisChunkGenerator.java
new file mode 100644
index 000000000..f415bbe69
--- /dev/null
+++ b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/IrisChunkGenerator.java
@@ -0,0 +1,241 @@
+package com.volmit.iris.core.nms.v1_20_R1;
+
+import com.mojang.datafixers.util.Pair;
+import com.mojang.serialization.Codec;
+import com.volmit.iris.Iris;
+import com.volmit.iris.engine.framework.Engine;
+import com.volmit.iris.engine.framework.ResultLocator;
+import com.volmit.iris.engine.framework.WrongEngineBroException;
+import com.volmit.iris.engine.object.IrisJigsawStructure;
+import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
+import com.volmit.iris.util.collection.KList;
+import com.volmit.iris.util.collection.KMap;
+import com.volmit.iris.util.collection.KSet;
+import com.volmit.iris.util.mantle.MantleFlag;
+import com.volmit.iris.util.math.Position2;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Holder;
+import net.minecraft.core.HolderSet;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.WorldGenRegion;
+import net.minecraft.tags.TagKey;
+import net.minecraft.util.random.WeightedRandomList;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.LevelHeightAccessor;
+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.BiomeManager;
+import net.minecraft.world.level.biome.BiomeSource;
+import net.minecraft.world.level.biome.MobSpawnSettings;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkGenerator;
+import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
+import net.minecraft.world.level.levelgen.GenerationStep;
+import net.minecraft.world.level.levelgen.Heightmap;
+import net.minecraft.world.level.levelgen.RandomState;
+import net.minecraft.world.level.levelgen.blending.Blender;
+import net.minecraft.world.level.levelgen.structure.Structure;
+import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
+import org.bukkit.World;
+import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_20_R1.generator.CustomChunkGenerator;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+
+public class IrisChunkGenerator extends CustomChunkGenerator {
+ private final ChunkGenerator delegate;
+ private final Engine engine;
+ private final BiomeSource biomeSource;
+ private final KMap, KSet> structures = new KMap<>();
+
+ public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
+ super(((CraftWorld) world).getHandle(), delegate, null);
+ this.delegate = delegate;
+ this.engine = engine;
+ this.biomeSource = new CustomBiomeSource(seed, engine, world);
+ var dimension = engine.getDimension();
+
+ KSet placements = new KSet<>();
+ addAll(dimension.getJigsawStructures(), placements);
+ for (var region : dimension.getAllRegions(engine)) {
+ addAll(region.getJigsawStructures(), placements);
+ for (var biome : region.getAllBiomes(engine))
+ addAll(biome.getJigsawStructures(), placements);
+ }
+ var stronghold = dimension.getStronghold();
+ if (stronghold != null)
+ placements.add(engine.getData().getJigsawStructureLoader().load(stronghold));
+ placements.removeIf(Objects::isNull);
+
+ var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow();
+ for (var s : placements) {
+ try {
+ String raw = s.getStructureKey();
+ if (raw == null) continue;
+ boolean tag = raw.startsWith("#");
+ if (tag) raw = raw.substring(1);
+
+ var location = new ResourceLocation(raw);
+ if (!tag) {
+ structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey());
+ continue;
+ }
+
+ var key = TagKey.create(Registries.STRUCTURE, location);
+ var set = registry.getTag(key).orElse(null);
+ if (set == null) {
+ Iris.error("Could not find structure tag: " + raw);
+ continue;
+ }
+ for (var holder : set) {
+ var resourceKey = holder.unwrapKey().orElse(null);
+ if (resourceKey == null) continue;
+ structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey());
+ }
+ } catch (Throwable e) {
+ Iris.error("Failed to load structure: " + s.getLoadKey());
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void addAll(KList placements, KSet structures) {
+ if (placements == null) return;
+ placements.stream()
+ .map(IrisJigsawStructurePlacement::getStructure)
+ .map(engine.getData().getJigsawStructureLoader()::load)
+ .filter(Objects::nonNull)
+ .forEach(structures::add);
+ }
+
+ @Override
+ public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) {
+ if (engine.getDimension().isDisableExplorerMaps())
+ return null;
+
+ KMap> structures = new KMap<>();
+ for (var holder : holders) {
+ if (holder == null) continue;
+ var key = holder.unwrapKey().orElse(null);
+ var set = this.structures.get(key);
+ if (set == null) continue;
+ for (var structure : set) {
+ structures.put(structure, holder);
+ }
+ }
+ if (structures.isEmpty())
+ return null;
+
+ var locator = ResultLocator.locateStructure(structures.keySet())
+ .then((e, p , s) -> structures.get(s.getLoadKey()));
+ if (findUnexplored)
+ locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s);
+
+ try {
+ var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get();
+ if (result == null) return null;
+ var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ());
+ return Pair.of(blockPos, result.obj());
+ } catch (WrongEngineBroException | ExecutionException | InterruptedException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected Codec extends ChunkGenerator> codec() {
+ return Codec.unit(null);
+ }
+
+ @Override
+ public ChunkGenerator getDelegate() {
+ if (delegate instanceof CustomChunkGenerator chunkGenerator)
+ return chunkGenerator.getDelegate();
+ return delegate;
+ }
+
+ @Override
+ public BiomeSource getBiomeSource() {
+ return biomeSource;
+ }
+
+ @Override
+ public int getMinY() {
+ return delegate.getMinY();
+ }
+
+ @Override
+ public int getSeaLevel() {
+ return delegate.getSeaLevel();
+ }
+
+ @Override
+ public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
+ delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
+ }
+
+ @Override
+ public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) {
+ delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess);
+ }
+
+ @Override
+ public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) {
+ delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features);
+ }
+
+ @Override
+ public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess 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
+ public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
+ return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
+ }
+
+ @Override
+ public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
+ delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
+ }
+
+ @Override
+ public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) {
+ delegate.addDebugScreenInfo(list, randomstate, blockposition);
+ }
+
+ @Override
+ public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) {
+ delegate.spawnOriginalMobs(regionlimitedworldaccess);
+ }
+
+ @Override
+ public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) {
+ return delegate.getSpawnHeight(levelheightaccessor);
+ }
+
+ @Override
+ public int getGenDepth() {
+ return delegate.getGenDepth();
+ }
+
+ @Override
+ public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
+ return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
+ }
+}
diff --git a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java
index 7bf4acf65..aeeb462cc 100644
--- a/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java
+++ b/nms/v1_20_R1/src/main/java/com/volmit/iris/core/nms/v1_20_R1/NMSBinding.java
@@ -27,6 +27,7 @@ import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.Lifecycle;
+import com.mojang.datafixers.util.Pair;
import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMSBinding;
import com.volmit.iris.core.nms.container.BiomeColor;
@@ -68,6 +69,7 @@ import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.commands.data.BlockDataAccessor;
import net.minecraft.server.level.ServerLevel;
+import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.level.LevelReader;
import net.minecraft.server.level.progress.ChunkProgressListener;
@@ -598,12 +600,6 @@ public class NMSBinding implements INMSBinding {
}
}
- public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) {
- CraftDolphin cd = (CraftDolphin)dolphin;
- cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
- cd.getHandle().setGotFish(true);
- }
-
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
Field[] fields = net.minecraft.world.entity.EntityType.class.getDeclaredFields();
for (Field field : fields) {
@@ -766,17 +762,9 @@ public class NMSBinding implements INMSBinding {
}
}
- public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
- ServerLevel serverLevel = ((CraftWorld)world).getHandle();
- Class> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass();
- Field biomeSource = getField(clazz, BiomeSource.class);
- biomeSource.setAccessible(true);
- Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
- unsafeField.setAccessible(true);
- Unsafe unsafe = (Unsafe)unsafeField.get(null);
- CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world);
- unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource);
- biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource);
+ public void inject(long seed, Engine engine, World world) {
+ var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
+ chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
}
@Override
@@ -803,6 +791,23 @@ public class NMSBinding implements INMSBinding {
return new Color(rgba, true);
}
+ @Override
+ public KList getStructureKeys() {
+ KList keys = new KList<>();
+
+ var registry = registry().registry(Registries.STRUCTURE).orElse(null);
+ if (registry == null) return keys;
+ registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add);
+ registry.getTags()
+ .map(Pair::getFirst)
+ .map(TagKey::location)
+ .map(ResourceLocation::toString)
+ .map(s -> "#" + s)
+ .forEach(keys::add);
+
+ return keys;
+ }
+
private static Field getField(Class> clazz, Class> fieldType) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
diff --git a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/IrisChunkGenerator.java b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/IrisChunkGenerator.java
new file mode 100644
index 000000000..27afcb0f7
--- /dev/null
+++ b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/IrisChunkGenerator.java
@@ -0,0 +1,241 @@
+package com.volmit.iris.core.nms.v1_20_R2;
+
+import com.mojang.datafixers.util.Pair;
+import com.mojang.serialization.Codec;
+import com.volmit.iris.Iris;
+import com.volmit.iris.engine.framework.Engine;
+import com.volmit.iris.engine.framework.ResultLocator;
+import com.volmit.iris.engine.framework.WrongEngineBroException;
+import com.volmit.iris.engine.object.IrisJigsawStructure;
+import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
+import com.volmit.iris.util.collection.KList;
+import com.volmit.iris.util.collection.KMap;
+import com.volmit.iris.util.collection.KSet;
+import com.volmit.iris.util.mantle.MantleFlag;
+import com.volmit.iris.util.math.Position2;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Holder;
+import net.minecraft.core.HolderSet;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.WorldGenRegion;
+import net.minecraft.tags.TagKey;
+import net.minecraft.util.random.WeightedRandomList;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.LevelHeightAccessor;
+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.BiomeManager;
+import net.minecraft.world.level.biome.BiomeSource;
+import net.minecraft.world.level.biome.MobSpawnSettings;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkGenerator;
+import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
+import net.minecraft.world.level.levelgen.GenerationStep;
+import net.minecraft.world.level.levelgen.Heightmap;
+import net.minecraft.world.level.levelgen.RandomState;
+import net.minecraft.world.level.levelgen.blending.Blender;
+import net.minecraft.world.level.levelgen.structure.Structure;
+import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
+import org.bukkit.World;
+import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
+import org.bukkit.craftbukkit.v1_20_R2.generator.CustomChunkGenerator;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+
+public class IrisChunkGenerator extends CustomChunkGenerator {
+ private final ChunkGenerator delegate;
+ private final Engine engine;
+ private final BiomeSource biomeSource;
+ private final KMap, KSet> structures = new KMap<>();
+
+ public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
+ super(((CraftWorld) world).getHandle(), delegate, null);
+ this.delegate = delegate;
+ this.engine = engine;
+ this.biomeSource = new CustomBiomeSource(seed, engine, world);
+ var dimension = engine.getDimension();
+
+ KSet placements = new KSet<>();
+ addAll(dimension.getJigsawStructures(), placements);
+ for (var region : dimension.getAllRegions(engine)) {
+ addAll(region.getJigsawStructures(), placements);
+ for (var biome : region.getAllBiomes(engine))
+ addAll(biome.getJigsawStructures(), placements);
+ }
+ var stronghold = dimension.getStronghold();
+ if (stronghold != null)
+ placements.add(engine.getData().getJigsawStructureLoader().load(stronghold));
+ placements.removeIf(Objects::isNull);
+
+ var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow();
+ for (var s : placements) {
+ try {
+ String raw = s.getStructureKey();
+ if (raw == null) continue;
+ boolean tag = raw.startsWith("#");
+ if (tag) raw = raw.substring(1);
+
+ var location = new ResourceLocation(raw);
+ if (!tag) {
+ structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey());
+ continue;
+ }
+
+ var key = TagKey.create(Registries.STRUCTURE, location);
+ var set = registry.getTag(key).orElse(null);
+ if (set == null) {
+ Iris.error("Could not find structure tag: " + raw);
+ continue;
+ }
+ for (var holder : set) {
+ var resourceKey = holder.unwrapKey().orElse(null);
+ if (resourceKey == null) continue;
+ structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey());
+ }
+ } catch (Throwable e) {
+ Iris.error("Failed to load structure: " + s.getLoadKey());
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void addAll(KList placements, KSet structures) {
+ if (placements == null) return;
+ placements.stream()
+ .map(IrisJigsawStructurePlacement::getStructure)
+ .map(engine.getData().getJigsawStructureLoader()::load)
+ .filter(Objects::nonNull)
+ .forEach(structures::add);
+ }
+
+ @Override
+ public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) {
+ if (engine.getDimension().isDisableExplorerMaps())
+ return null;
+
+ KMap> structures = new KMap<>();
+ for (var holder : holders) {
+ if (holder == null) continue;
+ var key = holder.unwrapKey().orElse(null);
+ var set = this.structures.get(key);
+ if (set == null) continue;
+ for (var structure : set) {
+ structures.put(structure, holder);
+ }
+ }
+ if (structures.isEmpty())
+ return null;
+
+ var locator = ResultLocator.locateStructure(structures.keySet())
+ .then((e, p , s) -> structures.get(s.getLoadKey()));
+ if (findUnexplored)
+ locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s);
+
+ try {
+ var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get();
+ if (result == null) return null;
+ var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ());
+ return Pair.of(blockPos, result.obj());
+ } catch (WrongEngineBroException | ExecutionException | InterruptedException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected Codec extends ChunkGenerator> codec() {
+ return Codec.unit(null);
+ }
+
+ @Override
+ public ChunkGenerator getDelegate() {
+ if (delegate instanceof CustomChunkGenerator chunkGenerator)
+ return chunkGenerator.getDelegate();
+ return delegate;
+ }
+
+ @Override
+ public BiomeSource getBiomeSource() {
+ return biomeSource;
+ }
+
+ @Override
+ public int getMinY() {
+ return delegate.getMinY();
+ }
+
+ @Override
+ public int getSeaLevel() {
+ return delegate.getSeaLevel();
+ }
+
+ @Override
+ public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
+ delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
+ }
+
+ @Override
+ public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) {
+ delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess);
+ }
+
+ @Override
+ public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) {
+ delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features);
+ }
+
+ @Override
+ public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess 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
+ public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
+ return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
+ }
+
+ @Override
+ public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
+ delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
+ }
+
+ @Override
+ public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) {
+ delegate.addDebugScreenInfo(list, randomstate, blockposition);
+ }
+
+ @Override
+ public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) {
+ delegate.spawnOriginalMobs(regionlimitedworldaccess);
+ }
+
+ @Override
+ public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) {
+ return delegate.getSpawnHeight(levelheightaccessor);
+ }
+
+ @Override
+ public int getGenDepth() {
+ return delegate.getGenDepth();
+ }
+
+ @Override
+ public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
+ return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
+ }
+}
diff --git a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java
index 5333e7bf5..51128928e 100644
--- a/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java
+++ b/nms/v1_20_R2/src/main/java/com/volmit/iris/core/nms/v1_20_R2/NMSBinding.java
@@ -34,11 +34,13 @@ import java.util.logging.Logger;
import java.util.stream.Collectors;
import com.google.gson.JsonNull;
+import com.mojang.datafixers.util.Pair;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.util.scheduling.J;
import net.minecraft.nbt.*;
import net.minecraft.nbt.Tag;
import net.minecraft.server.commands.data.BlockDataAccessor;
+import net.minecraft.tags.TagKey;
import com.volmit.iris.core.nms.container.IPackRepository;
import com.volmit.iris.util.io.IO;
import net.minecraft.server.commands.DataPackCommand;
@@ -599,23 +601,9 @@ public class NMSBinding implements INMSBinding {
}
}
- public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) {
- CraftDolphin cd = (CraftDolphin)dolphin;
- cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
- cd.getHandle().setGotFish(true);
- }
-
- public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
- ServerLevel serverLevel = ((CraftWorld)world).getHandle();
- Class> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass();
- Field biomeSource = getField(clazz, BiomeSource.class);
- biomeSource.setAccessible(true);
- Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
- unsafeField.setAccessible(true);
- Unsafe unsafe = (Unsafe)unsafeField.get(null);
- CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world);
- unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource);
- biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource);
+ public void inject(long seed, Engine engine, World world) {
+ var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
+ chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
}
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
@@ -805,6 +793,23 @@ public class NMSBinding implements INMSBinding {
return new Color(rgba, true);
}
+ @Override
+ public KList getStructureKeys() {
+ KList keys = new KList<>();
+
+ var registry = registry().registry(Registries.STRUCTURE).orElse(null);
+ if (registry == null) return keys;
+ registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add);
+ registry.getTags()
+ .map(Pair::getFirst)
+ .map(TagKey::location)
+ .map(ResourceLocation::toString)
+ .map(s -> "#" + s)
+ .forEach(keys::add);
+
+ return keys;
+ }
+
private static Field getField(Class> clazz, Class> fieldType) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/Headless.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/Headless.java
index ab8706256..71572d0a1 100644
--- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/Headless.java
+++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/Headless.java
@@ -40,6 +40,7 @@ import com.volmit.iris.util.mantle.MantleFlag;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
+import lombok.Getter;
import net.minecraft.core.Holder;
import net.minecraft.core.QuartPos;
import net.minecraft.nbt.CompoundTag;
@@ -68,6 +69,8 @@ public class Headless implements IHeadless, LevelHeightAccessor {
private final KMap> customBiomes = new KMap<>();
private final KMap> minecraftBiomes = new KMap<>();
private final RNG BIOME_RNG;
+ private final @Getter int minBuildHeight;
+ private final @Getter int height;
private boolean closed = false;
public Headless(NMSBinding binding, Engine engine) {
@@ -75,6 +78,8 @@ public class Headless implements IHeadless, LevelHeightAccessor {
this.engine = engine;
this.storage = new RegionFileStorage(new File(engine.getWorld().worldFolder(), "region").toPath(), true);
this.BIOME_RNG = new RNG(engine.getSeedManager().getBiome());
+ this.minBuildHeight = engine.getDimension().getMinHeight();
+ this.height = engine.getDimension().getMaxHeight() - minBuildHeight;
engine.getWorld().headless(this);
var dimKey = engine.getDimension().getLoadKey();
@@ -107,6 +112,8 @@ public class Headless implements IHeadless, LevelHeightAccessor {
@Override
public boolean exists(int x, int z) {
if (closed) return false;
+ if (engine.getWorld().hasRealWorld() && engine.getWorld().realWorld().isChunkLoaded(x, z))
+ return true;
try {
CompoundTag tag = storage.read(new ChunkPos(x, z));
return tag != null && !"empty".equals(tag.getString("Status"));
@@ -270,14 +277,4 @@ public class Headless implements IHeadless, LevelHeightAccessor {
minecraftBiomes.clear();
}
}
-
- @Override
- public int getHeight() {
- return engine.getHeight();
- }
-
- @Override
- public int getMinBuildHeight() {
- return engine.getMinHeight();
- }
}
diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/IrisChunkGenerator.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/IrisChunkGenerator.java
new file mode 100644
index 000000000..e61cbae71
--- /dev/null
+++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/IrisChunkGenerator.java
@@ -0,0 +1,244 @@
+package com.volmit.iris.core.nms.v1_20_R3;
+
+import com.mojang.datafixers.util.Pair;
+import com.mojang.serialization.Codec;
+import com.volmit.iris.Iris;
+import com.volmit.iris.engine.framework.Engine;
+import com.volmit.iris.engine.framework.ResultLocator;
+import com.volmit.iris.engine.framework.WrongEngineBroException;
+import com.volmit.iris.engine.object.IrisJigsawStructure;
+import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
+import com.volmit.iris.util.collection.KList;
+import com.volmit.iris.util.collection.KMap;
+import com.volmit.iris.util.collection.KSet;
+import com.volmit.iris.util.mantle.MantleFlag;
+import com.volmit.iris.util.math.Position2;
+import com.volmit.iris.util.scheduling.S;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Holder;
+import net.minecraft.core.HolderSet;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.WorldGenRegion;
+import net.minecraft.tags.StructureTags;
+import net.minecraft.tags.TagKey;
+import net.minecraft.util.random.WeightedRandomList;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.item.EnderEyeItem;
+import net.minecraft.world.level.LevelHeightAccessor;
+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.BiomeManager;
+import net.minecraft.world.level.biome.BiomeSource;
+import net.minecraft.world.level.biome.MobSpawnSettings;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkGenerator;
+import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
+import net.minecraft.world.level.levelgen.GenerationStep;
+import net.minecraft.world.level.levelgen.Heightmap;
+import net.minecraft.world.level.levelgen.RandomState;
+import net.minecraft.world.level.levelgen.blending.Blender;
+import net.minecraft.world.level.levelgen.structure.Structure;
+import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
+import org.bukkit.World;
+import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
+import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+
+public class IrisChunkGenerator extends CustomChunkGenerator {
+ private final ChunkGenerator delegate;
+ private final Engine engine;
+ private final BiomeSource biomeSource;
+ private final KMap, KSet> structures = new KMap<>();
+
+ public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
+ super(((CraftWorld) world).getHandle(), delegate, null);
+ this.delegate = delegate;
+ this.engine = engine;
+ this.biomeSource = new CustomBiomeSource(seed, engine, world);
+ var dimension = engine.getDimension();
+
+ KSet placements = new KSet<>();
+ addAll(dimension.getJigsawStructures(), placements);
+ for (var region : dimension.getAllRegions(engine)) {
+ addAll(region.getJigsawStructures(), placements);
+ for (var biome : region.getAllBiomes(engine))
+ addAll(biome.getJigsawStructures(), placements);
+ }
+ var stronghold = dimension.getStronghold();
+ if (stronghold != null)
+ placements.add(engine.getData().getJigsawStructureLoader().load(stronghold));
+ placements.removeIf(Objects::isNull);
+
+ var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow();
+ for (var s : placements) {
+ try {
+ String raw = s.getStructureKey();
+ if (raw == null) continue;
+ boolean tag = raw.startsWith("#");
+ if (tag) raw = raw.substring(1);
+
+ var location = new ResourceLocation(raw);
+ if (!tag) {
+ structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey());
+ continue;
+ }
+
+ var key = TagKey.create(Registries.STRUCTURE, location);
+ var set = registry.getTag(key).orElse(null);
+ if (set == null) {
+ Iris.error("Could not find structure tag: " + raw);
+ continue;
+ }
+ for (var holder : set) {
+ var resourceKey = holder.unwrapKey().orElse(null);
+ if (resourceKey == null) continue;
+ structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey());
+ }
+ } catch (Throwable e) {
+ Iris.error("Failed to load structure: " + s.getLoadKey());
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void addAll(KList placements, KSet structures) {
+ if (placements == null) return;
+ placements.stream()
+ .map(IrisJigsawStructurePlacement::getStructure)
+ .map(engine.getData().getJigsawStructureLoader()::load)
+ .filter(Objects::nonNull)
+ .forEach(structures::add);
+ }
+
+ @Override
+ public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) {
+ if (engine.getDimension().isDisableExplorerMaps())
+ return null;
+
+ KMap> structures = new KMap<>();
+ for (var holder : holders) {
+ if (holder == null) continue;
+ var key = holder.unwrapKey().orElse(null);
+ var set = this.structures.get(key);
+ if (set == null) continue;
+ for (var structure : set) {
+ structures.put(structure, holder);
+ }
+ }
+ if (structures.isEmpty())
+ return null;
+
+ var locator = ResultLocator.locateStructure(structures.keySet())
+ .then((e, p , s) -> structures.get(s.getLoadKey()));
+ if (findUnexplored)
+ locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s);
+
+ try {
+ var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get();
+ if (result == null) return null;
+ var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ());
+ return Pair.of(blockPos, result.obj());
+ } catch (WrongEngineBroException | ExecutionException | InterruptedException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected Codec extends ChunkGenerator> codec() {
+ return Codec.unit(null);
+ }
+
+ @Override
+ public ChunkGenerator getDelegate() {
+ if (delegate instanceof CustomChunkGenerator chunkGenerator)
+ return chunkGenerator.getDelegate();
+ return delegate;
+ }
+
+ @Override
+ public BiomeSource getBiomeSource() {
+ return biomeSource;
+ }
+
+ @Override
+ public int getMinY() {
+ return delegate.getMinY();
+ }
+
+ @Override
+ public int getSeaLevel() {
+ return delegate.getSeaLevel();
+ }
+
+ @Override
+ public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
+ delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
+ }
+
+ @Override
+ public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) {
+ delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess);
+ }
+
+ @Override
+ public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) {
+ delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features);
+ }
+
+ @Override
+ public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess 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
+ public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
+ return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
+ }
+
+ @Override
+ public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
+ delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
+ }
+
+ @Override
+ public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) {
+ delegate.addDebugScreenInfo(list, randomstate, blockposition);
+ }
+
+ @Override
+ public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) {
+ delegate.spawnOriginalMobs(regionlimitedworldaccess);
+ }
+
+ @Override
+ public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) {
+ return delegate.getSpawnHeight(levelheightaccessor);
+ }
+
+ @Override
+ public int getGenDepth() {
+ return delegate.getGenDepth();
+ }
+
+ @Override
+ public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
+ return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
+ }
+}
diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java
index 6ead57bf4..edbd353b6 100644
--- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java
+++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/NMSBinding.java
@@ -70,11 +70,13 @@ import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
+import com.mojang.datafixers.util.Pair;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.util.scheduling.J;
import net.minecraft.nbt.*;
import net.minecraft.nbt.Tag;
import net.minecraft.server.commands.data.BlockDataAccessor;
+import net.minecraft.tags.TagKey;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.EntityBlock;
import org.bukkit.*;
@@ -608,23 +610,9 @@ public class NMSBinding implements INMSBinding {
}
}
- public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) {
- CraftDolphin cd = (CraftDolphin)dolphin;
- cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
- cd.getHandle().setGotFish(true);
- }
-
- public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
- ServerLevel serverLevel = ((CraftWorld)world).getHandle();
- Class> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass();
- Field biomeSource = getField(clazz, BiomeSource.class);
- biomeSource.setAccessible(true);
- Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
- unsafeField.setAccessible(true);
- Unsafe unsafe = (Unsafe)unsafeField.get(null);
- CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world);
- unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource);
- biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource);
+ public void inject(long seed, Engine engine, World world) {
+ var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
+ chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
}
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
@@ -813,6 +801,23 @@ public class NMSBinding implements INMSBinding {
return new Color(rgba, true);
}
+ @Override
+ public KList getStructureKeys() {
+ KList keys = new KList<>();
+
+ var registry = registry().registry(Registries.STRUCTURE).orElse(null);
+ if (registry == null) return keys;
+ registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add);
+ registry.getTags()
+ .map(Pair::getFirst)
+ .map(TagKey::location)
+ .map(ResourceLocation::toString)
+ .map(s -> "#" + s)
+ .forEach(keys::add);
+
+ return keys;
+ }
+
private static Field getField(Class> clazz, Class> fieldType) throws NoSuchFieldException {
try {
for (Field f : clazz.getDeclaredFields()) {
diff --git a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/mca/MCATerrainChunk.java b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/mca/MCATerrainChunk.java
index 8c6adc3f4..55a5c8fca 100644
--- a/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/mca/MCATerrainChunk.java
+++ b/nms/v1_20_R3/src/main/java/com/volmit/iris/core/nms/v1_20_R3/mca/MCATerrainChunk.java
@@ -60,8 +60,6 @@ public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk {
@Override
public void setBiome(int x, int y, int z, Biome bio) {
- if (y < 0) return;
- y += getMinHeight();
if (y > getMaxHeight()) return;
chunk.setBiome(x & 15, y, z & 15, CraftBiome.bukkitToMinecraftHolder(bio));
}
@@ -82,10 +80,6 @@ public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk {
@Override
public void setBlock(int x, int y, int z, BlockData blockData) {
- if (y < 0) return;
- y += getMinHeight();
- if (y > getMaxHeight()) return;
-
if (blockData == null) {
Iris.error("NULL BD");
}
@@ -97,9 +91,6 @@ public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk {
}
private BlockState getBlockState(int x, int y, int z) {
- if (y < 0) {
- y = 0;
- }
y += getMinHeight();
if (y > getMaxHeight()) {
y = getMaxHeight();
diff --git a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/IrisChunkGenerator.java b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/IrisChunkGenerator.java
new file mode 100644
index 000000000..54382df77
--- /dev/null
+++ b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/IrisChunkGenerator.java
@@ -0,0 +1,239 @@
+package com.volmit.iris.core.nms.v1_20_R4;
+
+import com.mojang.datafixers.util.Pair;
+import com.mojang.serialization.MapCodec;
+import com.volmit.iris.Iris;
+import com.volmit.iris.engine.framework.Engine;
+import com.volmit.iris.engine.framework.ResultLocator;
+import com.volmit.iris.engine.framework.WrongEngineBroException;
+import com.volmit.iris.engine.object.IrisJigsawStructure;
+import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
+import com.volmit.iris.util.collection.KList;
+import com.volmit.iris.util.collection.KMap;
+import com.volmit.iris.util.collection.KSet;
+import com.volmit.iris.util.mantle.MantleFlag;
+import com.volmit.iris.util.math.Position2;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Holder;
+import net.minecraft.core.HolderSet;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.WorldGenRegion;
+import net.minecraft.tags.TagKey;
+import net.minecraft.util.random.WeightedRandomList;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.LevelHeightAccessor;
+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.BiomeManager;
+import net.minecraft.world.level.biome.BiomeSource;
+import net.minecraft.world.level.biome.MobSpawnSettings;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkGenerator;
+import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
+import net.minecraft.world.level.levelgen.GenerationStep;
+import net.minecraft.world.level.levelgen.Heightmap;
+import net.minecraft.world.level.levelgen.RandomState;
+import net.minecraft.world.level.levelgen.blending.Blender;
+import net.minecraft.world.level.levelgen.structure.Structure;
+import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
+import org.bukkit.World;
+import org.bukkit.craftbukkit.v1_20_R4.CraftWorld;
+import org.bukkit.craftbukkit.v1_20_R4.generator.CustomChunkGenerator;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.*;
+
+public class IrisChunkGenerator extends CustomChunkGenerator {
+ private final ChunkGenerator delegate;
+ private final Engine engine;
+ private final BiomeSource biomeSource;
+ private final KMap, KSet> structures = new KMap<>();
+
+ public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
+ super(((CraftWorld) world).getHandle(), delegate, null);
+ this.delegate = delegate;
+ this.engine = engine;
+ this.biomeSource = new CustomBiomeSource(seed, engine, world);
+ var dimension = engine.getDimension();
+
+ KSet placements = new KSet<>();
+ addAll(dimension.getJigsawStructures(), placements);
+ for (var region : dimension.getAllRegions(engine)) {
+ addAll(region.getJigsawStructures(), placements);
+ for (var biome : region.getAllBiomes(engine))
+ addAll(biome.getJigsawStructures(), placements);
+ }
+ var stronghold = dimension.getStronghold();
+ if (stronghold != null)
+ placements.add(engine.getData().getJigsawStructureLoader().load(stronghold));
+ placements.removeIf(Objects::isNull);
+
+ var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow();
+ for (var s : placements) {
+ try {
+ String raw = s.getStructureKey();
+ if (raw == null) continue;
+ boolean tag = raw.startsWith("#");
+ if (tag) raw = raw.substring(1);
+
+ var location = new ResourceLocation(raw);
+ if (!tag) {
+ structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey());
+ continue;
+ }
+
+ var key = TagKey.create(Registries.STRUCTURE, location);
+ var set = registry.getTag(key).orElse(null);
+ if (set == null) {
+ Iris.error("Could not find structure tag: " + raw);
+ continue;
+ }
+ for (var holder : set) {
+ var resourceKey = holder.unwrapKey().orElse(null);
+ if (resourceKey == null) continue;
+ structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey());
+ }
+ } catch (Throwable e) {
+ Iris.error("Failed to load structure: " + s.getLoadKey());
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void addAll(KList placements, KSet structures) {
+ if (placements == null) return;
+ placements.stream()
+ .map(IrisJigsawStructurePlacement::getStructure)
+ .map(engine.getData().getJigsawStructureLoader()::load)
+ .filter(Objects::nonNull)
+ .forEach(structures::add);
+ }
+
+ @Override
+ public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) {
+ if (engine.getDimension().isDisableExplorerMaps())
+ return null;
+
+ KMap> structures = new KMap<>();
+ for (var holder : holders) {
+ if (holder == null) continue;
+ var key = holder.unwrapKey().orElse(null);
+ var set = this.structures.get(key);
+ if (set == null) continue;
+ for (var structure : set) {
+ structures.put(structure, holder);
+ }
+ }
+ if (structures.isEmpty())
+ return null;
+
+ var locator = ResultLocator.locateStructure(structures.keySet())
+ .then((e, p , s) -> structures.get(s.getLoadKey()));
+ if (findUnexplored)
+ locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s);
+
+ try {
+ var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get();
+ if (result == null) return null;
+ var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ());
+ return Pair.of(blockPos, result.obj());
+ } catch (WrongEngineBroException | ExecutionException | InterruptedException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected MapCodec extends ChunkGenerator> codec() {
+ return MapCodec.unit(null);
+ }
+
+ @Override
+ public ChunkGenerator getDelegate() {
+ if (delegate instanceof CustomChunkGenerator chunkGenerator)
+ return chunkGenerator.getDelegate();
+ return delegate;
+ }
+
+ @Override
+ public BiomeSource getBiomeSource() {
+ return biomeSource;
+ }
+
+ @Override
+ public int getMinY() {
+ return delegate.getMinY();
+ }
+
+ @Override
+ public int getSeaLevel() {
+ return delegate.getSeaLevel();
+ }
+
+ @Override
+ public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
+ delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
+ }
+
+ @Override
+ public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) {
+ delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess);
+ }
+
+ @Override
+ public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) {
+ delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features);
+ }
+
+ @Override
+ public CompletableFuture fillFromNoise(Executor executor, Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess 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
+ public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
+ return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
+ }
+
+ @Override
+ public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
+ delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
+ }
+
+ @Override
+ public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) {
+ delegate.addDebugScreenInfo(list, randomstate, blockposition);
+ }
+
+ @Override
+ public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) {
+ delegate.spawnOriginalMobs(regionlimitedworldaccess);
+ }
+
+ @Override
+ public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) {
+ return delegate.getSpawnHeight(levelheightaccessor);
+ }
+
+ @Override
+ public int getGenDepth() {
+ return delegate.getGenDepth();
+ }
+
+ @Override
+ public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
+ return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
+ }
+}
diff --git a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java
index d0d1bf862..564e07fb6 100644
--- a/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java
+++ b/nms/v1_20_R4/src/main/java/com/volmit/iris/core/nms/v1_20_R4/NMSBinding.java
@@ -34,6 +34,7 @@ import java.util.logging.Logger;
import java.util.stream.Collectors;
import com.google.gson.JsonNull;
+import com.mojang.datafixers.util.Pair;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.google.common.base.Preconditions;
import com.google.gson.JsonElement;
@@ -75,6 +76,8 @@ import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag;
import net.minecraft.server.commands.data.BlockDataAccessor;
import net.minecraft.server.commands.data.DataCommands;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.tags.TagKey;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.Level;
@@ -96,6 +99,7 @@ import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlockStates;
import org.bukkit.craftbukkit.v1_20_R4.block.CraftBlockType;
import org.bukkit.craftbukkit.v1_20_R4.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_20_R4.entity.CraftDolphin;
+import org.bukkit.craftbukkit.v1_20_R4.generator.CustomChunkGenerator;
import org.bukkit.craftbukkit.v1_20_R4.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_20_R4.util.CraftNamespacedKey;
import org.bukkit.entity.Dolphin;
@@ -126,15 +130,12 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
-import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityType;
-import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunk;
-import sun.misc.Unsafe;
public class NMSBinding implements INMSBinding {
private final KMap baseBiomeCache = new KMap<>();
@@ -598,23 +599,9 @@ public class NMSBinding implements INMSBinding {
}
}
- public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) {
- CraftDolphin cd = (CraftDolphin)dolphin;
- cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
- cd.getHandle().setGotFish(true);
- }
-
- public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
- ServerLevel serverLevel = ((CraftWorld)world).getHandle();
- Class> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass();
- Field biomeSource = getField(clazz, BiomeSource.class);
- biomeSource.setAccessible(true);
- Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
- unsafeField.setAccessible(true);
- Unsafe unsafe = (Unsafe)unsafeField.get(null);
- CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world);
- unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource);
- biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource);
+ public void inject(long seed, Engine engine, World world) {
+ var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
+ chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
}
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
@@ -900,6 +887,23 @@ public class NMSBinding implements INMSBinding {
return (int) Math.pow(2 * radius + 1, 2);
}
+ @Override
+ public KList getStructureKeys() {
+ KList keys = new KList<>();
+
+ var registry = registry().registry(Registries.STRUCTURE).orElse(null);
+ if (registry == null) return keys;
+ registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add);
+ registry.getTags()
+ .map(Pair::getFirst)
+ .map(TagKey::location)
+ .map(ResourceLocation::toString)
+ .map(s -> "#" + s)
+ .forEach(keys::add);
+
+ return keys;
+ }
+
@Override
public IPackRepository getPackRepository() {
return packRepository;
diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/IrisChunkGenerator.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/IrisChunkGenerator.java
new file mode 100644
index 000000000..872daac16
--- /dev/null
+++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/IrisChunkGenerator.java
@@ -0,0 +1,240 @@
+package com.volmit.iris.core.nms.v1_21_R1;
+
+import com.mojang.datafixers.util.Pair;
+import com.mojang.serialization.MapCodec;
+import com.volmit.iris.Iris;
+import com.volmit.iris.engine.framework.Engine;
+import com.volmit.iris.engine.framework.ResultLocator;
+import com.volmit.iris.engine.framework.WrongEngineBroException;
+import com.volmit.iris.engine.object.IrisJigsawStructure;
+import com.volmit.iris.engine.object.IrisJigsawStructurePlacement;
+import com.volmit.iris.util.collection.KList;
+import com.volmit.iris.util.collection.KMap;
+import com.volmit.iris.util.collection.KSet;
+import com.volmit.iris.util.mantle.MantleFlag;
+import com.volmit.iris.util.math.Position2;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Holder;
+import net.minecraft.core.HolderSet;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.WorldGenRegion;
+import net.minecraft.tags.TagKey;
+import net.minecraft.util.random.WeightedRandomList;
+import net.minecraft.world.entity.MobCategory;
+import net.minecraft.world.level.LevelHeightAccessor;
+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.BiomeManager;
+import net.minecraft.world.level.biome.BiomeSource;
+import net.minecraft.world.level.biome.MobSpawnSettings;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.ChunkGenerator;
+import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
+import net.minecraft.world.level.levelgen.GenerationStep;
+import net.minecraft.world.level.levelgen.Heightmap;
+import net.minecraft.world.level.levelgen.RandomState;
+import net.minecraft.world.level.levelgen.blending.Blender;
+import net.minecraft.world.level.levelgen.structure.Structure;
+import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
+import org.bukkit.World;
+import org.bukkit.craftbukkit.v1_21_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_21_R1.generator.CustomChunkGenerator;
+
+import javax.annotation.Nullable;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+public class IrisChunkGenerator extends CustomChunkGenerator {
+ private final ChunkGenerator delegate;
+ private final Engine engine;
+ private final BiomeSource biomeSource;
+ private final KMap, KSet> structures = new KMap<>();
+
+ public IrisChunkGenerator(ChunkGenerator delegate, long seed, Engine engine, World world) {
+ super(((CraftWorld) world).getHandle(), delegate, null);
+ this.delegate = delegate;
+ this.engine = engine;
+ this.biomeSource = new CustomBiomeSource(seed, engine, world);
+ var dimension = engine.getDimension();
+
+ KSet placements = new KSet<>();
+ addAll(dimension.getJigsawStructures(), placements);
+ for (var region : dimension.getAllRegions(engine)) {
+ addAll(region.getJigsawStructures(), placements);
+ for (var biome : region.getAllBiomes(engine))
+ addAll(biome.getJigsawStructures(), placements);
+ }
+ var stronghold = dimension.getStronghold();
+ if (stronghold != null)
+ placements.add(engine.getData().getJigsawStructureLoader().load(stronghold));
+ placements.removeIf(Objects::isNull);
+
+ var registry = ((CraftWorld) world).getHandle().registryAccess().registry(Registries.STRUCTURE).orElseThrow();
+ for (var s : placements) {
+ try {
+ String raw = s.getStructureKey();
+ if (raw == null) continue;
+ boolean tag = raw.startsWith("#");
+ if (tag) raw = raw.substring(1);
+
+ var location = ResourceLocation.parse(raw);
+ if (!tag) {
+ structures.computeIfAbsent(ResourceKey.create(Registries.STRUCTURE, location), k -> new KSet<>()).add(s.getLoadKey());
+ continue;
+ }
+
+ var key = TagKey.create(Registries.STRUCTURE, location);
+ var set = registry.getTag(key).orElse(null);
+ if (set == null) {
+ Iris.error("Could not find structure tag: " + raw);
+ continue;
+ }
+ for (var holder : set) {
+ var resourceKey = holder.unwrapKey().orElse(null);
+ if (resourceKey == null) continue;
+ structures.computeIfAbsent(resourceKey, k -> new KSet<>()).add(s.getLoadKey());
+ }
+ } catch (Throwable e) {
+ Iris.error("Failed to load structure: " + s.getLoadKey());
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void addAll(KList placements, KSet structures) {
+ if (placements == null) return;
+ placements.stream()
+ .map(IrisJigsawStructurePlacement::getStructure)
+ .map(engine.getData().getJigsawStructureLoader()::load)
+ .filter(Objects::nonNull)
+ .forEach(structures::add);
+ }
+
+ @Override
+ public @Nullable Pair> findNearestMapStructure(ServerLevel level, HolderSet holders, BlockPos pos, int radius, boolean findUnexplored) {
+ if (engine.getDimension().isDisableExplorerMaps())
+ return null;
+
+ KMap> structures = new KMap<>();
+ for (var holder : holders) {
+ if (holder == null) continue;
+ var key = holder.unwrapKey().orElse(null);
+ var set = this.structures.get(key);
+ if (set == null) continue;
+ for (var structure : set) {
+ structures.put(structure, holder);
+ }
+ }
+ if (structures.isEmpty())
+ return null;
+
+ var locator = ResultLocator.locateStructure(structures.keySet())
+ .then((e, p , s) -> structures.get(s.getLoadKey()));
+ if (findUnexplored)
+ locator = locator.then((e, p, s) -> e.getMantle().getMantle().getChunk(p.getX(), p.getZ()).isFlagged(MantleFlag.DISCOVERED) ? null : s);
+
+ try {
+ var result = locator.find(engine, new Position2(pos.getX() >> 4, pos.getZ() >> 4), radius * 10L, i -> {}, false).get();
+ if (result == null) return null;
+ var blockPos = new BlockPos(result.getBlockX(), 0, result.getBlockZ());
+ return Pair.of(blockPos, result.obj());
+ } catch (WrongEngineBroException | ExecutionException | InterruptedException e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected MapCodec extends ChunkGenerator> codec() {
+ return MapCodec.unit(null);
+ }
+
+ @Override
+ public ChunkGenerator getDelegate() {
+ if (delegate instanceof CustomChunkGenerator chunkGenerator)
+ return chunkGenerator.getDelegate();
+ return delegate;
+ }
+
+ @Override
+ public BiomeSource getBiomeSource() {
+ return biomeSource;
+ }
+
+ @Override
+ public int getMinY() {
+ return delegate.getMinY();
+ }
+
+ @Override
+ public int getSeaLevel() {
+ return delegate.getSeaLevel();
+ }
+
+ @Override
+ public void createStructures(RegistryAccess iregistrycustom, ChunkGeneratorStructureState chunkgeneratorstructurestate, StructureManager structuremanager, ChunkAccess ichunkaccess, StructureTemplateManager structuretemplatemanager) {
+ delegate.createStructures(iregistrycustom, chunkgeneratorstructurestate, structuremanager, ichunkaccess, structuretemplatemanager);
+ }
+
+ @Override
+ public void buildSurface(WorldGenRegion regionlimitedworldaccess, StructureManager structuremanager, RandomState randomstate, ChunkAccess ichunkaccess) {
+ delegate.buildSurface(regionlimitedworldaccess, structuremanager, randomstate, ichunkaccess);
+ }
+
+ @Override
+ public void applyCarvers(WorldGenRegion regionlimitedworldaccess, long seed, RandomState randomstate, BiomeManager biomemanager, StructureManager structuremanager, ChunkAccess ichunkaccess, GenerationStep.Carving worldgenstage_features) {
+ delegate.applyCarvers(regionlimitedworldaccess, seed, randomstate, biomemanager, structuremanager, ichunkaccess, worldgenstage_features);
+ }
+
+ @Override
+ public CompletableFuture fillFromNoise(Blender blender, RandomState randomstate, StructureManager structuremanager, ChunkAccess 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
+ public WeightedRandomList getMobsAt(Holder holder, StructureManager structuremanager, MobCategory enumcreaturetype, BlockPos blockposition) {
+ return delegate.getMobsAt(holder, structuremanager, enumcreaturetype, blockposition);
+ }
+
+ @Override
+ public void applyBiomeDecoration(WorldGenLevel generatoraccessseed, ChunkAccess ichunkaccess, StructureManager structuremanager) {
+ delegate.applyBiomeDecoration(generatoraccessseed, ichunkaccess, structuremanager);
+ }
+
+ @Override
+ public void addDebugScreenInfo(List list, RandomState randomstate, BlockPos blockposition) {
+ delegate.addDebugScreenInfo(list, randomstate, blockposition);
+ }
+
+ @Override
+ public void spawnOriginalMobs(WorldGenRegion regionlimitedworldaccess) {
+ delegate.spawnOriginalMobs(regionlimitedworldaccess);
+ }
+
+ @Override
+ public int getSpawnHeight(LevelHeightAccessor levelheightaccessor) {
+ return delegate.getSpawnHeight(levelheightaccessor);
+ }
+
+ @Override
+ public int getGenDepth() {
+ return delegate.getGenDepth();
+ }
+
+ @Override
+ public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelheightaccessor, RandomState randomstate) {
+ return delegate.getBaseColumn(i, j, levelheightaccessor, randomstate);
+ }
+}
diff --git a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java
index 27d9908c7..900d85ec3 100644
--- a/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java
+++ b/nms/v1_21_R1/src/main/java/com/volmit/iris/core/nms/v1_21_R1/NMSBinding.java
@@ -36,6 +36,7 @@ import com.google.gson.JsonObject;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
+import com.mojang.datafixers.util.Pair;
import com.volmit.iris.core.nms.container.BiomeColor;
import com.volmit.iris.core.nms.container.IPackRepository;
import com.volmit.iris.core.nms.datapack.DataVersion;
@@ -57,6 +58,7 @@ import net.minecraft.nbt.Tag;
import net.minecraft.server.commands.data.BlockDataAccessor;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkMap;
+import net.minecraft.tags.TagKey;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.RandomSequences;
@@ -584,26 +586,17 @@ public class NMSBinding implements INMSBinding {
}
}
- public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) {
- CraftDolphin cd = (CraftDolphin)dolphin;
- cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
- cd.getHandle().setGotFish(true);
- }
-
public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class);
worldGenContextField.setAccessible(true);
var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap);
- Class> clazz = worldGenContext.generator().getClass();
- Field biomeSource = getField(clazz, BiomeSource.class);
- biomeSource.setAccessible(true);
- Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
- unsafeField.setAccessible(true);
- Unsafe unsafe = (Unsafe)unsafeField.get(null);
- CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world);
- unsafe.putObject(biomeSource.get(worldGenContext.generator()), unsafe.objectFieldOffset(biomeSource), customBiomeSource);
- biomeSource.set(worldGenContext.generator(), customBiomeSource);
+
+ var newContext = new WorldGenContext(
+ worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world),
+ worldGenContext.structureManager(), worldGenContext.lightEngine(), worldGenContext.mainThreadMailBox());
+
+ worldGenContextField.set(chunkMap, newContext);
}
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
@@ -889,6 +882,23 @@ public class NMSBinding implements INMSBinding {
return (int) Math.pow(2 * radius + 1, 2);
}
+ @Override
+ public KList getStructureKeys() {
+ KList keys = new KList<>();
+
+ var registry = registry().registry(Registries.STRUCTURE).orElse(null);
+ if (registry == null) return keys;
+ registry.keySet().stream().map(ResourceLocation::toString).forEach(keys::add);
+ registry.getTags()
+ .map(Pair::getFirst)
+ .map(TagKey::location)
+ .map(ResourceLocation::toString)
+ .map(s -> "#" + s)
+ .forEach(keys::add);
+
+ return keys;
+ }
+
@Override
public IPackRepository getPackRepository() {
return packRepository;