mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-06-19 23:31:27 +00:00
Merge remote-tracking branch 'origin/iris4' into iris4
This commit is contained in:
+1
-5
@@ -16,10 +16,6 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.function.Consumer
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
buildscript() {
|
buildscript() {
|
||||||
repositories {
|
repositories {
|
||||||
maven { url 'https://jitpack.io'}
|
maven { url 'https://jitpack.io'}
|
||||||
@@ -36,7 +32,7 @@ plugins {
|
|||||||
id "de.undercouch.download" version "5.0.1"
|
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
|
// ADD YOURSELF AS A NEW LINE IF YOU WANT YOUR OWN BUILD TASK GENERATED
|
||||||
// ======================== WINDOWS =============================
|
// ======================== WINDOWS =============================
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import com.volmit.iris.util.io.IO;
|
|||||||
import com.volmit.iris.util.mantle.TectonicPlate;
|
import com.volmit.iris.util.mantle.TectonicPlate;
|
||||||
import com.volmit.iris.util.nbt.mca.MCAFile;
|
import com.volmit.iris.util.nbt.mca.MCAFile;
|
||||||
import com.volmit.iris.util.nbt.mca.MCAUtil;
|
import com.volmit.iris.util.nbt.mca.MCAUtil;
|
||||||
|
import com.volmit.iris.util.parallel.MultiBurst;
|
||||||
import com.volmit.iris.util.plugin.VolmitSender;
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||||
@@ -50,6 +51,7 @@ import java.io.*;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
import java.util.zip.GZIPOutputStream;
|
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"})
|
@Decree(description = "Test", aliases = {"ip"})
|
||||||
public void network() {
|
public void network() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -50,10 +50,10 @@ public class ObjectResourceLoader extends ResourceLoader<IrisObject> {
|
|||||||
try {
|
try {
|
||||||
PrecisionStopwatch p = PrecisionStopwatch.start();
|
PrecisionStopwatch p = PrecisionStopwatch.start();
|
||||||
IrisObject t = new IrisObject(0, 0, 0);
|
IrisObject t = new IrisObject(0, 0, 0);
|
||||||
t.read(j);
|
|
||||||
t.setLoadKey(name);
|
t.setLoadKey(name);
|
||||||
t.setLoader(manager);
|
t.setLoader(manager);
|
||||||
t.setLoadFile(j);
|
t.setLoadFile(j);
|
||||||
|
t.read(j);
|
||||||
logLoad(j, t);
|
logLoad(j, t);
|
||||||
tlt.addAndGet(p.getMilliseconds());
|
tlt.addAndGet(p.getMilliseconds());
|
||||||
return t;
|
return t;
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ public class INMS {
|
|||||||
private static final Map<String, String> REVISION = Map.of(
|
private static final Map<String, String> REVISION = Map.of(
|
||||||
"1.20.5", "v1_20_R4",
|
"1.20.5", "v1_20_R4",
|
||||||
"1.20.6", "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
|
//@done
|
||||||
private static final INMSBinding binding = bind();
|
private static final INMSBinding binding = bind();
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import org.bukkit.entity.Entity;
|
|||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
import org.bukkit.generator.ChunkGenerator;
|
import org.bukkit.generator.ChunkGenerator;
|
||||||
|
import org.bukkit.generator.structure.Structure;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -110,8 +111,6 @@ public interface INMSBinding {
|
|||||||
|
|
||||||
ItemStack applyCustomNbt(ItemStack itemStack, KMap<String, Object> customNbt) throws IllegalArgumentException;
|
ItemStack applyCustomNbt(ItemStack itemStack, KMap<String, Object> 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;
|
void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException;
|
||||||
|
|
||||||
Vector3d getBoundingbox(org.bukkit.entity.EntityType entity);
|
Vector3d getBoundingbox(org.bukkit.entity.EntityType entity);
|
||||||
@@ -141,4 +140,6 @@ public interface INMSBinding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IPackRepository getPackRepository();
|
IPackRepository getPackRepository();
|
||||||
|
|
||||||
|
KList<String> getStructureKeys();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,7 @@ import net.bytebuddy.ByteBuddy;
|
|||||||
import net.bytebuddy.asm.Advice;
|
import net.bytebuddy.asm.Advice;
|
||||||
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
|
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy;
|
||||||
import net.bytebuddy.matcher.ElementMatchers;
|
import net.bytebuddy.matcher.ElementMatchers;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.*;
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.WorldCreator;
|
import org.bukkit.WorldCreator;
|
||||||
import org.bukkit.block.Biome;
|
import org.bukkit.block.Biome;
|
||||||
import org.bukkit.entity.Dolphin;
|
import org.bukkit.entity.Dolphin;
|
||||||
@@ -50,9 +47,10 @@ import org.bukkit.entity.Entity;
|
|||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
import org.bukkit.generator.ChunkGenerator;
|
import org.bukkit.generator.ChunkGenerator;
|
||||||
|
import org.bukkit.generator.structure.Structure;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.Color;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
public class NMSBinding1X implements INMSBinding {
|
public class NMSBinding1X implements INMSBinding {
|
||||||
@@ -104,11 +102,6 @@ public class NMSBinding1X implements INMSBinding {
|
|||||||
return itemStack;
|
return itemStack;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTreasurePos(Dolphin dolphin, BlockPos pos) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
|
public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
|
||||||
@@ -143,6 +136,15 @@ public class NMSBinding1X implements INMSBinding {
|
|||||||
return Color.GREEN;
|
return Color.GREEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KList<String> getStructureKeys() {
|
||||||
|
var list = Registry.STRUCTURE.stream()
|
||||||
|
.map(Structure::getKey)
|
||||||
|
.map(NamespacedKey::toString)
|
||||||
|
.toList();
|
||||||
|
return new KList<>(list);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag serializeEntity(Entity location) {
|
public CompoundTag serializeEntity(Entity location) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ public class IrisPregenerator {
|
|||||||
// updater.start();
|
// updater.start();
|
||||||
// }
|
// }
|
||||||
} else {
|
} else {
|
||||||
IrisPackBenchmarking.instance.finishedBenchmark(chunksPerSecondHistory);
|
IrisPackBenchmarking.getInstance().finishedBenchmark(chunksPerSecondHistory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import com.volmit.iris.Iris;
|
|||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
import com.volmit.iris.core.loader.IrisRegistrant;
|
import com.volmit.iris.core.loader.IrisRegistrant;
|
||||||
import com.volmit.iris.core.loader.ResourceLoader;
|
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.engine.object.annotations.*;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
@@ -309,6 +310,24 @@ public class SchemaBuilder {
|
|||||||
fancyType = "Enchantment Type";
|
fancyType = "Enchantment Type";
|
||||||
prop.put("$ref", "#/definitions/" + key);
|
prop.put("$ref", "#/definitions/" + key);
|
||||||
description.add(SYMBOL_TYPE__N + " Must be a valid Enchantment Type (use ctrl+space for auto complete!)");
|
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)) {
|
} else if (k.getType().equals(PotionEffectType.class)) {
|
||||||
String key = "enum-potion-effect-type";
|
String key = "enum-potion-effect-type";
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class UtilsSFG {
|
|||||||
}
|
}
|
||||||
if (ServerBootSFG.unsuportedversion) {
|
if (ServerBootSFG.unsuportedversion) {
|
||||||
Iris.safeguard(C.RED + "Server Version");
|
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) {
|
if (!ServerBootSFG.passedserversoftware) {
|
||||||
Iris.safeguard(C.YELLOW + "Unsupported Server Software");
|
Iris.safeguard(C.YELLOW + "Unsupported Server Software");
|
||||||
|
|||||||
@@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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<Integer, Integer, Integer, MatterStructurePOI> consumer) {
|
|
||||||
AtomicReference<MatterStructurePOI> 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<Integer, Integer, Integer, MatterStructurePOI> consumer) {
|
|
||||||
AtomicReference<MatterStructurePOI> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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<Player> 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");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -299,39 +299,44 @@ public class IrisEngine implements Engine {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IrisEngineData getEngineData() {
|
public IrisEngineData getEngineData() {
|
||||||
var ret = engineData.aquire(() -> {
|
return engineData.aquire(() -> {
|
||||||
//TODO: Method this file
|
//TODO: Method this file
|
||||||
File f = new File(getWorld().worldFolder(), "iris/engine-data/" + getDimension().getLoadKey() + ".json");
|
File f = new File(getWorld().worldFolder(), "iris/engine-data/" + getDimension().getLoadKey() + ".json");
|
||||||
|
IrisEngineData data = null;
|
||||||
|
|
||||||
if (!f.exists()) {
|
if (f.exists()) {
|
||||||
try {
|
try {
|
||||||
f.getParentFile().mkdirs();
|
data = new Gson().fromJson(IO.readAll(f), IrisEngineData.class);
|
||||||
IrisEngineData data = new IrisEngineData();
|
if (data == null) {
|
||||||
|
Iris.error("Failed to read Engine Data! Corrupted File? recreating...");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data == null) {
|
||||||
|
data = new IrisEngineData();
|
||||||
data.getStatistics().setIrisCreationVersion(Iris.instance.getIrisVersion());
|
data.getStatistics().setIrisCreationVersion(Iris.instance.getIrisVersion());
|
||||||
data.getStatistics().setMCVersion(Iris.instance.getMCVersion());
|
data.getStatistics().setMCVersion(Iris.instance.getMCVersion());
|
||||||
data.getStatistics().setIrisToUpgradedVersion(Iris.instance.getIrisVersion());
|
data.getStatistics().setIrisToUpgradedVersion(Iris.instance.getIrisVersion());
|
||||||
if (data.getStatistics().getIrisCreationVersion() == -1 || data.getStatistics().getMCVersion() == -1) {
|
if (data.getStatistics().getIrisCreationVersion() == -1 || data.getStatistics().getMCVersion() == -1) {
|
||||||
Iris.error("Failed to setup Engine Data!");
|
Iris.error("Failed to setup Engine Data!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (f.getParentFile().exists() || f.getParentFile().mkdirs()) {
|
||||||
|
try {
|
||||||
IO.writeAll(f, new Gson().toJson(data));
|
IO.writeAll(f, new Gson().toJson(data));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Iris.error("Failed to setup Engine Data!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
return data;
|
||||||
return new Gson().fromJson(IO.readAll(f), IrisEngineData.class);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new IrisEngineData();
|
|
||||||
});
|
});
|
||||||
if (ret == null) {
|
|
||||||
Iris.error("Failed to load Engine Data! (How did this happen?)");
|
|
||||||
return new IrisEngineData();
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
private final ChronoLatch ecl;
|
private final ChronoLatch ecl;
|
||||||
private final ChronoLatch cln;
|
private final ChronoLatch cln;
|
||||||
private final ChronoLatch chunkUpdater;
|
private final ChronoLatch chunkUpdater;
|
||||||
|
private final ChronoLatch chunkDiscovery;
|
||||||
private double energy = 25;
|
private double energy = 25;
|
||||||
private int entityCount = 0;
|
private int entityCount = 0;
|
||||||
private long charge = 0;
|
private long charge = 0;
|
||||||
@@ -92,12 +93,14 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
clw = null;
|
clw = null;
|
||||||
looper = null;
|
looper = null;
|
||||||
chunkUpdater = null;
|
chunkUpdater = null;
|
||||||
|
chunkDiscovery = null;
|
||||||
id = -1;
|
id = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IrisWorldManager(Engine engine) {
|
public IrisWorldManager(Engine engine) {
|
||||||
super(engine);
|
super(engine);
|
||||||
chunkUpdater = new ChronoLatch(3000);
|
chunkUpdater = new ChronoLatch(3000);
|
||||||
|
chunkDiscovery = new ChronoLatch(5000);
|
||||||
cln = new ChronoLatch(60000);
|
cln = new ChronoLatch(60000);
|
||||||
cl = new ChronoLatch(3000);
|
cl = new ChronoLatch(3000);
|
||||||
ecl = new ChronoLatch(250);
|
ecl = new ChronoLatch(250);
|
||||||
@@ -128,6 +131,10 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
updateChunks();
|
updateChunks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chunkDiscovery.flip()) {
|
||||||
|
discoverChunks();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (getDimension().isInfiniteEnergy()) {
|
if (getDimension().isInfiniteEnergy()) {
|
||||||
energy += 1000;
|
energy += 1000;
|
||||||
@@ -174,6 +181,19 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
|
|||||||
looper.start();
|
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() {
|
private void updateChunks() {
|
||||||
for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
|
for (Player i : getEngine().getWorld().realWorld().getPlayers()) {
|
||||||
int r = 1;
|
int r = 1;
|
||||||
|
|||||||
@@ -840,7 +840,7 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
|
|
||||||
default void gotoJigsaw(IrisJigsawStructure s, Player player, boolean teleport) {
|
default void gotoJigsaw(IrisJigsawStructure s, Player player, boolean teleport) {
|
||||||
if (s.getLoadKey().equals(getDimension().getStronghold())) {
|
if (s.getLoadKey().equals(getDimension().getStronghold())) {
|
||||||
KList<Position2> p = getDimension().getStrongholds(getSeedManager().getSpawn());
|
KList<Position2> p = getDimension().getStrongholds(getSeedManager().getMantle());
|
||||||
|
|
||||||
if (p.isEmpty()) {
|
if (p.isEmpty()) {
|
||||||
player.sendMessage(C.GOLD + "No strongholds in world.");
|
player.sendMessage(C.GOLD + "No strongholds in world.");
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ public abstract class EngineAssignedWorldManager extends EngineAssignedComponent
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
KList<Position2> positions = getEngine().getDimension().getStrongholds(getEngine().getSeedManager().getSpawn());
|
KList<Position2> positions = getEngine().getDimension().getStrongholds(getEngine().getSeedManager().getMantle());
|
||||||
if (positions.isEmpty()) {
|
if (positions.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.volmit.iris.engine.framework;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public interface ListFunction<T, R> extends Function<T, R> {
|
||||||
|
String key();
|
||||||
|
String fancyName();
|
||||||
|
}
|
||||||
@@ -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<T> {
|
||||||
|
static void cancelSearch() {
|
||||||
|
if (LocatorCanceller.cancel != null) {
|
||||||
|
LocatorCanceller.cancel.run();
|
||||||
|
LocatorCanceller.cancel = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ResultLocator<IrisJigsawStructure> locateStructure(Collection<String> keys) {
|
||||||
|
return (e, pos) -> {
|
||||||
|
var structure = e.getStructureAt(pos.getX(), pos.getZ());
|
||||||
|
return structure != null && keys.contains(structure.getLoadKey()) ? structure : null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static ResultLocator<IrisObject> locateObject(Collection<String> keys) {
|
||||||
|
return (e, pos) -> {
|
||||||
|
Set<String> 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 <R> ResultLocator<R> then(TriFunction<Engine, Position2, T, R> filter) {
|
||||||
|
return (e, pos) -> {
|
||||||
|
var t = find(e, pos);
|
||||||
|
return t != null ? filter.apply(e, pos, t) : null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
default Future<Result<T>> find(Engine engine, Position2 pos, long timeout, Consumer<Integer> 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<Result<T>> 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<Position2> 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>(T obj, Position2 pos) {
|
||||||
|
public int getBlockX() {
|
||||||
|
return (pos.getX() << 4) + 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBlockZ() {
|
||||||
|
return (pos.getZ() << 4) + 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -107,7 +107,7 @@ public interface EngineMantle extends IObjectPlacer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
default void setTile(int x, int y, int z, TileData d) {
|
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
|
@Override
|
||||||
|
|||||||
@@ -62,6 +62,8 @@ public class IrisBlockData extends IrisRegistrant {
|
|||||||
private IrisBlockData backup = null;
|
private IrisBlockData backup = null;
|
||||||
@Desc("Optional properties for this block data such as 'waterlogged': true")
|
@Desc("Optional properties for this block data such as 'waterlogged': true")
|
||||||
private KMap<String, Object> data = new KMap<>();
|
private KMap<String, Object> data = new KMap<>();
|
||||||
|
@Desc("Optional tile data for this block data")
|
||||||
|
private KMap<String, Object> tileData = new KMap<>();
|
||||||
|
|
||||||
public IrisBlockData(String b) {
|
public IrisBlockData(String b) {
|
||||||
this.block = b;
|
this.block = b;
|
||||||
@@ -200,9 +202,9 @@ public class IrisBlockData extends IrisRegistrant {
|
|||||||
public TileData tryGetTile(IrisData data) {
|
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.
|
//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();
|
var type = getBlockData(data).getMaterial();
|
||||||
if (!INMS.get().hasTile(type))
|
if (!INMS.get().hasTile(type) || tileData == null || tileData.isEmpty())
|
||||||
return null;
|
return null;
|
||||||
return new TileData().setMaterial(type).setProperties(this.data);
|
return new TileData(type, this.tileData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String keyify(String dat) {
|
private String keyify(String dat) {
|
||||||
|
|||||||
@@ -219,10 +219,8 @@ public class IrisDimension extends IrisRegistrant {
|
|||||||
private IrisMaterialPalette rockPalette = new IrisMaterialPalette().qclear().qadd("stone");
|
private IrisMaterialPalette rockPalette = new IrisMaterialPalette().qclear().qadd("stone");
|
||||||
@Desc("The palette of blocks for 'water'")
|
@Desc("The palette of blocks for 'water'")
|
||||||
private IrisMaterialPalette fluidPalette = new IrisMaterialPalette().qclear().qadd("water");
|
private IrisMaterialPalette fluidPalette = new IrisMaterialPalette().qclear().qadd("water");
|
||||||
@Desc("Remove cartographers so they do not crash the server (Iris worlds only)")
|
@Desc("Prevent cartographers to generate explorer maps (Iris worlds only)\nONLY TOUCH IF YOUR SERVER CRASHES WHILE GENERATING EXPLORER MAPS")
|
||||||
private boolean removeCartographersDueToCrash = true;
|
private boolean disableExplorerMaps = false;
|
||||||
@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("Collection of ores to be generated")
|
@Desc("Collection of ores to be generated")
|
||||||
@ArrayType(type = IrisOreGenerator.class, min = 1)
|
@ArrayType(type = IrisOreGenerator.class, min = 1)
|
||||||
private KList<IrisOreGenerator> ores = new KList<>();
|
private KList<IrisOreGenerator> ores = new KList<>();
|
||||||
|
|||||||
@@ -69,6 +69,10 @@ public class IrisJigsawStructure extends IrisRegistrant {
|
|||||||
@Desc("Set to true to prevent rotating the initial structure piece")
|
@Desc("Set to true to prevent rotating the initial structure piece")
|
||||||
private boolean disableInitialRotation = false;
|
private boolean disableInitialRotation = false;
|
||||||
|
|
||||||
|
@RegistryListFunction(StructureKeyFunction.class)
|
||||||
|
@Desc("The minecraft key to use when creating treasure maps")
|
||||||
|
private String structureKey = null;
|
||||||
|
|
||||||
private transient AtomicCache<Integer> maxDimension = new AtomicCache<>();
|
private transient AtomicCache<Integer> maxDimension = new AtomicCache<>();
|
||||||
|
|
||||||
private void loadPool(String p, KList<String> pools, KList<String> pieces) {
|
private void loadPool(String p, KList<String> pools, KList<String> pieces) {
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class IrisJigsawStructurePlacement implements IRare {
|
|||||||
private int separation = -1;
|
private int separation = -1;
|
||||||
|
|
||||||
@Desc("The method used to spread the structure")
|
@Desc("The method used to spread the structure")
|
||||||
private SpreadType spreadType = SpreadType.TRIANGULAR;
|
private SpreadType spreadType = SpreadType.LINEAR;
|
||||||
|
|
||||||
@ArrayType(type = IrisJigsawMinDistance.class)
|
@ArrayType(type = IrisJigsawMinDistance.class)
|
||||||
@Desc("List of minimum distances to check for")
|
@Desc("List of minimum distances to check for")
|
||||||
|
|||||||
@@ -385,14 +385,14 @@ public class IrisObject extends IrisRegistrant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void read(File file) throws IOException {
|
public void read(File file) throws IOException {
|
||||||
FileInputStream fin = new FileInputStream(file);
|
var fin = new BufferedInputStream(new FileInputStream(file));
|
||||||
try {
|
try {
|
||||||
read(fin);
|
read(fin);
|
||||||
fin.close();
|
fin.close();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
fin.close();
|
fin.close();
|
||||||
fin = new FileInputStream(file);
|
fin = new BufferedInputStream(new FileInputStream(file));
|
||||||
readLegacy(fin);
|
readLegacy(fin);
|
||||||
fin.close();
|
fin.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<Integer, IOFunction<DataInputStream, Handler>> 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<Pattern> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,11 +23,9 @@ import com.google.gson.GsonBuilder;
|
|||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.nms.INMS;
|
import com.volmit.iris.core.nms.INMS;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import lombok.Data;
|
import lombok.*;
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.BlockState;
|
|
||||||
import org.bukkit.block.TileState;
|
import org.bukkit.block.TileState;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
|
|
||||||
@@ -35,14 +33,19 @@ import java.io.DataInputStream;
|
|||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@Data
|
|
||||||
@SuppressWarnings("ALL")
|
@SuppressWarnings("ALL")
|
||||||
@Accessors(chain = true)
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
public class TileData implements Cloneable {
|
public class TileData implements Cloneable {
|
||||||
private static final Gson gson = new GsonBuilder().disableHtmlEscaping().setLenient().create();
|
private static final Gson gson = new GsonBuilder().disableHtmlEscaping().setLenient().create();
|
||||||
|
|
||||||
private Material material = null;
|
@NonNull
|
||||||
private KMap<String, Object> properties = new KMap<>();
|
private Material material;
|
||||||
|
@NonNull
|
||||||
|
private KMap<String, Object> properties;
|
||||||
|
|
||||||
public static boolean setTileState(Block block, TileData data) {
|
public static boolean setTileState(Block block, TileData data) {
|
||||||
if (block.getState() instanceof TileState && data.isApplicable(block.getBlockData()))
|
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 {
|
public static TileData read(DataInputStream in) throws IOException {
|
||||||
TileData d = new TileData();
|
if (!in.markSupported())
|
||||||
d.material = Material.matchMaterial(in.readUTF());
|
throw new IOException("Mark not supported");
|
||||||
d.properties = gson.fromJson(in.readUTF(), KMap.class);
|
in.mark(Integer.MAX_VALUE);
|
||||||
return d;
|
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) {
|
public boolean isApplicable(BlockData data) {
|
||||||
|
|||||||
+17
@@ -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<IrisData, KList<String>>> value();
|
||||||
|
}
|
||||||
+23
@@ -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<IrisData, KList<String>> {
|
||||||
|
@Override
|
||||||
|
public String key() {
|
||||||
|
return "structure-key";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String fancyName() {
|
||||||
|
return "Structure Key";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KList<String> apply(IrisData irisData) {
|
||||||
|
return INMS.get().getStructureKeys();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,8 @@ public enum MantleFlag {
|
|||||||
ETCHED,
|
ETCHED,
|
||||||
TILE,
|
TILE,
|
||||||
CUSTOM,
|
CUSTOM,
|
||||||
CUSTOM_ACTIVE;
|
CUSTOM_ACTIVE,
|
||||||
|
DISCOVERED;
|
||||||
|
|
||||||
static StateList getStateList() {
|
static StateList getStateList() {
|
||||||
return new StateList(MantleFlag.values());
|
return new StateList(MantleFlag.values());
|
||||||
|
|||||||
@@ -84,10 +84,10 @@ public class TectonicPlate {
|
|||||||
DataInputStream din;
|
DataInputStream din;
|
||||||
if (file.getName().endsWith("ttp.lz4b")) {
|
if (file.getName().endsWith("ttp.lz4b")) {
|
||||||
LZ4BlockInputStream lz4 = new LZ4BlockInputStream(fin);
|
LZ4BlockInputStream lz4 = new LZ4BlockInputStream(fin);
|
||||||
din = new DataInputStream(lz4);
|
din = new DataInputStream(new BufferedInputStream(lz4));
|
||||||
} else {
|
} else {
|
||||||
GZIPInputStream gzi = new GZIPInputStream(fin);
|
GZIPInputStream gzi = new GZIPInputStream(fin);
|
||||||
din = new DataInputStream(gzi);
|
din = new DataInputStream(new BufferedInputStream(gzi));
|
||||||
}
|
}
|
||||||
TectonicPlate p = new TectonicPlate(worldHeight, din);
|
TectonicPlate p = new TectonicPlate(worldHeight, din);
|
||||||
din.close();
|
din.close();
|
||||||
|
|||||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.util.matter;
|
||||||
|
|
||||||
|
import com.volmit.iris.engine.object.TileData;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class TileWrapper {
|
||||||
|
private final TileData data;
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ public class WorldMatter {
|
|||||||
matter.slice(MatterEntityGroup.class).writeInto(at);
|
matter.slice(MatterEntityGroup.class).writeInto(at);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matter.hasSlice(TileData.class)) {
|
if (matter.hasSlice(TileWrapper.class)) {
|
||||||
matter.slice(TileData.class).writeInto(at);
|
matter.slice(TileWrapper.class).writeInto(at);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ public class WorldMatter {
|
|||||||
s.getHeader().setAuthor(author);
|
s.getHeader().setAuthor(author);
|
||||||
s.slice(BlockData.class).readFrom(c.getLowerNE());
|
s.slice(BlockData.class).readFrom(c.getLowerNE());
|
||||||
s.slice(MatterEntityGroup.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();
|
s.trimSlices();
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package com.volmit.iris.util.matter.slices;
|
|||||||
import com.volmit.iris.engine.object.TileData;
|
import com.volmit.iris.engine.object.TileData;
|
||||||
import com.volmit.iris.util.data.palette.Palette;
|
import com.volmit.iris.util.data.palette.Palette;
|
||||||
import com.volmit.iris.util.matter.Sliced;
|
import com.volmit.iris.util.matter.Sliced;
|
||||||
|
import com.volmit.iris.util.matter.TileWrapper;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
|
||||||
@@ -30,28 +31,28 @@ import java.io.IOException;
|
|||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
@Sliced
|
@Sliced
|
||||||
public class TileMatter extends RawMatter<TileData> {
|
public class TileMatter extends RawMatter<TileWrapper> {
|
||||||
|
|
||||||
public TileMatter() {
|
public TileMatter() {
|
||||||
this(1, 1, 1);
|
this(1, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TileMatter(int width, int height, int depth) {
|
public TileMatter(int width, int height, int depth) {
|
||||||
super(width, height, depth, TileData.class);
|
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));
|
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) -> TileData.getTileState(w.getBlockAt(new Location(w, x, y, z))));
|
registerReader(World.class, (w, x, y, z) -> new TileWrapper(TileData.getTileState(w.getBlockAt(new Location(w, x, y, z)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Palette<TileData> getGlobalPalette() {
|
public Palette<TileWrapper> getGlobalPalette() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeNode(TileData b, DataOutputStream dos) throws IOException {
|
public void writeNode(TileWrapper b, DataOutputStream dos) throws IOException {
|
||||||
b.toBinary(dos);
|
b.getData().toBinary(dos);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TileData readNode(DataInputStream din) throws IOException {
|
public TileWrapper readNode(DataInputStream din) throws IOException {
|
||||||
return TileData.read(din);
|
return new TileWrapper(TileData.read(din));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<ResourceKey<Structure>, KSet<String>> 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<IrisJigsawStructure> 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<IrisJigsawStructurePlacement> placements, KSet<IrisJigsawStructure> 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<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel level, HolderSet<Structure> holders, BlockPos pos, int radius, boolean findUnexplored) {
|
||||||
|
if (engine.getDimension().isDisableExplorerMaps())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
KMap<String, Holder<Structure>> 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<ChunkAccess> 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<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> 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<String> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ import java.util.logging.Logger;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.google.gson.JsonNull;
|
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.BiomeColor;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
@@ -41,6 +42,7 @@ import net.minecraft.nbt.Tag;
|
|||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
import com.volmit.iris.core.nms.container.IPackRepository;
|
import com.volmit.iris.core.nms.container.IPackRepository;
|
||||||
import com.volmit.iris.util.io.IO;
|
import com.volmit.iris.util.io.IO;
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import com.google.common.base.Preconditions;
|
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) {
|
public void inject(long seed, Engine engine, World world) {
|
||||||
CraftDolphin cd = (CraftDolphin)dolphin;
|
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||||
cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
|
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||||
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 Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
||||||
@@ -865,6 +853,23 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new Color(rgba, true);
|
return new Color(rgba, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KList<String> getStructureKeys() {
|
||||||
|
KList<String> 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 {
|
private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException {
|
||||||
try {
|
try {
|
||||||
for (Field f : clazz.getDeclaredFields()) {
|
for (Field f : clazz.getDeclaredFields()) {
|
||||||
|
|||||||
@@ -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<ResourceKey<Structure>, KSet<String>> 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<IrisJigsawStructure> 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<IrisJigsawStructurePlacement> placements, KSet<IrisJigsawStructure> 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<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel level, HolderSet<Structure> holders, BlockPos pos, int radius, boolean findUnexplored) {
|
||||||
|
if (engine.getDimension().isDisableExplorerMaps())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
KMap<String, Holder<Structure>> 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<ChunkAccess> 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<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> 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<String> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@ import java.util.logging.Logger;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.google.gson.JsonNull;
|
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.BiomeColor;
|
||||||
import com.volmit.iris.core.nms.container.IPackRepository;
|
import com.volmit.iris.core.nms.container.IPackRepository;
|
||||||
import com.volmit.iris.util.io.IO;
|
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.*;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import com.google.common.base.Preconditions;
|
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) {
|
public void inject(long seed, Engine engine, World world) {
|
||||||
CraftDolphin cd = (CraftDolphin)dolphin;
|
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||||
cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
|
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -802,6 +790,23 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new Color(rgba, true);
|
return new Color(rgba, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KList<String> getStructureKeys() {
|
||||||
|
KList<String> 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 {
|
private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException {
|
||||||
try {
|
try {
|
||||||
for (Field f : clazz.getDeclaredFields()) {
|
for (Field f : clazz.getDeclaredFields()) {
|
||||||
|
|||||||
@@ -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<ResourceKey<Structure>, KSet<String>> 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<IrisJigsawStructure> 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<IrisJigsawStructurePlacement> placements, KSet<IrisJigsawStructure> 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<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel level, HolderSet<Structure> holders, BlockPos pos, int radius, boolean findUnexplored) {
|
||||||
|
if (engine.getDimension().isDisableExplorerMaps())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
KMap<String, Holder<Structure>> 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<ChunkAccess> 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<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> 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<String> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ import java.util.logging.Logger;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.google.gson.JsonNull;
|
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.BiomeColor;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
@@ -41,6 +42,7 @@ import net.minecraft.nbt.Tag;
|
|||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
import com.volmit.iris.core.nms.container.IPackRepository;
|
import com.volmit.iris.core.nms.container.IPackRepository;
|
||||||
import com.volmit.iris.util.io.IO;
|
import com.volmit.iris.util.io.IO;
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
@@ -603,17 +605,9 @@ public class NMSBinding implements INMSBinding {
|
|||||||
cd.getHandle().setGotFish(true);
|
cd.getHandle().setGotFish(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
|
public void inject(long seed, Engine engine, World world) {
|
||||||
ServerLevel serverLevel = ((CraftWorld)world).getHandle();
|
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||||
Class<?> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass();
|
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||||
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 Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
||||||
@@ -805,6 +799,23 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new Color(rgba, true);
|
return new Color(rgba, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KList<String> getStructureKeys() {
|
||||||
|
KList<String> 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 {
|
private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException {
|
||||||
try {
|
try {
|
||||||
for (Field f : clazz.getDeclaredFields()) {
|
for (Field f : clazz.getDeclaredFields()) {
|
||||||
|
|||||||
@@ -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<ResourceKey<Structure>, KSet<String>> 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<IrisJigsawStructure> 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<IrisJigsawStructurePlacement> placements, KSet<IrisJigsawStructure> 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<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel level, HolderSet<Structure> holders, BlockPos pos, int radius, boolean findUnexplored) {
|
||||||
|
if (engine.getDimension().isDisableExplorerMaps())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
KMap<String, Holder<Structure>> 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<ChunkAccess> 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<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> 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<String> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ import com.mojang.datafixers.util.Pair;
|
|||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.JsonOps;
|
import com.mojang.serialization.JsonOps;
|
||||||
import com.mojang.serialization.Lifecycle;
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.nms.INMSBinding;
|
import com.volmit.iris.core.nms.INMSBinding;
|
||||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
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.MinecraftServer;
|
||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.entity.EntityDimensions;
|
import net.minecraft.world.entity.EntityDimensions;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
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) {
|
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
||||||
Field[] fields = net.minecraft.world.entity.EntityType.class.getDeclaredFields();
|
Field[] fields = net.minecraft.world.entity.EntityType.class.getDeclaredFields();
|
||||||
for (Field field : fields) {
|
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 {
|
public void inject(long seed, Engine engine, World world) {
|
||||||
ServerLevel serverLevel = ((CraftWorld)world).getHandle();
|
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||||
Class<?> clazz = serverLevel.getChunkSource().chunkMap.generator.getClass();
|
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -803,6 +791,23 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new Color(rgba, true);
|
return new Color(rgba, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KList<String> getStructureKeys() {
|
||||||
|
KList<String> 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 {
|
private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException {
|
||||||
try {
|
try {
|
||||||
for (Field f : clazz.getDeclaredFields()) {
|
for (Field f : clazz.getDeclaredFields()) {
|
||||||
|
|||||||
@@ -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<ResourceKey<Structure>, KSet<String>> 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<IrisJigsawStructure> 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<IrisJigsawStructurePlacement> placements, KSet<IrisJigsawStructure> 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<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel level, HolderSet<Structure> holders, BlockPos pos, int radius, boolean findUnexplored) {
|
||||||
|
if (engine.getDimension().isDisableExplorerMaps())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
KMap<String, Holder<Structure>> 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<ChunkAccess> 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<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> 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<String> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,11 +34,13 @@ import java.util.logging.Logger;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.google.gson.JsonNull;
|
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.BiomeColor;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
import com.volmit.iris.core.nms.container.IPackRepository;
|
import com.volmit.iris.core.nms.container.IPackRepository;
|
||||||
import com.volmit.iris.util.io.IO;
|
import com.volmit.iris.util.io.IO;
|
||||||
import net.minecraft.server.commands.DataPackCommand;
|
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) {
|
public void inject(long seed, Engine engine, World world) {
|
||||||
CraftDolphin cd = (CraftDolphin)dolphin;
|
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||||
cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
|
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||||
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 Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
||||||
@@ -805,6 +793,23 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new Color(rgba, true);
|
return new Color(rgba, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KList<String> getStructureKeys() {
|
||||||
|
KList<String> 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 {
|
private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException {
|
||||||
try {
|
try {
|
||||||
for (Field f : clazz.getDeclaredFields()) {
|
for (Field f : clazz.getDeclaredFields()) {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import com.volmit.iris.util.mantle.MantleFlag;
|
|||||||
import com.volmit.iris.util.math.RNG;
|
import com.volmit.iris.util.math.RNG;
|
||||||
import com.volmit.iris.util.parallel.MultiBurst;
|
import com.volmit.iris.util.parallel.MultiBurst;
|
||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||||
|
import lombok.Getter;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
import net.minecraft.core.QuartPos;
|
import net.minecraft.core.QuartPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
@@ -68,6 +69,8 @@ public class Headless implements IHeadless, LevelHeightAccessor {
|
|||||||
private final KMap<String, Holder<Biome>> customBiomes = new KMap<>();
|
private final KMap<String, Holder<Biome>> customBiomes = new KMap<>();
|
||||||
private final KMap<org.bukkit.block.Biome, Holder<Biome>> minecraftBiomes = new KMap<>();
|
private final KMap<org.bukkit.block.Biome, Holder<Biome>> minecraftBiomes = new KMap<>();
|
||||||
private final RNG BIOME_RNG;
|
private final RNG BIOME_RNG;
|
||||||
|
private final @Getter int minBuildHeight;
|
||||||
|
private final @Getter int height;
|
||||||
private boolean closed = false;
|
private boolean closed = false;
|
||||||
|
|
||||||
public Headless(NMSBinding binding, Engine engine) {
|
public Headless(NMSBinding binding, Engine engine) {
|
||||||
@@ -75,6 +78,8 @@ public class Headless implements IHeadless, LevelHeightAccessor {
|
|||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
this.storage = new RegionFileStorage(new File(engine.getWorld().worldFolder(), "region").toPath(), true);
|
this.storage = new RegionFileStorage(new File(engine.getWorld().worldFolder(), "region").toPath(), true);
|
||||||
this.BIOME_RNG = new RNG(engine.getSeedManager().getBiome());
|
this.BIOME_RNG = new RNG(engine.getSeedManager().getBiome());
|
||||||
|
this.minBuildHeight = engine.getDimension().getMinHeight();
|
||||||
|
this.height = engine.getDimension().getMaxHeight() - minBuildHeight;
|
||||||
engine.getWorld().headless(this);
|
engine.getWorld().headless(this);
|
||||||
|
|
||||||
var dimKey = engine.getDimension().getLoadKey();
|
var dimKey = engine.getDimension().getLoadKey();
|
||||||
@@ -107,6 +112,8 @@ public class Headless implements IHeadless, LevelHeightAccessor {
|
|||||||
@Override
|
@Override
|
||||||
public boolean exists(int x, int z) {
|
public boolean exists(int x, int z) {
|
||||||
if (closed) return false;
|
if (closed) return false;
|
||||||
|
if (engine.getWorld().hasRealWorld() && engine.getWorld().realWorld().isChunkLoaded(x, z))
|
||||||
|
return true;
|
||||||
try {
|
try {
|
||||||
CompoundTag tag = storage.read(new ChunkPos(x, z));
|
CompoundTag tag = storage.read(new ChunkPos(x, z));
|
||||||
return tag != null && !"empty".equals(tag.getString("Status"));
|
return tag != null && !"empty".equals(tag.getString("Status"));
|
||||||
@@ -270,14 +277,4 @@ public class Headless implements IHeadless, LevelHeightAccessor {
|
|||||||
minecraftBiomes.clear();
|
minecraftBiomes.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight() {
|
|
||||||
return engine.getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMinBuildHeight() {
|
|
||||||
return engine.getMinHeight();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<ResourceKey<Structure>, KSet<String>> 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<IrisJigsawStructure> 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<IrisJigsawStructurePlacement> placements, KSet<IrisJigsawStructure> 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<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel level, HolderSet<Structure> holders, BlockPos pos, int radius, boolean findUnexplored) {
|
||||||
|
if (engine.getDimension().isDisableExplorerMaps())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
KMap<String, Holder<Structure>> 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<ChunkAccess> 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<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> 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<String> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -70,11 +70,13 @@ import net.minecraft.world.level.dimension.DimensionType;
|
|||||||
import net.minecraft.world.level.dimension.LevelStem;
|
import net.minecraft.world.level.dimension.LevelStem;
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||||
import com.volmit.iris.util.scheduling.J;
|
import com.volmit.iris.util.scheduling.J;
|
||||||
import net.minecraft.nbt.*;
|
import net.minecraft.nbt.*;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import org.bukkit.*;
|
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) {
|
public void inject(long seed, Engine engine, World world) {
|
||||||
CraftDolphin cd = (CraftDolphin)dolphin;
|
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||||
cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
|
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||||
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 Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
||||||
@@ -813,6 +801,23 @@ public class NMSBinding implements INMSBinding {
|
|||||||
return new Color(rgba, true);
|
return new Color(rgba, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KList<String> getStructureKeys() {
|
||||||
|
KList<String> 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 {
|
private static Field getField(Class<?> clazz, Class<?> fieldType) throws NoSuchFieldException {
|
||||||
try {
|
try {
|
||||||
for (Field f : clazz.getDeclaredFields()) {
|
for (Field f : clazz.getDeclaredFields()) {
|
||||||
|
|||||||
@@ -60,8 +60,6 @@ public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBiome(int x, int y, int z, Biome bio) {
|
public void setBiome(int x, int y, int z, Biome bio) {
|
||||||
if (y < 0) return;
|
|
||||||
y += getMinHeight();
|
|
||||||
if (y > getMaxHeight()) return;
|
if (y > getMaxHeight()) return;
|
||||||
chunk.setBiome(x & 15, y, z & 15, CraftBiome.bukkitToMinecraftHolder(bio));
|
chunk.setBiome(x & 15, y, z & 15, CraftBiome.bukkitToMinecraftHolder(bio));
|
||||||
}
|
}
|
||||||
@@ -82,10 +80,6 @@ public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBlock(int x, int y, int z, BlockData blockData) {
|
public void setBlock(int x, int y, int z, BlockData blockData) {
|
||||||
if (y < 0) return;
|
|
||||||
y += getMinHeight();
|
|
||||||
if (y > getMaxHeight()) return;
|
|
||||||
|
|
||||||
if (blockData == null) {
|
if (blockData == null) {
|
||||||
Iris.error("NULL BD");
|
Iris.error("NULL BD");
|
||||||
}
|
}
|
||||||
@@ -97,9 +91,6 @@ public record MCATerrainChunk(ChunkAccess chunk) implements TerrainChunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BlockState getBlockState(int x, int y, int z) {
|
private BlockState getBlockState(int x, int y, int z) {
|
||||||
if (y < 0) {
|
|
||||||
y = 0;
|
|
||||||
}
|
|
||||||
y += getMinHeight();
|
y += getMinHeight();
|
||||||
if (y > getMaxHeight()) {
|
if (y > getMaxHeight()) {
|
||||||
y = getMaxHeight();
|
y = getMaxHeight();
|
||||||
|
|||||||
@@ -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<ResourceKey<Structure>, KSet<String>> 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<IrisJigsawStructure> 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<IrisJigsawStructurePlacement> placements, KSet<IrisJigsawStructure> 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<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel level, HolderSet<Structure> holders, BlockPos pos, int radius, boolean findUnexplored) {
|
||||||
|
if (engine.getDimension().isDisableExplorerMaps())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
KMap<String, Holder<Structure>> 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<ChunkAccess> 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<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> 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<String> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,6 +34,7 @@ import java.util.logging.Logger;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.google.gson.JsonNull;
|
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.BiomeColor;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
@@ -75,6 +76,8 @@ import net.minecraft.nbt.StringTag;
|
|||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.server.commands.data.BlockDataAccessor;
|
import net.minecraft.server.commands.data.BlockDataAccessor;
|
||||||
import net.minecraft.server.commands.data.DataCommands;
|
import net.minecraft.server.commands.data.DataCommands;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.item.component.CustomData;
|
import net.minecraft.world.item.component.CustomData;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
import net.minecraft.world.level.Level;
|
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.CraftBlockType;
|
||||||
import org.bukkit.craftbukkit.v1_20_R4.block.data.CraftBlockData;
|
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.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.inventory.CraftItemStack;
|
||||||
import org.bukkit.craftbukkit.v1_20_R4.util.CraftNamespacedKey;
|
import org.bukkit.craftbukkit.v1_20_R4.util.CraftNamespacedKey;
|
||||||
import org.bukkit.entity.Dolphin;
|
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.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.world.entity.EntityType;
|
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.Block;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import sun.misc.Unsafe;
|
|
||||||
|
|
||||||
public class NMSBinding implements INMSBinding {
|
public class NMSBinding implements INMSBinding {
|
||||||
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
||||||
@@ -598,23 +599,9 @@ public class NMSBinding implements INMSBinding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTreasurePos(Dolphin dolphin, com.volmit.iris.core.nms.container.BlockPos pos) {
|
public void inject(long seed, Engine engine, World world) {
|
||||||
CraftDolphin cd = (CraftDolphin)dolphin;
|
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||||
cd.getHandle().setTreasurePos(new BlockPos(pos.getX(), pos.getY(), pos.getZ()));
|
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||||
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 Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
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);
|
return (int) Math.pow(2 * radius + 1, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KList<String> getStructureKeys() {
|
||||||
|
KList<String> 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
|
@Override
|
||||||
public IPackRepository getPackRepository() {
|
public IPackRepository getPackRepository() {
|
||||||
return packRepository;
|
return packRepository;
|
||||||
|
|||||||
@@ -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<ResourceKey<Structure>, KSet<String>> 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<IrisJigsawStructure> 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<IrisJigsawStructurePlacement> placements, KSet<IrisJigsawStructure> 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<BlockPos, Holder<Structure>> findNearestMapStructure(ServerLevel level, HolderSet<Structure> holders, BlockPos pos, int radius, boolean findUnexplored) {
|
||||||
|
if (engine.getDimension().isDisableExplorerMaps())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
KMap<String, Holder<Structure>> 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<ChunkAccess> 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<MobSpawnSettings.SpawnerData> getMobsAt(Holder<Biome> 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<String> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ import com.google.gson.JsonObject;
|
|||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import com.mojang.serialization.JsonOps;
|
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.BiomeColor;
|
||||||
import com.volmit.iris.core.nms.container.IPackRepository;
|
import com.volmit.iris.core.nms.container.IPackRepository;
|
||||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
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.commands.data.BlockDataAccessor;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||||
import net.minecraft.util.GsonHelper;
|
import net.minecraft.util.GsonHelper;
|
||||||
import net.minecraft.world.RandomSequences;
|
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 {
|
public void inject(long seed, Engine engine, World world) throws NoSuchFieldException, IllegalAccessException {
|
||||||
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||||
var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class);
|
var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class);
|
||||||
worldGenContextField.setAccessible(true);
|
worldGenContextField.setAccessible(true);
|
||||||
var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap);
|
var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap);
|
||||||
Class<?> clazz = worldGenContext.generator().getClass();
|
|
||||||
Field biomeSource = getField(clazz, BiomeSource.class);
|
var newContext = new WorldGenContext(
|
||||||
biomeSource.setAccessible(true);
|
worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world),
|
||||||
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
worldGenContext.structureManager(), worldGenContext.lightEngine(), worldGenContext.mainThreadMailBox());
|
||||||
unsafeField.setAccessible(true);
|
|
||||||
Unsafe unsafe = (Unsafe)unsafeField.get(null);
|
worldGenContextField.set(chunkMap, newContext);
|
||||||
CustomBiomeSource customBiomeSource = new CustomBiomeSource(seed, engine, world);
|
|
||||||
unsafe.putObject(biomeSource.get(worldGenContext.generator()), unsafe.objectFieldOffset(biomeSource), customBiomeSource);
|
|
||||||
biomeSource.set(worldGenContext.generator(), customBiomeSource);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3d getBoundingbox(org.bukkit.entity.EntityType entity) {
|
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);
|
return (int) Math.pow(2 * radius + 1, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KList<String> getStructureKeys() {
|
||||||
|
KList<String> 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
|
@Override
|
||||||
public IPackRepository getPackRepository() {
|
public IPackRepository getPackRepository() {
|
||||||
return packRepository;
|
return packRepository;
|
||||||
|
|||||||
Reference in New Issue
Block a user